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

import pandas as pd
import numpy as np
import os
import warnings
import datetime
import logging
from gtfparse import read_gtf

from cptac.dataset import Dataset
from cptac.dataframe_tools import *
from cptac.exceptions import FailedReindexWarning, PublicationEmbargoWarning, ReindexMapError
from cptac.utils import get_boxnote_text
from .mssmclinical import MssmClinical

class WashuPdac(Dataset):

    def __init__(self, no_internet, version):
        """Load all of the bcmbrca dataframes as values in the self._data dict variable, with names as keys, and format them properly.

        Parameters:
        version (str, optional): The version number to load, or the string "latest" to just load the latest building. Default is "latest".
        no_internet (bool, optional): Whether to skip the index update step because it requires an internet connection. This will be skipped automatically if there is no internet at all, but you may want to manually skip it if you have a spotty internet connection. Default is False.
        """
        #ignore logging messages
        logger = logging.getLogger()
        logger.setLevel(logging.CRITICAL)

        # Set some needed variables, and pass them to the parent Dataset class __init__ function

        # This keeps a record of all versions that the code is equipped to handle. That way, if there's a new data release but they didn't update their package, it won't try to parse the new data version it isn't equipped to handle.
        valid_versions = ["1.0"]

        data_files = {
            "1.0": [
                "PDA_discovery.dnp.annotated.exonic.maf.gz",
                "PDA_NAT_RNA-Seq_Expr_WashU_FPKM.tsv.gz",
                "PDA_tumor_RNA-Seq_Expr_WashU_FPKM.tsv.gz",
                "PDA_mature_miRNA_combined.tsv",
                "PDA_precursor_miRNA_combined.tsv",
                "PDA_total_miRNA_combined.tsv",
                "PDA_xCell.txt",
                "CIBERSORT.Output_Abs_PDA.txt",
                "PDA.gene_level.from_seg.filtered.tsv",
                "gencode.v22.annotation.gtf.gz",
                "CPTAC_pancan_RNA_tumor_purity_ESTIMATE_WashU.tsv.gz",
                "README_miRNA",
                "README_CIBERSORT",
                "README_xCell",
                "README_somatic_mutation_WXS",
                "README_gene_expression",
                "README.boxnote",
                "README_ESTIMATE_WashU"
            ]
        }

        # Call the parent class __init__ function
        super().__init__(cancer_type="washupdac", version=version, valid_versions=valid_versions, data_files=data_files, no_internet=no_internet)

        # get clinical df (used to slice out cancer specific patient_IDs in tumor_purity file)
        mssmclin = MssmClinical(no_internet=no_internet, version=version, filter_type='pancanpdac') #_get_version - pancandataset
        clinical_df = mssmclin.get_clinical()

        # Load the data into dataframes in the self._data dict
        loading_msg = f"Loading {self.get_cancer_type()} v{self.version()}"
        for file_path in self._data_files_paths: # Loops through files variable

            # Print a loading message. We add a dot every time, so the user knows it's not frozen.
            loading_msg = loading_msg + "."
            print(loading_msg, end='\r')

            path_elements = file_path.split(os.sep) # Get a list of the levels of the path
            file_name = path_elements[-1] # The last element will be the name of the file. We'll use this to identify files for parsing in the if/elif statements below

            if file_name == "PDA_discovery.dnp.annotated.exonic.maf.gz": # Note that we use the "file_name" variable to identify files. That way we don't have to use the whole path.
                df = pd.read_csv(file_path, sep='\t')
                # Rename the columns we want to keep to the appropriate names
                df = pd.read_csv(file_path, sep='\t')
                df['Patient_ID'] = df.loc[:, 'Tumor_Sample_Barcode']
                df = df.rename(columns={
                         "Hugo_Symbol":"Gene",
                         "Gene":"Gene_Database_ID",
                         "Variant_Classification":"Mutation",
                         "HGVSp_Short":"Location"})

                df = df.set_index("Patient_ID")
                df = df[ ['Gene'] + ["Mutation"] + ["Location"] + [ col for col in df.columns if col not in ["Gene","Mutation","Location"] ] ]
                df.index = df.index.str.replace(r"_T", "", regex=True)
                self._data["somatic_mutation"] = df

            if file_name == "PDA_NAT_RNA-Seq_Expr_WashU_FPKM.tsv.gz":
                df_norm = pd.read_csv(file_path, sep='\t')
                #change names to universal package names
                df_norm = df_norm.rename(columns={"gene_name": "Name","gene_id": "Database_ID"})
                df_norm = df_norm.set_index(["Name", "Database_ID"])
                df_norm = df_norm.sort_index()
                df_norm = df_norm.T #transpose
                df_norm.index.name = "Patient_ID"
                df_norm.index = df_norm.index.str.replace(r"-A", ".N", regex=True) #remove label for tumor samples
                self._helper_tables["transcriptomics_norm"] = df_norm

            if file_name == "PDA_tumor_RNA-Seq_Expr_WashU_FPKM.tsv.gz":
                df = pd.read_csv(file_path, sep='\t')
                #change names to universal package names
                df = df.rename(columns={"gene_name": "Name","gene_id": "Database_ID"})
                df = df.set_index(["Name", "Database_ID"])
                df = df.sort_index()
                df = df.T #transpose
                df.index.name = "Patient_ID"
                df.index = df.index.str.replace(r"-T", "", regex=True) #remove label for tumor samples
                self._helper_tables["transcriptomics_tumor"] = df

            elif 'miRNA_combined' in file_name:
                miRNA_type = file_name.split('_')[1] # get type of miRNA data (precursor, mature, or total)
                if miRNA_type == 'mature':
                    df = pd.read_csv(file_path, delimiter = '\t', index_col = ['Name', 'ID','Alias', 'Derives_from'])
                else:
                    df = pd.read_csv(file_path, delimiter = '\t', index_col = ['Name', 'ID','Alias'])
                df = df.transpose()
                df = average_replicates(df, common = '\.\d$') # average duplicates for C3L-02617 and C3N-02727
                df.index = df.index.str.replace('\.T$','', regex = True)
                df.index = df.index.str.replace('\.A$','.N', regex = True)
                df.index.name = 'Patient_ID'
                # Sort
                normal = df.loc[df.index.str.contains('\.N$', regex =True)]
                normal = normal.sort_values(by=["Patient_ID"])
                tumor = df.loc[~ df.index.str.contains('\.N$', regex =True)]
                tumor = tumor.sort_values(by=["Patient_ID"])
                all_df = tumor.append(normal)
                self._data[miRNA_type+'_miRNA'] = all_df

            elif file_name == "PDA_xCell.txt":
                df = pd.read_csv(file_path, sep = '\t', index_col = 0)
                df = df.transpose()
                df.columns.name = 'Name'
                df.index.name = 'Patient_ID'
                df.index = df.index.str.replace(r'-T$', '', regex=True) # remove label for tumor samples
                df.index = df.index.str.replace(r'-A$', '.N', regex=True) # change label for normal samples
                self._data["xcell"] = df

            elif file_name == "CIBERSORT.Output_Abs_PDA.txt":
                df = pd.read_csv(file_path, sep = '\t', index_col = 0)
                df.index.name = 'Patient_ID'
                df.columns.name = 'Name'
                df.index = df.index.str.replace(r'-T$', '', regex=True)
                df.index = df.index.str.replace(r'-A$', '.N', regex=True)
                self._data["cibersort"] = df

            elif file_name == "PDA.gene_level.from_seg.filtered.tsv":
                df = pd.read_csv(file_path, sep="\t")
                df = df.rename(columns={"Gene": "Name"})
                df = df.set_index("Name")
                self._data["CNV"] = df

            elif file_name == "gencode.v22.annotation.gtf.gz":
                df = read_gtf(file_path)
                df = df[["gene_name","gene_id"]]
                df = df.drop_duplicates()
                df = df.rename(columns={"gene_name": "Name","gene_id": "Database_ID"})
                df = df.set_index("Name")
                self._helper_tables["CNV_gene_ids"] = df

            elif file_name == "CPTAC_pancan_RNA_tumor_purity_ESTIMATE_WashU.tsv.gz":
                df = pd.read_csv(file_path, sep = "\t", na_values = 'NA')
                df.Sample_ID = df.Sample_ID.str.replace(r'-T', '', regex=True) # only tumor samples in file
                df = df.set_index('Sample_ID')
                df.index.name = 'Patient_ID'
                # Use list of patient_ids to slice out cancers
                patient_ids = clinical_df.index.to_list()
                df = df.loc[df.index.isin(patient_ids)]
                self._data["tumor_purity"] = df

            elif file_name == "README_miRNA":
                with open(file_path, 'r') as reader:
                    self._readme_files["readme_miRNA"] = reader.read()

            elif file_name == "README_CIBERSORT":
                with open(file_path, 'r') as reader:
                    self._readme_files["readme_cibersort"] = reader.read()

            elif file_name == "README_xCell":
                with open(file_path, 'r') as reader:
                    self._readme_files["readme_xcell"] = reader.read()

            elif file_name == "README_somatic_mutation_WXS":
                with open(file_path, 'r') as reader:
                    self._readme_files["readme_somatic_mutation"] = reader.read()

            elif file_name == "README_gene_expression":
                with open(file_path, 'r') as reader:
                    self._readme_files["readme_transcriptomics"] = reader.read()

            elif file_name == "README.boxnote":
                self._readme_files["readme_cnv"] = get_boxnote_text(file_path)

            elif file_name == "README_ESTIMATE_WashU":
                with open(file_path, 'r') as reader:
                    self._readme_files["readme_tumor_purity"] = reader.read()

        print(' ' * len(loading_msg), end='\r') # Erase the loading message
        formatting_msg = f"Formatting {self.get_cancer_type()} dataframes..."
        print(formatting_msg, end='\r')

        # combine and create transcriptomic dataframe
        rna_tumor = self._helper_tables.get("transcriptomics_tumor")
        rna_normal = self._helper_tables.get("transcriptomics_norm") # Normal entries are already marked with 'N' on the end of the ID
        rna_combined = rna_tumor.append(rna_normal)
        self._data["transcriptomics"] = rna_combined

        # CNV
        cnv = self._data["CNV"]
        gene_ids = self._helper_tables["CNV_gene_ids"]
        df = cnv.join(gene_ids,how = "left") #merge in gene_ids
        df = df.reset_index()
        df = df.set_index(["Name", "Database_ID"]) #create multi-index
        df = df.T
        df.index.name = 'Patient_ID'
        self._data["CNV"] = df

        self._data = sort_all_rows_pancan(self._data) # Sort IDs (tumor first then normal)

        print(" " * len(formatting_msg), end='\r') # Erase the formatting message


import factory
from random import randint
from random import choice

from django.test import TestCase
from django.conf import settings
from django.core.files import File

from .models import *

class ECFactory(factory.django.DjangoModelFactory):
    ec_name = "transferase"

    class Meta:
        model = EC

class SequencingFactory(factory.django.DjangoModelFactory):
    sequencing_factory = "Sanger"
    factory_location = "UK"

    class Meta:
        model = Sequencing

class GeneFactory(factory.django.DjangoModelFactory):
    gene_id = factory.Sequence(lambda n: 'gene%d' % n+str(1))
    entity = choice(['Plasmid', 'Chromosome'])
    start = randint(1, 100000)
    stop = start+randint(1, 10000)
    sense = "+"
    start_codon = "M"
    sequencing = factory.SubFactory(SequencingFactory)
    ec = factory.SubFactory(ECFactory)
    access = 0

    class Meta:
        model = Gene


import sys
from optparse import OptionParser
import matplotlib.pyplot as plt
import pandas
import seaborn as sns

parser = OptionParser()
parser.usage = "cat data | %prog [options]"
parser.add_option("-t", "--title", dest="title", default="", help="Title of the graph")
parser.add_option("-f", "--filename", dest="filename", default="", help="If this option is specified, it will save"
                                                                        "the figure to the corresponding filename")
parser.add_option("--xlabel", dest="xlabel", default="x", help="Title of x axis")
parser.add_option("--ylabel", dest="ylabel", default="y", help="Title of y axis")

parser.add_option("--xlim", dest="xlim", default=None, nargs=2)

(options, args) = parser.parse_args()
if sys.stdin.isatty():
    parser.print_usage()
    print('for more help, use --help')
    sys.exit(1)

df = pandas.read_csv(sys.stdin, header=0, names=['x', 'in_sol'])
good = df[df.in_sol == 1]['x']
bad = df[df.in_sol == 0]['x']

fig = plt.figure(figsize=(5, 5), dpi=100)
plt.title(options.title)

if options.xlim != None:
    plt.xlim(float(options.xlim[0]), float(options.xlim[1]))

# bad.plot.hist(alpha=0.5, color='red', ax=fig.gca())
# good.plot.hist(alpha=0.5, color='green', ax=fig.gca())
sns.distplot(good, color='green')
sns.distplot(bad, color='red')

plt.xlabel(options.xlabel)

if options.filename != "":
    plt.savefig(options.filename)
else:
    plt.show()


from bs4 import BeautifulSoup
import requests
import pandas as pd
from splinter import Browser
import time

def browser():
    executable_path = {'executable_path': '/Apps/Selenium/chromedriver'}
    browser = Browser('chrome', **executable_path, headless=False)

def scrape():

    #NASA Mars News
    nasa_mars_url = 'https://mars.nasa.gov/news/'
    browser.visit(nasa_mars_url)

    #Retrieve page
    response = browser.html

    #Create BeautifulSoup, results object,
    soup = BeautifulSoup(response, 'html.parser')
    results = soup.find('div', class_='list_text')

    #Article title
    article_title = results.find('div', class_='content_title').text
    article_title

    #Article text
    p_text = results.find('div', class_='article_teaser_body').text
    p_text

    #JPL Mars Space Images - Featured Image
    jpl_mars_url = 'https://www.jpl.nasa.gov/spaceimages/?search=&category=Mars'
    browser.visit(jpl_mars_url)
    response = browser.html
    soup = BeautifulSoup(response, 'html.parser')

    jpl_results = soup.find('img', class_='thumb')['src']
    featured_image_url= 'https://www.jpl.nasa.gov' + jpl_results
    featured_image_url

    #Mars Weather
    mars_weather = 'https://twitter.com/marswxreport?lang=en'
    browser.visit(mars_weather)
    response = browser.html
    soup = BeautifulSoup(response, 'html.parser')

    tweet_results = soup.find('div', class_='css-901oao css-16my406 r-1qd0xha r-ad9z0x r-bcqeeo r-qvutc0')
    tweet_results

    #Mars Facts

    mars_facts_url = 'https://space-facts.com/mars/'
    tables = pd.read_html(mars_facts_url)
    df_tables = pd.DataFrame(tables)
    html_table = df_tables.to_html()
    html_table

    #Mars Hemispheres
    mars_hemispheres_url = 'https://astrogeology.usgs.gov/search/results?q=hemisphere+enhanced&k1=target&v1=Mars'
    browser.visit(mars_hemispheres_url)
    response = browser.html
    soup = BeautifulSoup(response, 'html.parser')

    hemisphere_image_urls = []

    mars_hemi_results = soup.find("div", class_ = "result-list" )
    results = mars_hemi_results.find_all("div", class_="item")

    for result in results:
        title = mars_hemi_results.find("h3").text
        links = mars_hemi_results.find("a")["href"]
        image_url = "https://astrogeology.usgs.gov/" + links
        html = browser.html
        soup=BeautifulSoup(html, "html.parser")
        hemisphere_image_urls.append({"title": title, "img_url": image_url})

    hemisphere_image_urls


import queue as Q

class ITEM :
    def __init__(self, priority, target):
        self.priority = priority
        self.target = target

def getTime() :
    args = input().split()
    pos = int(args[1])
    pque = Q.PriorityQueue()
    que = Q.Queue()

    priorlist = input().split()
    order = 0
    for prior in priorlist :
        que.put(ITEM(int(prior), pos == order))
        pque.put(-int(prior))
        order = order + 1

    time = 0
    while pque.empty != False :
        target = pque.get()
        while que.empty != False :
            item = que.get()
            if -target == item.priority :
                time = time + 1
                if item.target == True :
                    return time
                else :
                    break
            else :
                que.put(item)

if __name__ == "__main__" :
    tcnum = int(input())
    for i in range(tcnum) :
        print(getTime())


"""
Definition of ListNode
class ListNode(object):
    def __init__(self, val, next=None):
        self.val = val
        self.next = next
"""

class Solution:
    """
    @param l1: the first list
    @param l2: the second list
    @return: the sum list of l1 and l2
    """
    def addLists(self, l1, l2):
        # write your code here
        dummy = ListNode(None)
        tail = dummy
        carry = 0
        while l1 or l2 or carry:
            num = 0
            if l1:
                num+= l1.val
                l1 = l1.next
            if l2:
                num += l2.val
                l2 = l2.next
            num += carry
            digit, carry = num%10, num//10
            node = ListNode(digit)
            tail.next, tail = node, node
        return dummy.next


"""ontrendclothing URL Configuration

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

urlpatterns = [
    path('', productviews.login),
    path('showproduct', productviews.showproduct),
    path('addproduct', productviews.addproduct),
    path('addtype', productviews.addtype),
    path('addvendor', productviews.addvendor),
    path('editproduct/<int:id>', productviews.editproduct),
    path('updateproduct/<int:id>', productviews.updateproduct),
    path('deleteproduct/<int:id>', productviews.deleteproduct),
    path('search', productviews.search),
    path('login', productviews.login),
    path('entry', productviews.entry),
    path('login', productviews.login),
]


#!/usr/bin/env python

import matplotlib.pylab as plt
import numpy as np
# from matplotlib import gridspec
# from matplotlib import colors
# from matplotlib.colors import LinearSegmentedColormap

def reshape_1D_to_2D(N_LOS,N_R, input_array):
    output_matrix = np.zeros([N_LOS, N_R])
    idx_work = 0
    if (N_LOS*N_R == input_array.shape[0]):
        for LL in xrange(N_LOS):
            for RR in xrange(N_R):
                output_matrix[LL,RR] = input_array[idx_work]
                idx_work += 1
    else:
        print("N_LOSxN_R does not match input array shape")
    return output_matrix

# path = '/tokp/work/osam/ECRad/ECRad_25781_ECO_ed1.mat'

# /tokp/work/osam/ECRad

# ECRad_25781_ECO_ed1.mat
import scipy.io
mat = scipy.io.loadmat('/tokp/work/osam/ECRad/ECRad_25781_ECO_ed2.mat')
# mat.keys()

mat['time']
mat['Te'].shape
mat['Trad'].shape
mat['R_warm'].shape
N_LOS = 16
N_R = 8
tt = 0
Trad = reshape_1D_to_2D(N_LOS, N_R, mat['Trad'][tt])
R = reshape_1D_to_2D(N_LOS, N_R, mat['R_warm'][tt])
z = reshape_1D_to_2D(N_LOS, N_R, mat['z_warm'][tt])

plt.contourf(R, z, Trad, 100, cmap ="jet")
plt.show()


'''
class student:
    __num = ''
    __name = ''
    __age = ''
    __sex = ''
    __height = ''
    __weight = ''
    __grade = ''
    __adress = ''
    __phone = ''

    def setnum(self,num):
        self.__num = num
    def getnum(self):
        return self.__num

    def setname(self,name):
        self.__name = name
    def getname(self):
        return self.__name

    def setage(self,age):
        self.__age = age
    def getage(self):
        return self.__age

    def setsex(self,sex):
        self.__sex = sex
    def getage(self):
        return self.__sex

    def setheight(self,height):
        self.__height = height
    def getheight(self):
        return self.__height

    def setweight(self,weight):
        self.__weight = weight
    def getweight(self):
        return self.__weight

    def setgrade(self,grade):
        self.__grade = grade
    def getgrade(self):
        return self.__grade

    def setadress(self,adress):
        self.__adress = adress
    def getadress(self):
        return self.__adress

    def setphone(self,phone):
        self.__phone = phone
    def getphone(self):
        return self.__phone

    def study(self,hours):
        print('学生',self.__name,'学习了',hours,'小时')
    def game(self,game_name):
        print('学生',self.__name,'正在玩',game_name)
    def program(self,rows):
        print('学生',self.__name,'已经写了',rows,'代码')
    def count(self):
        chinese = int(input('语文：'))
        math = int(input('数学：'))
        english = int(input('英语：'))
        sum = chinese+math+english
        print('成绩总和为：',sum)

s = student()
s.setnum(input('输入学号：'))
s.setname(input('输入姓名：'))
s.setage(input('输入年龄:'))
s.setsex(input('输入性别:'))
s.setheight(input('输入身高:'))
s.setweight(input('输入体重:'))
s.setgrade(input('输入成绩:'))
s.setadress(input('输入地址:'))
s.setphone(input('输入手机号:'))
s.study(2)
s.game('王者荣耀')
s.program(100)
s.count()

class vehicle:
    __name = ''
    __brand = ''
    __num = ''
    __color = ''
    __weight = ''
    __tank = ''

    def setname(self,name):
        self.__name = name
    def getname(self):
        return self.__name

    def setbrand(self,brand):
        self.__brand = brand
    def getbrand(self):
        return self.__brand

    def setnum(self,num):
        self.__num = num
    def getnum(self):
        return self.__num

    def setcolor(self,color):
        self.__color = color
    def getcolor(self):
        return self.__color

    def setweight(self,weight):
        self.__weight = weight
    def getweight(self):
        return self.__weight

    def settank(self,tank):
        self.__tank = tank
    def gettank(self):
        return self.__tank

    def run(self,action):
        print(self.__color,self.__name,'正在',action)

v = vehicle()
v.setname('法拉利')
v.setbrand('4')
v.setcolor('蓝色')
v.setweight('1000斤')
v.settank('500')
v.run('赛车')

v1 = vehicle()
v1.setname('宝马')
v1.setbrand('4')
v1.setcolor('白色')
v1.setweight('1000斤')
v1.settank('500')
v1.run('赛车')

v = vehicle()
v.setname('铃木')
v.setbrand('4')
v.setcolor('黑色')
v.setweight('1000斤')
v.settank('500')
v.run('越野')

v = vehicle()
v.setname('五菱')
v.setbrand('4')
v.setcolor('棕色')
v.setweight('1000斤')
v.settank('500')
v.run('拉货')

v = vehicle()
v.setname('拖拉机')
v.setbrand('3')
v.setcolor('红色')
v.setweight('1000斤')
v.settank('500')
v.run('爬山')
'''
class studet:
    def __init__(self,num,name,age,sex,height,weight,grade,adress,phone):
        self.__num = num
        self.__name = name
        self.__age = age
        self.__sex = sex
        self.__height = height
        self.__weight = weight
        self.__grade = grade
        self.__adress = adress
        self.__phone = phone

    def study(self,time):
        print(f'学生{self.__name}学习了{time}小时')

    def play(self,game):
        print(f'学生{self.__name}正在打{game}')

    def program(self,rows):
        print(f'学生{self.__name}已经写了{rows}代码')

    def count(self,*a,**b):
        return a + b

s = studet('1001','王小明','18','男','180cm','120斤','优秀','北京','1008820')
s.study(5)
s.play('王者荣耀')
s.program(5000)

class vehicle:
    def __init__(self,name,brand,color,weight,tank):
        self.__name = name
        self.__brand = brand
        self.__color = color
        self.__weight = weight
        self.__tank = tank

    def run(self,*action):
        for i in action:
            print(f'{self.__name}正在{i}')

v = vehicle('法拉利','4','金色','1000斤','500升')
v.run('越野','赛车')
v1 = vehicle('宝马','2','白色','1吨','500升')
v2 = vehicle('铃木','3','红色','1吨','500升')
v3 = vehicle('五菱','4','红色','1吨','500升')
v4 = vehicle('拖拉机','6','红色','1吨','500升')
v4.run('爬坡')

class computer:
    def __init__(self,model,standtime,color,weight,cpu,memory,hardpan):
        self.__model = model
        self.__standtime = standtime
        self.__color = color
        self.__weight = weight
        self.__cpu = cpu
        self.__memory = memory
        self.__hardpan = hardpan

    def playgame(self,game):
        print(f'我正在用{self.__model}牌子的电脑打{game}')

    def office(self):
        print(f'我在用{self.__color}的电脑办公')
c = computer('联想','2小时','蓝色','i7','1000g','8G','256G')
c.playgame('英雄联盟')
c.office()

class monkey:
    def __init__(self, sort, sex, color, weight):
        self.__sort = sort
        self.__sex = sex
        self.__color = color
        self.__weight = weight

    def fire(self, material):
        print(f'{self.__sort}正在用{material}造火')

    def learn(self, *thing):
        for i in thing:
            print(f'{self.__sort}正在学习{i}')

m = monkey('长臂猿', 'man', '黄色', '50kg')
m.fire('石头')
m.learn('烤鱼', '打球')


import torch
from metrics import NDCG_binary_at_k_batch, Recall_at_k_batch

def get_args(args):
    class dotdict(dict):
        """dot.notation access to dictionary attributes"""
        __getattr__ = dict.get
        __setattr__ = dict.__setitem__
        __delattr__ = dict.__delitem__

    args = dotdict(vars(args))

    args.device = 'cpu' if args.gpu == -1 else 'cuda:{}'.format(args.gpu)
    args.torchType = torch.float32

    ## Data and training parameters
    args.train_batch_size = 500
    args.val_batch_size = 2000
    args.n_epoches = 200

    args.print_info_ = 1

    ## Transition parameters (only for our vae)
    args.gamma = 0.1  # Stepsize
    args.alpha = 0.5  # For partial momentum refresh
    args.use_barker = True
    args.use_partialref = True

    args.annealing = True if args.annealing == 'True' else False
    args.learnable_reverse = True if args.learnable_reverse == 'True' else False

    if args.annealing:
        args.total_anneal_steps = 200000
        args.anneal_cap = 0.2
    else:
        args.total_anneal_steps = 0
        args.anneal_cap = 1.

    ## Metric
#     args.metric = NDCG_binary_at_k_batch
    args.metric = Recall_at_k_batch

    if args.model == 'MultiDAE':
        args.l2_coeff = 0.01 / args.train_batch_size
    else:
        args.l2_coeff = 0.

    return args


from datetime import datetime
import random
import os
import re

colors = ['31', '32', '33', '34', '35', '36']
gray = '\033[37m'

env = os.getenv('DEBUG')

def noop(*args):
  return

def Debug(name):
  if env is None:
    return noop

  escaped_env = re.escape(env)
  escaped_env = escaped_env.replace('\\*', '.*?')
  escaped_env = escaped_env.replace(',', '|')
  pattern = re.compile('^(' + escaped_env + ')$')

  if not pattern.match(name):
    return noop

  color = '\033[' + colors[random.randint(0, len(colors) - 1)] + 'm'

  def debug(format, *args):
    print(gray + now() + color + name + ' ' + format % args)

  return debug

def now():
  t = datetime.now()
  return str(t.hour) + ':' + str(t.minute) + ':' + str(t.second) + ' ' + str(
      int(t.microsecond / 1000)) + 'ms '


import os
import sys
import zipfile

try:
    import requests
    import clint
except ImportError:
    sys.exit("Convergence tests require `requests` and `clint`, please install using pip or conda")

def download_zip_with_progress_bar(url):
    r = requests.get(url, stream=True)
    path = url.rsplit('/', 1)[-1]
    with open(path, 'wb') as f:
        total_length = int(r.headers.get('content-length'))
        for chunk in clint.textui.progress.bar(r.iter_content(chunk_size=1024), expected_size=(total_length/1024) + 1):
            if chunk:
                f.write(chunk)
                f.flush()

def unzip(meshzip, folder_name, rename_folder):
    '''Unzip a zip file

    Arguments:
    ----------
    meshzip      : file we want to unzip
    folder_name  : str, name of the folder after extracting.
                  We want this to modify it when download, to follow pygbe
                  problem folder design for running.
    rename_folder: str, name of the folder were we want to store the download.
                   We rename the folder_name, to match config files.
    '''
    with zipfile.ZipFile(meshzip, 'r') as myzip:
        myzip.extractall(path='./tmp')

    print('Unzipping meshes to folder \'geometry/\'...')
    os.rename(os.path.join('tmp', folder_name), rename_folder)
    os.rmdir('tmp')
    print('Removing zip file...')
    os.remove(meshzip)

def check_mesh(mesh_file, folder_name, rename_folder, size):
    ''' Check if there's a geometry folder present in the directory.

    Arguments:
    ----------
    mesh_file    : str, mesh_file url
    folder_name  : str, name of the folder after extracting.
                   We want to pass this to be used in unzip function, where
                   we rename it.
    rename_folder: str, name of the folder were we want to store the download.
                   We rename the folder_name, to match config files.
    size         : str, estimate size of file
    '''
    if not os.path.isdir(rename_folder):
        dl_check = input('The meshes for convergence tests don\'t appear to '
                         'be loaded. Would you like to download them from '
                             'Zenodo?(' + size + ')(y/n): ')
        if dl_check == 'y':
            download_zip_with_progress_bar(mesh_file)
            unzip(mesh_file.split('/')[-1], folder_name, rename_folder)

            print('Done!')


from django.http import Http404, JsonResponse, HttpResponse
from django.core import serializers
from django.views.generic import View
from django.shortcuts import render, get_object_or_404
from django.core.exceptions import PermissionDenied
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic.base import TemplateView
from django.urls import reverse_lazy
from rest_framework.generics import ListAPIView
from rest_framework.views import APIView
from .serializers import NoteSerializer, CategorySerializer
from .models import Note, Category

class IndexView(LoginRequiredMixin, TemplateView):
    login_url = reverse_lazy('accounts:login')
    template_name = 'notes/index.html'

class NoteDetail(View):
    def get(self, request, pk):
        object = get_object_or_404(Note, pk=pk)
        if object.published or (request.user.is_authenticated and request.user == object.creator):
            return render(request, 'notes/detail.html', {'note': object})
        else:
            raise PermissionDenied()

class ApiNoteDetail(APIView):
    def get(self, request, pk):
        object = get_object_or_404(Note, pk=pk)
        if not object.published and object.creator != request.user:
            raise PermissionDenied()
        serializer = NoteSerializer(object)
        return JsonResponse(serializer.data, safe=False)

    def delete(self, request, pk):
        object = get_object_or_404(Note, pk=pk)
        if not object.published and object.creator != request.user:
            raise PermissionDenied()
        object.delete()
        return HttpResponse(status=204)
    def put(self, request, pk):
        object = get_object_or_404(Note, pk=pk)
        if not object.published and object.creator != request.user:
            raise PermissionDenied()
        serializer = NoteSerializer(object, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return HttpResponse(status=204)
        else:
            return JsonResponse(serializer.errors, status=400)

class GetNoteList(ListAPIView):
    serializer_class = NoteSerializer

    def get_queryset(self):
        if self.request.user.is_anonymous:
            raise PermissionDenied()
        query_list = Note.objects.filter(creator=self.request.user)
        dtcreate = self.request.query_params.get('dtcreate', None)
        title = self.request.query_params.get('title', None)
        category = self.request.query_params.get('category', None)
        bookmark = self.request.query_params.get('bookmark', None)
        sort_by = self.request.query_params.get('sort_by', None)
        # filters
        if dtcreate:
            query_list = query_list.filter(dtcreate__date=dtcreate)
        if title:
            query_list = query_list.filter(title__startswith=title)
        if category and category != '0':
            query_list = query_list.filter(category=category)
        if bookmark and bookmark != '0':
            bookmark = bookmark == 'True'
            query_list = query_list.filter(bookmark=bookmark)
        # sort
        if sort_by == 'category':
            query_list = query_list.order_by('category')
        elif sort_by == 'bookmark':
            query_list = query_list.order_by('bookmark')
        return query_list

def api_categories(request):
    if request.method == 'GET':
        categories = Category.objects.all()
        serializer = CategorySerializer(categories, many=True)
        return JsonResponse(serializer.data, safe=False)
    else:
        raise Http404

class CreateNote(APIView):
    def post(self, request):
        data = request.data
        data['creator'] = request.user.id
        serializer = NoteSerializer(data=data)
        if serializer.is_valid():
            serializer.save()
            return HttpResponse(status=201)
        else:
            return JsonResponse(serializer.errors, status=400)


import tkinter as tk
import time,random,public
import paho.mqtt.client as mqtt
import tkinter.ttk as ttk
class DS_Tool:
    def __init__(self,master):
        #初始化窗口，添加窗口中的部件
        master.title("DS-Tools V1.1")
        self.w1=tk.Label(master,text="平台地址：",bg="peru")
        self.server_url=tk.StringVar()
        self.server_url.set("10.5.17.52")
        self.w2=ttk.Combobox(master,textvariable=self.server_url,
                        value=[
                            "10.5.17.52",
                            "cd.inhandcloud.com",
                            "test.shebeiyun.net",
                            "shebeiyun.net",
                            "devicenetworks.io",
                            "smartatm.biz",
                            "c.inhand.com.cn"
                        ])
        self.w3=tk.Label(master,text="账号：",bg="pink")
        self.user_email=tk.StringVar()
        self.user_email.set("wangrc@inhand.com.cn")
        self. w4=ttk.Combobox(master,textvariable=self.user_email,
                        value=["wangrc@inhand.com.cn",
                               "liwei@inhand.com.cn",
                               "wrcyyy@126.com",
                               "wrcyyy@sina.com"])
        self.w5=tk.Label(master,text="设备序列号：",bg="red")
        self.w6=tk.Entry()
        self.w7=tk.Button(master,text="自注册",bg="paleturquoise",command=self.res)
        self.w8=tk.Button(master,text="随机序列号",bg="paleturquoise",command=self.randomSN)
        self.w9=tk.Label(master,text='流量发送频率：\n次/秒',bg="yellow")
        self.w10=tk.Entry(master,width=4)
        self.w11=tk.Label(master,text='流量发送次数：',bg="yellow")
        self.w12=tk.Entry(master,width=4)
        self.w13=tk.Button(master,text='点击发送\n流量数据',command=self.send_flow,bg="yellow")
        self.w14=tk.Button(master,text='点击发送事件',command=self.send_event,bg='turquoise')
        self.w15=tk.Label(master,text='设备ID：')
        self.w16=tk.Label(master,text='设备KEY：')
        self.w17=tk.Label(master,text='事件发送频率：\n次/秒',bg='turquoise')
        self.w18=tk.Label(master,text='事件发送次数：',bg='turquoise')
        self.w19=tk.Entry(master,width=4)
        self.w20=tk.Entry(master,width=4)
        self.w21=tk.Button(master,text='点击发送\n基站定位信息',command=self.send_LBS,bg='gray')
        self.w22=tk.Label(master,text='MCC：',bg='gray')
        self.w23=tk.Label(master,text='MNC：',bg='gray')
        self.w24=tk.Label(master,text='LAC：',bg='gray')
        self.w25=tk.Label(master,text='CID：',bg='gray')
        self.w26=tk.Entry(master,width=4)
        self.w26.insert('insert',460)
        self.w27=tk.Entry(master,width=4)
        self.w27.insert('insert',1)
        self.w28=tk.Entry(master,width=10)
        self.w29=tk.Entry(master,width=10)
        self.w30=tk.Label(master,text='寄存器开始地址：',bg='orange')
        self.w31=tk.Label(master,text='寄存器结束地址：',bg='orange')
        self.w32=tk.Label(master,text='实时数据发送频率：',bg='orange')
        self.w33=tk.Label(master,text='实时数据发送次数：',bg='orange')
        self.w34=tk.Button(master,text='点击发送实时数据',command=self.send_rt_data,bg='orange')
        self.w35=tk.Entry(master,width=8)
        self.w36=tk.Entry(master,width=8)
        self.w37=tk.Entry(master,width=8)
        self.w38=tk.Entry(master,width=8)
        self.w39=tk.Button(master,text='设备上线',command=self.continuous_online,bg='orange')
        self.w40=tk.Text(master,height=1,width=33)#mid文本输入框
        self.w41=tk.Button(master,text='点击发送换热站实时数据',command=self.send_sht_rt_data,bg='orange')
        self.deviceID=tk.Text(master,height=1,width=33)
        self.key=tk.Text(master,height=1,width=33)
        self.publish_log=tk.Text(master,bg='white',fg='brown')#程序运行显示框
        #部件位置
        self.w1.grid(row=0,column=0,sticky='W',pady=5)
        self.w2.grid(row=0,column=1,sticky='W')
        self.w3.grid(row=1,column=0,sticky='W',pady=5)
        self.w4.grid(row=1,column=1,sticky='W')
        self.w5.grid(row=2,column=0,sticky='W',pady=5)
        self.w6.grid(row=2,column=1,sticky='W')
        self.w7.grid(row=3,column=0,sticky='W',pady=5)
        self.w8.grid(row=3,column=1,sticky='W',pady=5)#随机序列号按钮
        self.w9.grid(row=0,column=2,sticky='W',pady=5)
        self.w10.grid(row=0,column=3,sticky='W')
        self.w11.grid(row=1,column=2,sticky='W',pady=5)
        self.w12.grid(row=1,column=3,sticky='W')
        self.w13.grid(row=0,column=4,sticky='W')
        self.w14.grid(row=2,column=4,sticky='W')
        self.w15.grid(row=4,column=0,sticky='W',pady=5)
        self.w16.grid(row=5,column=0,sticky='W',pady=5)
        self.w17.grid(row=2,column=2,sticky='W',pady=5)
        self.w18.grid(row=3,column=2,sticky='W',pady=5)
        self.w19.grid(row=2,column=3,sticky='W')
        self.w20.grid(row=3,column=3,sticky='W')
        self.w21.grid(row=4,column=4,sticky='W')
        self.w22.grid(row=4,column=2,sticky='W',pady=5)
        self.w23.grid(row=5,column=2,sticky='W',pady=5)
        self.w24.grid(row=6,column=2,sticky='W',pady=5)
        self.w25.grid(row=7,column=2,sticky='W',pady=5)
        self.w26.grid(row=4,column=3,sticky='W')
        self.w27.grid(row=5,column=3,sticky='W')
        self.w28.grid(row=6,column=3,sticky='W')
        self.w29.grid(row=7,column=3,sticky='W')
        self.w30.grid(row=8,column=2,sticky='W',pady=5)
        self.w31.grid(row=9,column=2,sticky='W',pady=5)
        self.w32.grid(row=10,column=2,sticky='W',pady=5)
        self.w33.grid(row=11,column=2,sticky='W',pady=5)
        self.w34.grid(row=8,column=4,sticky='W')
        self.w35.grid(row=8,column=3,sticky='W')
        self.w36.grid(row=9,column=3,sticky='W')
        self.w37.grid(row=10,column=3,sticky='W')
        self.w38.grid(row=11,column=3,sticky='W')
        # self.w39.grid(row=6,column=0,sticky='W')
        self.w40.grid(row=6,column=1,sticky='W',pady=5)
        self.w41.grid(row=6,column=0,sticky='W')
        self.deviceID.grid(row=4,column=1,sticky='W',pady=5)
        self.key.grid(row=5,column=1,sticky='W',pady=5)
        self.publish_log.grid(row=0,column=8,rowspan=12, padx=25, pady=15,sticky='N')
    def on_line(self,device_id,key):
        """
        mqtt连接函数，用于每次publish之前
        :param device_id:
        :param key:
        :return:
        """
        self.server = self.w2.get()
        if self.server == 'cd.inhandcloud.com':
            self.port = 9883
        else:
            self.port = 1883
        self.client=mqtt.Client(device_id)
        self.client.username_pw_set(device_id,key)
        self.client.connect(self.server,self.port,10)
        self.client.loop_start()
    def continuous_online(self):
        """
        持续在线函数，用于设备在线
        :return:
        """
        self.server = self.w2.get()
        self.device_id = self.deviceID.get("1.0", "end-1c")
        self.device_key = self.key.get("1.0", "end-1c")
        if len(self.device_id) == len(self.device_key) == 0:
            self.publish_log.delete(0.0, 'end')
            self.publish_log.insert('insert', "请输入正确的设备ID和KEY(点击自注册按钮)")
        else:
            if self.server == 'cd.inhandcloud.com':
                self.port = 9883
            else:
                self.port = 1883
            self.client=mqtt.Client(self.device_id)
            self.client.username_pw_set(self.device_id,self.device_key)
            self.client.connect(self.server,self.port)
            self.client.loop_forever()
    def res(self):
        """
        注册函数，并将注册后的deviceID和KEY填写到输入框内
        :return:
        """
        self.server = self.w2.get()
        self.userEmail = self.w4.get()
        self.sn = self.w6.get()
        if self.server == "":
            self.publish_log.delete(0.0, 'end')
            self.publish_log.insert('insert', "请输入服务器地址")
        elif self.userEmail == "":
            self.publish_log.delete(0.0, 'end')
            self.publish_log.insert('insert', "请输入用户邮箱")
        elif self.sn == "":
            self.publish_log.delete(0.0, 'end')
            self.publish_log.insert('insert', "请输入网关序列号")
        else:
            result = public.resign(self.server, self.userEmail, self.sn)
            self.deviceID.delete(0.0, 'end')
            self.key.delete(0.0, 'end')
            self.deviceID.insert('insert', result[0])
            self.key.insert('insert', result[1])
    def send_flow(self):
        """
        发送流量数据函数
        :return:
        """
        device_id = self.deviceID.get("1.0", "end-1c")
        device_key = self.key.get("1.0", "end-1c")
        flow_rate = self.w10.get()
        flow_count = self.w12.get()
        if len(device_id)==len(device_key)==0:
            self.publish_log.delete(0.0, 'end')
            self.publish_log.insert('insert', "请输入正确的设备ID和KEY(点击自注册按钮)")
        elif flow_rate == "":
            self.publish_log.delete(0.0, 'end')
            self.publish_log.insert('insert', "请输入发送频率")
        elif flow_count == "":
            self.publish_log.delete(0.0, 'end')
            self.publish_log.insert('insert', "请输入流量发送次数")
        else:
            self.on_line(device_id,device_key)
            num=0
            while num<int(flow_count):
                dataflow=public.constructData().flowPayload()
                self.client.publish(topic='v1/%s/series'%device_id,payload=dataflow)
                num+=1
                log = "已发送%d条流量数据" % num
                self.publish_log.delete(0.0, 'end')
                self.publish_log.insert('insert', log + '\n')
                self.publish_log.update()
                time.sleep(int(flow_rate))
            self.client.loop_stop()
            self.client.disconnect()
            self.publish_log.insert('insert', '流量发送完成！')
            self.publish_log.update()
    def randomSN(self):
        """
        随机设备序列号函数
        :return:
        """
        self.w6.delete(0, 15)  # 先清空文本框
        sn = 'RP9111700' + str(random.randint(123456, 999999))
        self.w6.insert('insert', sn)
    def send_event(self):
        """
        发送事件函数
        :return:
        """
        device_id = self.deviceID.get("1.0", "end-1c")
        device_key = self.key.get("1.0", "end-1c")
        event_rate = self.w19.get()
        event_count = self.w20.get()
        if len(device_id) == len(device_key) == 0:
            self.publish_log.delete(0.0, 'end')
            self.publish_log.insert('insert', "请输入正确的设备ID和KEY(点击自注册按钮)")
        elif event_rate == "":
            self.publish_log.delete(0.0, 'end')
            self.publish_log.insert('insert', "请输入事件发送频率")
        elif event_count == "":
            self.publish_log.delete(0.0, 'end')
            self.publish_log.insert('insert', "请输入事件发送次数")
        else:
            self.on_line(device_id,device_key)
            num=0
            while num<int(event_count):
                dataEvent=public.constructData().eventPayload()
                self.client.publish(topic='v1/%s/event' % device_id, payload=dataEvent)
                num += 1
                log = "已发送%d条事件" % num
                self.publish_log.delete(0.0, 'end')
                self.publish_log.insert('insert', log + '\n')
                self.publish_log.update()
                time.sleep(int(event_rate))
            self.client.loop_stop()
            self.client.disconnect()
            self.publish_log.insert('insert', '事件发送完成！')
            self.publish_log.update()
    def send_LBS(self):
        device_id = self.deviceID.get("1.0", "end-1c")
        device_key = self.key.get("1.0", "end-1c")
        mnc=self.w27.get()
        mcc=self.w26.get()
        lac=self.w28.get()
        cid=self.w29.get()
        if len(device_id) == len(device_key) == 0:
            self.publish_log.delete(0.0, 'end')
            self.publish_log.insert('insert', "请输入正确的设备ID和KEY(点击自注册按钮)")
        elif mnc == "" or mcc == "" or lac == "" or cid == "":
            self.publish_log.delete(0.0, 'end')
            self.publish_log.insert('insert', "MNC、MCC、LAC、CID均不能为空")
        else:
            self.on_line(device_id,device_key)
            dataLBS=public.constructData().lbsPayload(mnc,mcc,lac,cid)
            self.client.publish('v1/%s/lbs'%device_id,payload=dataLBS)
            self.client.loop_stop()
            self.client.disconnect()
            self.publish_log.delete(0.0, 'end')
            self.publish_log.insert('insert', dataLBS + '\n' + '基站信息发送完成！')
            self.publish_log.update()
    def send_rt_data(self):
        device_id = self.deviceID.get("1.0", "end-1c")
        device_key = self.key.get("1.0", "end-1c")
        start_num = self.w35.get()
        end_num = self.w36.get()
        rtdata_rate = self.w37.get()
        rtdata_count = self.w38.get()
        if len(device_id) == len(device_key) == 0:
            self.publish_log.delete(0.0, 'end')
            self.publish_log.insert('insert', "请输入正确的设备ID和KEY(点击自注册按钮)")
        elif start_num == "" or end_num=="":
            self.publish_log.delete(0.0, 'end')
            self.publish_log.insert('insert', "请输入寄存器起始地址")
        elif rtdata_rate == "":
            self.publish_log.delete(0.0, 'end')
            self.publish_log.insert('insert', "请输入实时数据发送频率")
        elif rtdata_count == "":
            self.publish_log.delete(0.0, 'end')
            self.publish_log.insert('insert', "请输入实时数据发送次数")
        else:
            self.on_line(device_id,device_key)
            siteInfo=public.constructData().siteInfoPayload()
            self.client.publish('v1/%s/site/info'%device_id, payload=siteInfo)
            self.publish_log.delete(0.0, 'end')
            self.publish_log.insert('insert', "发送设备信息成功\n")
            self.publish_log.update()
            time.sleep(1)
            controllers=public.constructData().groupPayload(int(start_num),int(end_num))
            self.client.publish('v1/%s/controllers_configuration' % device_id, payload=controllers)
            self.publish_log.insert('insert', "发送变量字典信息成功\n")
            self.publish_log.update()
            time.sleep(5)
            num=0
            while num < int(rtdata_count):
                rtData=public.constructData().rtDataPayload(int(start_num),int(end_num))
                self.client.publish(topic='v1/%s/series' % device_id, payload=rtData)
                num += 1
                log = "已发送%d条实时数据" % num
                self.publish_log.delete(0.0, 'end')
                self.publish_log.insert('insert', log + '\n')
                self.publish_log.update()
                time.sleep(int(rtdata_rate))
            self.client.loop_stop()
            self.client.disconnect()
            self.publish_log.insert('insert', "实时数据发送完毕！")
    def send_sht_rt_data(self):
        device_id = self.deviceID.get("1.0", "end-1c")
        device_key = self.key.get("1.0", "end-1c")
        mid=self.w40.get("1.0", "end-1c")
        if len(device_id) == len(device_key) == 0:
            self.publish_log.delete(0.0, 'end')
            self.publish_log.insert('insert', "请输入正确的设备ID和KEY(点击自注册按钮)")
        elif mid == "" :
            self.publish_log.delete(0.0, 'end')
            self.publish_log.insert('insert', "请输入机组id")
        else:
            self.on_line(device_id, device_key)
            num=1
            while True:
                payload = public.constructData().exchangeDataPayload()
                self.client.publish(topic='v1/%s/series' % mid, payload=payload)
                log = "已发送%d条实时数据" % num
                self.publish_log.delete(0.0, 'end')
                self.publish_log.insert('insert', log + '\n')
                self.publish_log.update()
                num += 1
                time.sleep(30)
if __name__=="__main__":
    root = tk.Tk()
    app = DS_Tool(root)
    root.mainloop()


#!/usr/bin/env python3
# -*- mode: python -*-
# -*- coding: utf-8 -*-
"""Shared base utilities for Python applications.

Mainly:
 - Configures the logging system with both console and file logging.
 - Command-line flags framework allowing other modules to declare
   their own flags.
 - Program startup procedure.

Template for a Python application:
  from kiji import base

  FLAGS = base.FLAGS

  def Main(args):
    ...
    return os.EX_OK

  if __name__ == '__main__':
    base.Run(Main)
"""

import collections
import datetime
import getpass
import http.server
import json
import logging
import os
import random
import re
import signal
import socketserver
import subprocess
import sys
import tempfile
import threading
import time

class Default(object):
  """Singleton used to in place of None for default parameter values.

  Useful when None is a valid parameter value and cannot be used
  to mean "use the default".
  """
  pass
Default = Default()

class Undefined(object):
  """Singleton used in place of None to represent a missing dictionary entry."""
  pass
Undefined = Undefined()

class Error(Exception):
  """Errors used in this module."""
  pass

# ------------------------------------------------------------------------------
# Time utilities

def NowMS():
  """Returns: the current time, in ms since the Epoch."""
  return int(1000 * time.time())

def NowNS():
  """Returns: the current time, in ns since the Epoch."""
  return int(1000000000 * time.time())

def NowDateTime():
  """Returns: the current time as a date/time object (local timezone)."""
  return datetime.datetime.now()

def Timestamp(ts=None):
  """Reports the current time as a human-readable timestamp.

  Timestamp has micro-second precision.
  Formatted as 'yyyymmdd-hhmmss-mmmmmm-tz'.

  Args:
    ts: Optional explicit timestamp, in seconds since Epoch.
  Returns:
    the current time as a human-readable timestamp.
  """
  if ts is None:
    ts = time.time()  # in seconds since Epoch
  now = time.localtime(ts)
  ts_subsecs = (ts - int(ts))
  microsecs = int(ts_subsecs * 1000000)
  return '%04d%02d%02d-%02d%02d%02d-%06d-%s' % (
      now.tm_year,
      now.tm_mon,
      now.tm_mday,
      now.tm_hour,
      now.tm_min,
      now.tm_sec,
      microsecs,
      time.tzname[now.tm_isdst],
  )

# ------------------------------------------------------------------------------
# JSON utilities

JSON_DECODER = json.JSONDecoder()
PRETTY_JSON_ENCODER = json.JSONEncoder(
  indent=2,
  sort_keys=True,
)
COMPACT_JSON_ENCODER = json.JSONEncoder(
  indent=None,
  sort_keys=True,
  separators=(',', ':'),
)

def JsonDecode(json_str):
  """Decodes a JSON encoded string into a Python value.

  Args:
    json_str: JSON encoded string.
  Returns:
    The Python value decoded from the specified JSON string.
  """
  return JSON_DECODER.decode(json_str)

def JsonEncode(py_value, pretty=True):
  """Encodes a Python value into a JSON string.

  Args:
    py_value: Python value to encode as a JSON string.
    pretty: True means pretty, False means compact.
  Returns:
    The specified Python value encoded as a JSON string.
  """
  encoder = PRETTY_JSON_ENCODER if pretty else COMPACT_JSON_ENCODER
  return encoder.encode(py_value)

# ------------------------------------------------------------------------------
# Text utilities

def Truth(text):
  """Parses a human truth value.

  Accepts 'true', 'false', 'yes', 'no', 'y', 'n'.
  Parsing is case insensitive.

  Args:
    text: Input to parse.
  Returns:
    Parsed truth value as a bool.
  """
  lowered = text.lower()
  if lowered in frozenset(['y', 'yes', 'true']):
    return True
  elif lowered in frozenset(['n', 'no', 'false']):
    return False
  else:
    raise Error('Invalid truth value: %r' % text)

def RandomAlphaNumChar():
  """Generates a random character in [A-Za-z0-9]."""
  num = random.randint(0, 26 + 26 + 10)
  if num < 26:
    return chr(num + 65)
  num -= 26
  if num < 26:
    return chr(num + 97)
  return chr(num + 48)

def RandomAlphaNumWord(length):
  """Generates a random word with the specified length.

  Uses characters from the set [A-Za-z0-9].

  Args:
    length: Length of the word to generate.
  Returns:
    A random word of the request length.
  """
  return ''.join([RandomAlphaNumChar() for _ in range(0, length)])

def StripPrefix(string, prefix):
  """Strips a required prefix from a given string.

  Args:
    string: String required to start with the specified prefix.
    prefix: Prefix to remove from the string.
  Returns:
    The given string without the prefix.
  """
  assert string.startswith(prefix)
  return string[len(prefix):]

def StripOptionalPrefix(string, prefix):
  """Strips an optional prefix from a given string.

  Args:
    string: String, potentially starting with the specified prefix.
    prefix: Prefix to remove from the string.
  Returns:
    The given string with the prefix removed, if applicable.
  """
  if string.startswith(prefix):
    string = string[len(prefix):]
  return string

def StripSuffix(string, suffix):
  """Strips a required suffix from a given string.

  Args:
    string: String required to end with the specified suffix.
    suffix: Suffix to remove from the string.
  Returns:
    The given string with the suffix removed.
  """
  assert string.endswith(suffix)
  return string[:-len(suffix)]

def StripOptionalSuffix(string, suffix):
  """Strips an optional suffix from a given string.

  Args:
    string: String required to end with the specified suffix.
    suffix: Suffix to remove from the string.
  Returns:
    The given string with the suffix removed, if applicable.
  """
  if string.endswith(suffix):
    string = string[:-len(suffix)]
  return string

def StripMargin(text, separator='|'):
  """Strips the left margin from a given text block.

  Args:
    text: Multi-line text with a delimited left margin.
    separator: Separator used to delimit the left margin.
  Returns:
    The specified text with the left margin removed.
  """
  lines = text.split('\n')
  lines = map(lambda line: line.split(separator, 1)[-1], lines)
  return '\n'.join(lines)

def AddMargin(text, margin):
  """Adds a left margin to a given text block.

  Args:
    text: Multi-line text block.
    margin: Left margin to add at the beginning of each line.
  Returns:
    The specified text with the added left margin.
  """
  lines = text.split('\n')
  lines = map(lambda line: margin + line, lines)
  return '\n'.join(lines)

def WrapText(text, ncolumns):
  """Wraps a text block to fit in the specified number of columns.

  Args:
    text: Multi-line text block.
    ncolumns: Maximum number of columns allowed for each line.
  Returns:
    The specified text block, where each line is ncolumns at most.
  """
  def ListWrappedLines():
    for line in text.split('\n'):
      while len(line) > ncolumns:
        yield line[:ncolumns]
        line = line[ncolumns:]
      yield line
  return '\n'.join(ListWrappedLines())

def CamelCase(text, separator='_'):
  """Camel-cases a given character sequence.

  E.g. 'this_string' becomes 'ThisString'.

  Args:
    text: Sequence of characters to convert to camel-case.
    separator: Separator to use to identify words.
  Returns:
    The camel-cased sequence of characters.
  """
  return ''.join(map(str.capitalize, text.split(separator)))

def UnCamelCase(text, separator='_'):
  """Un-camel-cases a camel-cased word.

  For example:
   - 'ThisString' becomes 'this_string',
   - 'JIRA' becomes 'jira',
   - 'JIRATool' becomes 'jira_tool'.

  Args:
    text: Camel-case sequence of characters.
    separator: Separator to use to identify words.
  Returns:
    The un-camel-cased sequence of characters.
  """
  split = re.findall(r'(?:[A-Z][a-z0-9]*|[a-z0.9]+)', text)
  split = map(str.lower, split)
  split = list(split)

  words = []

  while len(split) > 0:
    word = split[0]
    split = split[1:]

    if len(word) == 1:
      while (len(split) > 0) and (len(split[0]) == 1):
        word += split[0]
        split = split[1:]

    words.append(word)

  return separator.join(words)

def Truncate(text, width, ellipsis='..'):
  """Truncates a text to the specified number of characters.

  Args:
    text: Text to truncate.
    width: Number of characters allowed.
    ellipsis: Optional ellipsis text to append, if truncation occurs.
  Returns:
    The given text, truncated to at most width characters.
    If truncation occurs, the truncated text ends with the ellipsis.
  """
  if len(text) > width:
    text = text[:(width - len(ellipsis))] + ellipsis
  return text

_RE_NO_IDENT_CHARS = re.compile(r'[^A-Za-z0-9_]+')

def MakeIdent(text, sep='_'):
  """Makes an identifier out of a random text.

  Args:
    text: Text to create an identifier from.
    sep: Separator used to replace non-identifier characters.
  Returns:
    An identifier made after the specified text.
  """
  return _RE_NO_IDENT_CHARS.sub(sep, text)

# ------------------------------------------------------------------------------

def _ComputeProgramName():
  program_path = os.path.abspath(sys.argv[0])
  if not os.path.exists(program_path):
    return 'unknown'
  else:
    return os.path.basename(program_path)

_PROGRAM_NAME = _ComputeProgramName()

def SetProgramName(program_name):
  """Sets this program's name."""
  global _PROGRAM_NAME
  _PROGRAM_NAME = program_name

def GetProgramName():
  """Returns: this program's name."""
  global _PROGRAM_NAME
  return _PROGRAM_NAME

def ShellCommandOutput(command):
  """Runs a shell command and returns its output.

  Args:
    command: Shell command to run.
  Returns:
    The output from the shell command (stderr merged with stdout).
  """
  process = subprocess.Popen(
      args=['/bin/bash', '-c', command],
      stdout=subprocess.PIPE,
      stderr=subprocess.STDOUT,
  )
  process.wait()
  output = process.stdout.read().decode()
  assert process.returncode == 0, (
      'Shell command failed: %r : %s' % (command, output))
  return output

class MultiThreadedHTTPServer(
    socketserver.ThreadingMixIn,
    http.server.HTTPServer,
):
  """Multi-threaded HTTP server."""
  pass

# ------------------------------------------------------------------------------
# Files utilities

def MakeDir(path):
  """Creates a directory if necessary.

  Args:
    path: Path of the directory to create.
  Returns:
    True if the directory was created, false if it already existed.
  """
  if os.path.exists(path):
    return False
  else:
    os.makedirs(path, exist_ok=True)
    return True

def Remove(path):
  """Removes the file with the given path.

  Does nothing if no file exists with the specified path.

  Returns:
    Whether the file was deleted.
  """
  try:
    os.remove(path)
    return True
  except FileNotFoundError:
    return False

def Touch(path, atime=None, mtime=None):
  """Equivalent of the shell command 'touch'.

  Args:
    path: Path of the file to touch.
    atime: Access time, in seconds since the Epoch.
    mtime: Modification time, in seconds since the Epoch.
  """
  assert ((atime is None) == (mtime is None))
  if atime is None:
    times = None
  else:
    times = (atime, mtime)
  with open(path, 'ab+') as f:
    # Note: there is a race condition here.
    os.utime(path, times=times)

def Exit():
  self_pid = os.getpid()
  logging.info('Forcibly terminating program (PID=%s)', self_pid)
  os.kill(self_pid, signal.SIGKILL)

def ListJavaProcesses():
  """Lists the Java processes.

  Yields:
    Pairs (PID, Java class name).
  """
  for line in ShellCommandOutput('jps -l').splitlines():
    line = line.strip()
    if len(line) == 0: continue
    (pid, class_name) = line.split()
    yield (int(pid), class_name)

def ProcessExists(pid):
  """Tests whether a process exists.

  Args:
    pid: PID of the process to test the existence of.
  Returns:
    Whether a process with the specified PID exists.
  """
  try:
    os.kill(pid, 0)
    return True
  except ProcessLookupError:
    return False

# ------------------------------------------------------------------------------

class ImmutableDict(dict):
  """Dictionary guaranteed immutable.

  All mutations raise an exception.
  Behaves exactly as a dict otherwise.
  """

  def __init__(self, items=None, **kwargs):
    if items is not None:
      super(ImmutableDict, self).__init__(items)
      assert (len(kwargs) == 0)
    else:
      super(ImmutableDict, self).__init__(**kwargs)

  def __setitem__(self, key, value):
    raise Exception(
        'Attempting to map key %r to value %r in ImmutableDict %r'
        % (key, value, self))

  def __delitem__(self, key):
    raise Exception(
        'Attempting to remove mapping for key %r in ImmutableDict %r'
        % (key, self))

  def clear(self):
    raise Exception('Attempting to clear ImmutableDict %r' % self)

  def update(self, items=None, **kwargs):
    raise Exception(
        'Attempting to update ImmutableDict %r with items=%r, kwargs=%r'
        % (self, args, kwargs))

  def pop(self, key, default=None):
    raise Exception(
        'Attempting to pop key %r from ImmutableDict %r' % (key, self))

  def popitem(self):
    raise Exception('Attempting to pop item from ImmutableDict %r' % self)

# ------------------------------------------------------------------------------

RE_FLAG = re.compile(r'^--?([^=]+)(?:=(.*))?$')

class Flags(object):
  """Wrapper for command-line flags."""

  class StringFlag(object):
    """Basic string flag parser."""

    def __init__(self, name, default=None, help=None):
      """Constructs a specification for a string CLI flag.

      Args:
        name: Command-line flag name, eg. 'flag-name' or 'flag_name'.
            Dashes are normalized to underscores.
        default: Optional default value for the flag if unspecified.
        help: Help message to include when displaying the usage text.
      """
      self._name = name.replace('-', '_')
      self._value = default
      self._default = default
      self._help = help

    def Parse(self, argument):
      """Parses the command-line argument.

      Args:
        argument: Command-line argument, as a string.
      """
      self._value = argument

    @property
    def type(self):
      return 'string'

    @property
    def name(self):
      return self._name

    @property
    def value(self):
      return self._value

    @property
    def default(self):
      return self._default

    @property
    def help(self):
      return self._help

  class IntegerFlag(StringFlag):
    @property
    def type(self):
      return 'integer'

    def Parse(self, argument):
      self._value = int(argument)

  class FloatFlag(StringFlag):
    @property
    def type(self):
      return 'float'

    def Parse(self, argument):
      self._value = float(argument)

  class BooleanFlag(StringFlag):
    @property
    def type(self):
      return 'boolean'

    def Parse(self, argument):
      if argument is None:
        self._value = True
      else:
        self._value = Truth(argument)

  # ----------------------------------------------------------------------------

  def __init__(self, name, parent=None):
    """Initializes a new flags parser.

    Args:
      name: Name for this collection of flags.
          Used in PrintUsage().
      parent: Optional parent flags environment.
    """
    self._name = name
    self._parent = parent

    # Map: flag name -> flag definition
    self._defs = {}

    # After parsing, tuple of unparsed arguments:
    self._unparsed = None

  def Add(self, flag_def):
    assert (flag_def.name not in self), \
        ('Flag %r already defined' % flag_def.name)
    self._defs[flag_def.name] = flag_def

  def AddInteger(self, name, **kwargs):
    self.Add(Flags.IntegerFlag(name, **kwargs))

  def AddString(self, name, **kwargs):
    self.Add(Flags.StringFlag(name, **kwargs))

  def AddBoolean(self, name, **kwargs):
    self.Add(Flags.BooleanFlag(name, **kwargs))

  def AddFloat(self, name, **kwargs):
    self.Add(Flags.FloatFlag(name, **kwargs))

  def Parse(self, args, config_file=None):
    """Parses the command-line arguments.

    Args:
      args: List of command-line arguments.
      config_file: Location of a file containing a json object with base flag values (values in
          args will take precedence over these values).
    Returns:
      Whether successful.
    """
    unparsed = []

    skip_parse = False

    if config_file is not None:
      with open(config_file) as config_file_handle:
        config_dict = json.load(fp=config_file_handle)

        # Load configuration file values.
        for key, value in config_dict.items():
          if key not in self._defs:
            logging.warning('Found unused configuration entry. %s: %r' % (key, value))
            continue

          self._defs[key].Parse(value)

    for arg in args:
      if arg == '--':
        skip_parse = True
        continue

      if skip_parse:
        unparsed.append(arg)
        continue

      match = RE_FLAG.match(arg)
      if match is None:
        unparsed.append(arg)
        continue

      key = match.group(1).replace('-', '_')
      value = match.group(2)

      if key not in self._defs:
        unparsed.append(arg)
        continue

      self._defs[key].Parse(value)

    self._unparsed = tuple(unparsed)
    return True

  def __contains__(self, name):
    if name in self._defs:
      return True
    if self._parent is not None:
      return name in self._parent
    return False

  def __getattr__(self, name):
    assert (self._unparsed is not None), \
        ('Flags have not been parsed yet: cannot access flag %r' % name)
    if name in self._defs:
      return self._defs[name].value
    elif self._parent is not None:
      return getattr(self._parent, name)
    else:
      raise AttributeError(name)

  def GetUnparsed(self):
    assert (self._unparsed is not None), 'Flags have not been parsed yet'
    return self._unparsed

  def ListFlags(self):
    """Lists the declared flags.

    Yields:
      Pair: (flag name, flag descriptor).
    """
    yield from self._defs.items()

  def PrintUsage(self):
    indent = 8
    ncolumns = Terminal.columns

    print('-' * 80)
    print('%s:' % self._name)
    for (name, flag) in sorted(self._defs.items()):
      if flag.help is not None:
        flag_help = WrapText(text=flag.help, ncolumns=ncolumns - indent)
      else:
        flag_help = 'Undocumented'
      print(' --%s: %s = %r\n%s\n' % (
          name,
          flag.type,
          flag.default,
          AddMargin(StripMargin(flag_help), ' ' * indent),
      ))

    if self._parent is not None:
      self._parent.PrintUsage()

FLAGS = Flags(name='Global flags')

# ------------------------------------------------------------------------------

def MakeTuple(name, **kwargs):
  """Creates a read-only named-tuple with the specified key/value pair.

  Args:
    name: Name of the named-tuple.
    **kwargs: Key/value pairs in the named-tuple.
  Returns:
    A read-only named-tuple with the specified name and key/value pairs.
  """
  tuple_class = collections.namedtuple(
      typename=name,
      field_names=kwargs.keys(),
  )
  return tuple_class(**kwargs)

# Shell exit codes:
ExitCode = MakeTuple('ExitCode',
  SUCCESS = os.EX_OK,
  FAILURE = 1,
  USAGE   = os.EX_USAGE,
)

# ------------------------------------------------------------------------------

LogLevel = MakeTuple('LogLevel',
  FATAL         = 50,
  ERROR         = 40,
  WARNING       = 30,
  INFO          = 20,
  DEBUG         = 10,
  DEBUG_VERBOSE = 5,
  ALL           = 0,
)

def ParseLogLevelFlag(level):
  """Parses a logging level command-line flag.

  Args:
    level: Logging level command-line flag (string).
  Returns:
    Logging level (integer).
  """
  log_level = getattr(LogLevel, level.upper(), None)
  if type(log_level) == int:
    return log_level

  try:
    return int(level)
  except ValueError:
    level_names = sorted(LogLevel._asdict().keys())
    raise Error('Invalid logging-level %r. Use one of %s or an integer.'
                % (level, ', '.join(level_names)))

FLAGS.AddString(
    name='log_level',
    default='DEBUG',
    help=('Master log level (integer or level name).\n'
          'Overrides specific logging levels.'),
)

FLAGS.AddString(
    name='log_console_level',
    default='INFO',
    help='Filter log statements sent to the console (integer or level name).',
)

FLAGS.AddString(
    name='log_file_level',
    default='ALL',
    help='Filter log statements sent to the log file (integer or level name).',
)

FLAGS.AddString(
    name='log_dir',
    default=None,
    help='Directory where to write logs.',
)

# ------------------------------------------------------------------------------

def Synchronized(lock=None):
  """Decorator for synchronized functions.

  Similar but not equivalent to Java synchronized methods.
  """
  if lock is None:
    lock = threading.Lock()

  def _Wrap(function):
    def _SynchronizedWrapper(*args, **kwargs):
      with lock:
        return function(*args, **kwargs)
    return _SynchronizedWrapper

  return _Wrap

# ------------------------------------------------------------------------------

def Memoize():
  """Returns a decorator to memoize the function it is applied to.

  Memoization is incompatible with functions whose parameters are mutable.
  This memoization implementation is fairly incomplete and primitive.
  In particular, positional and keyword parameters are not normalized.
  """
  UNKNOWN = object()

  def Decorator(function):
    """Wraps a function and returns its memoized version.

    Args:
      function: Function to wrap with memoization.
    Returns:
      The memoized version of the specified function.
    """
    # Map: args tuple -> function(args)
    memoize = dict()

    def MemoizeWrapper(*args, **kwargs):
      all_args = (args, tuple(sorted(kwargs.items())))
      value = memoize.get(all_args, UNKNOWN)
      if value is UNKNOWN:
        value = function(*args, **kwargs)
        memoize[all_args] = value
      return value

    return MemoizeWrapper

  return Decorator

# ------------------------------------------------------------------------------

class _Terminal(object):
  """Map of terminal colors."""

  # Escape sequence to clear the screen:
  clear = '\033[2J'

  # Escape sequence to move the cursor to (y,x):
  move = '\033[%s;%sH'

  def MoveTo(self, x, y):
    """Makes an escape sequence to move the cursor."""
    return _Terminal.move % (y,x)

  normal    = '\033[0m'
  bold      = '\033[1m'
  underline = '\033[4m'
  blink     = '\033[5m'
  reverse   = '\033[7m'

  FG = MakeTuple('ForegroundColor',
    black   = '\033[01;30m',
    red     = '\033[01;31m',
    green   = '\033[01;32m',
    yellow  = '\033[01;33m',
    blue    = '\033[01;34m',
    magenta = '\033[01;35m',
    cyan    = '\033[01;36m',
    white   = '\033[01;37m',
  )

  BG = MakeTuple('BackgroundColor',
    black   = '\033[01;40m',
    red     = '\033[01;41m',
    green   = '\033[01;42m',
    yellow  = '\033[01;43m',
    blue    = '\033[01;44m',
    magenta = '\033[01;45m',
    cyan    = '\033[01;46m',
    white   = '\033[01;47m',
  )

  @property
  def columns(self):
    """Reports the number of columns in the calling shell.

    Returns:
      The number of columns in the terminal.
    """
    return int(ShellCommandOutput('tput cols'))

  @property
  def lines(self):
    """Reports the number of lines in the calling shell.

    Returns:
      The number of lines in the terminal.
    """
    return int(ShellCommandOutput('tput lines'))

Terminal = _Terminal()

# ------------------------------------------------------------------------------

RE_TEMPLATE_FIELD_LINE = re.compile(r'^(\w+):\s*(.*)\s*$')

def ParseTemplate(template):
  """Parses an issue template.

  A template is a text file describing fields with lines such as:
      'field_name: the field value'.
  A field value may span several lines, until another 'field_name:' is found.
  Lines starting with '#' are comments and are discarded.
  Field values are stripped of their leading/trailing spaces and new lines.

  Args:
    template: Filled-in template text.
  Yields:
    Pairs (field name, field text).
  """
  field_name = None
  field_value = []

  for line in template.strip().split('\n') + ['end:']:
    if line.startswith('#'): continue
    match = RE_TEMPLATE_FIELD_LINE.match(line)
    if match:
      if field_name is not None:
        yield (field_name, '\n'.join(field_value).strip())
      elif len(field_value) > 0:
        logging.warning('Ignoring lines: %r', field_value)

      field_name = match.group(1)
      field_value = [match.group(2)]
    else:
      field_value.append(line)

def InputTemplate(template, fields):
  """Queries the user for inputs through a template file.

  Args:
    template: Template with placeholders for the fields.
        Specified as a Python format with named % markers.
    fields: Dictionary with default values for the template.
  Returns:
    Fields dictionary as specified/modified by the user.
  """
  editor = os.environ.get('EDITOR', '/usr/bin/vim')
  with tempfile.NamedTemporaryFile('w+t') as f:
    f.write(template % fields)
    f.flush()
    user_command = '%s %s' % (editor, f.name)
    if os.system(user_command) != 0:
      raise Error('Error acquiring user input (command was %r).' % user_command)
    with open(f.name, 'r') as f:
      filled_template = f.read()

  fields = dict(ParseTemplate(filled_template))
  return fields

# ------------------------------------------------------------------------------

HttpMethod = MakeTuple('HttpMethod',
  GET = 'GET',
  POST = 'POST',
  PUT = 'PUT',
  DELETE = 'DELETE',
  HEAD = 'HEAD',
  OPTIONS = 'OPTIONS',
  TRACE = 'TRACE',
  CONNECT = 'CONNECT',
)

ContentType = MakeTuple('ContentType',
  JSON = 'application/json',
  XML = 'application/xml',
  PATCH = 'text/x-patch',
  PLAIN = 'text/plain',
)

# ------------------------------------------------------------------------------

_LOGGING_INITIALIZED = False

def SetupLogging(
    level,
    console_level,
    file_level,
):
  """Initializes the logging system.

  Args:
    level: Root logger level.
    console_level: Log level for the console handler.
    file_level: Log level for the file handler.
  """
  global _LOGGING_INITIALIZED
  if _LOGGING_INITIALIZED:
    logging.debug('SetupLogging: logging system already initialized')
    return

  program_name = GetProgramName()
  logging.addLevelName(LogLevel.DEBUG_VERBOSE, 'DEBUG_VERBOSE')
  logging.addLevelName(LogLevel.ALL, 'ALL')

  # Initialize the logging system:

  log_formatter = logging.Formatter(
      fmt='%(asctime)s %(levelname)s %(filename)s:%(lineno)s : %(message)s',
  )
  # Override the log date formatter to include the time zone:
  def FormatTime(record, datefmt=None):
    time_tuple = time.localtime(record.created)
    tz_name = time.tzname[time_tuple.tm_isdst]
    return '%(date_time)s-%(millis)03d-%(tz_name)s' % dict(
        date_time=time.strftime('%Y%m%d-%H%M%S', time_tuple),
        millis=record.msecs,
        tz_name=tz_name,
    )
  log_formatter.formatTime = FormatTime

  logging.root.handlers.clear()
  logging.root.setLevel(level)

  console_handler = logging.StreamHandler()
  console_handler.setFormatter(log_formatter)
  console_handler.setLevel(console_level)
  logging.root.addHandler(console_handler)

  # Initialize log dir:
  timestamp = Timestamp()
  pid = os.getpid()

  if FLAGS.log_dir is None:
    tmp_dir = os.path.join('/tmp', getpass.getuser(), program_name)
    if not os.path.exists(tmp_dir): os.makedirs(tmp_dir)
    FLAGS.log_dir = tempfile.mkdtemp(
        prefix='%s.%d.' % (timestamp, pid),
        dir=tmp_dir)
  logging.info('Using log dir: %s', FLAGS.log_dir)
  if not os.path.exists(FLAGS.log_dir):
    os.makedirs(FLAGS.log_dir)

  log_file = os.path.join(FLAGS.log_dir,
                          '%s.%s.%d.log' % (program_name, timestamp, pid))

  file_handler = logging.FileHandler(filename=log_file)
  file_handler.setFormatter(log_formatter)
  file_handler.setLevel(file_level)
  logging.root.addHandler(file_handler)

  _LOGGING_INITIALIZED = True

def Run(main):
  """Runs a Python program's Main() function.

  Args:
    main: Main function, with an expected signature like
      exit_code = main(args)
      where args is a list of the unparsed command-line arguments.
  """
  # Parse command-line arguments:
  if not FLAGS.Parse(sys.argv[1:]):
    FLAGS.PrintUsage()
    return os.EX_USAGE

  try:
    log_level = ParseLogLevelFlag(FLAGS.log_level)
    log_console_level = ParseLogLevelFlag(FLAGS.log_console_level)
    log_file_level = ParseLogLevelFlag(FLAGS.log_file_level)
  except Error as err:
    print(err)
    return os.EX_USAGE

  SetupLogging(
      level = log_level,
      console_level = log_console_level,
      file_level = log_file_level,
  )

  # Run program:
  sys.exit(main(FLAGS.GetUnparsed()))

if __name__ == '__main__':
  raise Error('%r cannot be used as a standalone script.' % sys.argv[0])


# MAIO exercise 2
# Fourier transforms
# Niek Collot d'Escury

import numpy as np
from scipy import fftpack
from scipy import signal
import matplotlib.pyplot as plt
import matplotlib as mpl
################################################################
# plotting parameters
mpl.rcParams["figure.figsize"] = [8 , 4.8]
mpl.rcParams['legend.fontsize'] = 12      #legend size
#title params
mpl.rcParams['axes.titlesize'] = 17
mpl.rcParams['axes.titleweight'] = 'bold'
mpl.rcParams['font.style'] = 'italic'    #all fonts italic
#axes params
mpl.rcParams['axes.labelsize'] = 15
mpl.rcParams["xtick.labelsize"] = 13
mpl.rcParams["ytick.labelsize"] = 13
# line width and grid
mpl.rcParams['lines.linewidth'] = 2
mpl.rcParams["axes.grid"] = 1
mpl.rcParams["figure.subplot.left"] = 0.15
# mpl.rcParams['savefig.pad_inches'] =  0.6
mpl.rcParams['legend.loc'] =  'best'

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

np.random.seed(42)

def plot(x , x_extent , steps , ex , title , noise):

    plt.figure(1)
    x_axis = np.arange(0 , x_extent , steps)
    plt.plot(x_axis , x)
    plt.title(ex + title)
    plt.xlabel("Time (yr)")
    plt.ylabel("Data")
    plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
    # plt.savefig('/Users/niekcollotdescury/Desktop/MAIO/ex2/figures/' + ex +noise+"data.png" )
    plt.show()

    X = fftpack.fft(x)   # fourier transform
    freqs = fftpack.fftfreq(len(x) , d = 1000)
    X = np.abs(X)**2

    length = int(len(X) / 2)
    cum    = np.zeros(length)
    cum[0] = X[0]
    for i in range (1 , length):
        cum[i] = X[i] + cum[i-1]
    cum = (cum / cum[-1] ) *100

    plt.figure(2)
    plt.bar(freqs[0 : length] , cum  , width = 5e-7)
    plt.title(ex + title +" integrated power")
    plt.xlabel('Frequency')
    plt.ylabel('Magnitude (%)')
    plt.xlim(0, 5e-5)
    plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
    # plt.savefig('/Users/niekcollotdescury/Desktop/MAIO/ex2/figures/' + ex + noise+ "cum.png" )
    plt.show()

    y_lim = max(X[1:-1]) *1.1

    plt.figure(3)
    plt.stem(freqs, X)
    plt.title(ex + title)
    plt.xlabel('Frequency')
    plt.ylabel('Magnitude')
    plt.xlim(-1e-6, 5e-5)
    plt.ylim(0, y_lim)
    plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
    # plt.savefig('/Users/niekcollotdescury/Desktop/MAIO/ex2/figures/' + ex + noise+ "freq.png" )
    plt.show()

############### exercise 2.1 ###############

x = np.zeros(600)
x[299:300] = 1

x_axis = len(x)
plot(x , x_axis , 1 , "Exercise 2.1 ","\nDelta function" , "")

############### exercise 2.2 ###############
k = 2*np.pi /1e5
listsin = np.arange(0,1e6,1000)
datasin =  np.sin(listsin*  k)

plot(datasin , 1e6 , 1000 , "Exercise 2.2 ","\nSine-wave" , "")

############## exercise 2.3 ###############

time = np.linspace(0, 1e6, 1000)
k = 20
saw = (signal.sawtooth(k * np.pi *time))

plot(saw , 1e6 , 1000 , "Exercise 2.3 ","\nSawtooth" , "")

############### exercise 2.5 ###############
saw_tot = []
time_tot = []
for i in range(11):
    T_high = 1.2e5   # +0.02 myr
    T_low = 8e4      # -0.02 myr
    T = np.random.uniform( T_low, T_high)
    k = 2 * np.pi / T

    T = np.arange(0 , T , 1000)
    saw = (signal.sawtooth(k *T)  )
    time_tot.extend(T)
    saw_tot.extend(saw)
saw_tot = saw_tot[0:1000]

plot(saw_tot[0:1000] , 1e6 , 1000 , "Exercise 2.5 ","\nSawtooth varying wavelength" , "")

############## exercise 2.6 ###############

saw_tot = []
time_tot = []
for i in range(11):
    T_high = 1.2e5   # +0.02 myr
    T_low = 8e4      # -0.02 myr
    T = np.random.uniform( T_low, T_high)
    k = 2 * np.pi / T

    T = np.arange(0 , T , 1000)
    saw = (signal.sawtooth(k *T))
    time_tot.extend(T)
    saw_tot.extend(saw)

saw_tot = saw_tot[0: 1000]
noise = np.random.normal(0, 0.5 , len(saw_tot))
saw_n = saw_tot + noise

plot(saw_tot , 1e6 , 1000 , "Exercise 2.6","\n Sawtooth varying wavelength" , "")
plot(saw_n , 1e6 , 1000 , "Exercise 2.6","\n Sawtooth varying wavelength\n"," with noise")


import os
from collections import defaultdict
from typing import List

import click

from kgx.validator import Error, NodeError, EdgeError

def append_errors_to_file(filename:str, errors:List[Error], time) -> None:
    """
    Creates a single file that logs all errors
    """
    dirname = os.path.dirname(filename)
    if dirname != '':
        os.makedirs(dirname, exist_ok=True)

    with click.open_file(filename, 'a+') as f:
        f.write('--- {} ---\n'.format(time))

        for e in errors:
            if isinstance(e, NodeError):
                f.write('node({})\t{}\n'.format(e.node, e.message))
            elif isinstance(e, EdgeError):
                f.write('edge({}, {})\t{}\n'.format(e.subject, e.object, e.message))
            else:
                raise Exception('Expected type {} but got: {}'.format(Error, type(error)))

        click.echo('Logged {} errors to {}'.format(len(errors), filename))

def append_errors_to_files(dirname:str, errors:List[Error], time) -> None:
    """
    Creates a series of files that logs all errors, each error type being logged
    to its own file.
    """
    os.makedirs(dirname, exist_ok=True)

    error_dict = defaultdict(list)
    for error in errors:
        error_dict[error.error_type].append(error)

    for error_type, typed_errors in error_dict.items():
        if error_type is None:
            error_type = 'default.log'
        else:
            error_type = error_type.replace(' ', '_') + '.log'

        filename = os.path.join(dirname, error_type)
        with click.open_file(filename, 'a+') as f:
            f.write('--- {} ---\n'.format(time))
            for e in typed_errors:
                if isinstance(e, NodeError):
                    f.write('node({})\t{}\n'.format(e.node, e.message))
                elif isinstance(e, EdgeError):
                    f.write('edge({}, {})\t{}\n'.format(e.subject, e.object, e.message))
                else:
                    raise Exception('Expected type {} but got: {}'.format(Error, type(e)))

            click.echo('Logged {} errors to {}'.format(len(typed_errors), filename))


#!/usr/bin/python

# Used by the ipPing.py and ndnPing.py scripts
# The my_neighbors dictionary is keyed by the name prefixes
# For ech key, the list of neighboring IP addresses are stored

import sys
import os

# 1: ONL; 0: NDN TESTBED
RUN_IN_ONL = 1

#my_neighbors = dict()
site_neighbors = dict()

site2site_prefix = dict()
site_prefix2site = dict()

site2ip_prefix = dict()
site_prefix2ip_prefix = dict()

ip_prefix2site = dict()
ip_prefix2site_prefix = dict()

if RUN_IN_ONL == 1:
  f = open('../routers', 'r')
else:
  f = open('../routers.testbed', 'r')

# urjc:es/urjc:insula:h44x1:192.168.44.1:lip6:orange:basel:padua:wu
for line in f:
  if "\"" in line:
    line = line.rstrip()
    line = line.split('"')[1]
    line = line.split('"')[0]
    comps = line.split(':')

    site = comps[0]
    site_prefix = "/ndn/" + comps[1]
    site2site_prefix[site] = site_prefix
    site_prefix2site[site_prefix] = site

    host = comps[2]
    onl_host = comps[3]
    ip_prefix = comps[4]

    site2ip_prefix[site] = ip_prefix
    site_prefix2ip_prefix[site_prefix] = ip_prefix

    ip_prefix2site[ip_prefix] = site
    ip_prefix2site_prefix[ip_prefix] = site_prefix

    for i in range(5, len(comps)):
      #print comps[i]
      if site in site_neighbors:
        site_neighbors[site].append(comps[i])
      else:
        empty_list = []
        site_neighbors[site] = empty_list
        site_neighbors[site].append(comps[i])

#print site_neighbors
#print site2site_prefix
#print site_prefix2site
#print site2ip_prefix


from flask import jsonify, request, g, abort, url_for, current_app, redirect, render_template, make_response
from flask_login import login_required, current_user

from app import db
from app.main.forms import CreateTHostForm
from . import api
from .decorators import permission_required
from ..models import THost, Permission

@api.route('/hosts', methods=['GET', 'POST'])
def hosts():
    form = CreateTHostForm()
    if current_user.can(Permission.WRITE_ARTICLES) and \
            form.validate_on_submit():
        #thost = THost(body=form,author=current_user._get_current_object())
        #db.session.add(thost)
        THost.save_form(form.data)
        return redirect(url_for('.hosts'))

    page = request.args.get('page', 1, type=int)

    show_activation_host = True
    if current_user.is_authenticated:
        show_activation_host = bool(request.cookies.get('show_activation_host', ''))
    if show_activation_host:
        query = THost.query.filter(THost.fstatus == 1)
    else:
        query = THost.query

    pagination = query.order_by(THost.fcreatetime.desc()).paginate(
        page, per_page=current_app.config['FLASKY_HOSTS_PER_PAGE'],
        error_out=False)
    hosts = pagination.items
    #hosts = [item.to_json for item in pagination.items]
    return render_template('hosts.html', form=form, hosts=hosts,show_activation_host=show_activation_host, pagination=pagination)

@api.route('/hosts/activation')
@login_required
def show_activation_host():
    resp = make_response(redirect(url_for('.hosts')))
    resp.set_cookie('show_activation_host', '1', max_age=30*24*60*60)
    return resp

@api.route('/hosts/all')
@login_required
def show_all_host():
    resp = make_response(redirect(url_for('.hosts')))
    resp.set_cookie('show_activation_host', '', max_age=30*24*60*60)
    return resp

@api.route('/hosts/')
def get_hosts():
    page = request.args.get('page', 1, type=int)
    pagination = THost.query.paginate(
        page, per_page=current_app.config['FLASKY_HOSTS_PER_PAGE'],
        error_out=False)
    hosts = pagination.items
    prev = None
    if pagination.has_prev:
        prev = url_for('api.get_hosts', page=page-1, _external=True)
    next = None
    if pagination.has_next:
        next = url_for('api.get_hosts', page=page+1, _external=True)
    return jsonify({
        'hosts': [host.to_json() for host in hosts],
        'prev': prev,
        'next': next,
        'count': pagination.total
    })

@api.route('/hosts/<int:id>')
def get_host():
    page = request.args.get('page', 1, type=int)
    pagination = THost.query.paginate(
        page, per_page=current_app.config['FLASKY_HOSTS_PER_PAGE'],
        error_out=False)
    hosts = pagination.items
    prev = None
    if pagination.has_prev:
        prev = url_for('api.get_hosts', page=page-1, _external=True)
    next = None
    if pagination.has_next:
        next = url_for('api.get_hosts', page=page+1, _external=True)
    return jsonify({
        'hosts': [host.to_json() for host in hosts],
        'prev': prev,
        'next': next,
        'count': pagination.total
    })


class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        result = {}

        for i in range(len(nums)):

            if nums[i] in result:

                return [result[nums[i]], i]

            else:
                result[target - nums[i]] = i

'''
First solution without reference solution:-->

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        result = {} #*len(nums)
        remainder = 0
        index = 0
        for i in range(len(nums)):
            remainder = target - nums[i]
            if remainder in nums:
                index = nums.index(remainder)
                result[remainder] = index
            else:
                continue
        #print(result)

        finalIndex = []
        for i in result:
            finalIndex.insert(result[i],result[i])
        #print(finalIndex)
        return finalIndex

'''