import typing as t
import datetime
import pandas as pd
import calendar as cal
from commodutil import forwards
from pylim import lim
from pylim import limutils
from pylim import limqueryutils as lqu

def quarterly(symbol: str, quarter: int = 1, start_year=datetime.date.today().year,
              end_year=datetime.date.today().year + 2, start_date=t.Optional[datetime.date]):
    """
    Given a symbol or formula, calculate the quarterly average and return as a series of yearly timeseries
    :param symbol:
    :param quarter:
    :param start_year:
    :param end_year:
    :return:
    """
    cmap = {1: ['F', 'G', 'H'], 2: ['J', 'K', 'M'], 3: ['N', 'Q', 'U'], 4: ['V', 'X', 'Z']}

    if quarter == 0:  # calc Q1,Q2,Q3,Q4
        df = lim.contracts(symbol, start_year=start_year, end_year=end_year, start_date=start_date)
        dfs = []
        for qtr in cmap:  # filter columns for each quarter
            d = df[[x for x in df.columns if x[-1] in cmap[qtr]]]
            d = limutils.convert_lim_contracts_to_datetime(d)
            d = limutils.pivots_contract_by_year(d)
            d = d.rename(columns={x: 'Q%s_%s' % (qtr, x) for x in d.columns})  # eg Q12020
            dfs.append(d)
        return pd.concat(dfs, 1)
    else:
        return calendar(symbol, start_year=start_year, end_year=end_year, months=cmap[quarter], start_date=start_date)

def calendar(symbol, start_year=datetime.date.today().year, end_year=datetime.date.today().year + 2,
             months: t.Optional[t.Tuple[str, ...]] = None,
             start_date: t.Optional[datetime.date] = None):
    """
    Given a symbol or formula, calculate the calendar (yearly) average and return as a series of yearly timeseries
    :param months:
    :param symbol:
    :param quarter:
    :param start_year:
    :param end_year:
    :return:
    """
    df = lim.contracts(symbol, start_year=start_year, end_year=end_year, months=months, start_date=start_date)
    df = limutils.convert_lim_contracts_to_datetime(df)
    return limutils.pivots_contract_by_year(df)

def spread(symbol: str, x: t.Tuple[int, str], y: t.Tuple[int, str], z: t.Optional[t.Tuple[int, str]] = None,
           start_year: datetime.date.today().year = None, end_year: datetime.date.today().year = None,
           start_date: t.Optional[datetime.date] = None) -> pd.DataFrame:
    contracts = lim.contracts(symbol, start_year=start_year, end_year=end_year, months=[x, y, z],
                                 start_date=start_date)
    contracts = limutils.convert_lim_contracts_to_datetime(contracts)

    if z is not None:
        if (isinstance(x, int) or x.isnumeric()) and (isinstance(y, int) or y.isnumeric()) and (isinstance(z, int) or z.isnumeric()):
            return forwards.fly(contracts, int(x), int(y), int(z))

    if (isinstance(x, int) or x.isnumeric()) and (isinstance(y, int) or y.isnumeric()):
        return forwards.time_spreads_monthly(contracts, x, y)

    if isinstance(x, str) and isinstance(y, str):
        x, y = x.upper(), y.upper()
        if x.startswith('Q') and y.startswith('Q'):
            return forwards.time_spreads_quarterly(contracts, x, y)

        if x.startswith('CAL') and y.startswith('CAL'):
            return forwards.cal_spreads(forwards.cal_contracts(contracts))

def fly(symbol: str, x: t.Tuple[int, str], y: t.Tuple[int, str], z: t.Optional[t.Tuple[int, str]],
        start_year: t.Optional[datetime.date] = None,
        end_year=None, start_date: t.Optional[datetime.date] = None):
    return spread(symbol, x, y, z, start_year=start_year, end_year=end_year, start_date=start_date)

def multi_spread(symbol, spreads, start_year: datetime.date.today().year = None,
                 end_year: datetime.date.today().year = None,
                 start_date: t.Optional[datetime.date] = None) -> pd.DataFrame:
    contracts = lim.contracts(symbol, start_year=start_year, end_year=end_year, start_date=start_date)
    contracts = limutils.convert_lim_contracts_to_datetime(contracts)

    dfs = []
    for spread in spreads:
        r = forwards.time_spreads_monthly(contracts, spread[0], spread[1])
        r = r.rename(
            columns={x: '%s%s_%s' % (cal.month_abbr[spread[0]], cal.month_abbr[spread[1]], x) for x in r.columns})
        dfs.append(r)

    res = pd.concat(dfs, 1)
    return res


from django.urls import path, include
from main.views import CityViewSet, CountryViewSet, ImageViewSet, OptionViewSet, AutoMarkViewSet, AutoModelViewSet, AutoSaloonViewSet, ComplectationViewSet, OfferViewSet, DiscountViewSet, test
from rest_framework import routers
from rest_framework_jwt.views import obtain_jwt_token

urlpatterns = [
    path('login/', obtain_jwt_token),
    path('test/', test),
]

router = routers.DefaultRouter()
router.register('cities', CityViewSet, )
router.register('countries', CountryViewSet, )
router.register('images', ImageViewSet, )
router.register('options', OptionViewSet, )
router.register('marks', AutoMarkViewSet, )
router.register('models', AutoModelViewSet, )
router.register('saloons', AutoSaloonViewSet, )
router.register('complectations', ComplectationViewSet, )
router.register('offers', OfferViewSet, )
router.register('discounts', DiscountViewSet, )

urlpatterns += router.urls


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
        ('people', '0002_auto_20161122_0857'),
    ]

    operations = [
        migrations.AddField(
            model_name='user',
            name='first_name',
            field=models.CharField(max_length=30, verbose_name='Nombre', blank=True),
        ),
        migrations.AddField(
            model_name='user',
            name='last_name',
            field=models.CharField(max_length=30, verbose_name='Apellido', blank=True),
        ),
    ]


import math
import torch

from torch import nn
from typing import Tuple

def init_param(module: nn.Module, gain: float = 1.) -> nn.Module:
    """
    Init the input neural network's linear layers Y = AX + B according to
        1.) A is orthogonal with gain
        2.) B = 0

    Parameters
    ----------
    module: nn.Module
        input neural network
    gain: float

    Returns
    -------
    module: nn.Module
        initialized neural network
    """
    nn.init.orthogonal_(module.weight.data, gain=gain)
    nn.init.constant_(module.bias.data, 0)
    return module

def build_mlp(
        input_dim: int,
        output_dim: int,
        hidden_units: tuple = (64, 64),
        hidden_activation: nn.Module = nn.Tanh(),
        init: bool = False,
        output_activation: nn.Module = None,
        gain: float = 1.
) -> nn.Module:
    """
    Build a MLP network

    Parameters
    ----------
    input_dim: int
        dimension of the input of the neural network
    output_dim: int
        dimension of the output of the neural network
    hidden_units: tuple
        hidden units of the neural network
    hidden_activation: nn.Module
        activation function of the hidden layers
    init: bool
        whether to init the neural network to be orthogonal weighted
    output_activation: nn.Module
        activation function of the output layer
    gain: float
        gain for the init function

    Returns
    -------
    nn: nn.Module
        MLP net
    """
    layers = []
    units = input_dim
    for next_units in hidden_units:
        if init:
            layers.append(init_param(nn.Linear(units, next_units), gain=gain))
        else:
            layers.append(nn.Linear(units, next_units))
        layers.append(hidden_activation)
        units = next_units
    if init:
        layers.append(init_param(nn.Linear(units, output_dim), gain=gain))
    else:
        layers.append(nn.Linear(units, output_dim))
    if output_activation is not None:
        layers.append(output_activation)
    return nn.Sequential(*layers)

def build_param_list(
        input_dim: int,
        output_dim: int,
        device: torch.device,
        hidden_units: tuple = (64, 64),
        requires_grad: bool = True
) -> Tuple[list, list]:
    """
    Build parameter list of the neural network

    Parameters
    ----------
    input_dim: int
        dimension of the input of the neural network
    output_dim: int
        dimension of the output of the neural network
    device: torch.device
        cpu or cuda
    hidden_units: tuple
        hidden units of the neural network
    requires_grad: bool
        whether the parameters need to be trained

    Returns
    -------
    weights: a list of torch.Tensor
        weights of each layer of the neural network
    biases: a list of torch.Tensor
        biases of each layer of the neural network
    """
    weights = []
    biases = []
    units = input_dim
    for next_units in hidden_units:
        weights.append(torch.zeros(next_units, units, requires_grad=requires_grad).to(device))
        biases.append(torch.zeros(next_units, requires_grad=requires_grad).to(device))
        units = next_units
    weights.append(torch.zeros(output_dim, units, requires_grad=requires_grad).to(device))
    biases.append(torch.zeros(output_dim, requires_grad=requires_grad).to(device))
    return weights, biases

def calculate_log_pi(log_stds: torch.Tensor, noises: torch.Tensor, actions: torch.Tensor) -> torch.Tensor:
    """
    Calculate log(\pi(a|s)) given log(std) of the distribution, noises, and actions to take

    Parameters
    ----------
    log_stds: torch.Tensor
        log(std) of the distribution
    noises: torch.Tensor
        noises added to the action
    actions: torch.Tensor
        actions to take

    Returns
    -------
    log_pi: torch.Tensor
        log(\pi(a|s))
    """
    gaussian_log_probs = (-0.5 * noises.pow(2) - log_stds).sum(
        dim=-1, keepdim=True) - 0.5 * math.log(2 * math.pi) * log_stds.size(-1)

    return gaussian_log_probs - torch.log(
        1 - actions.pow(2) + 1e-6).sum(dim=-1, keepdim=True)

def reparameterize(means: torch.Tensor, log_stds: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
    """
    Get action and its log_pi according to mean and log_std

    Parameters
    ----------
    means: torch.Tensor
        mean value of the action
    log_stds: torch.Tensor
        log(std) of the action

    Returns
    -------
    actions: torch.Tensor
        actions to take
    log_pi: torch.Tensor
        log_pi of the actions
    """
    noises = torch.randn_like(means)
    us = means + noises * log_stds.exp()
    actions = torch.tanh(us)
    return actions, calculate_log_pi(log_stds, noises, actions)

def atanh(x: torch.Tensor) -> torch.Tensor:
    """
    Return atanh of the input. Modified torch.atanh in case the output is nan.

    Parameters
    ----------
    x: torch.Tensor
        input

    Returns
    -------
    y: torch.Tensor
        atanh(x)
    """
    return 0.5 * (torch.log(1 + x + 1e-6) - torch.log(1 - x + 1e-6))

def evaluate_log_pi(means: torch.Tensor, log_stds: torch.Tensor, actions: torch.Tensor) -> torch.Tensor:
    """
    Evaluate the log(\pi(a|s)) of the given action

    Parameters
    ----------
    means: torch.Tensor
        mean value of the action distribution
    log_stds: torch.Tensor
        log(std) of the action distribution
    actions: torch.Tensor
        actions taken

    Returns
    -------
    log_pi: : torch.Tensor
        log(\pi(a|s))
    """
    noises = (atanh(actions) - means) / (log_stds.exp() + 1e-8)
    return calculate_log_pi(log_stds, noises, actions)


"""
FILE: skeleton_parser.py
------------------
Author: Firas Abuzaid (fabuzaid@stanford.edu)
Author: Perth Charernwattanagul (puch@stanford.edu)
Modified: 04/21/2014

Skeleton parser for CS564 programming project 1. Has useful imports and
functions for parsing, including:

1) Directory handling -- the parser takes a list of eBay json files
and opens each file inside of a loop. You just need to fill in the rest.
2) Dollar value conversions -- the json files store dollar value amounts in
a string like $3,453.23 -- we provide a function to convert it to a string
like XXXXX.xx.
3) Date/time conversions -- the json files store dates/ times in the form
Mon-DD-YY HH:MM:SS -- we wrote a function (transformDttm) that converts to the
for YYYY-MM-DD HH:MM:SS, which will sort chronologically in SQL.

Your job is to implement the parseJson function, which is invoked on each file by
the main function. We create the initial Python dictionary object of items for
you; the rest is up to you!
Happy parsing!
"""

import sys
from json import loads
from re import sub

columnSeparator = "|"

itemTable = ""
catTable = ""
sellerTable = ""
bidderTable = ""
bidTable = ""

# Dictionary of months used for date transformation
MONTHS = {'Jan':'01','Feb':'02','Mar':'03','Apr':'04','May':'05','Jun':'06',\
        'Jul':'07','Aug':'08','Sep':'09','Oct':'10','Nov':'11','Dec':'12'}

"""
Returns true if a file ends in .json
"""
def isJson(f):
    return len(f) > 5 and f[-5:] == '.json'

"""
Converts month to a number, e.g. 'Dec' to '12'
"""
def transformMonth(mon):
    if mon in MONTHS:
        return MONTHS[mon]
    else:
        return mon

"""
Transforms a timestamp from Mon-DD-YY HH:MM:SS to YYYY-MM-DD HH:MM:SS
"""
def transformDttm(dttm):
    dttm = dttm.strip().split(' ')
    dt = dttm[0].split('-')
    date = '20' + dt[2] + '-'
    date += transformMonth(dt[0]) + '-' + dt[1]
    return date + ' ' + dttm[1]

"""
Transform a dollar value amount from a string like $3,453.23 to XXXXX.xx
"""

def transformDollar(money):
    if money == None or len(money) == 0:
        return money
    return sub(r'[^\d.]', '', money)

"""
Parses a single json file. Currently, there's a loop that iterates over each
item in the data set. Your job is to extend this functionality to create all
of the necessary SQL tables for your database.
"""

def parse_items(item):
    line = ""

    if 'ItemID'in item and item['ItemID'] != None:
        item['ItemID']= item['ItemID'].replace('"', '""')
        line += item['ItemID']
        line = line + columnSeparator
    else :
        line = line + 'null'
        line = line + columnSeparator

    if 'Name' in item and item['Name'] != None:
        item['Name']= item['Name'].replace('"', '""')
        line += '\"' + item['Name'] + '\"'
        line += columnSeparator
    else:
        line += 'null'
        line += columnSeparator

    if 'Currently' in item and item['Currently'] != None:
        item['Currently']= item['Currently'].replace('"', '""')
        line += '\"' + transformDollar(item['Currently']) + '\"'
        line += columnSeparator
    else:
        line += 'null'
        line += columnSeparator

    if 'Buy_Price' in item and item['Buy_Price'] != None:
        item['Buy_Price']= item['Buy_Price'].replace('"', '""')
        line += '\"' + transformDollar(item['Buy_Price']) + '\"'
        line += columnSeparator
    else:
        line += 'null'
        line += columnSeparator

    if 'First_Bid' in item and item['First_Bid'] != None:
        item['First_Bid']= item['First_Bid'].replace('"', '""')
        line += '"' + transformDollar(item['First_Bid']) + '"'
        line += columnSeparator
    else:
        line += 'null'
        line += columnSeparator

    if 'Number_of_Bids' in item and item['Number_of_Bids'] != None:
        item['Number_of_Bids']= item['Number_of_Bids'].replace('"', '""')
        line += item['Number_of_Bids']
        line += columnSeparator
    else:
        line += 'null'
        line += columnSeparator

    if 'Started' in item and item['Started'] != None:
        item['Started']= item['Started'].replace('"', '""')
        line += '"' + transformDttm(item['Started']) + '"'
        line += columnSeparator
    else:
        line += 'null'
        line += columnSeparator

    if 'Ends' in item and item['Ends'] != None:
        item['Ends']= item['Ends'].replace('"', '""')
        line += '"' + transformDttm(item['Ends']) + '"'
        line += columnSeparator
    else:
        line += 'null'
        line += columnSeparator

    if 'Description' in item and item['Description'] != None:
        item['Description'] = item['Description'].replace('\"', '""')
        line += '"' + item['Description'] + '"'
        line += columnSeparator
    else:
        line += 'null'
        line += columnSeparator

    if 'Seller' in item and item['Seller'] != None:
        item['Seller']['UserID']= item['Seller']['UserID'].replace('"', '""')
        line += '"' + item['Seller']['UserID'] + '"'

    else:
        line += 'null'

    line += '\n'
    return line

def categoryTable(item):
    line = ""
    if 'ItemID' in item and item['ItemID'] != None :
        if('Category' in item and item['Category'] != None):
            i = 0
            for ele in item['Category']:
                line += item['ItemID']
                line += columnSeparator
                item['Category'][i] = item['Category'][i].replace('"', '""')
                line += '"' + item['Category'][i] + '"'
                line += '\n'
                i += 1
        else:
            for i in item['Category']:
                line += item['ItemID']
                line += columnSeparator
                line += 'null'
                line += '\n'
    return line

def sTable(item):
    line = ""
    if 'Seller' in item and item['Seller'] != None:
        line += '"' + item['Seller']['UserID'] + '"'
        line += columnSeparator
        if 'Location' in item and item['Location'] != None:
            item['Location']= item['Location'].replace('"', '""')
            line += '"' + item['Location'] + '"'
        else:
            line += 'null'
        line += columnSeparator
        if 'Country' in item and item['Country'] != None:
            item['Country']= item['Country'].replace('"', '""')
            line += '"' + item['Country'] + '"'
        else:
            line += 'null'
        line += columnSeparator
        if 'Rating' in item['Seller'] and item['Seller']['Rating'] != None:
            line += item['Seller']['Rating']
        else:
            line += 'null'
        line += '\n'
    return line

def bTable(item):
    line = ""

    if 'Bids' in item and item['Bids'] != None:
        for bidder in item['Bids']:
            #print(bidder)
            bidder['Bid']['Bidder']['UserID']= bidder['Bid']['Bidder']['UserID'].replace('"', '""')
            line += '\"' + bidder['Bid']['Bidder']['UserID'] + '\"'
            line += columnSeparator
            if 'Location' in bidder['Bid']['Bidder'] and bidder['Bid']['Bidder']['Location'] != None:
                bidder['Bid']['Bidder']['Location']= bidder['Bid']['Bidder']['Location'].replace('"', '""')
                line += '"' + bidder['Bid']['Bidder']['Location'] + '"'
            else:
                line += 'null'

            line += columnSeparator

            if 'Country' in bidder['Bid']['Bidder'] and bidder['Bid']['Bidder']['Country'] != None:
                bidder['Bid']['Bidder']['Country']= bidder['Bid']['Bidder']['Country'].replace('"', '""')
                line += '"' + bidder['Bid']['Bidder']['Country'] + '"'
            else:
                line += 'null'

            line += columnSeparator

            if 'Rating' in bidder['Bid']['Bidder'] and bidder['Bid']['Bidder']['Rating'] != None:
                line += bidder['Bid']['Bidder']['Rating']
            else:
                line += 'null'

            line += '\n'
    return line

def parse_bid(item):
    line = ""
    if 'Bids' in item and item['Bids'] != None:
        for bid_i in item['Bids']:
            line += item['ItemID']
            line += columnSeparator

            line += '"' + bid_i['Bid']['Bidder']['UserID'] + '"'
            line += columnSeparator

            if bid_i['Bid']['Time'] != None:

                line += '"' + transformDttm(bid_i['Bid']['Time']) + '"'
            else:
                line += 'null'
            line += columnSeparator
            if bid_i['Bid']['Amount'] != None:
                bid_i['Bid']['Amount']= bid_i['Bid']['Amount'].replace('"', '""')
                line += '"' + transformDollar(bid_i['Bid']['Amount']) + '"'
            else: line += 'null'
            line += '\n'

    return line

def parseJson(json_file):
    global itemTable, catTable, bidderTable, bidTable, sellerTable
    with open(json_file, 'r') as f:
        items = loads(f.read())['Items'] # creates a Python dictionary of Items for the supplied json file

        for item in items:
            """
            TODO: traverse the items dictionary to extract information from the
            given `json_file' and generate the necessary .dat files to generate
            the SQL tables based on your relation design
            """

            itemTable += parse_items(item)
            catTable += categoryTable(item)
            bidderTable += bTable(item)
            sellerTable += sTable(item)
            bidTable += parse_bid(item)

def output():
    f1 = open("itemTable.dat", "a")
    f2 = open("categoryTable.dat", "a")
    f3 = open("bidderTable.dat", "a")
    f4 = open("bidTable.dat", "a")
    f5 = open("sellerTable.dat", "a")
    f1.write(itemTable)
    f2.write(catTable)
    f3.write(bidderTable)
    f4.write(bidTable)
    f5.write(sellerTable)
    f1.close()
    f2.close()
    f3.close()
    f4.close()
    f5.close()

"""
Loops through each json files provided on the command line and passes each file
to the parser
"""
def main(argv):
    if len(argv) < 2:
        print >> sys.stderr, 'Usage: python skeleton_json_parser.py <path to json files>'
        sys.exit(1)
    # loops over all .json files in the argument
    for f in argv[1:]:
        if isJson(f):
            parseJson(f)
            print("Success parsing " + f)
    output()

if __name__ == '__main__':
    main(sys.argv)


from django.conf.urls import url

from . import views

urlpatterns = [
    # 客户资料新增
    url(r'^add/$', views.add, name='add'),
    # 客户资料更新
    url(r'^update/$', views.update, name='update'),
    # 客户资料 ID 查询
    url(r'^get/(.+)/$', views.get_by_id, name='get_by_id'),
    # 客户资料 删除
    url(r'^delete/(.+)/$', views.delete, name='delete'),
    # 提交pcb 资料 审核
    url(r'^check/(.+)/$', views.check, name='check'),
    # 客户上传PCB文件
    url(r'^pcb_upload/$', views.pcb_upload, name='pcb_upload'),
    # 客户下载PCB文件
    url(r'^pcb_down/(.+)/$', views.pcb_down, name='pcb_down'),
    # 客户资料 customer_id 查询 （查询客户自己的资料信息）
    url(r'^list/$', views.list_by_customer_id, name='list_by_customer_id'),
    # 分页查询客户资料
    url(r'^list/(\d+)/(\d+)/$', views.list, name='list'),
    # 查询 PCB 资料 下单 信息
    url(r'^get_order_info/(.+)/$', views.get__order_info, name='get__order_info'),
]


#!/usr/bin/env python3

import itertools

import networkx as nx
import numpy as np

from pgmpy.base import UndirectedGraph
from pgmpy.global_vars import logger
from pgmpy.independencies import Independencies

class DAG(nx.DiGraph):
    """
    Base class for all Directed Graphical Models.

    Each node in the graph can represent either a random variable, `Factor`,
    or a cluster of random variables. Edges in the graph represent the
    dependencies between these.

    Parameters
    ----------
    data: input graph
        Data to initialize graph. If data=None (default) an empty graph is
        created. The data can be an edge list or any Networkx graph object.

    Examples
    --------
    Create an empty DAG with no nodes and no edges

    >>> from pgmpy.base import DAG
    >>> G = DAG()

    G can be grown in several ways:

    **Nodes:**

    Add one node at a time:

    >>> G.add_node(node='a')

    Add the nodes from any container (a list, set or tuple or the nodes
    from another graph).

    >>> G.add_nodes_from(nodes=['a', 'b'])

    **Edges:**

    G can also be grown by adding edges.

    Add one edge,

    >>> G.add_edge(u='a', v='b')

    a list of edges,

    >>> G.add_edges_from(ebunch=[('a', 'b'), ('b', 'c')])

    If some edges connect nodes not yet in the model, the nodes
    are added automatically. There are no errors when adding
    nodes or edges that already exist.

    **Shortcuts:**

    Many common graph features allow python syntax for speed reporting.

    >>> 'a' in G     # check if node in graph
    True
    >>> len(G)  # number of nodes in graph
    3
    """

    def __init__(self, ebunch=None, latents=set()):
        super(DAG, self).__init__(ebunch)
        self.latents = set(latents)
        cycles = []
        try:
            cycles = list(nx.find_cycle(self))
        except nx.NetworkXNoCycle:
            pass
        else:
            out_str = "Cycles are not allowed in a DAG."
            out_str += "\nEdges indicating the path taken for a loop: "
            out_str += "".join([f"({u},{v}) " for (u, v) in cycles])
            raise ValueError(out_str)

    def add_node(self, node, weight=None, latent=False):
        """
        Adds a single node to the Graph.

        Parameters
        ----------
        node: str, int, or any hashable python object.
            The node to add to the graph.

        weight: int, float
            The weight of the node.

        latent: boolean (default: False)
            Specifies whether the variable is latent or not.

        Examples
        --------
        >>> from pgmpy.base import DAG
        >>> G = DAG()
        >>> G.add_node(node='A')
        >>> sorted(G.nodes())
        ['A']

        Adding a node with some weight.
        >>> G.add_node(node='B', weight=0.3)

        The weight of these nodes can be accessed as:
        >>> G.nodes['B']
        {'weight': 0.3}
        >>> G.nodes['A']
        {'weight': None}
        """

        # Check for networkx 2.0 syntax
        if isinstance(node, tuple) and len(node) == 2 and isinstance(node[1], dict):
            node, attrs = node
            if attrs.get("weight", None) is not None:
                attrs["weight"] = weight
        else:
            attrs = {"weight": weight}

        if latent:
            self.latents.add(node)

        super(DAG, self).add_node(node, weight=weight)

    def add_nodes_from(self, nodes, weights=None, latent=False):
        """
        Add multiple nodes to the Graph.

        **The behviour of adding weights is different than in networkx.

        Parameters
        ----------
        nodes: iterable container
            A container of nodes (list, dict, set, or any hashable python
            object).

        weights: list, tuple (default=None)
            A container of weights (int, float). The weight value at index i
            is associated with the variable at index i.

        latent: list, tuple (default=False)
            A container of boolean. The value at index i tells whether the
            node at index i is latent or not.

        Examples
        --------
        >>> from pgmpy.base import DAG
        >>> G = DAG()
        >>> G.add_nodes_from(nodes=['A', 'B', 'C'])
        >>> G.nodes()
        NodeView(('A', 'B', 'C'))

        Adding nodes with weights:
        >>> G.add_nodes_from(nodes=['D', 'E'], weights=[0.3, 0.6])
        >>> G.nodes['D']
        {'weight': 0.3}
        >>> G.nodes['E']
        {'weight': 0.6}
        >>> G.nodes['A']
        {'weight': None}
        """
        nodes = list(nodes)

        if isinstance(latent, bool):
            latent = [latent] * len(nodes)

        if weights:
            if len(nodes) != len(weights):
                raise ValueError(
                    "The number of elements in nodes and weights" "should be equal."
                )
            for index in range(len(nodes)):
                self.add_node(
                    node=nodes[index], weight=weights[index], latent=latent[index]
                )
        else:
            for index in range(len(nodes)):
                self.add_node(node=nodes[index], latent=latent[index])

    def add_edge(self, u, v, weight=None):
        """
        Add an edge between u and v.

        The nodes u and v will be automatically added if they are
        not already in the graph.

        Parameters
        ----------
        u, v : nodes
            Nodes can be any hashable Python object.

        weight: int, float (default=None)
            The weight of the edge

        Examples
        --------
        >>> from pgmpy.base import DAG
        >>> G = DAG()
        >>> G.add_nodes_from(nodes=['Alice', 'Bob', 'Charles'])
        >>> G.add_edge(u='Alice', v='Bob')
        >>> G.nodes()
        NodeView(('Alice', 'Bob', 'Charles'))
        >>> G.edges()
        OutEdgeView([('Alice', 'Bob')])

        When the node is not already present in the graph:
        >>> G.add_edge(u='Alice', v='Ankur')
        >>> G.nodes()
        NodeView(('Alice', 'Ankur', 'Bob', 'Charles'))
        >>> G.edges()
        OutEdgeView([('Alice', 'Bob'), ('Alice', 'Ankur')])

        Adding edges with weight:
        >>> G.add_edge('Ankur', 'Maria', weight=0.1)
        >>> G.edge['Ankur']['Maria']
        {'weight': 0.1}
        """
        super(DAG, self).add_edge(u, v, weight=weight)

    def add_edges_from(self, ebunch, weights=None):
        """
        Add all the edges in ebunch.

        If nodes referred in the ebunch are not already present, they
        will be automatically added. Node names can be any hashable python
        object.

        **The behavior of adding weights is different than networkx.

        Parameters
        ----------
        ebunch : container of edges
            Each edge given in the container will be added to the graph.
            The edges must be given as 2-tuples (u, v).

        weights: list, tuple (default=None)
            A container of weights (int, float). The weight value at index i
            is associated with the edge at index i.

        Examples
        --------
        >>> from pgmpy.base import DAG
        >>> G = DAG()
        >>> G.add_nodes_from(nodes=['Alice', 'Bob', 'Charles'])
        >>> G.add_edges_from(ebunch=[('Alice', 'Bob'), ('Bob', 'Charles')])
        >>> G.nodes()
        NodeView(('Alice', 'Bob', 'Charles'))
        >>> G.edges()
        OutEdgeView([('Alice', 'Bob'), ('Bob', 'Charles')])

        When the node is not already in the model:
        >>> G.add_edges_from(ebunch=[('Alice', 'Ankur')])
        >>> G.nodes()
        NodeView(('Alice', 'Bob', 'Charles', 'Ankur'))
        >>> G.edges()
        OutEdgeView([('Alice', 'Bob'), ('Bob', 'Charles'), ('Alice', 'Ankur')])

        Adding edges with weights:
        >>> G.add_edges_from([('Ankur', 'Maria'), ('Maria', 'Mason')],
        ...                  weights=[0.3, 0.5])
        >>> G.edge['Ankur']['Maria']
        {'weight': 0.3}
        >>> G.edge['Maria']['Mason']
        {'weight': 0.5}
        """
        ebunch = list(ebunch)

        if weights:
            if len(ebunch) != len(weights):
                raise ValueError(
                    "The number of elements in ebunch and weights" "should be equal"
                )
            for index in range(len(ebunch)):
                self.add_edge(ebunch[index][0], ebunch[index][1], weight=weights[index])
        else:
            for edge in ebunch:
                self.add_edge(edge[0], edge[1])

    def get_parents(self, node):
        """
        Returns a list of parents of node.

        Throws an error if the node is not present in the graph.

        Parameters
        ----------
        node: string, int or any hashable python object.
            The node whose parents would be returned.

        Examples
        --------
        >>> from pgmpy.base import DAG
        >>> G = DAG(ebunch=[('diff', 'grade'), ('intel', 'grade')])
        >>> G.get_parents(node='grade')
        ['diff', 'intel']
        """
        return list(self.predecessors(node))

    def moralize(self):
        """
        Removes all the immoralities in the DAG and creates a moral
        graph (UndirectedGraph).

        A v-structure X->Z<-Y is an immorality if there is no directed edge
        between X and Y.

        Examples
        --------
        >>> from pgmpy.base import DAG
        >>> G = DAG(ebunch=[('diff', 'grade'), ('intel', 'grade')])
        >>> moral_graph = G.moralize()
        >>> moral_graph.edges()
        EdgeView([('intel', 'grade'), ('intel', 'diff'), ('grade', 'diff')])
        """
        moral_graph = UndirectedGraph()
        moral_graph.add_nodes_from(self.nodes())
        moral_graph.add_edges_from(self.to_undirected().edges())

        for node in self.nodes():
            moral_graph.add_edges_from(
                itertools.combinations(self.get_parents(node), 2)
            )

        return moral_graph

    def get_leaves(self):
        """
        Returns a list of leaves of the graph.

        Examples
        --------
        >>> from pgmpy.base import DAG
        >>> graph = DAG([('A', 'B'), ('B', 'C'), ('B', 'D')])
        >>> graph.get_leaves()
        ['C', 'D']
        """
        return [node for node, out_degree in self.out_degree_iter() if out_degree == 0]

    def out_degree_iter(self, nbunch=None, weight=None):
        if nx.__version__.startswith("1"):
            return super(DAG, self).out_degree_iter(nbunch, weight)
        else:
            return iter(self.out_degree(nbunch, weight))

    def in_degree_iter(self, nbunch=None, weight=None):
        if nx.__version__.startswith("1"):
            return super(DAG, self).in_degree_iter(nbunch, weight)
        else:
            return iter(self.in_degree(nbunch, weight))

    def get_roots(self):
        """
        Returns a list of roots of the graph.

        Examples
        --------
        >>> from pgmpy.base import DAG
        >>> graph = DAG([('A', 'B'), ('B', 'C'), ('B', 'D'), ('E', 'B')])
        >>> graph.get_roots()
        ['A', 'E']
        """
        return [
            node for node, in_degree in dict(self.in_degree()).items() if in_degree == 0
        ]

    def get_children(self, node):
        """
        Returns a list of children of node.
        Throws an error if the node is not present in the graph.

        Parameters
        ----------
        node: string, int or any hashable python object.
            The node whose children would be returned.

        Examples
        --------
        >>> from pgmpy.base import DAG
        >>> g = DAG(ebunch=[('A', 'B'), ('C', 'B'), ('B', 'D'),
                                      ('B', 'E'), ('B', 'F'), ('E', 'G')])
        >>> g.get_children(node='B')
        ['D', 'E', 'F']
        """
        return list(self.successors(node))

    def get_independencies(self, latex=False, include_latents=False):
        """
        Computes independencies in the DAG, by checking d-seperation.

        Parameters
        ----------
        latex: boolean
            If latex=True then latex string of the independence assertion
            would be created.

        include_latents: boolean
            If True, includes latent variables in the independencies. Otherwise,
            only generates independencies on observed variables.

        Examples
        --------
        >>> from pgmpy.base import DAG
        >>> chain = DAG([('X', 'Y'), ('Y', 'Z')])
        >>> chain.get_independencies()
        (X \u27C2 Z | Y)
        (Z \u27C2 X | Y)
        """
        nodes = set(self.nodes())
        if not include_latents:
            nodes = set(self.nodes()) - self.latents

        independencies = Independencies()
        for start in nodes:
            if not include_latents:
                rest = set(self.nodes()) - {start} - self.latents
            else:
                rest = set(self.nodes()) - {start}

            for r in range(len(rest)):
                for observed in itertools.combinations(rest, r):
                    d_seperated_variables = (
                        rest
                        - set(observed)
                        - set(
                            self.active_trail_nodes(
                                start,
                                observed=observed,
                                include_latents=include_latents,
                            )[start]
                        )
                    )
                    if d_seperated_variables:
                        independencies.add_assertions(
                            [start, d_seperated_variables, observed]
                        )
        independencies.reduce()

        if not latex:
            return independencies
        else:
            return independencies.latex_string()

    def local_independencies(self, variables):
        """
        Returns an instance of Independencies containing the local independencies
        of each of the variables.

        Parameters
        ----------
        variables: str or array like
            variables whose local independencies are to be found.

        Examples
        --------
        >>> from pgmpy.base import DAG
        >>> student = DAG()
        >>> student.add_edges_from([('diff', 'grade'), ('intel', 'grade'),
        >>>                         ('grade', 'letter'), ('intel', 'SAT')])
        >>> ind = student.local_independencies('grade')
        >>> ind
        (grade \u27C2 SAT | diff, intel)
        """

        independencies = Independencies()
        for variable in (
            variables if isinstance(variables, (list, tuple)) else [variables]
        ):
            non_descendents = (
                set(self.nodes())
                - {variable}
                - set(nx.dfs_preorder_nodes(self, variable))
            )
            parents = set(self.get_parents(variable))
            if non_descendents - parents:
                independencies.add_assertions(
                    [variable, non_descendents - parents, parents]
                )
        return independencies

    def is_iequivalent(self, model):
        """
        Checks whether the given model is I-equivalent

        Two graphs G1 and G2 are said to be I-equivalent if they have same skeleton
        and have same set of immoralities.

        Parameters
        ----------
        model : A DAG object, for which you want to check I-equivalence

        Returns
        --------
        I-equivalence: boolean
            True if both are I-equivalent, False otherwise

        Examples
        --------
        >>> from pgmpy.base import DAG
        >>> G = DAG()
        >>> G.add_edges_from([('V', 'W'), ('W', 'X'),
        ...                   ('X', 'Y'), ('Z', 'Y')])
        >>> G1 = DAG()
        >>> G1.add_edges_from([('W', 'V'), ('X', 'W'),
        ...                    ('X', 'Y'), ('Z', 'Y')])
        >>> G.is_iequivalent(G1)
        True

        """
        if not isinstance(model, DAG):
            raise TypeError(
                f"Model must be an instance of DAG. Got type: {type(model)}"
            )

        if (self.to_undirected().edges() == model.to_undirected().edges()) and (
            self.get_immoralities() == model.get_immoralities()
        ):
            return True
        return False

    def get_immoralities(self):
        """
        Finds all the immoralities in the model
        A v-structure X -> Z <- Y is an immorality if there is no direct edge between X and Y .

        Returns
        -------
        Immoralities: set
            A set of all the immoralities in the model

        Examples
        ---------
        >>> from pgmpy.base import DAG
        >>> student = DAG()
        >>> student.add_edges_from([('diff', 'grade'), ('intel', 'grade'),
        ...                         ('intel', 'SAT'), ('grade', 'letter')])
        >>> student.get_immoralities()
        {('diff', 'intel')}
        """
        immoralities = set()
        for node in self.nodes():
            for parents in itertools.combinations(self.predecessors(node), 2):
                if not self.has_edge(parents[0], parents[1]) and not self.has_edge(
                    parents[1], parents[0]
                ):
                    immoralities.add(tuple(sorted(parents)))
        return immoralities

    def is_dconnected(self, start, end, observed=None):
        """
        Returns True if there is an active trail (i.e. d-connection) between
        `start` and `end` node given that `observed` is observed.

        Parameters
        ----------
        start, end : int, str, any hashable python object.
            The nodes in the DAG between which to check the d-connection/active trail.

        observed : list, array-like (optional)
            If given the active trail would be computed assuming these nodes to
            be observed.

        Examples
        --------
        >>> from pgmpy.base import DAG
        >>> student = DAG()
        >>> student.add_nodes_from(['diff', 'intel', 'grades', 'letter', 'sat'])
        >>> student.add_edges_from([('diff', 'grades'), ('intel', 'grades'), ('grades', 'letter'),
        ...                         ('intel', 'sat')])
        >>> student.is_dconnected('diff', 'intel')
        False
        >>> student.is_dconnected('grades', 'sat')
        True
        """
        if end in self.active_trail_nodes(start, observed)[start]:
            return True
        else:
            return False

    def minimal_dseparator(self, start, end):
        """
        Finds the minimal d-separating set for `start` and `end`.

        Parameters
        ----------
        start: node
            The first node.

        end: node
            The second node.

        Examples
        --------
        >>> dag = DAG([('A', 'B'), ('B', 'C')])
        >>> dag.minimal_dseparator(start='A', end='C')
        {'B'}

        References
        ----------
        [1] Algorithm 4, Page 10: Tian, Jin, Azaria Paz, and Judea Pearl. Finding minimal d-separators. Computer Science Department, University of California, 1998.
        """
        if (end in self.neighbors(start)) or (start in self.neighbors(end)):
            raise ValueError(
                "No possible separators because start and end are adjacent"
            )
        an_graph = self.get_ancestral_graph([start, end])
        separator = set(
            itertools.chain(self.predecessors(start), self.predecessors(end))
        )
        # If any of the parents were latents, take the latent's parent
        while len(separator.intersection(self.latents)) != 0:
            separator_copy = separator.copy()
            for u in separator:
                if u in self.latents:
                    separator_copy.remove(u)
                    separator_copy.update(set(self.predecessors(u)))
            separator = separator_copy
        # Remove the start and end nodes in case it reaches there while removing latents.
        separator.difference_update({start, end})

        # If the initial set is not able to d-separate, no d-separator is possible.
        if an_graph.is_dconnected(start, end, observed=separator):
            return None

        # Go through the separator set, remove one element and check if it remains
        # a dseparating set.
        minimal_separator = separator.copy()

        for u in separator:
            if not an_graph.is_dconnected(start, end, observed=minimal_separator - {u}):
                minimal_separator.remove(u)

        return minimal_separator

    def get_markov_blanket(self, node):
        """
        Returns a markov blanket for a random variable. In the case
        of Bayesian Networks, the markov blanket is the set of
        node's parents, its children and its children's other parents.

        Returns
        -------
        Markov Blanket: list
            List of nodes in the markov blanket of `node`.

        Parameters
        ----------
        node: string, int or any hashable python object.
              The node whose markov blanket would be returned.

        Examples
        --------
        >>> from pgmpy.base import DAG
        >>> from pgmpy.factors.discrete import TabularCPD
        >>> G = DAG([('x', 'y'), ('z', 'y'), ('y', 'w'), ('y', 'v'), ('u', 'w'),
                               ('s', 'v'), ('w', 't'), ('w', 'm'), ('v', 'n'), ('v', 'q')])
        >>> G.get_markov_blanket('y')
        ['s', 'w', 'x', 'u', 'z', 'v']
        """
        children = self.get_children(node)
        parents = self.get_parents(node)
        blanket_nodes = children + parents
        for child_node in children:
            blanket_nodes.extend(self.get_parents(child_node))
        blanket_nodes = set(blanket_nodes)
        blanket_nodes.discard(node)
        return list(blanket_nodes)

    def active_trail_nodes(self, variables, observed=None, include_latents=False):
        """
        Returns a dictionary with the given variables as keys and all the nodes reachable
        from that respective variable as values.

        Parameters
        ----------
        variables: str or array like
            variables whose active trails are to be found.

        observed : List of nodes (optional)
            If given the active trails would be computed assuming these nodes to be
            observed.

        include_latents: boolean (default: False)
            Whether to include the latent variables in the returned active trail nodes.

        Examples
        --------
        >>> from pgmpy.base import DAG
        >>> student = DAG()
        >>> student.add_nodes_from(['diff', 'intel', 'grades'])
        >>> student.add_edges_from([('diff', 'grades'), ('intel', 'grades')])
        >>> student.active_trail_nodes('diff')
        {'diff': {'diff', 'grades'}}
        >>> student.active_trail_nodes(['diff', 'intel'], observed='grades')
        {'diff': {'diff', 'intel'}, 'intel': {'diff', 'intel'}}

        References
        ----------
        Details of the algorithm can be found in 'Probabilistic Graphical Model
        Principles and Techniques' - Koller and Friedman
        Page 75 Algorithm 3.1
        """
        if observed:
            if isinstance(observed, set):
                observed = list(observed)

            observed_list = (
                observed if isinstance(observed, (list, tuple)) else [observed]
            )
        else:
            observed_list = []
        ancestors_list = self._get_ancestors_of(observed_list)

        # Direction of flow of information
        # up ->  from parent to child
        # down -> from child to parent

        active_trails = {}
        for start in variables if isinstance(variables, list) else [variables]:
            visit_list = set()
            visit_list.add((start, "up"))
            traversed_list = set()
            active_nodes = set()
            while visit_list:
                node, direction = visit_list.pop()
                if (node, direction) not in traversed_list:
                    if node not in observed_list:
                        active_nodes.add(node)
                    traversed_list.add((node, direction))
                    if direction == "up" and node not in observed_list:
                        for parent in self.predecessors(node):
                            visit_list.add((parent, "up"))
                        for child in self.successors(node):
                            visit_list.add((child, "down"))
                    elif direction == "down":
                        if node not in observed_list:
                            for child in self.successors(node):
                                visit_list.add((child, "down"))
                        if node in ancestors_list:
                            for parent in self.predecessors(node):
                                visit_list.add((parent, "up"))
            if include_latents:
                active_trails[start] = active_nodes
            else:
                active_trails[start] = active_nodes - self.latents

        return active_trails

    def _get_ancestors_of(self, nodes):
        """
        Returns a dictionary of all ancestors of all the observed nodes including the
        node itself.

        Parameters
        ----------
        nodes: string, list-type
            name of all the observed nodes

        Examples
        --------
        >>> from pgmpy.base import DAG
        >>> model = DAG([('D', 'G'), ('I', 'G'), ('G', 'L'),
        ...                        ('I', 'L')])
        >>> model._get_ancestors_of('G')
        {'D', 'G', 'I'}
        >>> model._get_ancestors_of(['G', 'I'])
        {'D', 'G', 'I'}
        """
        if not isinstance(nodes, (list, tuple)):
            nodes = [nodes]

        for node in nodes:
            if node not in self.nodes():
                raise ValueError(f"Node {node} not in not in graph")

        ancestors_list = set()
        nodes_list = set(nodes)
        while nodes_list:
            node = nodes_list.pop()
            if node not in ancestors_list:
                nodes_list.update(self.predecessors(node))
            ancestors_list.add(node)
        return ancestors_list

    # TODO: Commented out till the method is implemented.
    #     def to_pdag(self):
    #         """
    #         Returns the PDAG (the equivalence class of DAG; also known as CPDAG) of the DAG.
    #
    #         Returns
    #         -------
    #         Partially oriented DAG: pgmpy.base.PDAG
    #             An instance of pgmpy.base.PDAG.
    #
    #         Examples
    #         --------
    #
    #         """
    #         pass

    def do(self, nodes, inplace=False):
        """
        Applies the do operator to the graph and returns a new DAG with the
        transformed graph.

        The do-operator, do(X = x) has the effect of removing all edges from
        the parents of X and setting X to the given value x.

        Parameters
        ----------
        nodes : list, array-like
            The names of the nodes to apply the do-operator for.

        inplace: boolean (default: False)
            If inplace=True, makes the changes to the current object,
            otherwise returns a new instance.

        Returns
        -------
        Modified DAG: pgmpy.base.DAG
            A new instance of DAG modified by the do-operator

        Examples
        --------
        Initialize a DAG
        >>> graph = DAG()
        >>> graph.add_edges_from([('X', 'A'),
        ...                       ('A', 'Y'),
        ...                       ('A', 'B')])
        >>> # Applying the do-operator will return a new DAG with the desired structure.
        >>> graph_do_A = graph.do('A')
        >>> # Which we can verify is missing the edges we would expect.
        >>> graph_do_A.edges
        OutEdgeView([('A', 'B'), ('A', 'Y')])

        References
        ----------
        Causality: Models, Reasoning, and Inference, Judea Pearl (2000). p.70.
        """
        dag = self if inplace else self.copy()

        if isinstance(nodes, (str, int)):
            nodes = [nodes]
        else:
            nodes = list(nodes)

        if not set(nodes).issubset(set(self.nodes())):
            raise ValueError(
                f"Nodes not found in the model: {set(nodes) - set(self.nodes)}"
            )

        for node in nodes:
            parents = list(dag.predecessors(node))
            for parent in parents:
                dag.remove_edge(parent, node)
        return dag

    def get_ancestral_graph(self, nodes):
        """
        Returns the ancestral graph of the given `nodes`. The ancestral graph only
        contains the nodes which are ancestors of atleast one of the variables in
        node.

        Parameters
        ----------
        node: iterable
            List of nodes whose ancestral graph needs to be computed.

        Returns
        -------
        Ancestral Graph: pgmpy.base.DAG

        Examples
        --------
        >>> from pgmpy.base import DAG
        >>> dag = DAG([('A', 'C'), ('B', 'C'), ('D', 'A'), ('D', 'B')])
        >>> anc_dag = dag.get_ancestral_graph(nodes=['A', 'B'])
        >>> anc_dag.edges()
        OutEdgeView([('D', 'A'), ('D', 'B')])
        """
        return self.subgraph(nodes=self._get_ancestors_of(nodes=nodes))

    def to_daft(
        self,
        node_pos="circular",
        latex=True,
        pgm_params={},
        edge_params={},
        node_params={},
    ):
        """
        Returns a daft (https://docs.daft-pgm.org/en/latest/) object which can be rendered for
        publication quality plots. The returned object's render method can be called to see the plots.

        Parameters
        ----------
        node_pos: str or dict (default: circular)
            If str: Must be one of the following: circular, kamada_kawai, planar, random, shell, sprint,
                spectral, spiral. Please refer: https://networkx.org/documentation/stable//reference/drawing.html#module-networkx.drawing.layout for details on these layouts.

            If dict should be of the form {node: (x coordinate, y coordinate)} describing the x and y coordinate of each
            node.

            If no argument is provided uses circular layout.

        latex: boolean
            Whether to use latex for rendering the node names.

        pgm_params: dict (optional)
            Any additional parameters that need to be passed to `daft.PGM` initializer.
            Should be of the form: {param_name: param_value}

        edge_params: dict (optional)
            Any additional edge parameters that need to be passed to `daft.add_edge` method.
            Should be of the form: {(u1, v1): {param_name: param_value}, (u2, v2): {...} }

        node_params: dict (optional)
            Any additional node parameters that need to be passed to `daft.add_node` method.
            Should be of the form: {node1: {param_name: param_value}, node2: {...} }

        Returns
        -------
        Daft object: daft.PGM object
            Daft object for plotting the DAG.

        Examples
        --------
        >>> from pgmpy.base import DAG
        >>> dag = DAG([('a', 'b'), ('b', 'c'), ('d', 'c')])
        >>> dag.to_daft(node_pos={'a': (0, 0), 'b': (1, 0), 'c': (2, 0), 'd': (1, 1)})
        <daft.PGM at 0x7fc756e936d0>
        >>> dag.to_daft(node_pos="circular")
        <daft.PGM at 0x7f9bb48c5eb0>
        >>> dag.to_daft(node_pos="circular", pgm_params={'observed_style': 'inner'})
        <daft.PGM at 0x7f9bb48b0bb0>
        >>> dag.to_daft(node_pos="circular",
        ...             edge_params={('a', 'b'): {'label': 2}},
        ...             node_params={'a': {'shape': 'rectangle'}})
        <daft.PGM at 0x7f9bb48b0bb0>
        """
        try:
            from daft import PGM
        except ImportError as e:
            raise ImportError(
                "Package daft required. Please visit: https://docs.daft-pgm.org/en/latest/ for installation instructions."
            )

        if isinstance(node_pos, str):
            supported_layouts = {
                "circular": nx.circular_layout,
                "kamada_kawai": nx.kamada_kawai_layout,
                "planar": nx.planar_layout,
                "random": nx.random_layout,
                "shell": nx.shell_layout,
                "spring": nx.spring_layout,
                "spectral": nx.spectral_layout,
                "spiral": nx.spiral_layout,
            }
            if node_pos not in supported_layouts.keys():
                raise ValueError(
                    "Unknown node_pos argument. Please refer docstring for accepted values"
                )
            else:
                node_pos = supported_layouts[node_pos](self)
        elif isinstance(node_pos, dict):
            for node in self.nodes():
                if node not in node_pos.keys():
                    raise ValueError(f"No position specified for {node}.")
        else:
            raise ValueError(
                "Argument node_pos not valid. Please refer to the docstring."
            )

        daft_pgm = PGM(**pgm_params)
        for node in self.nodes():
            try:
                extra_params = node_params[node]
            except KeyError:
                extra_params = dict()

            if latex:
                daft_pgm.add_node(
                    node,
                    rf"${node}$",
                    node_pos[node][0],
                    node_pos[node][1],
                    observed=True,
                    **extra_params,
                )
            else:
                daft_pgm.add_node(
                    node,
                    f"{node}",
                    node_pos[node][0],
                    node_pos[node][1],
                    observed=True,
                    **extra_params,
                )

        for u, v in self.edges():
            try:
                extra_params = edge_params[(u, v)]
            except KeyError:
                extra_params = dict()
            daft_pgm.add_edge(u, v, **extra_params)

        return daft_pgm

    @staticmethod
    def get_random(n_nodes=5, edge_prob=0.5, latents=False):
        """
        Returns a randomly generated DAG with `n_nodes` number of nodes with
        edge probability being `edge_prob`.

        Parameters
        ----------
        n_nodes: int
            The number of nodes in the randomly generated DAG.

        edge_prob: float
            The probability of edge between any two nodes in the topologically
            sorted DAG.

        latents: bool (default: False)
            If True, includes latent variables in the generated DAG.

        Returns
        -------
        Random DAG: pgmpy.base.DAG
            The randomly generated DAG.

        Examples
        --------
        >>> from pgmpy.base import DAG
        >>> random_dag = DAG.get_random(n_nodes=10, edge_prob=0.3)
        >>> random_dag.nodes()
        NodeView((0, 1, 2, 3, 4, 5, 6, 7, 8, 9))
        >>> random_dag.edges()
        OutEdgeView([(0, 6), (1, 6), (1, 7), (7, 9), (2, 5), (2, 7), (2, 8), (5, 9), (3, 7)])
        """
        # Step 1: Generate a matrix of 0 and 1. Prob of choosing 1 = edge_prob
        adj_mat = np.random.choice(
            [0, 1], size=(n_nodes, n_nodes), p=[1 - edge_prob, edge_prob]
        )

        # Step 2: Use the upper triangular part of the matrix as adjacency.
        nodes = list(range(n_nodes))
        edges = nx.convert_matrix.from_numpy_array(
            np.triu(adj_mat, k=1), create_using=nx.DiGraph
        ).edges()

        dag = DAG(edges)
        dag.add_nodes_from(nodes)
        if latents:
            dag.latents = set(
                np.random.choice(
                    dag.nodes(), np.random.randint(low=0, high=len(dag.nodes()))
                )
            )
        return dag

    def to_graphviz(self):
        """
        Retuns a pygraphviz object for the DAG. pygraphviz is useful for
        visualizing the network structure.

        Examples
        --------
        >>> from pgmpy.utils import get_example_model
        >>> model = get_example_model('alarm')
        >>> model.to_graphviz()
        <AGraph <Swig Object of type 'Agraph_t *' at 0x7fdea4cde040>>
        """
        return nx.nx_agraph.to_agraph(self)

class PDAG(nx.DiGraph):
    """
    Class for representing PDAGs (also known as CPDAG). PDAGs are the equivalence classes of
    DAGs and contain both directed and undirected edges.

    Note: In this class, undirected edges are represented using two edges in both direction i.e.
    an undirected edge between X - Y is represented using X -> Y and X <- Y.
    """

    def __init__(self, directed_ebunch=[], undirected_ebunch=[], latents=[]):
        """
        Initializes a PDAG class.

        Parameters
        ----------
        directed_ebunch: list, array-like of 2-tuples
            List of directed edges in the PDAG.

        undirected_ebunch: list, array-like of 2-tuples
            List of undirected edges in the PDAG.

        latents: list, array-like
            List of nodes which are latent variables.

        Returns
        -------
        An instance of the PDAG object.

        Examples
        --------
        """
        super(PDAG, self).__init__(
            directed_ebunch
            + undirected_ebunch
            + [(Y, X) for (X, Y) in undirected_ebunch]
        )
        self.latents = set(latents)
        self.directed_edges = set(directed_ebunch)
        self.undirected_edges = set(undirected_ebunch)
        # TODO: Fix the cycle issue
        # import pdb; pdb.set_trace()
        # try:
        #     # Filter out undirected edges as they also form a cycle in
        #     # themself when represented using directed edges.
        #     cycles = filter(lambda t: len(t) > 2, nx.simple_cycles(self))
        #     if cycles:
        #         out_str = "Cycles are not allowed in a PDAG. "
        #         out_str += "The following path forms a loop: "
        #         out_str += "".join(["({u},{v}) ".format(u=u, v=v) for (u, v) in cycles])
        #         raise ValueError(out_str)
        # except nx.NetworkXNoCycle:
        #     pass

    def copy(self):
        """
        Returns a copy of the object instance.

        Returns
        -------
        Copy of PDAG: pgmpy.dag.PDAG
            Returns a copy of self.
        """
        return PDAG(
            directed_ebunch=list(self.directed_edges.copy()),
            undirected_ebunch=list(self.undirected_edges.copy()),
            latents=self.latents,
        )

    def to_dag(self, required_edges=[]):
        """
        Returns one possible DAG which is represented using the PDAG.

        Parameters
        ----------
        required_edges: list, array-like of 2-tuples
            The list of edges that should be included in the DAG.

        Returns
        -------
        Returns an instance of DAG.

        Examples
        --------

        """
        # Add required edges if it doesn't form a new v-structure or an opposite edge
        # is already present in the network.
        dag = DAG()
        # Add all the nodes and the directed edges
        dag.add_nodes_from(self.nodes())
        dag.add_edges_from(self.directed_edges)
        dag.latents = self.latents

        pdag = self.copy()
        while pdag.number_of_nodes() > 0:
            # find node with (1) no directed outgoing edges and
            #                (2) the set of undirected neighbors is either empty or
            #                    undirected neighbors + parents of X are a clique
            found = False
            for X in pdag.nodes():
                directed_outgoing_edges = set(pdag.successors(X)) - set(
                    pdag.predecessors(X)
                )
                undirected_neighbors = set(pdag.successors(X)) & set(
                    pdag.predecessors(X)
                )
                neighbors_are_clique = all(
                    (
                        pdag.has_edge(Y, Z)
                        for Z in pdag.predecessors(X)
                        for Y in undirected_neighbors
                        if not Y == Z
                    )
                )

                if not directed_outgoing_edges and (
                    not undirected_neighbors or neighbors_are_clique
                ):
                    found = True
                    # add all edges of X as outgoing edges to dag
                    for Y in pdag.predecessors(X):
                        dag.add_edge(Y, X)
                    pdag.remove_node(X)
                    break

            if not found:
                logger.warning(
                    "PDAG has no faithful extension (= no oriented DAG with the "
                    + "same v-structures as PDAG). Remaining undirected PDAG edges "
                    + "oriented arbitrarily."
                )
                for X, Y in pdag.edges():
                    if not dag.has_edge(Y, X):
                        try:
                            dag.add_edge(X, Y)
                        except ValueError:
                            pass
                break
        return dag

    def to_graphviz(self):
        """
        Retuns a pygraphviz object for the DAG. pygraphviz is useful for
        visualizing the network structure.

        Examples
        --------
        >>> from pgmpy.utils import get_example_model
        >>> model = get_example_model('alarm')
        >>> model.to_graphviz()
        <AGraph <Swig Object of type 'Agraph_t *' at 0x7fdea4cde040>>
        """
        return nx.nx_agraph.to_agraph(self)


import os
import sys
from io import BytesIO
import pygame
import requests

lon = input('Введите долготу: ')
lat = input('Введите широту: ')

while True:
    scale = input('Введите масштаб(0-17): ')
    if 0 <= int(scale) <= 17:
        break
    print('Неправильно!')

map_params = {
    "l": "map",
    "ll": "{},{}".format(lon, lat),
    'z': '{}'.format(scale)
}

map_api_server = "http://static-maps.yandex.ru/1.x/"
response = requests.get(map_api_server, params=map_params)

if not response:
    print("Ошибка выполнения запроса:")
    print(map_api_server)
    print("Http статус:", response.status_code, "(", response.reason, ")")
    sys.exit(1)

pygame.init()
screen = pygame.display.set_mode((600, 450))
screen.blit(pygame.image.load(BytesIO(response.content)), (0, 0))
pygame.display.flip()
running = True
update = False
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.K_PAGEDOWN:
            if 0 <= int(scale) + 1 <= 17:
                scale = str(int(scale) + 1)
                update = True
        if event.type == pygame.K_PAGEUP:
            if 0 <= int(scale) - 1 <= 17:
                scale = str(int(scale) - 1)
                update = True
    if update:
        map_params = {
            "l": "map",
            "ll": "{},{}".format(lon, lat),
            'z': '{}'.format(scale)
        }
        map_api_server = "http://static-maps.yandex.ru/1.x/"
        response = requests.get(map_api_server, params=map_params)
        screen.fill('black')
        screen.blit(pygame.image.load(BytesIO(response.content)), (0, 0))
        update = False
    pygame.display.flip()
pygame.quit()


# coding: utf-8

# In[ ]:

import numpy as np
import json
import nltk
import scipy.spatial.distance as distance

# In[ ]:

def get_json(filename):
    with open(filename, 'r', encoding = 'utf-8') as f:
        return json.load(f)

# In[ ]:

def get_distances(embeddings):
    similarities = {}
    for course in embeddings:
        similarities[course] = {}
        for lecture in embeddings[course]:
            similarities[course][lecture] = {}
            for slide in embeddings[course][lecture]:
                similarities[course][lecture][slide] = {}
                for content in embeddings[course][lecture][slide]:
                    similarities[course][lecture][slide][content] = {}
                    for course2 in embeddings:
                        for lecture2 in embeddings[course2]:
                            for slide2 in embeddings[course2][lecture2]:
                                if content in embeddings[course2][lecture2][slide2]:
                                    similarities[course][lecture][slide][content][course2 + '##' + lecture2 + '##' + slide2] = distance.cosine(
                                        embeddings[course][lecture][slide][content], embeddings[course2][lecture2][slide2][content])
                                    if len(similarities[course][lecture][slide][content]) > 10:
                                        del similarities[course][lecture][slide][content][min(d, key=d.get)]
    return similarities

# In[ ]:

def write_to_json(filename, data):
    with open(filename + '.json', 'w', encoding = 'utf-8') as outfile:
        json.dump(data, outfile)

# In[ ]:

def make_json_readable(jsonname, filename):
    data = {}
    with open(jsonname, 'r', encoding = 'utf-8') as f:
        data = json.load(f)
    with open(filename, 'w', encoding = 'utf-8') as f:
        f.write('')
    with open(filename, 'a', encoding = 'utf-8') as f:
        for course in data:
            f.write(course + '{\n')
            for lecture in data[course]:
                f.write('\t' + lecture + '{\n')
                for slide in data[course][lecture]:
                    f.write('\t\t' + slide + '{\n')
                    for content in data[course][lecture][slide]:
                        f.write('\t\t\t' + content + ':' + str(np.array(data[course][lecture][slide][content])) + '\n')
                    f.write('\t\t}\n')
                f.write('\t}\n')
            f.write('}\n')

# In[ ]:

def main():
    embeddings = get_json('multiplicative_embeddings.json')
    similarities = get_distances(embeddings)
    write_to_json('multiplicative_embeddings_analysis.json')
    make_json_readable('multiplicative_embeddings_analysis.json', 'multiplicative_embeddings_analysis_readable.txt')

# In[ ]:

main()


"""VideoInfo URL Configuration

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

from VideoInfo import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.video_index, name='video_index'),
    path('video/index/', views.video_index, name='video_index'),
    path('video/index/<int:page>', views.video_index, name='video_index'),
    path('video/index/search/<str:search>', views.video_search, name='video_search'),
    path('author/index/', views.author_index, name='author_index'),
    path('author/index/<int:page>', views.author_index, name='author_index'),
    path('author/index/search/<str:search>', views.author_search, name='author_search'),
    path('video/detail/<str:bvid>', views.video_detail, name='video_detail'),
    path('author/detail/<str:uid>', views.author_detail, name='author_detail'),
]


import traceback
from typing import Callable, Iterable, List, Optional, Tuple, Type, Union

from fastapi import Request
from fastapi.encoders import jsonable_encoder
from fastapi.exceptions import RequestValidationError, StarletteHTTPException
from lark.exceptions import VisitError
from pydantic import ValidationError

from optimade.exceptions import BadRequest, OptimadeHTTPException
from optimade.models import ErrorResponse, ErrorSource, OptimadeError
from optimade.server.config import CONFIG
from optimade.server.logger import LOGGER
from optimade.server.routers.utils import JSONAPIResponse, meta_values

def general_exception(
    request: Request,
    exc: Exception,
    status_code: int = 500,  # A status_code in `exc` will take precedence
    errors: Optional[List[OptimadeError]] = None,
) -> JSONAPIResponse:
    """Handle an exception

    Parameters:
        request: The HTTP request resulting in the exception being raised.
        exc: The exception being raised.
        status_code: The returned HTTP status code for the error response.
        errors: List of error resources as defined in
            [the OPTIMADE specification](https://github.com/Materials-Consortia/OPTIMADE/blob/develop/optimade.rst#json-response-schema-common-fields).

    Returns:
        A JSON HTTP response based on [`ErrorResponse`][optimade.models.responses.ErrorResponse].

    """
    debug_info = {}
    if CONFIG.debug:
        tb = "".join(
            traceback.format_exception(type(exc), value=exc, tb=exc.__traceback__)
        )
        LOGGER.error("Traceback:\n%s", tb)
        debug_info[f"_{CONFIG.provider.prefix}_traceback"] = tb

    try:
        http_response_code = int(exc.status_code)  # type: ignore[attr-defined]
    except AttributeError:
        http_response_code = int(status_code)

    try:
        title = str(exc.title)  # type: ignore[attr-defined]
    except AttributeError:
        title = str(exc.__class__.__name__)

    try:
        detail = str(exc.detail)  # type: ignore[attr-defined]
    except AttributeError:
        detail = str(exc)

    if errors is None:
        errors = [OptimadeError(detail=detail, status=http_response_code, title=title)]

    response = ErrorResponse(
        meta=meta_values(
            url=request.url,
            data_returned=0,
            data_available=0,
            more_data_available=False,
            schema=CONFIG.schema_url,
            **debug_info,
        ),
        errors=errors,
    )

    return JSONAPIResponse(
        status_code=http_response_code,
        content=jsonable_encoder(response, exclude_unset=True),
    )

def http_exception_handler(
    request: Request,
    exc: Union[StarletteHTTPException, OptimadeHTTPException],
) -> JSONAPIResponse:
    """Handle a general HTTP Exception from Starlette

    Parameters:
        request: The HTTP request resulting in the exception being raised.
        exc: The exception being raised.

    Returns:
        A JSON HTTP response through [`general_exception()`][optimade.server.exception_handlers.general_exception].

    """
    return general_exception(request, exc)

def request_validation_exception_handler(
    request: Request, exc: RequestValidationError
) -> JSONAPIResponse:
    """Handle a request validation error from FastAPI

    `RequestValidationError` is a specialization of a general pydantic `ValidationError`.
    Pass-through directly to [`general_exception()`][optimade.server.exception_handlers.general_exception].

    Parameters:
        request: The HTTP request resulting in the exception being raised.
        exc: The exception being raised.

    Returns:
        A JSON HTTP response through [`general_exception()`][optimade.server.exception_handlers.general_exception].

    """
    return general_exception(request, exc)

def validation_exception_handler(
    request: Request, exc: ValidationError
) -> JSONAPIResponse:
    """Handle a general pydantic validation error

    The pydantic `ValidationError` usually contains a list of errors,
    this function extracts them and wraps them in the OPTIMADE specific error resource.

    Parameters:
        request: The HTTP request resulting in the exception being raised.
        exc: The exception being raised.

    Returns:
        A JSON HTTP response through [`general_exception()`][optimade.server.exception_handlers.general_exception].

    """
    status = 500
    title = "ValidationError"
    errors = set()
    for error in exc.errors():
        pointer = "/" + "/".join([str(_) for _ in error["loc"]])
        source = ErrorSource(pointer=pointer)
        code = error["type"]
        detail = error["msg"]
        errors.add(
            OptimadeError(
                detail=detail, status=status, title=title, source=source, code=code
            )
        )
    return general_exception(request, exc, status_code=status, errors=list(errors))

def grammar_not_implemented_handler(
    request: Request, exc: VisitError
) -> JSONAPIResponse:
    """Handle an error raised by Lark during filter transformation

    All errors raised during filter transformation are wrapped in the Lark `VisitError`.
    According to the OPTIMADE specification, these errors are repurposed to be 501 NotImplementedErrors.

    For special exceptions, like [`BadRequest`][optimade.exceptions.BadRequest], we pass-through to
    [`general_exception()`][optimade.server.exception_handlers.general_exception], since they should not
    return a 501 NotImplementedError.

    Parameters:
        request: The HTTP request resulting in the exception being raised.
        exc: The exception being raised.

    Returns:
        A JSON HTTP response through [`general_exception()`][optimade.server.exception_handlers.general_exception].

    """
    pass_through_exceptions = (BadRequest,)

    orig_exc = getattr(exc, "orig_exc", None)
    if isinstance(orig_exc, pass_through_exceptions):
        return general_exception(request, orig_exc)

    rule = getattr(exc.obj, "data", getattr(exc.obj, "type", str(exc)))

    status = 501
    title = "NotImplementedError"
    detail = (
        f"Error trying to process rule '{rule}'"
        if not str(exc.orig_exc)
        else str(exc.orig_exc)
    )
    error = OptimadeError(detail=detail, status=status, title=title)
    return general_exception(request, exc, status_code=status, errors=[error])

def not_implemented_handler(
    request: Request, exc: NotImplementedError
) -> JSONAPIResponse:
    """Handle a standard NotImplementedError Python exception

    Parameters:
        request: The HTTP request resulting in the exception being raised.
        exc: The exception being raised.

    Returns:
        A JSON HTTP response through [`general_exception()`][optimade.server.exception_handlers.general_exception].

    """
    status = 501
    title = "NotImplementedError"
    detail = str(exc)
    error = OptimadeError(detail=detail, status=status, title=title)
    return general_exception(request, exc, status_code=status, errors=[error])

def general_exception_handler(request: Request, exc: Exception) -> JSONAPIResponse:
    """Catch all Python Exceptions not handled by other exception handlers

    Pass-through directly to [`general_exception()`][optimade.server.exception_handlers.general_exception].

    Parameters:
        request: The HTTP request resulting in the exception being raised.
        exc: The exception being raised.

    Returns:
        A JSON HTTP response through [`general_exception()`][optimade.server.exception_handlers.general_exception].

    """
    return general_exception(request, exc)

OPTIMADE_EXCEPTIONS: Iterable[
    Tuple[
        Type[Exception],
        Callable[[Request, Exception], JSONAPIResponse],
    ]
] = [
    (StarletteHTTPException, http_exception_handler),
    (OptimadeHTTPException, http_exception_handler),
    (RequestValidationError, request_validation_exception_handler),
    (ValidationError, validation_exception_handler),
    (VisitError, grammar_not_implemented_handler),
    (NotImplementedError, not_implemented_handler),  # type: ignore[list-item] # not entirely sure why this entry triggers mypy
    (Exception, general_exception_handler),
]
"""A tuple of all pairs of exceptions and handler functions that allow for
appropriate responses to be returned in certain scenarios according to the
OPTIMADE specification.

To use these in FastAPI app code:

```python
from fastapi import FastAPI
app = FastAPI()
for exception, handler in OPTIMADE_EXCEPTIONS:
    app.add_exception_handler(exception, handler)
```

"""


# Local libraries
import input_reader
import interpreter
import physics

# Third-party libraries
from numpy import genfromtxt, nan, array

INPUT_FILE_NAME = "config.in"

def main():
    input_dict = input_reader.create_input_dictionary(INPUT_FILE_NAME)
    properties_dict = input_reader.create_properties_dictionary(input_dict[0]["ADSORBATE_DATA_FILE"])
    data_dict = {}

    for index in input_dict:
        data_dict[index] = {}
        properties_dict = input_reader.create_properties_dictionary(input_dict[index]["ADSORBATE_DATA_FILE"])

        file_data = genfromtxt(fname=input_dict[index]["DATA_FILES"], filling_values=nan)
        if input_dict[index]["DATA_TYPES"] == "isotherm":
            data_dict[index]["temperature"] = input_dict[index]["TEMPERATURES"]
            data_dict[index]["pressure"] = file_data[:, 0] * interpreter.convert_input(
                                                                    unit=input_dict[index]["PRESSURE_UNITS"],
                                                                    molecular_mass=properties_dict["MOLECULAR_MASS"])

            data_dict[index]["loading"] = file_data[:, 1] * interpreter.convert_input(
                                                                    unit=input_dict[index]["LOADING_UNITS"],
                                                                    molecular_mass=properties_dict["MOLECULAR_MASS"])
        elif input_dict[index]["DATA_TYPES"] == "isobar":
            data_dict[index]["pressure"] = input_dict[index]["PRESSURES"]
            data_dict[index]["temperature"] = file_data[:, 0] * interpreter.convert_input(
                                                                    unit=input_dict[index]["TEMPERATURE_UNITS"],
                                                                    molecular_mass=properties_dict["MOLECULAR_MASS"])

            data_dict[index]["loading"] = file_data[:, 1] * interpreter.convert_input(
                                                                    unit=input_dict[index]["LOADING_UNITS"],
                                                                    molecular_mass=properties_dict["MOLECULAR_MASS"])
        elif input_dict[index]["DATA_TYPES"] == "characteristic":
            data_dict[index]["potential"] = file_data[:, 0] * interpreter.convert_input(
                                                                    unit=input_dict[index]["POTENTIAL_UNITS"],
                                                                    molecular_mass=properties_dict["MOLECULAR_MASS"])

            data_dict[index]["volume"] = file_data[:, 1] * interpreter.convert_input(
                                                                    unit=input_dict[index]["VOLUME_UNITS"],
                                                                    molecular_mass=properties_dict["MOLECULAR_MASS"])
        else:
            raise ValueError(f"{input_dict[index]['DATA_TYPES']} is not a recognized argument!")

    if input_dict[0]["PLOT_DATA"] == "yes":
        interpreter.plot_data(source_dictionary=data_dict, input_dictionary=input_dict,
                              plot_format=input_dict[0]["DATA_TYPES"], save=input_dict[0]["SAVE_DATA_PLOT"])

    if input_dict[0]["COMPUTE_ENTHALPY"] == "yes":
        enthalpy = interpreter.compute_adsorption_enthalpy(data_dictionary=data_dict, input_dictionary=input_dict)

        if input_dict[0]["PLOT_ENTHALPY"] == "yes":
            interpreter.plot_data(source_dictionary=enthalpy, input_dictionary=input_dict,
                                  plot_format="enthalpy", save=input_dict[0]["SAVE_ENTHALPY_PLOT"])

        if input_dict[0]["SAVE_ENTHALPY_DATA"] == "yes":
            interpreter.write_data(source_dictionary=enthalpy, input_dictionary=input_dict,
                                   properties_dictionary=properties_dict, write_format="enthalpy")

    if input_dict[0]["COMPUTE_CHARACTERISTIC_CURVE"] == "yes":

        for index in data_dict:
            if input_dict[index]["DATA_TYPES"] == "isotherm":
                data_dict[index]["saturation_pressure"] = interpreter.compute_saturation_pressure_from_method(
                                                method=input_dict[index]["ADSORBATE_SATURATION_PRESSURE"],
                                                temperature=data_dict[index]["temperature"],
                                                properties_dictionary=properties_dict,
                                                saturation_pressure_file=input_dict[index]["SATURATION_PRESSURE_FILE"])

                data_dict[index]["density"] = interpreter.compute_density_from_method(
                                                                        method=input_dict[index]["ADSORBATE_DENSITY"],
                                                                        temperature=data_dict[index]["temperature"],
                                                                        properties_dictionary=properties_dict)

            elif input_dict[index]["DATA_TYPES"] == "isobar":
                saturation_pressure_array = []
                density_array = []
                for temperature in data_dict[index]["temperature"]:
                    saturation_pressure_array.append(interpreter.compute_saturation_pressure_from_method(
                                                method=input_dict[index]["ADSORBATE_SATURATION_PRESSURE"],
                                                temperature=temperature,
                                                properties_dictionary=properties_dict,
                                                saturation_pressure_file=input_dict[index]["SATURATION_PRESSURE_FILE"]))

                    density_array.append(interpreter.compute_density_from_method(
                                                method=input_dict[index]["ADSORBATE_DENSITY"],
                                                temperature=temperature,
                                                properties_dictionary=properties_dict))

                data_dict[index]["saturation_pressure"] = array(saturation_pressure_array)
                data_dict[index]["density"] = array(density_array)

            elif input_dict[index]["DATA_TYPE"] == "characteristic":
                continue

            data_dict[index]["potential"] = physics.get_adsorption_potential(
                                                            temperature=data_dict[index]["temperature"],
                                                            saturation_pressure=data_dict[index]["saturation_pressure"],
                                                            pressure=data_dict[index]["pressure"])

            data_dict[index]["volume"] = physics.get_adsorption_volume(
                                                            adsorbed_amount=data_dict[index]["loading"],
                                                            adsorbate_density=data_dict[index]["density"])

        if input_dict[0]["SAVE_CHARACTERISTIC_CURVE_DATA"] == "yes":
            interpreter.write_data(source_dictionary=data_dict, input_dictionary=input_dict,
                                   properties_dictionary=properties_dict, write_format="characteristic")

        if input_dict[0]["PLOT_CHARACTERISTIC_CURVE"] == "yes":
            interpreter.plot_data(source_dictionary=data_dict, input_dictionary=input_dict,
                                  plot_format="characteristic", save=input_dict[0]["SAVE_CHARACTERISTIC_CURVE_PLOT"])

    if input_dict[0]["PREDICT_ISOTHERMS"] == "yes":
        predicted_isotherms = interpreter.predict_data(data_dictionary=data_dict,
                                                       input_dictionary=input_dict,
                                                       prediction_type="isotherm",
                                                       properties_dictionary=properties_dict)

        if input_dict[0]["PLOT_PREDICTED_ISOTHERMS"] == "yes":
            interpreter.plot_data(source_dictionary=predicted_isotherms, input_dictionary=input_dict,
                                  plot_format="isotherm", save=input_dict[0]["SAVE_PREDICTED_ISOTHERMS_PLOT"])

        if input_dict[0]["SAVE_PREDICTED_ISOTHERMS_DATA"] == "yes":
            interpreter.write_data(source_dictionary=predicted_isotherms, input_dictionary=input_dict,
                                   properties_dictionary=properties_dict, write_format="isotherm")

    if input_dict[0]["PREDICT_ISOBARS"] == "yes":
        predicted_isobars = interpreter.predict_data(data_dictionary=data_dict,
                                                     input_dictionary=input_dict,
                                                     prediction_type="isobar",
                                                     properties_dictionary=properties_dict)

        if input_dict[0]["PLOT_PREDICTED_ISOBARS"] == "yes":
            interpreter.plot_data(source_dictionary=predicted_isobars, input_dictionary=input_dict,
                                  plot_format="isobar", save=input_dict[0]["SAVE_PREDICTED_ISOBARS_PLOT"])

        if input_dict[0]["SAVE_PREDICTED_ISOBARS_DATA"] == "yes":
            interpreter.write_data(source_dictionary=predicted_isobars, input_dictionary=input_dict,
                                   properties_dictionary=properties_dict, write_format="isobar")

    if input_dict[0]["PREDICT_ISOSTERES"] == "yes":
        predicted_isosteres = interpreter.predict_data(data_dictionary=data_dict,
                                                       input_dictionary=input_dict,
                                                       prediction_type="isostere",
                                                       properties_dictionary=properties_dict)

        if input_dict[0]["PLOT_PREDICTED_ISOSTERES"] == "yes":
            interpreter.plot_data(source_dictionary=predicted_isosteres, input_dictionary=input_dict,
                                  plot_format="isostere", save=input_dict[0]["SAVE_PREDICTED_ISOSTERES_PLOT"])

        if input_dict[0]["SAVE_PREDICTED_ISOSTERES_DATA"] == "yes":
            interpreter.write_data(source_dictionary=predicted_isosteres, input_dictionary=input_dict,
                                   properties_dictionary=properties_dict, write_format="isostere")

    if input_dict[0]["SHOW_PLOTS"] == "yes":
        interpreter.show_plots()

if __name__ == "__main__":
    main()


#!/usr/bin/env python3
# Number plate detection

__author__ = "Cristian Chitiva"
__date__ = "September 17, 2021"
__email__ = "cychitivav@unal.edu.co"

import cv2
import numpy as np

if __name__ == '__main__':
    cap = cv2.VideoCapture(0)

    plateCascade = cv2.CascadeClassifier()
    plateCascade.load(
        'resources/haarcascade_russian_plate_number.xml')
    minArea = 200

    retval = -1
    while retval < 0:
        success, img = cap.read()
        # img = cv2.flip(img, flipCode=1)

        imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

        plates = plateCascade.detectMultiScale(
            imgGray, scaleFactor=1.1, minNeighbors=4)

        for (x, y, w, h) in plates:
            area = w*h
            if area > minArea:
                cv2.rectangle(img, pt1=(x, y), pt2=(x+w, y+h),
                              color=(255, 0, 0), thickness=2)
                cv2.putText(img, text='Number plate', org=(x, y-5),
                            fontFace=cv2.FONT_HERSHEY_COMPLEX_SMALL,
                            fontScale=1, color=(255, 0, 0), thickness=2)

                imgROI = img[y:y+h, x:x+w]
                cv2.imshow('Plate', imgROI)

        cv2.imshow('Original', img)
        retval = cv2.waitKey(1)

    cv2.imwrite('outputs/numberPlate.jpg', imgROI)


import BigWorld, FMOD
from collections import namedtuple
import struct
from constants import ARENA_GUI_TYPE
from tutorial.control import context
from tutorial.control.context import ClientCtx, GlobalStorage
from tutorial.logger import LOG_DEBUG, LOG_ERROR, LOG_WARNING
BATTLE_RECORDS = ['completed',
 'failed',
 'accCompleted',
 'startedAt',
 'chapterIdx']
EXTENDED_BATTLE_RECORDS = ['playerTeam',
 'winnerTeam',
 'finishReason',
 'vTypeCD',
 'arenaTypeID',
 'arenaUniqueID']
ALL_BATTLE_RECORDS = BATTLE_RECORDS + EXTENDED_BATTLE_RECORDS
BATTLE_RECORDS_FORMAT = '3ifh'
ALL_BATTLE_RECORDS_FORMAT = '3if4h2iQ'

class TRAINING_RESULT_KEY:
    FINISHED = 'finished'
    FAILED = 'failed'

class TRAINING_FINISH_REASON_KEY:
    FINISHED = 'finished'
    FAILED = 'failed'
    TIMEOUT = 'timeout'
    EXTERMINATION = 'extermination'

class BattleClientCtx(ClientCtx, namedtuple('BattleClientCtx', BATTLE_RECORDS)):

    @classmethod
    def _makeDefault(cls):
        return cls.__new__(cls, 0, -1, -1, 0.0, -1)

    @classmethod
    def makeCtx(cls, record):
        result = cls._makeDefault()
        if record is not None and len(record):
            try:
                result = cls._make(struct.unpack(BATTLE_RECORDS_FORMAT, record))
            except struct.error:
                LOG_ERROR('Client ctx is not valid', record)

        return result

    @classmethod
    def fetch(cls, *args):
        player = BigWorld.player()
        if player is None or not hasattr(player, 'clientCtx'):
            LOG_DEBUG('Avatar.clientCtx not found', player)
            result = cls._makeDefault()
        else:
            result = cls.makeCtx(player.clientCtx)
        return result

    def _store(self):
        record = self.makeRecord()
        player = BigWorld.player()
        if player is None or not hasattr(player, 'storeClientCtx'):
            LOG_DEBUG('Avatar.storeClientCtx not found', player)
            return False
        else:
            player.storeClientCtx(record)
            return True

    def makeRecord(self):
        return struct.pack(BATTLE_RECORDS_FORMAT, *self)

    def addMask(self, mask, done = True):
        completed = self.completed
        failed = self.failed
        if done:
            completed |= mask
        else:
            failed |= mask
        newCtx = self._replace(completed=completed, failed=failed)
        if newCtx._store():
            return newCtx
        return self

    def setChapterIdx(self, chapterIdx):
        newCtx = self._replace(chapterIdx=chapterIdx)
        if newCtx._store():
            return newCtx
        return self

    def setAccCompleted(self, accCompleted):
        newCtx = self._replace(accCompleted=accCompleted)
        if newCtx._store():
            return newCtx
        return self

    def setStartedAt(self, time):
        newCtx = self._replace(startedAt=time)
        if newCtx._store():
            return newCtx
        return self

class ExtendedBattleClientCtx(ClientCtx, namedtuple('ExtendedBattleClientCtx', ALL_BATTLE_RECORDS)):

    @classmethod
    def _makeDefault(cls):
        return cls.__new__(cls, 0, -1, -1, 0.0, -1, 1, 2, -1, -1, -1, -1)

    @classmethod
    def makeCtx(cls, record):
        result = cls._makeDefault()
        if record is not None and len(record):
            try:
                result = cls._make(struct.unpack(ALL_BATTLE_RECORDS_FORMAT, record))
            except struct.error:
                LOG_ERROR('Client ctx is not valid', record)

        return result

    @classmethod
    def fetch(cls, *args):
        params = ExtendedBattleClientCtx._makeDefault()._asdict()
        player = BigWorld.player()
        params.update(BattleClientCtx.fetch()._asdict())
        arena = getattr(player, 'arena', None)
        if arena is not None:
            info = arena.periodAdditionalInfo
            if info is not None and len(info) > 1:
                params['winnerTeam'] = info[0]
                params['finishReason'] = info[1]
            params['arenaUniqueID'] = arena.arenaUniqueID
            arenaType = arena.arenaType
            if arenaType is not None:
                params['arenaTypeID'] = arenaType.id
            pVehID = getattr(player, 'playerVehicleID', None)
            vehicles = arena.vehicles
            if pVehID in vehicles:
                vDescriptor = vehicles[pVehID]['vehicleType']
                if vDescriptor is not None:
                    params['vTypeCD'] = vDescriptor.type.compactDescr
        params['playerTeam'] = getattr(player, 'team', 1)
        LOG_DEBUG('All records in context', params)
        return ExtendedBattleClientCtx(**params)

    def makeRecord(self):
        return struct.pack(ALL_BATTLE_RECORDS_FORMAT, *self)

class BattleStartReqs(context.StartReqs):

    def isEnabled(self):
        arena = getattr(BigWorld.player(), 'arena', None)
        enabled = False
        if arena is not None:
            enabled = arena.guiType == ARENA_GUI_TYPE.TUTORIAL
        return enabled

    def process(self):
        loader, ctx = self._flush()
        clientCtx = BattleClientCtx.fetch()
        ctx.bonusCompleted = clientCtx.completed
        GlobalStorage.clearVars()
        loader._doRun(ctx)

class BattleBonusesRequester(context.BonusesRequester):

    def request(self, chapterID = None):
        chapter = self.getChapter(chapterID=chapterID)
        if chapter is None:
            LOG_ERROR('Chapter not found', chapterID)
            return
        elif not chapter.hasBonus():
            LOG_ERROR('Chapter has not bonus', chapter.getID())
            return
        else:
            bonusID = chapter.getBonusID()
            mask = 1 << bonusID
            localCtx = BattleClientCtx.fetch().addMask(mask)
            if chapter.isBonusReceived(self._completed):
                LOG_DEBUG('Bonus already received', chapter.getID(), self._completed)
                self._isReceived = True
                return
            LOG_DEBUG('Received bonus', bonusID)
            self._completed |= mask
            self._gui.setTrainingProgress(self._tutorial._descriptor.getProgress(localCtx.completed))
            return

class BattleSoundPlayer(context.SoundPlayer):
    __guiSounds = {context.SOUND_EVENT.TASK_FAILED: '/GUI/notifications_FX/task_new',
     context.SOUND_EVENT.TASK_COMPLETED: '/GUI/notifications_FX/task_complete',
     context.SOUND_EVENT.NEXT_CHAPTER: '/GUI/notifications_FX/task_part_complete'}

    def __init__(self):
        super(BattleSoundPlayer, self).__init__()
        self.__ignoreNext = False
        self.__speakSnd = None
        self.__nextSpeakID = None
        self.__prevSpeaks = set()
        return

    def play(self, event, sndID = None):
        if self.isMuted():
            return
        if event in self.__guiSounds.keys():
            self._playGUI(event)
        elif event is context.SOUND_EVENT.SPEAKING:
            self._speak(sndID)
        else:
            LOG_WARNING('Sound event is not supported', event)

    def stop(self):
        self._clear()
        self.__ignoreNext = False
        self.__nextSpeakID = None
        self.__prevSpeaks.clear()
        return

    def isPlaying(self, event, sndID = None):
        result = False
        if event is context.SOUND_EVENT.SPEAKING:
            if self.__speakSnd is not None:
                if sndID is not None:
                    result = len(self.__prevSpeaks) and list(self.__prevSpeaks)[-1] == sndID
                else:
                    result = True
        else:
            LOG_WARNING('Sound event is not supported', event)
        return result

    def goToNextChapter(self):
        self.__prevSpeaks.clear()

    def _playGUI(self, event):
        if self.__ignoreNext:
            self.__ignoreNext = False
            return
        if event is context.SOUND_EVENT.NEXT_CHAPTER:
            self.__ignoreNext = True
        sndID = self.__guiSounds[event]
        sound = FMOD.getSound(sndID)
        if sound:
            sound.play()
        else:
            LOG_ERROR('Sound not found', sndID)

    def _clear(self):
        if self.__speakSnd is not None:
            self.__speakSnd.setCallback('EVENTFINISHED', None)
            self.__speakSnd.stop()
            self.__speakSnd = None
        return

    def _speak(self, sndID):
        if sndID in self.__prevSpeaks:
            LOG_DEBUG('Speaking played, ignore', sndID)
            return
        elif sndID is None:
            LOG_WARNING('Sound ID for speaking is not defined')
            return
        elif self.__speakSnd is not None:
            self.__nextSndID = sndID
            return
        else:
            sound = FMOD.getSound(sndID)
            if not sound:
                LOG_ERROR('Sound not found', sndID)
                return
            self.__nextSndID = None
            self.__speakSnd = sound
            self.__prevSpeaks.add(sndID)
            sound.setCallback('EVENTFINISHED', self.__onSpeakingStop)
            sound.play()
            return

    def __onSpeakingStop(self, sound):
        LOG_DEBUG('Stop playing sound by event', sound)
        self._clear()
        if self.__nextSndID is not None:
            self._speak(self.__nextSndID)
        return