# -*- coding: utf-8 -*-
from django.contrib import admin

from .models import Pedido, ProductosPedido, OrdenTrabajo

class ProductoInline(admin.TabularInline):
    """Tabular Inline View for Producto"""

    model = ProductosPedido
    min_num = 1
    max_num = 20
    extra = 1
    exclude = ("is_removed",)

@admin.register(Pedido)
class PedidoAdmin(admin.ModelAdmin):
    def get_queryset(self, request):
        return Pedido.all_objects.all()

    list_display = (
        "id",
        "usuario",
        "cliente",
        "precio_total",
        "detalles",
        "estado",
        "pagado",
        "fecha_entrega",
        "created",
        "modified",
        "is_removed",
    )
    list_filter = ("cliente", "fecha_entrega")
    autocomplete_fields = ["productos_pedido"]

    inlines = [ProductoInline]

@admin.register(ProductosPedido)
class ProductosPedidoAdmin(admin.ModelAdmin):
    def get_queryset(self, request):
        return ProductosPedido.all_objects.all()

    list_display = (
        "id",
        "created",
        "modified",
        "is_removed",
        "pedido",
        "producto",
        "cantidad",
    )
    list_filter = ("created", "modified", "is_removed", "pedido", "producto")

@admin.register(OrdenTrabajo)
class OrdenTrabajoAdmin(admin.ModelAdmin):
    def get_queryset(self, request):
        return OrdenTrabajo.all_objects.all()

    list_display = (
        "id",
        "pedido",
        "estado",
        "detalles",
        "created",
        "modified",
        "is_removed",
    )
    list_filter = (
        "created",
        "modified",
        "is_removed",
        "pedido",
    )


## creates song class
## used for parsing scraped text into artists, albums, and lyrics
## challenge is finding standardized artist identification for each verse

import re

class Song():

	def __init__(self, text):
		'''
		CONSTRUCTOR!!!!!!!!!
		'''
		self.raw_page = text

		self.find_song(text)
		self.find_artist(text)
		self.find_album(text)
		self.find_lyrics(text)
		# self.artist = None
		# self.album = None

	def find_song(self, text):
		lines = re.findall(r"Song:.*", text, flags=re.I)
		if lines:
			self.title = ' '.join(lines[0].split()[1:])
		else:
			self.title = ""

	def find_artist(self, text):
		lines = re.findall(r"Artist:.*", text, flags=re.I)
		if lines:
			self.artist = ' '.join(lines[0].split()[1:])
		else:
			self.artist = ""

	def find_album(self, text):
		lines = re.findall(r"Album:.*", text, flags=re.I)
		if lines:
			self.album = ' '.join(lines[0].split()[1:])
		else:
			self.album = ""

	def find_lyrics(self, text):

		lyrics = re.sub(r"[\(\[].*?[\)\]]", "", text)  ### remove brackets and parens
		lyrics = re.sub(r"[^\w\s:]", "", lyrics)
		lyrics = re.findall(r"^[^:\n]*?$", lyrics, flags=re.MULTILINE)
		lyrics = filter(lambda x: x.strip(), lyrics)
		lyrics = '\n'.join(list(lyrics))
		self.lyrics = lyrics.lower()
			# ^()\[\]:].*", text, flags=re.MULTILINE)
		# return re.sub(r"[^()\[\]:].*", text, flags=re.MULTILINE))

	def __repr__(self):

		title = "Title: {}".format(self.title)
		artist = "Arist: {}".format(self.artist)
		album = "Album: {}".format(self.album)

		s = '\n'.join([title, artist, album])

		return s

class Verse():

	def __init__(self, text, song, song_artist, verse_artist=None):

		self.text = text
		self.song = song
		self.song_artist = song_artist
		self.verse_artist = verse_artist

		if not verse_artist:
			self.find_verse_artist()

	def find_verse_artist():
		artist_line = re.findall(r'\[.*\]|\(.*\)', line)

		if len(artist_line) == 1:
			self.verse_artist = artist_line[0][1:-1]

		if len(artist_line) > 1:
			self.verse_artist = artist_line[0][1:-1]

			for a in artist_line[1:]:
				v = Verse(self.text, self.song, self.song_artist, self.verse_artist)

		else:
			### Check if artist is in artist list
			self.verse_artist = self.song_artist

	# def find_artist(self):
	# 	snip = re.search(r'\[.*\]|\(.*\)|:', self.lyrics.split('\n')[0])

	# 	if snip

	# 	if re.match(r"[.*\]")


import os
import pandas as pd
import numpy as np
import sys
from pathlib import Path

path_variable = Path(os.path.dirname(__file__))
sys.path.insert(0, str(path_variable))
sys.path.insert(0, str(path_variable.parent))

from models.networks.layers.attn_augconv import AttentionAugmentation2D

from tensorflow.keras import Model
from tensorflow.keras.models import load_model
from pydicom import read_file

from utils.utils import Params

SEGMENTED_CLASSES = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]

target_dict = {0: 'class 0', 1: 'class 1', 2: 'class 2',
               3: 'class 3', 4: 'class 4', 5: 'class 5',
               6: 'class 6', 7: 'class 7', 8: 'class 8',
               9: 'class 9', 10: 'class 10', 11: 'class 11',
               12: 'class 12', 13: 'class 13', 14: 'class 14',
               15: 'class 15'}

def ensemble_vote(predictions):
    """
    Parameters
    ----------
    predictions : list of arrays with soft max predictions from all models on one image

    Returns
    -------
    ensemble prediction labels as an array
    """
    ensemble_prediction = np.mean(np.array(predictions), 0)
    return np.argmax(ensemble_prediction, -1)[0, :, :].astype(int)

def ensemble_uncertainty(predictions):
    """
    Parameters
    ----------
    predictions : list of arrays with soft max predictions from all models on one image

    Returns
    -------
    ensemble prediction labels as an array
    """
    prediction_array = np.array(predictions)

    ensemble_softmax = np.mean(prediction_array, 0)

    ensemble_prediction = np.argmax(ensemble_softmax, -1)[0, :, :].astype(int).flatten()
    ensemble_std = np.std(np.array(predictions), 0).reshape(-1, 16)

    uncertainty = []
    for k, idx in enumerate(ensemble_prediction):
        uncertainty.append(ensemble_std[k, idx])

    uq_map = np.array(uncertainty).reshape(256, 256)
    return uq_map

def ensemble_predict(ensemble_dict, img):
    """
    Parameters
    ----------
    ensemble_dict : dict of models
    img : array, numpy array with preprocessed image to predict on

    Returns
    --------
    integer label map from prediction and soft max scores for each class
    """
    # check so shape is 4 channel
    if len(img.shape) == 3:
        img = img.reshape((1, img.shape[0], img.shape[1], img.shape[-1]))

    # pre process (255. divide) as when training
    img = img / 255.

    model_segmentations = {}
    predictions = []
    for ensemble_model in ensemble_dict.keys():
        model = ensemble_dict[ensemble_model]["model"]

        # get probability map
        pred = model.predict(img)

        predictions.append(pred)
        model_segmentations[ensemble_model] = np.argmax(pred, -1)[0, :, :].astype(int)

    uq_map = ensemble_uncertainty(predictions)
    return model_segmentations, ensemble_vote(predictions), uq_map

def check_enseble_test_ids(ensemble_dict):
    """
    This  function asserts so the ensemble models have been trained on the same samples
    Parameters
    ----------
    ensemble_dict : dict with all enseble information

    Returns
    -------
    None
    """
    # check so test ids are same
    not_same_ids = []
    for k, model in enumerate(ensemble_dict.keys()):
        model_test_ids = ensemble_dict[model]["test_ids"]
        model_test_ids.sort()

        if k > 0:
            if model_test_ids == last_models_ids:
                not_same_ids.append(False)
            else:
                not_same_ids.append(True)

        last_models_ids = model_test_ids

        assert sum(not_same_ids) == 0, "models in ensemble not trained on the same ids, stop evaluation"

def predict_on_batch(model, img):
    """
    Parameters
    ----------
    model : tensorflow.keras model for segmentation
    img : array, numpy array with preprocessed image to predict on

    Returns
    -------
    integer label map from prediction and soft max scores for each class
    """

    # check so shape is 4 channel
    if len(img.shape) == 3:
        img = img.reshape((img.shape[0], img.shape[0], img.shape[1], img.shape[-1]))

    # pre process (255. divide) as when training
    img = img / 255.

    # get probability map
    pred = model.predict_on_batch(img)
    return np.argmax(pred, -1).astype(np.uint8), pred

def predict(model, img):
    """
    Parameters
    ----------
    model : tensorflow.keras model for segmentation
    img : array, numpy array with preprocessed image to predict on

    Returns
    -------
    integer label map from prediction and soft max scores for each class
    """

    # check so shape is 4 channel
    if len(img.shape) == 3:
        img = img.reshape((1, img.shape[0], img.shape[1], img.shape[-1]))

    # pre process (255. divide) as when training
    img = img / 255.

    # get probability map
    pred = model.predict(img)
    return np.argmax(pred, -1)[0, :, :].astype(int), pred

def load_test_config(model_path):
    """
    Parameters
    ----------
    model_path : path to specific model

    Returns
    -------
    tensorflow.keras model, test ids for the model, params object with model config
    """

    # load utils classes
    params = Params(os.path.join(model_path, "config.json"))

    # cast all numeric types to float and save to json
    cast_params_types(params, model_path)

    params = Params(os.path.join(model_path, "params.json"))

    # read test images from trained model
    test_ids = pd.read_csv(os.path.join(model_path, "test_ids.csv"))["0"].tolist()
    validation_ids = pd.read_csv(os.path.join(model_path, "validation_ids.csv"))["0"].tolist()
    train_ids = pd.read_csv(os.path.join(model_path, "train_ids.csv"))["0"].tolist()

    save_model_path = os.path.join(model_path, "weights.hdf5")
    model = load_model(save_model_path, custom_objects={'AttentionAugmentation2D': AttentionAugmentation2D})

    # model = load_model(save_model_path)
    return model, test_ids, validation_ids, train_ids, params

def get_ensemble_dict(ensemble_models, models_directory):
    """
    Parameters
    ----------
    ensemble_models : list of model names (strings)

    Returns
    -------
    dict, with each model and corresponding params and test ids
    """
    ensemble_dict = {}

    # get ensemble config dict
    for ensemble_model in ensemble_models:
        model_path = os.path.join(models_directory, ensemble_model)

        # load test configurations
        model, test_ids, validation_ids, train_ids, params = load_test_config(model_path)

        ensemble_dict[ensemble_model] = {"model": model, "test_ids": test_ids, "params": params}
    return ensemble_dict

def save_volume(segmentation, save_path, record_name):
    """
    Parameters
    ----------
    segmentation : segmented oct
    save_path : str; where to save

    Returns
    -------
    None
    """

    if not os.path.exists(save_path):
        os.makedirs(save_path)

    np.save(save_path + f"/{record_name}.npy", segmentation)

def save_segmentation(segmentation, save_path, record_name):
    """
    Parameters
    ----------
    segmentation : segmented oct
    save_path : str; where to save

    Returns
    -------
    None
    """

    if not os.path.exists(save_path):
        os.makedirs(save_path)
    np.save(save_path + f"/{record_name}.npy", segmentation)

def save_embedding(embeding, save_path, record_name):
    """
    Parameters
    ----------
    embeding : embedded oct volume
    save_path : str; where to save

    Returns
    -------
    None
    """
    if not os.path.exists(save_path):
        os.makedirs(save_path)

    np.save(save_path + f"/{record_name}.npy", embeding)

def embedd(model, img):
    """
    Parameters
    ----------
    model : tensorflow.keras model for segmentation
    img : array, numpy array with preprocessed image to predict on

    Returns
    -------
    flattened embedding vector from bottle neck of segmenter
    """

    # check so shape is 4 channel
    if len(img.shape) == 3:
        img = img.reshape((1, img.shape[0], img.shape[1], img.shape[-1]))

    # pre process (255. divide) as when training
    img = img / 255.

    return model.predict(img).flatten()

def segment_volume(oct_volume, ensemble_dict):
    """
    Parameters
    ----------
    save_path :
    oct_volume : array of shape (n, 256, 256, 3) with all resized oct form a dicom
    ensemble_dict : dict holding all models in ensemble
    save_volume: boolean; if volume should be save
    Returns
    -------
    array with segmented OCTs
    """
    segmented_octs = []
    for i in range(oct_volume.shape[0]):
        _, segmented_oct = ensemble_predict(ensemble_dict, oct_volume[i])
        segmented_octs.append(segmented_oct)

    return np.array(segmented_octs)

def initialize_volume_feature_dict():
    """
    Returns
    -------
    dict, with all features and id element.
    """
    return {"frame": [], 0: [], 1: [], 2: [], 3: [], 4: [],
            5: [], 6: [], 7: [], 8: [], 9: [], 10: [],
            11: [], 12: [], 13: [], 14: [], 15: []}

def oct_segmentation_to_vector(segmentation):
    """
    Parameters
    ----------
    segmentation : array, segmented oct
    feature_dict : dict with counts for each feature

    Returns
    -------
    feature dict with feature statistics for segmentation
    """
    feature_dict = {}

    # count features
    feature_counts = np.unique(segmentation, return_counts = True)

    # add do dict
    for feature in SEGMENTED_CLASSES:
        if int(feature) in feature_counts[0]:
            feature_dict[feature] = feature_counts[1][feature_counts[0].tolist().index(int(feature))]
        else:
            feature_dict[feature] = 0
    return feature_dict

def segmentation_to_vector(segmentation, feature_dict={}):
    """
    Parameters
    ----------
    segmentation : array, segmented oct
    feature_dict : dict with counts for each feature

    Returns
    -------
    feature dict with feature statistics for segmentation
    """

    # count features
    feature_counts = np.unique(segmentation, return_counts = True)

    # add do dict
    for feature in SEGMENTED_CLASSES:
        if int(feature) in feature_counts[0]:
            feature_dict[feature].append(feature_counts[1][feature_counts[0].tolist().index(int(feature))])
        else:
            feature_dict[feature].append(0)
    return feature_dict

def get_feature_dict(dicom_path, segmented_volume):
    """
    Parameters
    ----------
    dicom_path : str, path to dicom
    segmented_volume : array, segmented oct volume

    Returns
    -------
    dict with all information from oct
    """
    dc_header = read_file(dicom_path, stop_before_pixels = True)

    feature_dict = initialize_volume_feature_dict()

    feature_dict["patient_id"] = dc_header.PatientID.replace("ps:", "")
    feature_dict["study_date"] = dc_header.StudyDate
    feature_dict["laterality"] = dc_header.ImageLaterality
    feature_dict["dicom_path"] = dicom_path

    num_segmentations = segmented_volume.shape[0]
    for i in range(num_segmentations):
        feature_dict["frame"].append(i)
        feature_dict = segmentation_to_vector(segmented_volume[i], feature_dict)

    return feature_dict

def get_embedding_model(model_directory):
    """
    Parameters
    ----------
    model_directory : str; full path to model

    Returns
    -------
    tensorflow.keras model to use for embedding the octs
    """
    save_model_path = os.path.join(model_directory, "weights.hdf5")
    model = load_model(save_model_path)

    # set up inference model
    model_input = model.layers[0]
    model_embedding = model.layers[len(model.layers) // 2]

    # inference model
    embedding_model = Model(inputs = model_input.output, outputs = [model_embedding.output])
    return embedding_model

def save_predicted_detections(pred, save_path, id_):
    """
    Parameters
    ----------
    pred :
    save_path :

    Returns
    -------

    """

    NON_TISSUE_LABELS = [0, 12, 11, 14, 15]

    if not os.path.exists(save_path):
        os.makedirs(save_path)

    detections = []
    from skimage.measure import regionprops
    for region in regionprops(pred):
        if region.area >= 100 and (region.label not in NON_TISSUE_LABELS):
            minr, minc, maxr, maxc = region.bbox
            detections.append((region.label, 1, minr, minc, maxr, maxc))

    pd.DataFrame(detections).to_csv(os.path.join(save_path, id_), sep = " ", header = None, index = None)

def save_groundtruth_detections(lbl, save_path, id_):
    """
    Parameters
    ----------
    pred :
    save_path :

    Returns
    -------

    """

    NON_TISSUE_LABELS = [0, 12, 11, 14, 15]

    if len(lbl.shape) > 2:
        lbl = lbl[:, :, 0]

    if not os.path.exists(save_path):
        os.makedirs(save_path)

    detections = []
    from skimage.measure import regionprops
    for region in regionprops(lbl):
        if region.area >= 100 and (region.label not in NON_TISSUE_LABELS):
            minr, minc, maxr, maxc = region.bbox
            detections.append((region.label, minr, minc, maxr, maxc))

    pd.DataFrame(detections).to_csv(os.path.join(save_path, id_), sep = " ", header = None, index = None)


# python detect_capture_faces.py --video swing.mp4

from imutils.video import FileVideoStream
import numpy as np
import argparse
import imutils
import cv2
import os

# ap = argparse.ArgumentParser()
# ap.add_argument("-v", "--video", required=True,
#                 help="path to input video file")
# args = vars(ap.parse_args())

faces = []
video_file_name = 'swing.mp4'
confidence_threshold = 0.5
model = cv2.dnn.readNetFromCaffe('model/deploy.prototxt.txt', "model/opencv_face_detector.caffemodel")
file_name_no_ext = video_file_name.split('.')[0]
face_directory = f'{file_name_no_ext}-faces'
if not os.path.exists(face_directory):
    os.makedirs(face_directory)

video_stream = FileVideoStream(video_file_name).start()

while True:
    # grab the frame from the threaded video stream and resize it
    # to have a maximum width of 400 pixels
    frame = video_stream.read()

    if frame is None:
        break

    frame = imutils.resize(frame, width=400)

    # grab the frame dimensions and convert it to a blob
    (h, w) = frame.shape[:2]
    blob = cv2.dnn.blobFromImage(cv2.resize(frame, (300, 300)), 1.0, (300, 300), (104.0, 177.0, 123.0))

    # pass the blob through the network and obtain the detections and
    # predictions
    model.setInput(blob)
    detections = model.forward()

    # we only care about detections which are greater than the threshold
    num_detections = detections.shape[2]
    detections = detections[0, 0, detections[0, 0, 0:num_detections, 2] > confidence_threshold, 0:7]

    if detections.size > 0:

        # get the size of each box as the sum of two sides of the rectangle
        num_detections = detections.shape[0]
        sizes = ((detections[0:num_detections, 5] - detections[0:num_detections, 3])
                 + (detections[0:num_detections, 6] - detections[0:num_detections, 4]))

        # print(detections[0:num_detections, 5])
        # print(detections[0:num_detections, 3])
        # print(detections[0:num_detections, 6])
        # print(detections[0:num_detections, 4])
        # print()

        # get the largest box
        ordered_sizes = -sizes.argsort()

        if sizes[ordered_sizes[0]] > .5:
            box = detections[ordered_sizes[0], 3:7] * np.array([w, h, w, h])
            (startX, startY, endX, endY) = box.astype("int")
            faces.append(frame[startY:endY, startX:endX])

    # show the output frame
    cv2.imshow("Frame", frame)
    key = cv2.waitKey(1) & 0xFF

    # if the `q` key was pressed, break from the loop
    if key == ord("q"):
        break

# write all the faces to a file
for i, face in enumerate(faces):
    cv2.imwrite(f'{face_directory}/face{i}.jpg', face)

# do a bit of cleanup
cv2.destroyAllWindows()
video_stream.stop()


import scrapy
import re

article_count_to_load = 5000
num_loads = 100 # 500k articles

base_url = "http://www.wikihow.com/index.php?title=Special:PopularPages&limit={}&offset={}"

class WikihowLinksSpider(scrapy.Spider):
	name = 'wikihow_links'
	start_urls = [base_url.format(article_count_to_load, i*article_count_to_load) for i in range(num_loads)]
	DOWNLOAD_DELAY = 10

	def clean_views(self, view_str):
		view_str = re.search('\(([0-9,]+) views\)', view_str)
		return int(view_str.group(1).replace(',', ''))

	def parse(self, response):
		for link in response.css('ol li'):
			yield {'title': link.css('a::text').extract_first(), 'href': "http://www.wikihow.com"+link.css('a::attr("href")').extract_first(), 'views': self.clean_views(link.xpath('string()').extract_first())}


### This script extracts double PP constructions from UD treebanks ###

#usr/bin/env python3

import glob, os, io, argparse, csv

### Reading CoNLL formatted file sentence by sentence ###

def conll_read_sentence(file_handle):

	sent = []

	for line in file_handle:
		line = line.strip('\n')

		if line.startswith('#') is False :
			toks = line.split("\t")

			if len(toks) == 1:
				return sent
			else:
				if toks[0].isdigit() == True:
					sent.append(toks)

	return None

### Get all verbs from a sentence ###

def verb_list(sentence):

	verbs = []

	for tok in sentence:
		if tok[3] == 'VERB':
			verbs.append(tok[0])

	return verbs

### Get the syntactic head of a token ###

def head(index, sentence):

	tok = sentence[int(index) - 1]

	h_idx = int(tok[6])

	if h_idx != 0:
		return sentence[h_idx - 1]

	return 'ROOT'

### Get the syntactic dependents of a token ###

def dependents(index, sentence):

	dependent = []

	for tok in sentence:
		if tok[6] == index:
			dependent.append(tok[0])

	if len(dependent) != 0:
		return dependent

	return None

### Get exactly two PP dependents on the same side of the head verb ###

def extract_pp(verb_index, sentence):

	v_d = dependents(verb_index, sentence)

	pp_list = {}

	if v_d is not None:

		preverbal_pp = []
		postverbal_pp = []

		for d in v_d:
			d_tok = sentence[int(d) - 1]

			if d_tok[7] == 'obl':
				d_d = dependents(d_tok[0], sentence)

				if d_d is not None:

					adp_list = []

					for z in d_d:
						z_tok = sentence[int(z) - 1]

						if z_tok[3] == 'ADP' and z_tok[7] == 'case':
							adp_list.append(int(z_tok[0]))

					if len(adp_list) > 0:
						adp_list.sort()

						adp_toks = []
						for adp in adp_list:
							adp_toks.append(sentence[int(adp) - 1][2])

						adp = ' '.join(w for w in adp_toks)

						pp_idx = adp_list.copy()
						pp_idx.append(int(d_tok[0]))
						pp_idx.sort()

						pp_simple = []
						pp_simple_lexical = []

						for i in pp_idx:
							pp_simple.append(sentence[int(i) - 1][2])
							pp_simple_lexical.append(sentence[int(i) - 1][1])

						pp_simple = ' '.join(w for w in pp_simple)
						pp_simple_lexical = ' '.join(w for w in pp_simple_lexical)

						### P NP V ###

						if adp_list[-1] < int(d_tok[0]) and int(d_tok[0]) < int(verb_index):
							preverbal_pp.append([verb_index, d_tok[0], str(adp), pp_simple, pp_simple_lexical, 'prepositional', 'preverbal'])

						### P NP P V ###

						if adp_list[0] < int(d_tok[0]) and adp_list[-1] > int(d_tok[0]) and adp_list[-1] < int(verb_index):
							preverbal_pp.append([verb_index, d_tok[0], str(adp), pp_simple, pp_simple_lexical, 'circumpositional', 'preverbal'])

						### NP P V ###

						if adp_list[0] > int(d_tok[0]) and adp_list[-1] < int(verb_index):
							preverbal_pp.append([verb_index, d_tok[0], str(adp), pp_simple, pp_simple_lexical, 'postpositional', 'preverbal'])

						### V P NP ###

						if adp_list[0] > int(verb_index) and adp_list[-1] < int(d_tok[0]):
							postverbal_pp.append([verb_index, d_tok[0], str(adp), pp_simple, pp_simple_lexical, 'prepositional', 'postverbal'])

						### V P NP P ###

						if adp_list[0] > int(verb_index) and adp_list[0] < int(d_tok[0]) and adp_list[-1] > int(d_tok[0]):
							postverbal_pp.append([verb_index, d_tok[0], str(adp), pp_simple, pp_simple_lexical, 'circumpositional', 'postverbal'])

						### V NP P ###

						if adp_list[0] > int(d_tok[0]) and int(d_tok[0]) > int(verb_index):
							postverbal_pp.append([verb_index, d_tok[0], str(adp), pp_simple, pp_simple_lexical, 'postpositional', 'postverbal'])

		if len(preverbal_pp) == 2 and len(postverbal_pp) == 2:
			pp_list['Preverbal'] = preverbal_pp
			pp_list['Postverbal'] = postverbal_pp

		if len(preverbal_pp) == 2 and len(postverbal_pp) != 2:
			pp_list['Preverbal'] = preverbal_pp

		if len(preverbal_pp) != 2 and len(postverbal_pp) == 2:
			pp_list['Postverbal'] = postverbal_pp

	return pp_list

####### Get the subtree of a syntactic head ######

def subtree_generate(index, sentence):

	idxlist = [index]
	min_idx = len(sentence)
	max_idx = 0

	while len(idxlist) != 0:
		i = idxlist.pop()

		if int(i) < min_idx:
			min_idx = int(i)

		if int(i) > max_idx:
			max_idx = int(i)

		i_d = dependents(i, sentence)

		if i_d is not None:
			for d in i_d:
				idxlist.append(d)

	subtree = sentence[min_idx - 1 : max_idx]

	subtree_idx = []

	for idx in range(min_idx - 1, max_idx):
		subtree_idx.append(int(idx))

	subtree_idx.sort()

	return subtree, subtree_idx

#### Getting data from one language ####

def Expelliarmus(file_handle, directory, language):

	data = [['Sentence', 'Context_PP1', 'Context_PP2', 'Context_PP1_simple', 'Context_PP2_simple', 'PP1_simple', 'PP2_simple', 'Verb', 'PP1', 'PP2', 'PP1_len', 'PP2_len', 'Adp1', 'Adp2', 'NP1', 'NP2', 'PP1_Pronom', 'PP2_Pronom', 'PP1_Type', 'PP2_Type', 'Position', 'Language']]
	tuples = []

	with io.open(directory + '/' + file_handle, encoding = 'utf-8') as f:
		sent = conll_read_sentence(f)

		while sent is not None:
			verbs = verb_list(sent)

			for v in verbs:
				pp_list = extract_pp(v, sent)

				if len(pp_list) != 0:
					for position, pps in pp_list.items():

						pp1 = ''
						pp2 = ''

						if int(pps[0][1]) < int(pps[1][1]):
							pp1 = pps[0]
							pp2 = pps[1]
						else:
							pp1 = pps[1]
							pp2 = pps[0]

						v_tok = sent[int(v) - 1][2]

						pp1_np = sent[int(pp1[1]) - 1][2]
						pp1_pronom = sent[int(pp1[1]) - 1][3]
						pp1_adp = pp1[2]
						pp1_simple = pp1[3]
						pp1_simple_lexical = pp1[4]
						pp1_type = pp1[-2]
						pp1_subtree, pp1_subtree_idx = subtree_generate(pp1[1], sent)
						pp1_toks = ' '.join(w[1] for w in pp1_subtree)
						pp1_len = len(pp1_subtree_idx)

						context_pp1 = pp1_toks
						if pp1_subtree_idx[0] != 0:
							context_pp1 = ' '.join(w[1] for w in sent[ : pp1_subtree_idx[0]]) + ' ' + pp1_toks

						context_pp1_simple = pp1_simple_lexical
						if pp1_subtree_idx[0] != 0:
							context_pp1_simple = ' '.join(w[1] for w in sent[ : pp1_subtree_idx[0]]) + ' ' + pp1_simple_lexical

						tuples.append(v_tok + ' ' + pp1_np + ' ' + pp1_adp)

						pp2_np = sent[int(pp2[1]) - 1][2]
						pp2_pronom = sent[int(pp2[1]) - 1][3]
						pp2_adp = pp2[2]
						pp2_simple = pp2[3]
						pp2_simple_lexical = pp2[4]
						pp2_type = pp2[-2]
						pp2_subtree, pp2_subtree_idx = subtree_generate(pp2[1], sent)
						pp2_toks = ' '.join(w[1] for w in pp2_subtree)
						pp2_len = len(pp2_subtree_idx)

						context_pp2 = pp2_toks
						if pp1_subtree_idx[0] != 0:
							context_pp2 = ' '.join(w[1] for w in sent[ : pp1_subtree_idx[0]]) + ' ' + pp2_toks

						context_pp2_simple = pp2_simple_lexical
						if pp1_subtree_idx[0] != 0:
							context_pp2_simple = ' '.join(w[1] for w in sent[ : pp1_subtree_idx[0]]) + ' ' + pp2_simple_lexical

						tuples.append(v_tok + ' ' + pp2_np + ' ' + pp2_adp)

						sent_toks = ' '.join(w[1] for w in sent)

					#data = [['Sentence', 'Context_PP1', 'Context_PP2', 'Verb', 'PP1', 'PP2', 'PP1_len', 'PP2_len', 'Adp1', 'Adp2', 'NP1', 'NP2', 'PP1_Type', 'PP2_Type', 'Position']]
						data.append([sent_toks, context_pp1, context_pp2, context_pp1_simple, context_pp2_simple, pp1_simple, pp2_simple, v_tok, pp1_toks, pp2_toks, pp1_len, pp2_len, pp1_adp, pp2_adp, pp1_np, pp2_np, pp1_pronom, pp2_pronom, pp1_type, pp2_type, position, language])

			sent = conll_read_sentence(f)

	return data, set(tuples)

if __name__ == '__main__':

	parser = argparse.ArgumentParser()
	parser.add_argument('--input', type = str, help = 'input path to UD directory')
	parser.add_argument('--output', type = str, help = 'output path')

	args = parser.parse_args()

	path = args.input
	os.chdir(path)

	for directory in glob.glob('*'):
		for file in os.listdir(directory):
			if file.endswith('.conllu'):

				language = directory.split('-')[0][3 : ]
				pp_data, pp_tuples = Expelliarmus(file, directory, language)

				if len(pp_data) >= 51:

					preverbal = 0
					postverbal = 0

					output = io.open(args.output + language + '_pp.csv', 'w', newline = '', encoding = 'utf-8')
					writer = csv.writer(output)

					for pp in pp_data:
						writer.writerow(pp)

						if pp[-2] == 'Preverbal':
							preverbal += 1
						if pp[-2] == 'Postverbal':
							postverbal += 1

					print(language + ' ' + str(preverbal) + ' ' + str(postverbal) + ' ' + str(len(pp_data)))

					words = []
					words_out = io.open(args.output + language + '_words.txt', 'w', newline = '', encoding = 'utf-8')

					tuples_out = io.open(args.output + language + '_tuples.txt', 'w', newline = '', encoding = 'utf-8')

					for tok in pp_tuples:
						tuples_out.write(tok + '\n')

						for w in tok.split():
							words.append(w)

					for w in set(words):
						words_out.write(w + '\n')


#필요한 패키지 임포트
import torch
import torch.nn as nn
from torchvision.datasets import MNIST
from torchvision.transforms import ToTensor
from torch.utils.data import DataLoader

#하이퍼파라메터 선언
input_size = 28 # MNIST 데이터의 input Size
hidden_layer = 500 # hidden_layer의 size 500으로 설정
class_nums = 10 # 출력단의 분류 class 갯수 10으로 설정
batch_size = 100 # batch_size 100
lr = 0.001 # learning rate 0.001 사용
epochs = 3 # epochs 3회 실시
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') #CPU/GPU 설정

#모델 설계도 그리기
class MLP(nn.Module):
    def __init__(self,input_size,hidden_layer,class_nums):
        super().__init__()
        self.input_size = input_size
        self.mlp1 = nn.Linear(input_size*input_size,hidden_layer)
        self.mlp2 = nn.Linear(hidden_layer,hidden_layer)
        self.mlp3 = nn.Linear(hidden_layer,hidden_layer)
        self.mlp4 = nn.Linear(hidden_layer,class_nums)
    def forward(self,x):
        batch_size = x.shape[0]
        x = torch.reshape(x,(-1,self.input_size*self.input_size))
        x = self.mlp1(x)
        x = self.mlp2(x)
        x = self.mlp3(x)
        x = self.mlp4(x)
        return x

 #nn.moule class 생성
 #레고 조각생성
 # nn.moudle를 깨우는 역할, super를 사용하여 클래스 상속해줌
 # self를 사용하여 init 밖에서도 사용할수 있는 객체 변수로 설정
 # 첫번째 layer로 input을 받아 hidden layer로 넘김
 # 2번째 layer로 hidden layer를 쌓음
 # 3번째 layer로 hidden layer를 쌓음
 # 4번째 layer로 분류 실시
 # 레고 조각을 조립
        # x : [batch_size,28,28,1]
        #[batch_size,28*28]
        #batch size에 따라 reshape 해줌
         # -1로 해서 batch 사이즈를 알아서 처리하게 함
         #[batch_size,500]
         #[batch_size,500]
         #[batch_size,500]
         #[batch_size,10]

#설계도를 바탕으로 모델을 만들어야함
 #클래스를 객체로 사용하기 위해서 괄호 사용하고 파라미터들을 괄호 안에 넣음
myMLP = MLP(input_size,hidden_layer,class_nums).to(device)
#데이터 불러오기
train_MNIST = MNIST(root= '../../data/MNIST',train=True,transform=ToTensor(),download= True)
test_MNIST = MNIST(root= '../../data/MNIST',train=False,transform=ToTensor(),download= True)
#dataset설정
 # MNIST dataset에서 train data를 불러옴
 # MNIST dataset에서 test data를 불러옴
train_DataLoader = DataLoader(dataset= train_MNIST,batch_size=batch_size,shuffle= True)
test_DataLoader = DataLoader(dataset= test_MNIST,batch_size=batch_size,shuffle= False)
#dataloader 설정
 # train data를 Dataloader에서 처리함
 # test data를 Dataloader에서 처리함

#Loss 설정
 # CrossEntroyLoss 사용
loss_fn = nn.CrossEntropyLoss()
#Optimizer 선언
 # Adam optimizer 사용
optim = torch.optim.Adam(params=myMLP.parameters(),lr=lr)
#학습을 위한 반복(Loop) for /while
 # for문을 이용하여 epoch 반복
for epoch in range(epochs):
    for idx, (images,targets) in enumerate (train_DataLoader):
        images = images.to(device)
        targets = targets.to(device)
        output = myMLP(images)
        loss = loss_fn(output,targets)
        loss.backward()
        optim.step()
        optim.zero_grad()

        if idx % 100 == 0:
            print(loss)

 #입력할 데이터를 위해 데이터 준비
     #데이터를 입력
         #images 입력
         # targerts 입력
# 모델에 데이터를 넣기
        # 모델에 데이터 입력
# 모델의 출력과 정답을 비교하기 (Loss 사용)
       # loss_fn를 이용하여 정답과 비교
# Loss를 바탕으로 업데이트 진행 (Optimizer)
         #backwrard 진행
        # 업데이트 진행
         # backward 하기전에 zerograd로 없애 나야지 에러가 안남/ 기존값을 날려버려야함
# 평가(로깅, print), 저장

        #100번에 한번 loss 출력
             #print로 loss 출력


import os
import random
from enum import Enum

from .dictionary import Dictionary
from .wordentry import WordEntry, DefinitionEntry

class Category(Enum):
    """Enum class representing the categories for HSK3.0.

    Attributes:
        title: The string name of the category.
        index: The integer representing the associated index, used by the HSK3 class.
    """

    ENTRY = ("普及化 - Entry Level", 0)
    INTERMEDIATE = ("中级 - Intermediate Level", 1)
    ADVANCED = ("高级 - Advanced Level", 2)
    SUPPLEMENTAL = ("附录 - Supplemental Vocab", 3)

    def __init__(self, title, index):
        self.title = title
        self.index = index

    @classmethod
    def get_by_index(cls, index):
        for c in cls:
            if c.index == index:
                return c

class HSK3:
    """HSK3.0 utility for post-2020, categorizing Chinese words by difficulty.

    Parses HSK2.0 file on initialization. Contains 4 categories: entry, intermediate, advanced, supplemental.

    Attributes:
        dictionary: Optional Dictionary instance. If not provided, a new Dictionary instance will be instantiated.
    """

    def __init__(self, dictionary: Dictionary = None):
        if dictionary is None:
            dictionary = Dictionary()
        self.category_list = []  # contains categories to lists of WordEntry
        self.word_to_category_map = {}  # for retrieving category of given word
        self.dictionary = dictionary
        self.parse()

    def parse(self):
        """Parses the HSK3.0 file.

        Called on initialization of HSK3 instance. For each category in HSK3.0, a new entry is added to `category_list`; each category contains a list of corresponding words.
        """

        dirname = os.path.dirname(__file__)
        hsk_file = os.path.join(dirname, "hsk/HSK3.0 wordlist [post-2020].txt")

        category_index = -1
        category_words = None

        with open(hsk_file) as file:
            for line in file:

                # read new category for words that follow
                if line.startswith("//"):
                    category_words = []
                    self.category_list.append(category_words)
                    category_index += 1
                    continue

                word = line.strip()
                word_entry = self.dictionary.lookup(word)
                if word_entry is not None:
                    category_words.append(word_entry)
                    self.word_to_category_map[word] = category_index

    def get_category_for_word(self, word):
        """Returns the corresponding HSK category for the given word.

        Args:
            word: The string of the Chinese word to look up (can be multiple characters).

        Returns:
            The string name of the HSK category associated to the word, if found. Otherwise, returns None.
        """
        word = word.strip()
        if word in self.word_to_category_map:
            category_index = self.word_to_category_map.get(word)
            return Category.get_by_index(category_index).title
        return None

    def get_words_for_category(self, category=Category):
        """Returns the words corresponding to the given HSK category.

        Args:
            category: The Category to get words for.

        Returns:
            A list containing the words for the given HSK category.
        """
        return self.category_list[category.index]

    def get_entry(self):
        """Returns the words corresponding to HSK Entry level."""
        return self.get_words_for_category(Category.ENTRY)

    def get_intermediate(self):
        """Returns the words corresponding to HSK Intemediate level."""
        return self.get_words_for_category(Category.INTERMEDIATE)

    def get_advanced(self):
        """Returns the words corresponding to HSK Advanced level."""
        return self.get_words_for_category(Category.ADVANCED)

    def get_supplemental(self):
        """Returns the words corresponding to HSK Supplemental level."""
        return self.get_words_for_category(Category.SUPPLEMENTAL)


def solve1(X, A, D, N):
    if D < 0:
        A = A + D * (N - 1)
        D = -D
    left = 0
    right = N-1
    while right - left > 1:
        mid = (left + right) // 2
        if X < A + mid * D:
            right = mid
        else:
            left = mid
    ans = min(abs(X - (A + left * D)), abs(X - (A + right * D)))
    return ans

def solve2(X, A, D, N):
    if D < 0:
        A = A + D * (N - 1)
        D = -D
    if D == 0 or X <= A:
        return abs(X - A)

    n = min(N-1, abs((X - A) // D))
    m = min(N-1, n+1)
    return min(abs(X - (A + n * D)), abs(X - (A + m * D)))

if __name__ == '__main__':
    X, A, D, N = map(int, input().split())
    solve = solve2
    ans = solve(X, A, D, N)
    print(ans)


"""The alarm device class."""
# -*- coding: utf-8 -*-

import logging

from .fritzhomedevicebase import FritzhomeDeviceBase
from .fritzhomedevicefeatures import FritzhomeDeviceFeatures

_LOGGER = logging.getLogger(__name__)

class FritzhomeDeviceAlarm(FritzhomeDeviceBase):
    """The Fritzhome Device class."""

    alert_state = None

    def _update_from_node(self, node):
        super()._update_from_node(node)
        if self.present is False:
            return

        if self.has_alarm:
            self._update_alarm_from_node(node)

    # Alarm
    @property
    def has_alarm(self):
        """Check if the device has alarm function."""
        return self._has_feature(FritzhomeDeviceFeatures.ALARM)

    def _update_alarm_from_node(self, node):
        val = node.find("alert")
        try:
            self.alert_state = self.get_node_value_as_int_as_bool(val, "state")
        except (Exception, ValueError):
            self.alert_state = None


#defaultdict: another take on missing keys
#collections.defaultdict
'''
if 'new-key' is not in dd(defaultdict) then the expression dd['new-key'] does the following steps:
1. calls list() to create a new list
2. inserts the list into dd using 'new-key' as key
3. returns s reference to that list
'''
import sys
import re
import collections

WORD_RE = re.compile('\w+')

index = collections.defaultdict(list)
with open('test', encoding='utf-8') as fp:
    for line_no, line in enumerate(fp, 1):
        for match in WORD_RE.finditer(line):
            word = match.group()
            column_no = match.start() + 1
            location = (line_no, column_no)
            index[word].append(location)

for word in sorted(index, key=str.upper):
    print(word, index[word])


import stat
import shutil

from pathlib import Path
from typing import Any, Dict, List

from snapfs import transform

def make_dirs(path: Path):
    path.mkdir(0o774, True, True)

def store_file(file_path: Path, content: str, override: bool = False) -> None:
    if file_path.is_file() and override:
        # make file writeable
        file_path.chmod(stat.S_IWRITE | stat.S_IWGRP | stat.S_IROTH)

    if not file_path.is_file() or override:
        make_dirs(file_path.parent)

        with open(file_path, "w") as f:
            f.write(content)

        # make file read only
        file_path.chmod(stat.S_IREAD | stat.S_IRGRP | stat.S_IROTH)

def store_dict_as_file(
    file_path: Path, data: Dict[str, Any], override: bool = False
) -> None:
    store_file(file_path, transform.dict_as_json(data), override)

def store_dict_as_blob(directory: Path, data: Dict[str, Any]) -> str:
    contents = transform.dict_as_json(data)

    hashid = transform.string_as_hashid(contents)

    hashid_path = directory.joinpath(transform.hashid_as_path(hashid))

    store_file(hashid_path, contents)

    return hashid

def load_file(file_path: Path) -> str:
    data: str = ""

    with open(file_path, "r") as f:
        data = f.read()

    return data

def load_file_as_dict(file_path: Path) -> Dict[str, Any]:
    return transform.json_as_dict(load_file(file_path))

def load_blob_as_dict(directory: Path, hashid: str) -> Dict[str, Any]:
    hashid_path = directory.joinpath(transform.hashid_as_path(hashid))

    return load_file_as_dict(hashid_path)

def copy_file(source: Path, target: Path) -> None:
    make_dirs(target.parent)

    shutil.copyfile(source, target)

def copy_file_as_blob(directory: Path, source: Path) -> str:
    hashid = transform.file_as_hashid(source)

    hashid_path = directory.joinpath(transform.hashid_as_path(hashid))

    if not hashid_path.is_file():
        make_dirs(hashid_path.parent)

        copy_file(source, hashid_path)

        hashid_path.chmod(stat.S_IREAD | stat.S_IRGRP | stat.S_IROTH)

    return hashid

def load_ignore_file_as_patterns(directory: Path) -> List[str]:
    patterns = []

    ignore_file_path = directory.joinpath(".ignore")

    if ignore_file_path.is_file():
        contents = load_file(ignore_file_path)

        patterns = list(
            filter(
                bool,
                [
                    x.strip()
                    for x in contents.split("\n")
                    if not x.startswith("#")
                ],
            )
        )

    return patterns


# # Python program to find maximum product of two
# # non-intersecting paths

# # Returns maximum length path in subtree rooted
# # at u after removing edge connecting u and v
# def dfs(g, curMax, u, v):

# 	# To find lengths of first and second maximum
# 	# in subtrees. currMax is to store overall
# 	# maximum.
# 	max1 = 0
# 	max2 = 0
# 	total = 0

# 	# loop through all neighbors of u
# 	for i in range(len(g[u])):

# 		# if neighbor is v, then skip it
# 		if (g[u][i] == v):
# 			continue

# 		# call recursively with current neighbor as root
# 		total = max(total, dfs(g, curMax, g[u][i], u))

# 		# get max from one side and update
# 		if (curMax[0] > max1):
# 			max2 = max1
# 			max1 = curMax[0]
# 		else:
# 			max2 = max(max2, curMax[0])

# 	# store total length by adding max
# 	# and second max
# 	total = max(total, max1 + max2)

# 	# update current max by adding 1, i.e.
# 	# current node is included
# 	curMax[0] = max1 + 1
# 	return total

# # method returns maximum product of length of
# # two non-intersecting paths
# def maxProductOfTwoPaths(g, N):
# 	res = -999999999999
# 	path1, path2 = None, None

# 	# one by one removing all edges and calling
# 	# dfs on both subtrees
# 	for i in range(N):
# 		for j in range(len(g[i])):
# 			# print(g[i][j], i, '-', i, g[i][j])
# 			# calling dfs on subtree rooted at
# 			# g[i][j], excluding edge from g[i][j]
# 			# to i.
# 			curMax = [0]
# 			path1 = dfs(g, curMax, g[i][j], i)

# 			# calling dfs on subtree rooted at
# 			# i, edge from i to g[i][j]
# 			curMax = [0]
# 			path2 = dfs(g, curMax, i, g[i][j])
# 			print(path1, path2)

# 			res = max(res, path1 * path2)
# 	return res

# # Utility function to add an undirected edge (u,v)
# def addEdge(g, u, v):
# 	g[u].append(v)
# 	g[v].append(u)

# # Driver code
# if __name__ == '__main__':
# 	edges = [[1, 8], [2, 6], [3, 1], [5, 3], [7, 8], [8, 4], [8, 6]]
# 	N = len(edges)

# 	# there are N edges, so +1 for nodes and +1
# 	# for 1-based indexing
# 	g = [[] for i in range(N + 2)]
# 	for i in range(N):
# 		addEdge(g, edges[i][0], edges[i][1])

# 	print(g)
# 	print(maxProductOfTwoPaths(g, N))

# # This code is contributed by PranchalK

from Graph import UnDirectedGraph
import sys

class MaxProductNInterPath(UnDirectedGraph):

	def __init__(self):
		UnDirectedGraph.__init__(self)

	def findMax(self):
		visited = {key: 0 for key, val in self.graph.items()}

		path1, path2 = 0, 0
		print(self.graph)
		res = -sys.maxsize
		for src in self.graph:

			for dest in self.graph[src]:
				# print(src, dest)
				path1 = self.DFS(src, visited, 0, dest)
				# print(path1)
				# print(dest, src)
				path2 = self.DFS(dest, visited,0, src)

				print(path1, path2)

		print(res)

	def DFS(self, src, visited, max1, dest = None):

		visited[src] = 1
		for i in self.graph[src]:

			if i is dest:
				continue

			# print(visited)
			if not visited[i]:
				print(visited)

				visited[i] = visited[src] + 1
				max2 = self.DFS(i, visited, max1+1)
			if max1 < max2:
				max1 = max2

		return max1

graph = MaxProductNInterPath()

edges = [(8, 4), (8, 7), (8, 6), (8, 1), (6, 2), (1, 3), (3, 5)]
for src, dest in edges:

	graph.addEdge(src, dest)

graph.findMax()


from ipywidgets import VBox, HBox, Layout, Label, ColorPicker, GridBox, Dropdown, Button
import ipyvuetify as v
from matplotlib.colors import to_hex, to_rgba, ListedColormap
from moneta.settings import *
import numpy as np
import os
from vaex.jupyter.utils import debounced
from moneta.trace import ThreadTag, SpaceTimeTag

class Accesses():
    def __init__(self, model, update_selection):
        self.model = model
        self.update_selection = update_selection
        self.colormap = np.copy(newc)
        self.colorpickers = {}
        self.custom_layer_preset = None
        self.all_tags =  self.model.curr_trace.tags # includes spacetime and thread
        self.layer_options = [
            ('None', [0]), ('accesses-read', [READ_HIT, READ_MISS, COMP_R_MISS]), ('accesses-write', [WRITE_HIT, WRITE_MISS, COMP_W_MISS]),
            ('hits-all', [WRITE_HIT, READ_HIT]), ('hits-read', [READ_HIT]),  ('hits-write', [WRITE_HIT]),
            ('misses-all', [READ_MISS, WRITE_MISS, COMP_R_MISS, COMP_W_MISS]), ('misses-reads', [READ_MISS, COMP_R_MISS]),
            ('misses-writes', [WRITE_MISS, COMP_W_MISS]), ('misses-capacity-all', [WRITE_MISS, READ_MISS]),
            ('misses-capacity-reads', [READ_MISS]), ('misses-capacity-writes', [WRITE_MISS]), ('misses-compulsory-all', [WRITE_MISS, READ_MISS]),
            ('misses-compulsory-reads', [COMP_R_MISS]), ('misses-compulsory-writes', [COMP_W_MISS])
         ]

        i_val = 9
        for tag in self.all_tags:
           i_layer = (tag.display_name(), tag)
           i_val += 1
           self.layer_options.append(i_layer)

        self.widgets = self.init_widgets()

    def init_widgets(self):
        #######################################################################
        '''
            Helper functions to help with wrapping widgets in layouts and initializing UI
            elements
        '''
        def clr_picker(enum_color, cache=False, miss_acc=False):
            '''

            '''
            def handle_color_picker(change):
                print(enum_color, change)
                self.colormap[enum_color] = to_rgba(change.new, 1)
                self.model.plot.colormap = ListedColormap(self.colormap)
                self.model.plot.backend.plot.update_image()

            if cache:
                clr_picker = ColorPicker(concise=True, value=to_hex(self.colormap[enum_color][0:3]),
                        disabled=False, layout=Layout(width="30px"))
            else:
                clr_picker = ColorPicker(concise=True, value=to_hex(self.colormap[enum_color][0:3]),
                        disabled=False, layout=Layout(width="25px", margin="0 4px 0 4px"))

            clr_picker.observe(handle_color_picker, names='value')
            self.colorpickers[enum_color] = clr_picker

            clr_picker.observing = True
            return clr_picker

        def ParentBox(parent_widgets):
            # Create wrapper to combine clrpicker checkbox and dropdown
            return HBox([clr_picker(enum_color=parent_widgets.enum_color), parent_widgets.check_widget , parent_widgets.dropdown_widget],
                        layout=Layout(align_items="center", overflow="hidden", justify_content="flex-start"))

        #######################################################################
        # drop down menue for color view selection
        self.dropdown = Dropdown(options=C_VIEW_OPTIONS,
                            value='None',
                            disabled=False,
                            layout={'width': 'min-content'}
                            )
        self.dropdown.observe(self.update_presets, names='value')
        self.dropdown.observing = True
        dropdown_row = HBox([GridBox([Label(value='Layer Preset:'), self.dropdown],
                            layout=Layout(grid_template_rows="30px", grid_template_columns="120px 200px"))],
                            layout=Layout( padding="0px 0px 14px 100px"))

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

        # Primary layers
        self.layer1_widgets = ParentWidgets(label='1', tooltip="Layer1", enum_color=9, clr=6.1,
                                            init_layer_val=[0], layer_options=self.layer_options, compute=self.compute_layers)
        self.layer2_widgets = ParentWidgets(label='2', tooltip="Layer2", enum_color=8, clr=5.5,
                                            init_layer_val=[0], layer_options=self.layer_options, compute=self.compute_layers)
        self.layer3_widgets = ParentWidgets(label='3', tooltip="Layer3", enum_color=7, clr=5.1,
                                            init_layer_val=[0], layer_options=self.layer_options, compute=self.compute_layers)
        self.layer4_widgets = ParentWidgets(label='4', tooltip="Layer4", enum_color=6, clr=4.4,
                                            init_layer_val=[0], layer_options=self.layer_options, compute=self.compute_layers)
        self.layer5_widgets = ParentWidgets(label='5', tooltip="Layer5", enum_color=5, clr=3.5,
                                            init_layer_val=[0], layer_options=self.layer_options, compute=self.compute_layers)
        self.layer6_widgets = ParentWidgets(label='6', tooltip="Layer6", enum_color=4, clr=3.1,
                                            init_layer_val=[0], layer_options=self.layer_options, compute=self.compute_layers)
        self.layer7_widgets = ParentWidgets(label='7', tooltip="Layer7", enum_color=3, clr=2.4,
                                            init_layer_val=[0], layer_options=self.layer_options, compute=self.compute_layers)
        self.layer8_widgets = ParentWidgets(label='8', tooltip="Layer8", enum_color=2, clr=1.4,
                                            init_layer_val=[0], layer_options=self.layer_options, compute=self.compute_layers)

        self.layers = [self.layer1_widgets, self.layer2_widgets, self.layer3_widgets, self.layer4_widgets,
                       self.layer5_widgets, self.layer6_widgets, self.layer7_widgets, self.layer8_widgets]

        # Wrap parent widgets in a layout with a color picker
        layer1 = ParentBox(self.layer1_widgets)
        layer2 = ParentBox(self.layer2_widgets)
        layer3 = ParentBox(self.layer3_widgets)
        layer4 = ParentBox(self.layer4_widgets)
        layer5 = ParentBox(self.layer5_widgets)
        layer6 = ParentBox(self.layer6_widgets)
        layer7 = ParentBox(self.layer7_widgets)
        layer8 = ParentBox(self.layer8_widgets)

        grid_elements = [layer1, vdiv, layer2,
                            Whdiv, hdiv, Whdiv,
                            layer3, vdiv, layer4,
                            Whdiv, hdiv, Whdiv,
                            layer5, vdiv, layer6,
                            Whdiv, hdiv, Whdiv,
                            layer7, vdiv, layer8,
                            Whdiv, hdiv, Whdiv,
                        ]
        row_template = "50px 2px 50px 2px 50px 2px 50px 2px 50px 2px"
        column_template = "180px 2px 180px"

        # Add pseudo grid and wrap primary boxes in ipywidget
        gridbox = HBox([GridBox(grid_elements,
                                layout=Layout(grid_template_rows=row_template, grid_template_columns=column_template))],
                                layout=Layout( padding="0 0 0 14px"))

        # cache_icon = v.Icon(children=['fa-database'], v_on='tooltip.on')
        # cache_icon_tp = v.Tooltip(bottom=True, v_slots=[{'name': 'activator', 'variable': 'tooltip', 'children': cache_icon}], children=["Cache"])

        # cache_clrpkr = clr_picker(3, cache=True)

        # reset_clrs = v.Btn(v_on='tooltip.on', icon=True, children=[v.Icon(children=['refresh'])])
        # reset_clrs.on_event('click', self.reset_colormap)
        # reset_clrs_tp = v.Tooltip(bottom=True, v_slots=[{'name': 'activator', 'variable': 'tooltip', 'children': reset_clrs}], children=["Reset all colors"])
        # cache_row = HBox([cache_icon_tp, cache_clrpkr, reset_clrs_tp],
        #                 layout=Layout(padding="0 20px 20px 20px", align_items="center", justify_content="space-between"))  ## , cache_row
        return VBox([dropdown_row, gridbox])

    # @debounced(0.2)
    def compute_layers(self, change):

        # reset the layer value of old selections
        # tags threads and accesses use seperate queries
        if type(change['old']) is SpaceTimeTag :
            addr_low = float(change['old'].address[0])
            addr_high = float(change['old'].address[1]) + 1
            indx_low = float(change['old'].access[0])
            indx_high = float(change['old'].access[1]) + 1

            # !See Explantion Below
            self.model.curr_trace.df.Temp1 = self.model.curr_trace.df.func.where(
                (addr_low <= self.model.curr_trace.df.Address), 1.0 , 2.0)

            self.model.curr_trace.df.Temp2 = self.model.curr_trace.df.func.where(
                (addr_high >= self.model.curr_trace.df.Address), 1.0 , 3.0)

            self.model.curr_trace.df.TempA = self.model.curr_trace.df.func.where(
                (self.model.curr_trace.df.Temp1 == self.model.curr_trace.df.Temp2), 1.0 , 6.0)

            self.model.curr_trace.df.Temp3 = self.model.curr_trace.df.func.where(
                ( indx_low <= self.model.curr_trace.df.index ), 1.0 , 4.0)
            self.model.curr_trace.df.Temp4 = self.model.curr_trace.df.func.where(
                ( indx_high >= self.model.curr_trace.df.index ), 1.0, 5.0)
            self.model.curr_trace.df.TempB = self.model.curr_trace.df.func.where(
                (self.model.curr_trace.df.Temp3 == self.model.curr_trace.df.Temp4), 1.0 , 7.0)

            self.model.curr_trace.df[LAYER] = self.model.curr_trace.df.func.where(
                (self.model.curr_trace.df.TempA == self.model.curr_trace.df.TempB),
                0.4 , self.model.curr_trace.df.Layer)

        elif type(change['old']) is ThreadTag:
            t_id = change['old'].thread_id
            self.model.curr_trace.df[LAYER] = self.model.curr_trace.df.func.where(self.model.curr_trace.df.ThreadID == t_id, 1, self.model.curr_trace.df.Layer)
        else:
            for atype in change['old']:
                self.model.curr_trace.df[LAYER] = self.model.curr_trace.df.func.where(self.model.curr_trace.df.Access == atype, 1 , self.model.curr_trace.df.Layer)

        for layer in reversed(self.layers):
            # check if the layer checkbox is enabled first
            if layer.check.v_model == True:
                # do not update none layers and layer.dropdown_widget.value == change['new']
                if layer.dropdown_widget.value != [0] :
                    # tags threads and accesses use seperate queries
                    if type(layer.dropdown_widget.value) is SpaceTimeTag :
                        addr_low = float(layer.dropdown_widget.value.address[0])
                        addr_high = float(layer.dropdown_widget.value.address[1]) + 1
                        indx_low = float(layer.dropdown_widget.value.access[0])
                        indx_high = float(layer.dropdown_widget.value.access[1]) + 1

                        # df.func.where has a bug where it can only evaluate single boolean value expressions
                        #   EX. self.model.curr_trace.df.Address >= addr_low and self.model.curr_trace.df.Address <= addr_high
                        #   results in only the first comparison being evaluated.
                        # Thus we must seperate the upper and lower bound calculations, this is not efficient but has minimal
                        # impact on perfomance.

                        # create temp layer to find which accesses belong to tag.
                        self.model.curr_trace.df.Temp1 = self.model.curr_trace.df.func.where(
                            (addr_low <= self.model.curr_trace.df.Address), 1.0 , 2.0)

                        self.model.curr_trace.df.Temp2 = self.model.curr_trace.df.func.where(
                            (addr_high >= self.model.curr_trace.df.Address), 1.0 , 3.0)

                        self.model.curr_trace.df.TempA = self.model.curr_trace.df.func.where(
                            (self.model.curr_trace.df.Temp1 == self.model.curr_trace.df.Temp2), 1.0 , 6.0)

                        self.model.curr_trace.df.Temp3 = self.model.curr_trace.df.func.where(
                            ( indx_low <= self.model.curr_trace.df.index ), 1.0 , 4.0)
                        self.model.curr_trace.df.Temp4 = self.model.curr_trace.df.func.where(
                            ( indx_high >= self.model.curr_trace.df.index ), 1.0, 5.0)
                        self.model.curr_trace.df.TempB = self.model.curr_trace.df.func.where(
                            (self.model.curr_trace.df.Temp3 == self.model.curr_trace.df.Temp4), 1.0 , 7.0)

                        self.model.curr_trace.df[LAYER] = self.model.curr_trace.df.func.where(
                            self.model.curr_trace.df.TempA == self.model.curr_trace.df.TempB,
                            layer.clr , self.model.curr_trace.df.Layer)

                    elif type(layer.dropdown_widget.value) is ThreadTag:
                        t_id = layer.dropdown_widget.value.thread_id
                        self.model.curr_trace.df[LAYER] = self.model.curr_trace.df.func.where(
                            self.model.curr_trace.df.ThreadID == t_id, layer.clr , self.model.curr_trace.df.Layer)
                    else:
                        for atype in layer.dropdown_widget.value:
                            self.model.curr_trace.df[LAYER] = self.model.curr_trace.df.func.where(
                                self.model.curr_trace.df.Access == atype, layer.clr , self.model.curr_trace.df.Layer)

            else:
                for atype in layer.dropdown_widget.value:
                    self.model.curr_trace.df[LAYER] = self.model.curr_trace.df.func.where(
                        self.model.curr_trace.df.Access == atype, 1, self.model.curr_trace.df.Layer)

        self.model.plot.colormap = ListedColormap(self.colormap)
        self.model.plot.backend.plot.update_grid()

    def update_presets(self, change):
        new_preset = change.new
        if new_preset == 'None':
            for layer in self.layers:
                layer.update_selection([0])
        elif new_preset == 'AccessType':
            self.layers[0].update_selection([COMP_W_MISS])
            self.layers[1].update_selection([WRITE_MISS])
            self.layers[2].update_selection([COMP_R_MISS])
            self.layers[3].update_selection([COMP_R_MISS])
            self.layers[4].update_selection([WRITE_HIT])
            self.layers[5].update_selection([READ_HIT])

        elif new_preset == 'TAG':
            layer_index = 0
            for layer_option in reversed(self.layer_options):
                if type(layer_option[1]) is SpaceTimeTag and layer_index < len(self.layers):
                    if layer_option[0] != 'Stack' and layer_option[0] != 'Heap':
                        self.layers[layer_index].update_selection(layer_option[1])
                        layer_index += 1
        elif new_preset == 'THREAD':
            layer_index = 0
            for layer_option in reversed(self.layer_options):
                if type(layer_option[1]) is ThreadTag and layer_index < len(self.layers):
                    self.layers[layer_index].update_selection(layer_option[1])
                    layer_index += 1
        elif new_preset == 'Custom':
            if self.custom_layer_preset is not None:
                for (index, layer_option) in enumerate(self.custom_layer_preset):
                    for option in self.layer_options:
                        if option[0] == layer_option:
                            self.layers[index].update_selection(option[1])

    def set_custom_presets(self, layer_preset):
        self.custom_layer_preset = layer_preset
        self.dropdown.value = 'Custom'

    def reset_colormap(self, *_):
        self.colormap = np.copy(newc)
        for clr, clr_picker in self.colorpickers.items():
            if clr < TOP_READ:
                clr_picker.observing = False
                clr_picker.value = to_hex(self.colormap[enum_color][0:3])
                clr_picker.observing = True
        self.model.plot.colormap = ListedColormap(self.colormap)
        self.model.plot.backend.plot._update_image()

class ParentWidgets:
    def __init__(self, label, tooltip, enum_color, clr, init_layer_val, layer_options, compute):

        self.check = v.Checkbox(v_on='tooltip.on', label=label, v_model=True , color='primary')
        self.check_widget = v.Tooltip(bottom=True, v_slots=[{'name': 'activator', 'variable': 'tooltip', 'children': self.check}],
                children=[tooltip])

        self.compute = compute
        self.enum_color = enum_color
        self.init_layer_val = init_layer_val
        self.layer_options = layer_options
        self.dropdown_widget = Dropdown(options=self.layer_options ,
                                        value=init_layer_val,
                                        disabled=False,
                                        layout={'width': '90px'}
                                        )
        self.dropdown_widget.observe(self.compute, names='value')
        self.dropdown_widget.observing = True
        self.clr = clr

    def update_selection(self, new_preset):
        self.dropdown_widget.observing = False
        self.dropdown_widget.value = new_preset
        self.dropdown_widget.observing = True


'''百度搜素'''
import requests
url = "https://www.baidu.com/s"
try:
    kw = {
        'wd':'比亚迪'
    }
    r = requests.get(url,params=kw)
    ss = r.raise_for_status()
    print(r.request.url)
    print(r.text)
except:
    print('爬取失败')

print('分割线'+'*'*50)
url2 = "https://www.so.com/s"
try:
    kw = {
        'q':'比亚迪'
    }
    r = requests.get(url2,params=kw)
    ss = r.raise_for_status()
    print(r.request.url)
    print(r.text)
except:
    print('爬取失败')


import tweepy
import time

auth = tweepy.OAuthHandler('X24kkVr17Tb1XhEETMXpdCrFR', '94i7VjUZqEF8QbHGjo1pVZGtfFOlLW2OAlqKNkDmXCXH5gGCGo')
auth.set_access_token('1238177705604112384-1Zq1xgii5DiNu61g3XjkTdDZVEhIc6', '7MoLXXTYmKwfTwOdvrFVNRWkBR6RrbTgzm65nr6s7XN2V')

api = tweepy.API(auth, wait_on_rate_limit=True, wait_on_rate_limit_notify=True)

user = api.me()

search = 'SoftServe'
nrTweets = 15

for tweet in tweepy.Cursor(api.search, search).items(nrTweets):
    try:
        print('Tweet Liked')
        tweet.favorite()
        time.sleep(2)
    except tweepy.TweepError as e:
        print(e.reason)
    except StopIteration:
        break

for tweet in tweepy.Cursor(api.search, search).items(nrTweets):
    try:
        print('Tweet Retweeted')
        tweet.retweet()
        time.sleep(2)
    except tweepy.TweepError as e:
        print(e.reason)
    except StopIteration:
        break


import click
import numpy as np

class cmd_depth(object):
    @classmethod
    def decorate(cls, cmd):
        cmd = click.option(
            '--depth', type=int, help="Normalize depth to positive (1) or negative(-1)"
        )(cmd)
        return cmd

    @classmethod
    def transform(cls, data, depth, **kw):
        for section in data:
            if "data" in section:
                for col in ("depth", "start_depth", "end_depth"):
                    if col in section["data"].columns:
                        section["data"][col] = np.abs(section["data"][col]) * depth
        return data


import re

class MyAnswer:
    def isPalindrome(self, s: str) -> bool:
        s = s.lower()
        s = [char for char in s if char.isalpha() or char.isdigit()]
        return s == s[::-1]

class Solution1:
    def isPalindrome(self, s: str) -> bool:
        s = s.lower()
        s = [char for char in s if char.isalnum()]
        return s == s[::-1]

class Solution2:
    def isPalindrome(self, s: str) -> bool:
        s = s.lower()
        s = re.sub("[^a-z0-9]", "", s)
        return s == s[::-1]

if __name__ == "__main__":
    testcase = "A man, a plan, a canal: Panama"
    print(f"My Answer  : {MyAnswer().isPalindrome(testcase)}")
    print(f"Solution 1 : {Solution1().isPalindrome(testcase)}")
    print(f"Solution 2 : {Solution1().isPalindrome(testcase)}")


# -*- coding: utf-8 -*-
import re
from decimal import Decimal
from datetime import timedelta
from datetime import datetime
from .log import logger as log
_author_ = 'luwt'
_date_ = '2021/9/1 16:20'

# 执行策略里，变量必须和convert_type函数的参数名保持一致
need_convert_types = {
    datetime: 'str(value)',
    # decimal 转为字符串形式
    Decimal: 'float(value)',
}

def convert_type(value):
    """将一些特殊类型转换为字符串，避免插入数据库时，参数错误"""
    result = value
    for data_type, deal_strategy in need_convert_types.items():
        if isinstance(value, data_type):
            result = eval(deal_strategy)
            break
    return result

def get_data(cursor, sql):
    cursor.execute(sql)
    return cursor.fetchall()

def get_pattern_matches(table_names, pattern, pattern_name):
    if not pattern:
        return set()
    log.info(f"{pattern_name} pattern is {pattern}")
    result = set(filter(lambda x: re.fullmatch(pattern, x), table_names))
    log.info(f"{pattern_name} match {len(result)} tables: {result}")
    return result

def times(f):
    def count_time(*args, **kw):
        start = datetime.now()
        log.info(f"开始时间为：{start}")
        try:
            f(*args, **kw)
        finally:
            end = datetime.now()
            interval = (end.timestamp() - start.timestamp())
            time_sec = timedelta(seconds=interval)
            log.info(f"结束时间：{end}，耗时{time_sec}")
    return count_time


# -*- coding: utf-8 -*-
"""
Created on Fri May  5 09:38:49 2017

Ranks according to similarities

Args: extraction_file corpusA corpusB ctxA ctxB nos

@author: vurga
"""

import sys
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
from collections import defaultdict as ddict
import math
import unicodedata
import string
import pandas as pd
import pickle
import re

def cosine_sim(dictionary):

    cosine_sim = 0
    for value in dictionary.values():
        cosine_sim += value[0] * value[1]

    length1 = sum([value[0] ** 2 for value in dictionary.values()])
    length2 = sum([value[1] ** 2 for value in dictionary.values()])

    try:
        cosine_sim /= math.sqrt(length1) * math.sqrt(length2)
    except ZeroDivisionError:
        cosine_sim = None

    return cosine_sim

def char_ngram(line1, line2, n=2):

    ngramdict = ddict(lambda: ddict(lambda: 0))
    line_pair = [line1, line2]

    for i, line in enumerate(line_pair):
        line = ''.join(line.split())
        j = 0
        while (j + (n - 1)) < len(line):
            ngramdict[line[j:j+n]][i] += 1
            j += 1

    return cosine_sim(ngramdict)

def strip_accents(s):
   return ''.join(c for c in unicodedata.normalize('NFD', s)
                  if unicodedata.category(c) != 'Mn')

def cognate(line1, line2):

    cognatedict = ddict(lambda: ddict(lambda: 0))
    line_pair = [line1, line2]

    for i, line in enumerate(line_pair):
        for word in line.split():
            if word.isdigit():
                cognatedict[word][i] += 1
            elif len(word) >= 4:
                cognatedict[strip_accents(word[:4])][i] += 1
            elif len(word) == 1 and word in string.punctuation:
                cognatedict[word][i] += 1

    return cosine_sim(cognatedict)

def lf(line1, line2):
    return math.exp(-.5*((((len(line2)/len(line1))-1.133)/0.415))**2)

def extract_fea(tA, tB):

    ngram_cosine_sims = {}
    for n in range(2,6):
        ngram_cosine_sims[n] = char_ngram(tA, tB, n)

    cognate_cosine_sims = cognate(tA, tB)
    lfs = lf(tA, tB)
    #tokens = (len(tA.split()), len(tB.split()))
    #chars=(sum([len(word) for word in tA.split()]), sum([len(word) for word in tB.split()]))

    return np.array([ngram_cosine_sims[2], ngram_cosine_sims[3], ngram_cosine_sims[4], ngram_cosine_sims[5], cognate_cosine_sims, lfs])

with open(sys.argv[1], 'r') as source:
    extractions = source.readlines()
with open(sys.argv[6], 'r') as source:
    nos = source.readlines()

with open(sys.argv[6]+'.srank', 'w'):
     pass

for extraction in extractions:
    article_id = int(extraction.strip().split()[0])
    a_id = int(extraction.strip().split()[1])
    b_id = int(extraction.strip().split()[2])

    index_a = 0
    index_b = 0
    for no in nos[:article_id]:
        index_a += int(no.strip().split()[0])
        index_b += int(no.strip().split()[1])

    with open(sys.argv[2], 'r') as corpusA, open(sys.argv[3], 'r') as corpusB, open(sys.argv[4], 'r') as ctxA, open(sys.argv[5], 'r') as ctxB:
        ## get to position
        for i in range(index_a + a_id):
            l_a = next(corpusA)
            c_a = next(ctxA)
        for i in range(index_b + b_id):
            l_b = next(corpusB)
            c_b = next(ctxB)

    ## compute cosine sim
    cvec_1 = np.fromstring(c_a.strip(), sep=" ")
    cvec_2 = np.fromstring(c_b.strip(), sep=" ")
    ## compute cosine sim
    sim = cosine_similarity(cvec_1, cvec_2)

    ## extract all sx feas
    feas = extract_fea(l_a, l_b)
    feas_c = np.append(sim, feas)

    with open(sys.argv[6]+'.srank', 'a+') as target:
        try:
            score = np.mean(feas_c[:-1]) * feas[-1]
        except:
            score = 0.0
        target.write(str(score) + '\n')


from collections import OrderedDict as OD
from itertools import chain, combinations
from SloppyCell.ReactionNetworks.Reactions import Reaction
import libtype

def get_substrates(stoich):
    return [spid for spid, stoichcoef in stoich.items() if stoichcoef<0]

def get_products(stoich):
    return [spid for spid, stoichcoef in stoich.items() if stoichcoef>0]

def get_reactants(stoich):
    """
    Sometimes a stoichiometry has species that are not reactants, whose
    stoichiometry coefficients are zero.
    """
    return get_substrates(stoich) + get_products(stoich)

class IrreversibleMultisubstrateMichaelisMenten(Reaction):
    """

    """

    def __init__(self, id, stoichiometry, info_inhibitors=None, activators=None):
        """
        Parameters
        ----------
        info_inhibitors, a dict
            example:
            [{'inhibitor': 'I1', 'substrate': 'S1', 'mode': 'competitive'},
             {'inhibitor': 'I1', 'substrate': 'S1', 'mode': 'uncompetitive'},
             {'inhibitor': 'I2', 'substrate': 'S2', 'mode': 'competitive'},
             {'inhibitor': 'I3', 'substrate': 'S1', 'mode': 'competitive'}
            ]
            Let:
                id = 13
                substrates = ['S1', 'S2']
            Then:
                kineticLaw = 'Vm_13*S1*S2/((Km_13_S1*(1+I1/Kic_13_S1_I1+I3/Kic_13_S1_I3)+
                              S1*(1+I1/Kiu_13_S1_I1))*(Km_13_S2*(1+I2/Kic_13_S2_I2)+S2))'
        activators, a dict
            example: to be implemented.
        """
        str_Vm = 'Vm_' + id
        substrates = get_substrates(stoichiometry)
        kineticLaw_numerator = str_Vm + '*' + '*'.join(substrates)
        kineticLaw_denominator_components = []
        for substrate in substrates:
            str_Km = 'Km_' + id + '_' + substrate
            str_concn = substrate
            if info_inhibitors:  # if the reaction has inhibitors
                for info in info_inhibitors:
                    if isinstance(info, tuple):
                        inhibitor, substrate_inhibited, mode = info
                    else:
                        substrate_inhibited = info['substrate']
                        inhibitor = info['inhibitor']
                        mode = info['mode']
                    if substrate == substrate_inhibited:
                        if mode == 'competitive' or mode == 'c':
                            str_Ki = 'Kic_' + id + '_' + substrate + '_' + inhibitor
                            if not str_Km.endswith(')'):
                                str_Km = str_Km + '*(1+' + inhibitor + '/' +  str_Ki + ')'
                            else:
                                str_Km = str_Km[:-1] + '+' + inhibitor + '/' + str_Ki + ')'
                        else:  # uncompetitive inhibition
                            str_Ki = 'Kiu_' + id + '_' + substrate + '_' + inhibitor
                            if not str_concn.endswith(')'):
                                str_concn = str_concn + '*(1+' + inhibitor + '/' +  str_Ki + ')'
                            else:
                                str_concn = str_concn[:-1] + '+' + inhibitor + '/' + str_Ki + ')'
            else:  # if the reaction has no inhibitors
                pass
            kineticLaw_denominator_components.append('('+str_Km+'+'+str_concn+')')
        kineticLaw_denominator = '*'.join(kineticLaw_denominator_components)
        kineticLaw = kineticLaw_numerator + '/(' + kineticLaw_denominator + ')'
        Reaction.__init__(self, id, stoichiometry, kineticLaw)

class ReversibleMassAction(Reaction):
    """
    """
    def __init__(self, id, stoichiometry):
        """
        """
        str_substrates = '*'.join(['pow('+sp+','+str(abs(stoichiometry[sp]))+')'
                                   for sp in stoichiometry.keys() if stoichiometry[sp]<0])
        str_products = '*'.join(['pow('+sp+','+str(stoichiometry[sp])+')'
                                 for sp in stoichiometry.keys() if stoichiometry[sp]>0])
        kineticLaw = 'k_'+id+'*('+str_substrates+'-'+str_products+'/'+'Ke_'+id+')'
        Reaction.__init__(self, id, stoichiometry, kineticLaw)

def powerset(iterable):
    s = list(iterable)
    return list(chain.from_iterable(combinations(s,r) for r in range(len(s)+1)))

def get_MM_ratelaw(rxnid, stoich, reversible=True, Keq=None, KIcs=None,
                KIus=None, one_step=False, states_allowed=None):
    """

    """
    if Keq:
        Keq = 'Keq_' + rxnid
    Vf = 'Vf_' + rxnid
    Vb = 'Vb_' + rxnid
    subs = get_substrates(stoich)
    prods = get_products(stoich)
    KMsubs = ['KM_'+rxnid+'_'+sub for sub in subs]
    KMprods = ['KM_'+rxnid+'_'+prod for prod in prods]
    # substrate/product concentrations normalized by Michaelis constants
    subs_norm = ['('+subs[i]+'/'+KMsubs[i]+')' for i in range(len(subs))]
    prods_norm = ['('+prods[i]+'/'+KMprods[i]+')' for i in range(len(prods))]
    ## make a dictionary, state2term, that maps from binding state
    ## of the enzyme to the corresponding term
    states = [frozenset(s) for s in powerset(subs)] +\
             [frozenset(s) for s in powerset(prods)]
    terms = ['*'.join(s) for s in powerset(subs_norm)] +\
            ['*'.join(s) for s in powerset(prods_norm)]
    state2term = OD(zip(states, terms))
    state2term[frozenset([])] = '1'
    state_subs = frozenset(subs)
    state_prods = frozenset(prods)
    # not random order, only certain bound states are allowed
    if states_allowed:
        # add the unbound state
        if () not in states_allowed:
            states_allowed.insert(0, ())
        states_allowed = [frozenset(state) for state in states_allowed]
        state2term = libtype.get_submapping(state2term, states_allowed)
    # add the competitive-inhibitor bound states
    if KIcs:
        for spid in KIcs.keys():
            state = frozenset([spid])
            term = '(%s/%s)' % (spid, 'KIc_'+rxnid+'_'+spid)
            state2term[state] = term
    # add the uncompetitive-inhibitor bound states
    if KIus:
        for spid in KIus.keys():
            state = frozenset([spid]).union(state_subs)
            term = state2term[state_subs] +\
                   '*(%s/%s)' % (spid, 'KIu_'+rxnid+'_'+spid)
            state2term[state] = term

    ## construct the numerator
    if Keq:
        # Haldane's relation: at equilibrium Vf*s/KMs = Vb*p/KMp
        # Therefore p/s = Keq = Vf*KMp/(Vb*KMs), Vb = Vf*(KMp/(KMs*Keq))
        Vb = '(%s*%s/(%s*%s))' % (Vf, '*'.join(KMsubs), '*'.join(KMprods), Keq)
    numerator = '(%s*%s - %s*%s)' % (Vf, state2term[state_subs],
                                     Vb, state2term[state_prods])
    if not reversible:
        numerator = '(%s*%s)' % (Vf, state2term[state_subs])
    ## construct the denominator
    denominator = '(' + '+'.join(state2term.values()) + ')'

    if one_step:
        pass
    ratelaw = '%s/%s' % (numerator, denominator)
    return ratelaw

def add_MM_reaction(net, rxnid, Vs, stoich, KMs, reversible=True, KIcs=None, KIus=None, Keq=None,
                    one_step=False, duplicate_error=True, param_optimizable=True, states_allowed=None):
    """
    Requires the species to be in the network
    """
    # check if the species are already in the network

    # add the parameters
    for direction, paramval in Vs.items():
        if isinstance(paramval, tuple):
            paramval = paramval[0]
        paramid = 'V' + direction + '_' + rxnid
        net.add_parameter(paramid, paramval, is_optimizable=True)
    if Keq:
        if isinstance(Keq, tuple):
            paramval = Keq[0]
        net.add_parameter('Keq_'+rxnid, Keq, is_optimizable=False)
    for spid, paramval in KMs.items():
        if isinstance(paramval, tuple):
            paramval = paramval[0]
        paramid = 'KM_' + rxnid + '_' + spid
        net.add_parameter(paramid, paramval, is_optimizable=True)
    if KIcs is not None:
        for spid, paramval in KIcs.items():
            if isinstance(paramval, tuple):
                paramval = paramval[0]
            paramid = 'KIc_' + rxnid + '_' + spid
            net.add_parameter(paramid, paramval, is_optimizable=True)
    if KIus is not None:
        for spid, paramval in KIus.items():
            if isinstance(paramval, tuple):
                paramval = paramval[0]
            paramid = 'KIu_' + rxnid + '_' + spid
            net.add_parameter(paramid, paramval, is_optimizable=True)

    # get the rate law
    ratelaw = get_MM_ratelaw(rxnid=rxnid, stoich=stoich, reversible=reversible,
                            Keq=Keq, KIcs=KIcs, KIus=KIus, one_step=one_step,
                            states_allowed=states_allowed)
    # add the reaction
    net.addReaction(rxnid, stoich, kineticLaw=ratelaw)

def get_MA_ratelaw(rxnid, stoich, reversible, Keq):
    subs = get_substrates(stoich)
    prods = get_products(stoich)
    kf = 'kf_' + rxnid
    kb = 'kb_' + rxnid
    if Keq:
        Keq = 'Keq_' + rxnid
    if not reversible:
        ratelaw = '%s*%s' % (kf, '*'.join(subs))
    else:
        if Keq:
            kb = '(%s/%s)' % (kf, Keq)
        ratelaw = '%s*%s-%s*%s' % (kf, '*'.join(subs),
                                   kb, '*'.join(prods))
    return ratelaw

def add_MA_reaction(net, rxnid, ks, stoich, reversible=True, Keq=None, duplicate_error=True):
    """
    """
    # check if the species are already in the network
    for spid in stoich.keys():
        if spid not in net.species.keys():
            raise StandardException("Error when adding reaction %s:\
                                     species %s has not been added yet."
                                    % (rxnid, spid))
    # add the parameters
    for direction, paramval in ks.items():
        if isinstance(paramval, tuple):
            paramval = paramval[0]
        paramid = 'k' + direction + '_' + rxnid
        net.add_parameter(paramid, paramval, is_optimizable=True)
    if Keq:
        net.add_parameter('Keq_'+rxnid, Keq, is_optimizable=False)
    # get the rate law
    ratelaw = get_MA_ratelaw(rxnid=rxnid, stoich=stoich,
                             reversible=reversible, Keq=Keq)
    # add the reaction
    net.addReaction(rxnid, stoich, kineticLaw=ratelaw)


#!/usr/bin/python

import praw
import pdb
import re
import os

class redditReply(object):

    reddit = praw.Reddit('defbotboot')
    subreddit = reddit.subreddit("rsab")

    def reply_comment(self, limit):

        if not os.path.isfile("reply_text.txt"):
            reply_post = []

        else:

            # use with so we don't have to try, catch to debug errors
            with open("reply_text.txt", "r") as f:
                # read the file and split on newline
                reply_post = f.read()
                reply_post = reply_post.split("\n")
                # if file contains empty elements, remove them
                reply_post = list(filter(None, reply_post))

        for submission in self.subreddit.comments(limit = limit):
            if submission.id not in reply_post:

                print("submission id: ", submission.id, " // reply_post match: ", reply_post)
                if re.search("!defbot rate comments", submission.body, re.IGNORECASE):
                    # reply to the post
                    # submission.reply("Insert Sentiment Analysis here")
                    print("Bot replying to : ", submission.body)
                    reply_post.append(submission.id)

        with open("reply_post.txt", "w") as f:
            for post_id in reply_post:
                f.write(post_id + "\n")

def main():
    reddit = redditReply()
    reddit.reply_comment(limit = 25)

if __name__ == "__main__":
    main()


from __future__ import print_function

import numpy as np
import tensorflow as tf
from collections import defaultdict
from IPython import embed
import matplotlib.pyplot as plt

DATA_LOC = './assistments.txt'
MAX_LENGTH = 100
LR = 0.0005
HIDDEN_SIZE = 200
BATCH_SIZE = 32
MAX_EPOCHS = 10
DROPOUT = 0.3
TRAIN_SPLIT = 0.7
EMBEDDING_SIZE = 25

def read_assistments_data(loc):
    with open(loc) as f:
        data = [[int(y) for y in x.strip().split()] for x in f.readlines()]

    topic_seqs = defaultdict(list)
    answer_seqs = defaultdict(list)
    topics = set()

    for d in data:
        student_id = d[0]
        if(len(topic_seqs[student_id])) >= MAX_LENGTH: continue
        topic_seqs[student_id].append(d[1])
        answer_seqs[student_id].append(d[2])
        topics.add(d[1])

    #keys = topic_seqs.keys()
    #np.random.shuffle(keys)
    #return [topic_seqs[k] for k in keys], [answer_seqs[k] for k in keys], max(topics) + 1
    #topics may not be consecutively numbered but assume they are
    order = list(topic_seqs.keys())

    return [topic_seqs[x] for x in order], [answer_seqs[x] for x in order], max(topics) + 1

# Takes jagged arrays of topic and answer sequences
# Pads them into square arrays; returns that and a mask
def load_data(topic_seqs, answer_seqs, num_topics):
    assert(len(topic_seqs) == len(answer_seqs))
    N = len(topic_seqs)

    topics_padded = []
    answers_padded = []
    masks = []
    embeddings = np.zeros((N, MAX_LENGTH + 1, num_topics*2))
    seq_lens = []

    for i in range(N):
        assert(len(topic_seqs[i]) == len(answer_seqs[i]))
        seq_len = len(topic_seqs[i])
        seq_lens.append(seq_len)
        padding = [0] * (MAX_LENGTH - seq_len)
        topics_padded.append(topic_seqs[i] + padding)
        answers_padded.append(answer_seqs[i] + padding)
        masks.append([1] * seq_len + padding)
        #TODO: we can actually modify the code so that we predict the
        #probabilities of correct answers *after* the sequence ends as well.
        #This requires modifying some shapes as well as doing one more step
        #in this loop
        for j in range(seq_len):
            # Make the one-hot representation; for each sequence and time step,
            # 2*n_topics length vector, one-hot for topic/answer index
            one_hot_index = topic_seqs[i][j] * 2 + answer_seqs[i][j]
            embeddings[i][j + 1][one_hot_index] = 1

    #padded topics and answers not actually used, could remove?
    topics = topics_padded
    answers = answers_padded
    #return embeddings, seq_lens, masks, answers, topics
    return seq_lens, masks, answers, topics

class DKTModel(object):

    def add_placeholders(self):
        self.topics_placeholder = tf.placeholder(tf.int32,(None, MAX_LENGTH))
        self.answers_placeholder = tf.placeholder(tf.int32, (None, MAX_LENGTH))
        #self.seqs_placeholder = tf.placeholder(tf.float32, (None, self.max_length, 2 * self.num_topics))
        self.seq_lens_placeholder = tf.placeholder(tf.int32, (None))
        self.mask_placeholder = tf.placeholder(tf.bool, (None, self.max_length))
        self.dropout_placeholder = tf.placeholder_with_default(DROPOUT, ())
        self.lr_placeholder = tf.placeholder_with_default(LR, ())

    def data_pipeline(self):
        xav_init = tf.contrib.layers.xavier_initializer()
        d = 1.0 - self.dropout_placeholder
        h = self.hidden_size

        embeddings = tf.Variable(
            tf.random_uniform([self.num_topics * 2, EMBEDDING_SIZE], -1.0, 1.0))

        #Can use this instead of seqs_placeholder
        #obs_seqs = tf.one_hot(self.topics_placeholder * 2 + self.answers_placeholder, 2*self.num_topics)
        #batch_size = tf.shape(obs_seqs)[0]
        #self.seqs = tf.concat([tf.zeros((batch_size, 1, 2*self.num_topics)), obs_seqs], 1)
        init_state1 = tf.Variable(tf.random_uniform([BATCH_SIZE, self.hidden_size], -1.0, 1.0))
        init_state2 = tf.Variable(tf.random_uniform([BATCH_SIZE, self.hidden_size], -1.0, 1.0))
        batch_size = tf.shape(self.topics_placeholder)[0]

        # add start token,
        topics_wo_start = self.topics_placeholder + self.num_topics * self.answers_placeholder
        all_topics = tf.concat((tf.zeros((batch_size, 1), dtype=tf.int32), topics_wo_start), axis=1)

        topic_seqs = tf.nn.embedding_lookup(embeddings, all_topics)
        # answers_embedding = tf.to_float(tf.reshape(self.answers_placeholder, (-1, MAX_LENGTH, 1)))
        # seqs_with_answers = tf.concat([topic_seqs, answers_embedding], 2)
        # self.seqs = tf.concat([tf.zeros((batch_size, 1, EMBEDDING_SIZE + 1)), seqs_with_answers], 1)
        self.seqs = topic_seqs

        with tf.variable_scope('lstm1'):
            cell = tf.contrib.rnn.LSTMCell(h)
            cell = tf.contrib.rnn.DropoutWrapper(cell, output_keep_prob=d)
            outputs1, hidden_states = tf.nn.dynamic_rnn(# initial_state=init_state1,
                cell=cell, inputs=self.seqs,
                sequence_length=self.seq_lens_placeholder + 1, dtype=tf.float32,
                swap_memory=True)

        with tf.variable_scope('lstm2'):
            cell2 = tf.contrib.rnn.LSTMCell(h)
            cell2 = tf.contrib.rnn.DropoutWrapper(cell2, output_keep_prob=d)

            outputs, hidden_states = tf.nn.dynamic_rnn(# initial_state=init_state2,
                cell=cell2, inputs=outputs1,
                sequence_length=self.seq_lens_placeholder + 1, dtype=tf.float32,
                swap_memory=True)

        w = tf.get_variable("W", (self.hidden_size, self.num_topics), tf.float32, xav_init)
        b = tf.get_variable("b", (self.num_topics,), tf.float32, tf.constant_initializer(0.0))
        outputs_flat = tf.reshape(outputs, [-1, self.hidden_size])
        inner = tf.matmul(outputs_flat, w) + b

        # p(correct) predicted for each time step, for each topic class
        self.all_probs = tf.sigmoid(tf.reshape(inner, [-1, self.max_length + 1, self.num_topics]))

        #Slice up the probabilities so that the last ones (for the *next*
        #questions encountered) are in a separate op
        # self.post_probs = tf.slice(self.all_probs, [0,self.seq_lens_placeholder - 1,0], [-1, -1, -1])
        self.post_probs = self.all_probs[:, self.seq_lens_placeholder[0]] # assumes all seq_lens are equal
        self.probs = tf.slice(self.all_probs, [0,0,0], [-1, self.max_length, -1])

        self.v_hats = tf.reduce_sum(self.probs, 2)

        topic_indicators = tf.one_hot(self.topics_placeholder, self.num_topics)
        self.topical_probs = tf.reduce_sum(self.probs * topic_indicators, 2)

        return self.topical_probs

    def evaluate_probs(self):
        #Probabilities of getting each class at each time correct, for reference
        self.guesses = tf.to_int32(tf.round(self.topical_probs))
        corrects = tf.to_int32(tf.equal(self.guesses, self.answers_placeholder))
        masked_corrects = tf.boolean_mask(corrects, self.mask_placeholder)
        num_correct = tf.reduce_sum(masked_corrects)

        self.auc_score, self.auc_op = tf.metrics.auc(self.answers_placeholder, self.topical_probs)

        # How many total examples in this batch - for the denominator of # correct
        self.num_total = tf.reduce_sum(tf.to_int32(self.mask_placeholder))

        return num_correct

    def find_loss(self, probs, labels):
        losses = probs - tf.to_float(labels)
        masked_losses = tf.boolean_mask(losses, self.mask_placeholder)

        #Calculate mean-squared error
        total_loss = tf.reduce_sum(masked_losses**2)
        return total_loss

    def setup_system(self):
        self.add_placeholders()

        with tf.variable_scope("dkt"):
            self.topical_probs = self.data_pipeline()
            self.num_correct = self.evaluate_probs()

        self.loss = self.find_loss(self.topical_probs, self.answers_placeholder)
        self.train_op = tf.train.AdamOptimizer(self.lr_placeholder).minimize(self.loss)

        self.saver = tf.train.Saver()

    def train_on_batch(self, session, lens_batch, masks_batch, answers_batch, topics_batch):
        feed_dict = {#self.seqs_placeholder: seqs_batch,
                     self.seq_lens_placeholder: lens_batch,
                     self.mask_placeholder: masks_batch,
                     self.answers_placeholder: answers_batch,
                     self.topics_placeholder: topics_batch}
        _, loss = session.run([self.train_op, self.loss], feed_dict=feed_dict)
        return loss

    def test_on_batch(self, session, lens_batch, masks_batch, answers_batch, topics_batch):
        feed_dict = {#self.seqs_placeholder: seqs_batch,
                     self.seq_lens_placeholder: lens_batch,
                     self.mask_placeholder: masks_batch,
                     self.answers_placeholder: answers_batch,
                     self.topics_placeholder: topics_batch}
        num_correct, num_total, auc, v_hats = \
            session.run([self.num_correct, self.num_total, self.auc_op, self.v_hats], feed_dict=feed_dict)
        return num_correct, num_total, auc, v_hats

    # Returns array of predicted next probabilities of correctness
    # Shape 1 x batch size x 1 x num_topics
    def next_probs(self, session, lens_batch, masks_batch, answers_batch, topics_batch):
        feed_dict = {
            self.seq_lens_placeholder: lens_batch,
            self.mask_placeholder: masks_batch,
            self.answers_placeholder: answers_batch,
            self.topics_placeholder: topics_batch}
        post_probs, = session.run([self.post_probs], feed_dict=feed_dict)
        return post_probs

    def next_probs_with_topical(self, session, lens_batch, masks_batch, answers_batch, topics_batch):
        feed_dict = {
            self.seq_lens_placeholder: lens_batch,
            self.mask_placeholder: masks_batch,
            self.answers_placeholder: answers_batch,
            self.topics_placeholder: topics_batch}
        post_probs, topical_probs = session.run([self.post_probs, self.topical_probs], feed_dict=feed_dict)
        return post_probs, topical_probs

    def __init__(self, num_topics, hidden_size, max_length):
        self.num_topics = num_topics
        self.hidden_size = hidden_size
        self.max_length = max_length

        self.setup_system()

#Takes list of tuples of fields eg [(seqs0, lens0), (seqs1, lens1)...]
#returns batches of form [seqs_batch, lens_batch, ...]
def batchify(data):
    num_batches = int(np.ceil(len(data) / BATCH_SIZE))
    num_fields = len(data[0])

    batches = []
    for i in range(num_batches):
        #batch up all the different sequences of data (seqs, lens, etc)
        batch_data = data[i*BATCH_SIZE:(i+1)*BATCH_SIZE]

        batch = [[] for i in range(len(batch_data[0]))]
        for b in batch_data:
            for j in range(num_fields):
                batch[j].append(b[j])
        batches.append(batch)

    return batches

CKPT_FILE = './models.ckpt'
#Trains 2 DKT models, one on each half of the data
def train_paired_models(session, data, num_topics):

    with tf.variable_scope("model1"):
        model1 = DKTModel(num_topics, HIDDEN_SIZE, MAX_LENGTH)
    with tf.variable_scope("model2"):
        model2 = DKTModel(num_topics, HIDDEN_SIZE, MAX_LENGTH)

    session.run(tf.local_variables_initializer())

    lens, masks, answers, topics = data
    assert(len(lens) == len(masks) == len(answers) == len(topics))
    cutoff = int(len(lens) * 0.5)
    zipped_data = list(zip(*data))
    first_data = zipped_data[:cutoff]
    second_data = zipped_data[cutoff:]

    saver = tf.train.Saver()
    try:
        saver.restore(session, CKPT_FILE)
        return model1, model2, second_data
    except:
        pass

    session.run(tf.global_variables_initializer())

    def train_model_epoch(model, train_data, dev_data, epoch_num, ):
        np.random.shuffle(train_data)
        train_batches = batchify(train_data)

        print("starting training epoch", epoch_num)
        for batch_num, train_batch in enumerate(train_batches):
            loss = model.train_on_batch(session, *train_batch)
            if batch_num % 10 == 0:
                print("On batch number {}, loss is {}".format(batch_num, loss))

        print("Epoch {} complete, evaluating model...".format(epoch_num))
        eval_model(dev_data, model, session)

    for epoch in range(3):
        print("First Model")
        train_model_epoch(model1, first_data, second_data, epoch)

    for epoch in range(3):
        print("Second Model")
        train_model_epoch(model2, second_data, first_data, epoch)

    saver.save(session, CKPT_FILE)

    #return model1, first_seq_lens, first_answers, first_topics, first_masks, first_v_hats, \
    #    model2, second_seq_lens, second_answers, second_topics, second_masks, second_v_hats,
    return model1, model2, second_data

def test_paired_models(session, data, model1, model2):
    zipped_data = list(zip(*data))
    cutoff = int(len(data[0]) * 0.5)
    first_data = zipped_data[:cutoff]
    second_data = zipped_data[cutoff:]

    print("Evaluating first model")
    eval_model(second_data, model1, session)
    print("Evaluating second model")
    eval_model(first_data, model2, session)

def train_model(model, session, data):
    lens, masks, answers, topics = data
    assert(len(lens) == len(masks) == len(answers) == len(topics))
    cutoff = int(len(lens) * TRAIN_SPLIT)
    zipped_data = list(zip(*data))
    train_data = zipped_data[:cutoff]
    test_data = zipped_data[cutoff:]

    for epoch in range(MAX_EPOCHS):
        np.random.shuffle(train_data)
        train_batches = batchify(train_data)

        print("Starting training epoch", epoch)
        for batch_num, train_batch in enumerate(train_batches):
            loss = model.train_on_batch(session, *train_batch)
            print("On batch number {}, loss is {}".format(batch_num, loss))

        print("Epoch {} complete, evaluating model...".format(epoch))
        eval_model(test_data, model, session)

def eval_model(test_data, model, session):
    np.random.shuffle(test_data)
    test_batches = batchify(test_data)
    total_correct = 0 #total number of examples we got right
    total_total = 0 #total number of examples we tried on
    total_auc = 0.0
    for test_batch in test_batches:
        num_correct, num_total, auc, v_hats = model.test_on_batch(session, *test_batch)
        total_auc += num_total * auc
        total_correct += num_correct
        total_total += num_total
    print("{} test examples right out of {}, which is {} percent. Mean AUC {}\n".format(
        total_correct, total_total, 100.0*total_correct/total_total, 1.0*total_auc/total_total))

def get_paired_models(session, return_second_data = False):
    topics, answers, num_topics = read_assistments_data(DATA_LOC)
    full_data = load_data(topics, answers, num_topics)

    model1, model2, second_data = train_paired_models(session, full_data, num_topics)
    #test_paired_models(session, full_data, model1, model2)

    if return_second_data: return model1, model2, second_data
    return model1, model2

def main(_):
    print('tf version', tf.__version__)

    topics, answers, num_topics = read_assistments_data(DATA_LOC)
    full_data = load_data(topics, answers, num_topics)

    model = DKTModel(num_topics, HIDDEN_SIZE, MAX_LENGTH)

    with tf.Session() as session:
        session.run(tf.global_variables_initializer())
        #We need to explicitly initialize local variables to use
        #TensorFlow's AUC function for some reason...
        session.run(tf.local_variables_initializer())
        train_model(model, session, full_data)
        #model1, model2 = train_paired_models(session, full_data, num_topics)
        #test_paired_models(session, full_data, model1, model2)
        #embed()

if __name__ == "__main__":
    tf.app.run()


from pyfcm import FCMNotification

APIKEY = "AAAAsLhtlp8:APA91bF7A7f_Rr0tBhpZmgBAzZ5wAIGifzAyMtLJgerJyR-uX6t6bdpjyZ6dNE1IDOk22wm3vItH9xx4mZwzzI_4lcbGBJ-ZBi8kHh9Cxwf_2Kb14SUAnDPkCFPZhHGEP-pdYEeucLfS"

# 파이어베이스 콘솔에서 얻어 온 서버 키를 넣어 줌
push_service = FCMNotification(APIKEY)

def sendMessage(body, title):
    # 메시지 (data 타입)
    data_message = {
        "body": body,
        "title": title
    }

    # topic을 이용해 다수의 구독자에게 푸시알림을 전송함
    result = push_service.notify_topic_subscribers(topic_name="generalTopic", data_message=data_message)

    # 전송 결과 출력
    print(result)

sendMessage("TEST Message", "데이터 업데이트 알림")