#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import logging
import module.api.config as config
import module.common.const as const
import module.common.util as util
from xml.etree.ElementTree import Element,SubElement
from bottle import route, request, HTTPResponse
from module.common.topologydb import *
from module.common.md import post_md,search_target_table,DBHandle
from module.common.se_md import DBUploader

# constants
BASE_URI = '/' + config.rest_base + '/' + const.REST_MONITORING
POST_URI = config.post_uri + "/" + const.TYPE_MON_SE

# logger.
logger = logging.getLogger(const.MODULE_NAME_API)

# set data uploader script file path.
db_upld = DBUploader(log_name=const.MODULE_NAME_API,
                        db_name=config.mon_data_se_db,
                        db_host=config.db_addr,db_port=config.db_port,
                        db_user=config.db_user,db_pass=config.db_pass)

@route(BASE_URI + '/' + const.TYPE_MON_SE, method='POST')
@route(BASE_URI + '/' + const.TYPE_MON_SE + '/', method='POST')
def monitoring_se_post():
    logger.info('POST monitoring-data({0}). -start-'.format(const.TYPE_MON_SE))
    try:
        # get request body.(xml message.)
        param_list=request.body
        param_string=""
        for row in param_list:
            param_string += row
        if not param_string:
            logger.warn('no message.')
            return HTTPResponse("POST monitoring-data({0}) error.(request body is empty.)"
                                .format(const.TYPE_MON_SE), status=400)
        logger.debug(param_string)

        # lock -start-
        with util.semaphore_md:
            # open topology database connection.
            tpldb_setup()

            # upload all monitoring-data to DB.
            mon_data_dict = db_upld.cleate_monitoring_data_dict(param_string)
            if not mon_data_dict:
                logger.warn('parse monitoring-data xml error.')
                return HTTPResponse("POST monitoring-data({0}) error.(parse monitoring-data xml error.)"
                                    .format(const.TYPE_MON_SE), status=400)
            val_dict_list = db_upld.cleate_upload_data_list(mon_data_dict)
        # lock -end-
        db_upld.upload_monitoring_data_all(val_dict_list)

        # forwarding master-monitoring-server
        if mon_data_dict[const.XML_ATTR_FWD] == True:
            logger.debug('forward monitoring-data.(post_uri={0})'.format(POST_URI))
            res_flg,res = post_md(POST_URI,param_string,'no')
            if res_flg is False:
                logger.error('forward monitoring-data error.')
            if res:
                logger.debug("HTTP Response({0}):{1}".format(res.status_code,res.text))

    except Exception:
        logger.exception('POST monitoring-data({0}) error.'.format(const.TYPE_MON_SE))
        return HTTPResponse("POST monitoring-data({0}) error."
                            .format(const.TYPE_MON_SE), status=500)

    finally:
        # close topology database connection.
        tpldb_close()
    logger.info('POST monitoring-data({0}). -end-'.format(const.TYPE_MON_SE))

    return

@route(BASE_URI + '/' + const.TYPE_MON_SE + '/<topology_type>/', method='GET')
def monitoring_se_get(topology_type=""):
    logger.info('GET monitoring-data({0}). -start-'.format(const.TYPE_MON_SE))

    # database handle.
    db_handle = DBHandle()
    try:
        # create <monitoring-data>
        xml_mon_data = Element(const.XML_TAG_MON_DATA)

        # topology_type==[physical | slice]
        logger.debug('topology type=' + topology_type)

        # param_type_list==[status | in_bps | etc...]
        param_type_list = request.query.getall(const.HTTP_GET_OPT_TYPE)
        if param_type_list:
            logger.debug('HTTP GET option ('+ const.HTTP_GET_OPT_TYPE +')=' + str(param_type_list))

        # get HTTP GET option.
        param_topol = request.query.get(const.HTTP_GET_OPT_TOPOL)
        if param_topol:
            logger.debug('HTTP GET option ('+ const.HTTP_GET_OPT_TOPOL +')=' + param_topol)

        param_node = request.query.get(const.HTTP_GET_OPT_NODE)
        if param_node:
            logger.debug('HTTP GET option ('+ const.HTTP_GET_OPT_NODE +')=' + param_node)

        param_port = request.query.get(const.HTTP_GET_OPT_PORT)
        if param_port:
            logger.debug('HTTP GET option ('+ const.HTTP_GET_OPT_PORT +')=' + param_port)

        param_stime = request.query.get(const.HTTP_GET_OPT_STIME)
        if param_stime:
            logger.debug('HTTP GET option ('+ const.HTTP_GET_OPT_STIME +')=' + param_stime)

        param_etime = request.query.get(const.HTTP_GET_OPT_ETIME)
        if param_etime:
            logger.debug('HTTP GET option ('+ const.HTTP_GET_OPT_ETIME +')=' + param_etime)

        param_limit = request.query.get(const.HTTP_GET_OPT_LMT)
        if param_limit:
            logger.debug('HTTP GET option ('+ const.HTTP_GET_OPT_LMT +')=' + param_limit)
        else:
            # set the default value if not specified.
            param_limit = str(const.DEFAULT_LIMIT)
            logger.debug('HTTP GET option ('+ const.HTTP_GET_OPT_LMT +')=default value(' + param_limit +')')

        # required check.(topology_type)
        if not topology_type == const.TYPE_NW_PHYSICAL and \
            not topology_type == const.TYPE_NW_SLICE:

            logger.warn('topology type is invalid. ('+ topology_type +')')
            return HTTPResponse("GET monitoring-data({0}) error.(topology type({1}) is invalid.)"
                                .format(const.TYPE_MON_SE,topology_type), status=400)

        # required check.(HTTP GET option)
        if not param_type_list:
            logger.warn('Required HTTP GET option({0}) have not been set.'.format(const.HTTP_GET_OPT_TYPE))
            return HTTPResponse("GET monitoring-data({0}) error.(Required HTTP GET option({1}) not specified.)"
                                .format(const.TYPE_MON_SE,const.HTTP_GET_OPT_TYPE), status=400)

        if not param_stime:
            logger.warn('Required HTTP GET option({0}) have not been set.'.format(const.HTTP_GET_OPT_STIME))
            return HTTPResponse("GET monitoring-data({0}) error.(Required HTTP GET option({1}) not specified.)"
                                .format(const.TYPE_MON_SE,const.HTTP_GET_OPT_STIME), status=400)

        if not param_etime:
            logger.warn('Required HTTP GET option({0}) have not been set.'.format(const.HTTP_GET_OPT_ETIME))
            return HTTPResponse("GET monitoring-data({0}) error.(Required HTTP GET option({1}) not specified.)"
                                .format(const.TYPE_MON_SE,const.HTTP_GET_OPT_ETIME), status=400)

        # lock -start-
        with util.semaphore_md:
            # open topology database connection.
            tpldb_setup()

            # required check.(HTTP GET option:topology)
            nw_list = []
            if not param_topol:
                # If the topology type is 'slice', topology(sliceID) is required
                if topology_type == const.TYPE_NW_SLICE:
                    logger.warn('Required HTTP GET option({0}) have not been set.'.format(const.HTTP_GET_OPT_TOPOL))
                    return HTTPResponse("GET monitoring-data({0}) error.(Required HTTP GET option({1}) not specified.)"
                                        .format(const.TYPE_MON_SE,const.HTTP_GET_OPT_TOPOL), status=400)

                # If the topology type is 'physical',target all network.
                elif topology_type == const.TYPE_NW_PHYSICAL:
                    nw_list = get_all_network(const.TYPE_NW_PHYSICAL)

                # Without network specified, if the node is specified, the value of the node are ignored.
                param_node = None
            else:
                tmp_nw = Network.query.filter(Network.network_name == param_topol).first()
                if tmp_nw:
                    nw_list.append(tmp_nw)

            # parameter check.(HTTP GET option:node)
            if not param_node:
                # Without node specified, if the port is specified, the value of the port are ignored.
                param_port = None

            # search target table name.
            tbl_name_list = search_target_table(logger,int(param_stime),int(param_etime),config.mon_data_se_db)

            # add <topology_list>
            xml_topol_list = SubElement(xml_mon_data, const.XML_TAG_TOPOL_LIST)

            # connect to the database.
            db_con = db_handle.connect(config.mon_data_se_db,config.db_addr
                                       ,config.db_port,config.db_user,config.db_pass)

            for nw in nw_list:
                # add <topology type=topology_type name='xxx'>
                xml_topol = SubElement(xml_topol_list, const.XML_TAG_TOPOL,
                                        {const.XML_ATTR_TYPE:nw.type,const.XML_ATTR_NAME:nw.network_name})

                node_list = []
                if not param_node:
                    # not specified. cover all of the node.
                    node_list = get_all_se(nw)
                else:
                    tmp_node = Node.query.filter(Node.node_name == param_node)\
                                 .filter(Node.network_name == nw.network_name)\
                                 .filter(Node.type == const.TYPE_NODE_SE).first()
                    if tmp_node:
                        node_list.append(tmp_node)

                for node in node_list:
                    # add <node id='xxx' type='switch'>
                    xml_node = SubElement(xml_topol, const.XML_TAG_NODE,
                                            {const.XML_ATTR_ID:node.node_name,
                                             const.XML_ATTR_TYPE:node.type
                                                })

                    if_list = []
                    if not param_port:
                        # not specified. cover all of the port.
                        if_list = get_all_if(node)
                    else:
                        tmp_if = InterFace.query.filter(InterFace.idNode == node.id)\
                                 .filter(InterFace.port == param_port).first()
                        if tmp_if:
                            if_list.append(tmp_if)

                    for interface in if_list:
                        # add <port num=param_port>
                        xml_port = SubElement(xml_node, const.XML_TAG_PORT, {const.XML_ATTR_NUM:interface.port})

                        for param_type in param_type_list:
                            # add <parameter type=param_type>
                            xml_param = SubElement(xml_port, const.XML_TAG_PARAM, {const.XML_ATTR_TYPE:param_type})

                            # no data in the search time-range.
                            if not tbl_name_list:
                                continue

                            # search database.(metaID)
                            sql = "(SELECT metaID FROM metaData " \
                                   + "WHERE network_name='{0}' AND node_name='{1}' AND port='{2}' AND type='{3}')"\
                                        .format(nw.network_name,node.node_name,interface.port,param_type)
                            logger.debug(sql)
                            db_con.execute(sql)

                            res_metaid = db_con.fetchone()
                            if res_metaid:
                                metaid = res_metaid['metaID']
                            else:
                                continue

                            # search database.(data)
                            sql_base = "(SELECT timestamp,value FROM {0} WHERE metaID={1}"\
                                        + " AND timestamp >= {0}".format(param_stime)\
                                        + " AND timestamp <= {0})".format(param_etime)
                            sql_list = []
                            for tbl_name in tbl_name_list:
                                sql_list.append(sql_base.format(tbl_name,metaid))
                            sql = " UNION ".join(sql_list)
                            sql += " ORDER BY timestamp DESC LIMIT " + param_limit
                            logger.debug(sql)
                            db_con.execute(sql)
                            res_mon_data = db_con.fetchall()

                            for mon_data in res_mon_data:
                                # add <value timestamp=mon_data["timestamp"]>
                                xml_value = SubElement(xml_param, const.XML_TAG_VAL, {const.XML_ATTR_TIME_STAMP:str(mon_data["timestamp"])})
                                # add <value>mon_data["value"]</value>
                                xml_value.text = str(mon_data["value"])
        # lock -end-

    except Exception:
        logger.exception('GET monitoring-data({0}) error.'.format(const.TYPE_MON_SE))
        return HTTPResponse("GET monitoring-data({0}) error."
                            .format(const.TYPE_MON_SE), status=500)

    finally:
        # close monitoring database connection.
        db_handle.close()

        # close topology database connection.
        tpldb_close()
    logger.info('GET monitoring-data({0}). -end-'.format(const.TYPE_MON_SE))

    return util.prettify(xml_mon_data)


import typing

import antlr4
from antlr4.ParserRuleContext import ParserRuleContext
from antlr4.Token import CommonToken
from antlr4.tree.Tree import TerminalNodeImpl

from .aptLexer import aptLexer
from .aptParser import aptParser

from ...RecordParser import RecordParser
from ...Record import Record

class ANTLRParser(RecordParser):
	__slots__ = ()

	def parseURI(self, rec: Record, uri: aptParser.UriRContext) -> str:
		uri = uri.children[0]
		schema = list(self.descendIntoURISchema(uri.schema))
		rec.schemaModifiers = schema[:-1]
		schema = schema[-1]
		uri = self.mergeShit(schema) + ":" + self.mergeShit(uri.restOfURI)
		return uri

	def iterateList(self, lst: ParserRuleContext) -> typing.Any:
		if lst:
			if lst.children:
				return lst.children

		return ()

	def isList(self, lst: typing.Any) -> bool:
		return isinstance(lst, antlr4.RuleContext)

	def parse(self, s: str) -> aptParser.RecordContext:
		input_stream = antlr4.InputStream(s)
		lexer = aptLexer(input_stream)
		stream = antlr4.CommonTokenStream(lexer)
		parser = aptParser(stream)
		return parser.record()

	def getTextFromToken(self, token: typing.Optional[typing.Union[str, aptParser.CommenterRContext, TerminalNodeImpl, CommonToken]]) -> typing.Optional[str]:
		if token is not None:
			if isinstance(token, str):
				return token
			elif isinstance(token, antlr4.Token):
				return token.text
			else:
				return token.getText()


from flask import Flask, render_template , request , session , url_for
from src.calculator.rank import rank_calculate

app = Flask(__name__)

@app.route('/',methods = ['GET','POST'])
def hello():
    return render_template('calculate.html')

@app.route('/calculate', methods=['GET','POST'])
def calculate():
    letters=str(request.form['word'])

    rank=rank_calculate(letters)

    return render_template("calculate.html",wordie=letters , result=rank)

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


"""
    jupylet/audio/__init__.py

    Copyright (c) 2020, Nir Aides - nir@winpdb.org

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this
       list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice,
       this list of conditions and the following disclaimer in the documentation
       and/or other materials provided with the distribution.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
    ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""

import asyncio
import pathlib
import time
import os

from ..utils import callerframe, callerpath

def sonic_py(resource_dir='.'):

    from ..app import App

    red = os.path.join(callerpath(), resource_dir)
    red = pathlib.Path(red).absolute()

    app = App(32, 32, resource_dir=str(red))
    app.run(0)

    return app

FPS = 44100

def t2frames(t):
    """Convert time in seconds to frames at 44100 frames per second.

    Args:
        t (float): The time duration in seconds.

    Returns:
        int: The number of frames.
    """
    return int(FPS * t)

def frames2t(frames):
    """Convert frames at 44100 frames per second to time in seconds.

    Args:
        frames (int): The number of frames.

    Returns:
        float: The time duration in seconds.
    """
    return frames  / FPS

def get_time():
    return time.time()

_note_value = 4

def set_note_value(v=4):
    global _note_value
    _note_value = v

def get_note_value():
    return _note_value

_bpm = 240

def set_bpm(bpm=4):
    global _bpm
    _bpm = bpm

def get_bpm():
    return _bpm

dtd = {}
syd = {}

def use(synth, **kwargs):

    if kwargs:
        synth = synth.copy().set(**kwargs)

    cf = callerframe()
    cn = cf.f_code.co_name
    hh = cn if cn == '<module>' else hash(cf)

    syd[hh] = synth

PLAY_EXTRA_LATENCY = 0.150

def play(note, *args, **kwargs):

    cf = callerframe()
    cn = cf.f_code.co_name
    hh = cn if cn == '<module>' else hash(cf)

    sy = syd[hh]

    tt = dtd.get(hh) or get_time()
    tt += PLAY_EXTRA_LATENCY

    return sy.play_new(note, t=tt, *args, **kwargs)

def sleep(dt=0):

    tt = get_time()

    cf = callerframe()
    cn = cf.f_code.co_name
    hh = cn if cn == '<module>' else hash(cf)

    sy = syd.get(hh)
    if sy is not None:
        dt = dt * get_note_value() * 60 / get_bpm()

    t0 = dtd.get(hh)
    if not t0 or t0 + 1 < tt:
        t0 = tt

    t1 = dtd[hh] = max(t0 + dt, tt)

    return asyncio.sleep(t1 - tt)

def stop():

    from .device import stop_sound
    stop_sound()


import tensorflow as tf
from abc import ABCMeta, abstractmethod
from os import path
import json
import numpy as np

import network
import data
import meta

def _decode_step(X, A, NX, NA, last_action, finished,
                 get_init, get_action,
                 random=False, n_node_types=len(meta.ATOM_TYPES), n_edge_types=len(meta.BOND_TYPES)):
    if X is None:
        init = get_init()

        if random:
            X = []
            for i in range(init.shape[0]):
                p = init[i, :]
                selected_atom = np.random.choice(np.arange(init.shape[1]), 1, p=p)[0]
                X.append(selected_atom)
            X = np.array(X, dtype=np.int32)
        else:
            X = np.argmax(init, axis=1)
        A = np.zeros((0, 3), dtype=np.int32)
        NX = last_action = np.ones([X.shape[0]], dtype=np.int32)
        NA = np.zeros([X.shape[0]], dtype=np.int32)
        finished = np.array([False, ] * X.shape[0], dtype=np.bool)

        return X, A, NX, NA, last_action, finished
    else:
        X_u = X[np.repeat(np.logical_not(finished), NX)]
        A_u = A[np.repeat(np.logical_not(finished), NA), :]
        NX_u = NX[np.logical_not(finished)]
        NA_u = NA[np.logical_not(finished)]
        last_action_u = last_action[np.logical_not(finished)]

        # conv
        mol_ids_rep = NX_rep = np.repeat(np.arange(NX_u.shape[0]), NX_u)
        rep_ids_rep = np.zeros_like(mol_ids_rep)

        if A.shape[0] == 0:
            D_2 = D_3 = np.zeros((0, 2), dtype=np.int32)
            A_u = [np.zeros((0, 2), dtype=np.int32) for _ in range(meta)]
            A_u += [D_2, D_3]
        else:
            cumsum = np.cumsum(np.pad(NX_u, [[1, 0]], mode='constant')[:-1])
            shift = np.repeat(cumsum, NA_u)
            A_u[:, :2] += np.stack([shift, ] * 2, axis=1)
            D_2, D_3 = data.get_d(A_u, X_u)
            A_u = [A_u[A_u[:, 2] == _i, :2] for _i in range(n_edge_types)]
            A_u += [D_2, D_3]

        mask = np.zeros([X_u.shape[0]], dtype=np.int32)
        last_append_index = np.cumsum(NX_u) - 1
        mask[last_append_index] = np.where(last_action_u == 1,
                                           np.ones_like(last_append_index, dtype=np.int32),
                                           np.ones_like(last_append_index, dtype=np.int32) * 2)

        decode_input = [X_u, A_u, NX_u, NX_rep, mask, mol_ids_rep, rep_ids_rep]
        append, connect, end = get_action(decode_input)

        if A.shape[0] == 0:
            max_index = np.argmax(np.reshape(append, [-1, n_node_types * n_edge_types]), axis=1)
            atom_type, bond_type = np.unravel_index(max_index, [n_node_types, n_edge_types])
            X = np.reshape(np.stack([X, atom_type], axis=1), [-1])
            NX = np.array([2, ] * len(finished), dtype=np.int32)
            A = np.stack([np.zeros(finished, dtype=np.int32),
                          np.ones(finished, dtype=np.int32),
                          bond_type], axis=1)
            NA = np.ones([finished], dtype=np.int32)
            last_action = np.ones_like(NX, dtype=np.int32)

        else:
            # process for each molecule
            append, connect = np.split(append, np.cumsum(NX_u)), np.split(connect, np.cumsum(NX_u))
            end = end.tolist()

            unfinished_ids = np.where(np.logical_not(finished))[0].tolist()
            cumsum = np.cumsum(NX)
            cumsum_a = np.cumsum(NA)

            X_insert = []
            X_insert_ids = []
            A_insert = []
            A_insert_ids = []
            finished_ids = []

            for i, (unfinished_id, append_i, connect_i, end_i) \
                    in enumerate(zip(unfinished_ids, append, connect, end)):
                if random:
                    def _rand_id(*_x):
                        _x_reshaped = [np.reshape(_xi, [-1]) for _xi in _x]
                        _x_length = np.array([_x_reshape_i.shape[0] for _x_reshape_i in _x_reshaped],
                                             dtype=np.int32)
                        _begin = np.cumsum(np.pad(_x_length, [[1, 0]], mode='constant')[:-1])
                        _end = np.cumsum(_x_length) - 1
                        _p = np.concatenate(_x_reshaped)
                        _p = _p / np.sum(_p)
                        _rand_index = np.random.choice(np.arange(_p.shape[0]), 1, p=_p)[0]
                        _p_step = _p[_rand_index]
                        _x_index = np.where(np.logical_and(_begin <= _rand_index, _end >= _rand_index))[0][0]
                        _rand_index = _rand_index - _begin[_x_index]
                        _rand_index = np.unravel_index(_rand_index, _x[_x_index].shape)
                        return _x_index, _rand_index, _p_step

                    action_type, action_index, p_step = _rand_id(append_i, connect_i, np.array([end_i]))
                else:
                    _argmax = lambda _x: np.unravel_index(np.argmax(_x), _x.shape)
                    append_id, append_val = _argmax(append_i), np.max(append_i)
                    connect_id, connect_val = _argmax(connect_i), np.max(connect_i)
                    end_val = end_i
                    if end_val >= append_val and end_val >= connect_val:
                        action_type = 2
                        action_index = None
                    elif append_val >= connect_val and append_val >= end_val:
                        action_type = 0
                        action_index = append_id
                    else:
                        action_type = 1
                        action_index = connect_id
                if action_type == 2:
                    # finish growth
                    finished_ids.append(unfinished_id)
                elif action_type == 0:
                    # append action
                    append_pos, atom_type, bond_type = action_index
                    X_insert.append(atom_type)
                    X_insert_ids.append(unfinished_id)
                    A_insert.append([append_pos, NX[unfinished_id], bond_type])
                    A_insert_ids.append(unfinished_id)
                else:
                    # connect
                    connect_ps, bond_type = action_index
                    A_insert.append([NX[unfinished_id] - 1, connect_ps, bond_type])
                    A_insert_ids.append(unfinished_id)
            if len(A_insert_ids) > 0:
                A = np.insert(A, cumsum_a[A_insert_ids], A_insert, axis=0)
                NA[A_insert_ids] += 1
                last_action[A_insert_ids] = 0
            if len(X_insert_ids) > 0:
                X = np.insert(X, cumsum[X_insert_ids], X_insert, axis=0)
                NX[X_insert_ids] += 1
                last_action[X_insert_ids] = 1
            if len(finished_ids) > 0:
                finished[finished_ids] = True
            # print finished

        return X, A, NX, NA, last_action, finished

class Visualizer(object):

    __metaclass__ = ABCMeta

    def __init__(self, model_dir):
        self.g = tf.Graph()
        with open(path.join(model_dir, 'model.json')) as f:
            self.params = json.load(f)
        with self.g.as_default():
            self._build()
            self.sess = tf.Session()
            self.saver = tf.train.Saver()
            self.saver.restore(self.sess, path.join(model_dir, 'ckpt'))
            self.g.finalize()

    @abstractmethod
    def _build(self):
        raise NotImplementedError

class GraphLM_Visualizer(Visualizer):

    def _build(self):
        self.mdl = network.GraphLM(self.params)
        self._build_in_out()

    def _build_in_out(self):
        _, self.decode_0_output = self.mdl('decode_0')
        self.decode_step_input, self.decode_step_output = self.mdl('decode_step')
        self.loss_input, self.loss_output = self.mdl('val')

    def sample(self, num_samples):
        with self.g.as_default():
            # step one
            finished = [False,]*num_samples
            def get_init():
                init = self.sess.run(self.decode_0_output)[0]
                init = np.tile(init, [num_samples, 1])
                return init
            outputs = _decode_step(X=None, A=None, NX=None, NA=None, last_action=None, finished=finished,
                                   get_init=get_init, get_action=None,
                                   n_node_types=self.mdl.n_node_types, n_edge_types=self.mdl.n_edge_types,
                                   random=False)
            X, A, NX, NA, last_action, finished = outputs

            count = 1
            while not np.all(finished) and count < 100:
                def get_action(inputs):
                    return self.sess.run(self.decode_step_output,
                                         network.get_feed_dict(self.decode_step_input,
                                                               inputs[:-2]))

                outputs = _decode_step(X, A, NX, NA, last_action, finished,
                                       get_init=None, get_action=get_action,
                                       n_node_types=self.mdl.n_node_types, n_edge_types=self.mdl.n_edge_types,
                                       random=False)
                X, A, NX, NA, last_action, finished = outputs

                count += 1

            graph_list = []

            cumsum_X_ = np.cumsum(np.pad(NX, [[1, 0]], mode='constant')).tolist()
            cumsum_A_ = np.cumsum(np.pad(NA, [[1, 0]], mode='constant')).tolist()

            for cumsum_A_pre, cumsum_A_post, \
                cumsum_X_pre, cumsum_X_post in zip(cumsum_A_[:-1], cumsum_A_[1:],
                           cumsum_X_[:-1], cumsum_X_[1:]):
                graph_list.append([X[cumsum_X_pre:cumsum_X_post], A[cumsum_A_pre:cumsum_A_post, :]])

            return graph_list

class CGraphLM_Visualizer(Visualizer):

    def _build(self):
        self.mdl = network.CGraphLM(self.params)
        self._build_in_out()

    def _build_in_out(self):
        self.decode_0_input, self.decode_0_output = self.mdl('decode_0')
        self.decode_step_input, self.decode_step_output = self.mdl('decode_step')
        self.loss_input, self.loss_output = self.mdl('val')

    def sample(self, num_samples, c):
        if len(c.shape) < 2:
            c = c[np.newaxis, :]
            c = np.tile(c, [num_samples, 1])

        with self.g.as_default():
            # step one
            finished = [False,]*num_samples
            def get_init():
                init = self.sess.run(self.decode_0_output,
                                     {self.decode_0_input[0]:c})[0]
                return init
            outputs = _decode_step(X=None, A=None, NX=None, NA=None, last_action=None, finished=finished,
                                   get_init=get_init, get_action=None,
                                   n_node_types=self.mdl.n_node_types, n_edge_types=self.mdl.n_edge_types,
                                   random=False)
            X, A, NX, NA, last_action, finished = outputs

            count = 1
            while not np.all(finished) and count < 100:
                def get_action(inputs):
                    c_u = c[np.logical_not(finished), :]
                    return self.sess.run(self.decode_step_output,
                                         network.get_feed_dict(self.decode_step_input,
                                                               inputs + [c_u, ]))

                outputs = _decode_step(X, A, NX, NA, last_action, finished,
                                       get_init=None, get_action=get_action,
                                       n_node_types=self.mdl.n_node_types, n_edge_types=self.mdl.n_edge_types,
                                       random=False)
                X, A, NX, NA, last_action, finished = outputs

                count += 1

            graph_list = []

            cumsum_X_ = np.cumsum(np.pad(NX, [[1, 0]], mode='constant')).tolist()
            cumsum_A_ = np.cumsum(np.pad(NA, [[1, 0]], mode='constant')).tolist()

            for cumsum_A_pre, cumsum_A_post, \
                cumsum_X_pre, cumsum_X_post in zip(cumsum_A_[:-1], cumsum_A_[1:],
                           cumsum_X_[:-1], cumsum_X_[1:]):
                graph_list.append([X[cumsum_X_pre:cumsum_X_post], A[cumsum_A_pre:cumsum_A_post, :]])

            return graph_list


import numpy as np		# importowanie przydatnych modulow
import matplotlib.pyplot as plt

fig = plt.figure()	# stworzenie domyslnego obiektu figure

file = "out.txt"	# wczytanie pliku z danymi
data = np.loadtxt(file)	# do tablicy data
tw=np.arange(0,200,0.01)
t = data[:, 0]
x = data[:, 1]

plt.plot(t, x, 'bx', lw=2, label='x(t), h=0.1') # rysowanie wykresu
plt.plot(tw, np.cos(tw/10), 'k-', lw=2, label='cos(t)') # wykres funkcji analitycznej

l1 = plt.legend()	# legenda
plt.grid()	# siatka pomocnicza

plt.xlabel('t')	# tytuly osi i wykresu
plt.ylabel('x(t)')
plt.title('wychylenie x(t)')

plt.savefig("zad1.png")	# zapis wykresu do pliku


import numpy    as np
from   numpy    import linalg as la
from   numpy    import matrix as mt
from matplotlib import pyplot as plt
from matplotlib.pyplot import title
import utility  as ut

# ### Surface Denoise
def singularValueCutOff(Sig, img_shape, cutoff, diff):
    """cut of singular values according to a given cutoff and regenerates the new singualr value matrix

    Args:
        Sig ([type]): Singular value matrix
        img ([type]): image shape
        cutoff ([type]): cutoff value for skipping noise generator values in sigma
        diff ([type]): dimension difference

    Returns:
        [type]: new(revised) Singular value matrix
    """
    R = np.zeros(img_shape[1])
    for i in range(len(Sig)):
        R[i] = Sig[i] if(Sig[i] > cutoff) else 0
    R = np.reshape(np.append(np.diag(R), np.zeros((diff, img_shape[1]))),(img_shape[0], img_shape[1]))
    return R

# driver code
if __name__ == "__main__":

    print("..close main area to continue..")
    ut.show_main()
    print("..close noisy area to continue..")
    ut.show_noisy()

    ########################
    # ### SVD Decompostion #
    ########################
    records = ut.get_function()
    records.shape
    fdc = {
        'U':0,
        'S':0,
        'V':0,
        'R':0
    }
    fdc['U'], fdc['S'], fdc['V'] = la.svd(records)

    ######################################################
    # #### choosing a cuttoff value according to scatter #
    ######################################################
    plt.scatter(range(30), fdc['S'], color='red', s=1)
    plt.scatter(range(30), fdc['S'], color='blue', s=1)
    plt.title("singular value scatter")
    print("..close scatter to continue..")
    plt.show()

    ########################################################################
    # ### Denoising Coordination and Reconstructing Function Coordinations #
    ########################################################################
    fcutoff = 0.5
    ##
    diff = records.shape[0] - records.shape[1]
    diff = 0 if(diff < 0) else diff
    ## cutting off
    fdc['R'] = singularValueCutOff(fdc['S'], records.shape, 0.5, diff)

    ######################
    # ### reconstruction #
    ######################
    new_func = np.matrix(fdc['U'])*np.matrix(fdc['R'])*np.matrix(fdc['V'])

    #########################
    # ### comparing results #
    #########################
    print('Noisy function:\n')
    ut.show_noisy()
    print('Denoised function: with cut off value ' + str(fcutoff) + '\n')
    ut.show_my_matrix(new_func)


# -*- coding: utf-8 ; test-case-name: bridgedb.test.test_email_server -*-
#_____________________________________________________________________________
#
# This file is part of BridgeDB, a Tor bridge distribution system.
#
# :authors: Nick Mathewson <nickm@torproject.org>
#           Isis Lovecruft <isis@torproject.org> 0xA3ADB67A2CDB8B35
#           Matthew Finkel <sysrqb@torproject.org>
#           please also see AUTHORS file
# :copyright: (c) 2007-2014, The Tor Project, Inc.
#             (c) 2013-2014, Isis Lovecruft
# :license: see LICENSE for licensing information
#_____________________________________________________________________________

"""Servers which interface with clients and distribute bridges over SMTP."""

from __future__ import unicode_literals

import logging
import io
import time

from twisted.internet import defer
from twisted.internet import reactor
from twisted.internet.task import LoopingCall
from twisted.mail import smtp

from zope.interface import implements

from bridgedb import safelog
from bridgedb import translations
from bridgedb.crypto import getGPGContext
from bridgedb.crypto import gpgSignMessage
from bridgedb.crypto import NEW_BUFFER_INTERFACE
from bridgedb.Dist import EmailRequestedHelp
from bridgedb.Dist import EmailRequestedKey
from bridgedb.Dist import TooSoonEmail
from bridgedb.Dist import IgnoreEmail
from bridgedb.email import templates
from bridgedb.email import request
from bridgedb.parse import addr
from bridgedb.parse.addr import BadEmail
from bridgedb.parse.addr import UnsupportedDomain
from bridgedb.parse.addr import canonicalizeEmailDomain

def checkDKIM(message, rules):
    """Check the DKIM verification results header.

    This check is only run if the incoming email, **message**, originated from
    a domain for which we're configured (in the ``EMAIL_DOMAIN_RULES``
    dictionary in the config file) to check DKIM verification results for.

    :type message: :api:`twisted.mail.smtp.rfc822.Message`
    :param message: The incoming client request email, including headers.
    :param dict rules: The list of configured ``EMAIL_DOMAIN_RULES`` for the
        canonical domain which the client's email request originated from.

    :rtype: bool
    :returns: ``False`` if:
        1. We're supposed to expect and check the DKIM headers for the
           client's email provider domain.
        2. Those headers were *not* okay.
        Otherwise, returns ``True``.
    """
    if 'dkim' in rules:
        # getheader() returns the last of a given kind of header; we want
        # to get the first, so we use getheaders() instead.
        dkimHeaders = message.getheaders("X-DKIM-Authentication-Results")
        dkimHeader = "<no header>"
        if dkimHeaders:
            dkimHeader = dkimHeaders[0]
        if not dkimHeader.startswith("pass"):
            logging.info("Rejecting bad DKIM header on incoming email: %r "
                         % dkimHeader)
            return False
    return True

def createResponseBody(lines, context, clientAddress, lang='en'):
    """Parse the **lines** from an incoming email request and determine how to
    respond.

    :param list lines: The list of lines from the original request sent by the
        client.
    :type context: class:`MailContext`
    :param context: The context which contains settings for the email server.
    :type clientAddress: :api:`twisted.mail.smtp.Address`
    :param clientAddress: The client's email address which should be in the
        :header:`To:` header of the response email.
    :param str lang: The 2-5 character locale code to use for translating the
        email. This is obtained from a client sending a email to a valid plus
        address which includes the translation desired, i.e. by sending an
        email to ``bridges+fa@torproject.org``, the client should receive a
        response in Farsi.
    :rtype: None or str
    :returns: None if we shouldn't respond to the client (i.e., if they have
        already received a rate-limiting warning email). Otherwise, returns a
        string containing the (optionally translated) body for the email
        response which we should send out.
    """
    clientAddr = '@'.join([clientAddress.local, clientAddress.domain])
    t = translations.installTranslations(lang)

    bridges = None
    try:
        bridgeRequest = request.determineBridgeRequestOptions(lines)

        # The request was invalid, respond with a help email which explains
        # valid email commands:
        if not bridgeRequest.isValid():
            raise EmailRequestedHelp("Email request from %r was invalid."
                                     % clientAddr)

        # Otherwise they must have requested bridges:
        interval = context.schedule.getInterval(time.time())
        bridges = context.distributor.getBridgesForEmail(
            clientAddr,
            interval,
            context.nBridges,
            countryCode=None,
            bridgeFilterRules=bridgeRequest.filters)
    except EmailRequestedHelp as error:
        logging.info(error)
        return templates.buildWelcomeText(t, clientAddress)
    except EmailRequestedKey as error:
        logging.info(error)
        return templates.buildKeyMessage(t, clientAddress)
    except TooSoonEmail as error:
        logging.info("Got a mail too frequently: %s." % error)
        return templates.buildSpamWarning(t, clientAddress)
    except (IgnoreEmail, BadEmail) as error:
        logging.info(error)
        # Don't generate a response if their email address is unparsable or
        # invalid, or if we've already warned them about rate-limiting:
        return None
    else:
        answer = "(no bridges currently available)\r\n"
        if bridges:
            transport = bridgeRequest.justOnePTType()
            answer = "".join("  %s\r\n" % b.getConfigLine(
                includeFingerprint=context.includeFingerprints,
                addressClass=bridgeRequest.addressClass,
                transport=transport,
                request=clientAddr) for b in bridges)
        return templates.buildAnswerMessage(t, clientAddress, answer)

def generateResponse(fromAddress, clientAddress, body, subject=None,
                     messageID=None, gpgContext=None):
    """Create a :class:`MailResponse`, which acts like an in-memory
    ``io.StringIO`` file, by creating and writing all headers and the email
    body into the file-like ``MailResponse.mailfile``.

    :param str fromAddress: The rfc:`2821` email address which should be in
        the :header:`From:` header.
    :param str clientAddress: The rfc:`2821` email address which should be in
        the :header:`To:` header.
    :param str subject: The string to write to the :header:`subject` header.
    :param str body: The body of the email. If a **gpgContext** is also given,
        and that ``Context`` has email signing configured, then
        :meth:`MailResponse.writeBody` will generate and include any
        ascii-armored OpenPGP signatures in the **body**.
    :type messageID: None or str
    :param messageID: The :rfc:`2822` specifier for the :header:`Message-ID:`
        header, if including one is desirable.
    :type gpgContext: None or ``gpgme.Context``.
    :param gpgContext: A pre-configured GPGME context. See
        :meth:`~crypto.getGPGContext`.
    :rtype: :class:`MailResponse`
    :returns: A ``MailResponse`` which contains the entire email. To obtain
        the contents of the email, including all headers, simply use
        :meth:`MailResponse.read`.
    """
    response = MailResponse(gpgContext)
    response.writeHeaders(fromAddress, clientAddress, subject,
                          inReplyTo=messageID)
    response.writeBody(body)

    # Only log the email text (including all headers) if SAFE_LOGGING is
    # disabled:
    if not safelog.safe_logging:
        contents = response.readContents()
        logging.debug("Email contents:\n%s" % contents)
    else:
        logging.debug("Email text for %r created." % clientAddress)
    response.rewind()
    return response

class MailContext(object):
    """Helper object that holds information used by email subsystem."""

    def __init__(self, config, distributor, schedule):
        """DOCDOC

        :ivar str username: Reject any RCPT TO lines that aren't to this
            user. See the ``EMAIL_USERNAME`` option in the config file.
            (default: ``'bridges'``)
        :ivar int maximumSize: Reject any incoming emails longer than
            this size (in bytes). (default: 3084 bytes).
        :ivar int smtpPort: The port to use for outgoing SMTP.
        :ivar str smtpServer: The IP address to use for outgoing SMTP.
        :ivar str smtpFromAddr: Use this address in the raw SMTP ``MAIL FROM``
            line for outgoing mail. (default: ``bridges@torproject.org``)
        :ivar str fromAddr: Use this address in the email :header:`From:`
            line for outgoing mail. (default: ``bridges@torproject.org``)
        :ivar int nBridges: The number of bridges to send for each email.
        :ivar gpgContext: A ``gpgme.GpgmeContext`` (as created by
            :func:`bridgedb.crypto.getGPGContext`), or None if we couldn't
            create a proper GPGME context for some reason.

        :type config: :class:`bridgedb.persistent.Conf`
        :type distributor: :class:`bridgedb.Dist.EmailBasedDistributor`.
        :param distributor: DOCDOC
        :type schedule: :class:`bridgedb.schedule.ScheduledInterval`.
        :param schedule: DOCDOC
        """
        self.config = config
        self.distributor = distributor
        self.schedule = schedule

        self.maximumSize = 32*1024
        self.includeFingerprints = config.EMAIL_INCLUDE_FINGERPRINTS
        self.nBridges = config.EMAIL_N_BRIDGES_PER_ANSWER

        self.username = (config.EMAIL_USERNAME or "bridges")
        self.fromAddr = (config.EMAIL_FROM_ADDR or "bridges@torproject.org")
        self.smtpFromAddr = (config.EMAIL_SMTP_FROM_ADDR or self.fromAddr)
        self.smtpServerPort = (config.EMAIL_SMTP_PORT or 25)
        self.smtpServerIP = (config.EMAIL_SMTP_HOST or "127.0.0.1")

        self.domainRules = config.EMAIL_DOMAIN_RULES or {}
        self.domainMap = config.EMAIL_DOMAIN_MAP or {}
        self.canon = self.buildCanonicalDomainMap()

        self.gpgContext = getGPGContext(config)

    def buildCanonicalDomainMap(self):
        """Build a map for all email provider domains from which we will accept
        emails to their canonical domain name.

        .. note:: Be sure that ``MailContext.domainRules`` and
            ``MailContext.domainMap`` are set appropriately before calling
            this method.

        This method is automatically called during initialisation, and the
        resulting domain map is stored as ``MailContext.canon``.

        :rtype: dict
        :returns: A dictionary which maps all domains and subdomains which we
            accept emails from to their second-level, canonical domain names.
        """
        canon = self.domainMap
        for domain, rule in self.domainRules.items():
            if domain not in canon.keys():
                canon[domain] = domain
        for domain in self.config.EMAIL_DOMAINS:
            canon[domain] = domain
        return canon

class MailResponse(object):
    """Holds information for generating a response email for a request.

    .. todo:: At some point, we may want to change this class to optionally
        handle creating Multipart MIME encoding messages, so that we can
        include attachments. (This would be useful for attaching our GnuPG
        keyfile, for example, rather than simply pasting it into the body of
        the email.)

    :type _buff: unicode or buffer
    :cvar _buff: Used internally to write lines for the response email into
        the ``_mailfile``. The reason why both of these attributes have two
        possible types is for the same Python-buggy reasons which require
        :data:`~bridgedb.crypto.NEW_BUFFER_INTERFACE`.
    :type mailfile: :class:`io.StringIO` or :class:`io.BytesIO`.
    :cvar mailfile: An in-memory file for storing the formatted headers and
        body of the response email.
    """

    implements(smtp.IMessage)

    _buff = buffer if NEW_BUFFER_INTERFACE else unicode
    mailfile = io.BytesIO if NEW_BUFFER_INTERFACE else io.StringIO

    def __init__(self, gpgContext=None):
        """Create a response to an email we have recieved.

        This class deals with correctly formatting text for the response email
        headers and the response body into an instance of :cvar:`mailfile`.

        :type gpgContext: None or ``gpgme.Context``
        :param gpgContext: A pre-configured GPGME context. See
            :meth:`bridgedb.crypto.getGPGContext` for obtaining a
            pre-configured **gpgContext**. If given, and the ``Context`` has
            been configured to sign emails, then a response email body string
            given to :meth:`writeBody` will be signed before being written
            into the ``mailfile``.
        """
        self.gpgContext = gpgContext
        self.mailfile = self.mailfile()
        self.closed = False

    # These are methods and attributes for controlling I/O operations on our
    # underlying ``mailfile``.

    def close(self):
        self.mailfile.close()
        self.closed = True
    close.__doc__ = mailfile.close.__doc__

    def flush(self, *args, **kwargs): self.mailfile.flush(*args, **kwargs)
    flush.__doc__ = mailfile.flush.__doc__

    def read(self, *args, **kwargs):
        self.mailfile.read(*args, **kwargs)
    read.__doc__ = mailfile.read.__doc__

    def readline(self, *args, **kwargs):
        self.mailfile.readline(*args, **kwargs)
    readline.__doc__ = mailfile.readline.__doc__

    def readlines(self, *args, **kwargs):
        self.mailfile.readlines(*args, **kwargs)
    readlines.__doc__ = mailfile.readlines.__doc__

    def seek(self, *args, **kwargs):
        self.mailfile.seek(*args, **kwargs)
    seek.__doc__ = mailfile.seek.__doc__

    def tell(self, *args, **kwargs):
        self.mailfile.tell(*args, **kwargs)
    tell.__doc__ = mailfile.tell.__doc__

    def truncate(self, *args, **kwargs):
        self.mailfile.truncate(*args, **kwargs)
    truncate.__doc__ = mailfile.truncate.__doc__

    # The following are custom methods to control reading and writing to the
    # underlying ``mailfile``.

    def readContents(self):
        """Read the all the contents written thus far to the :cvar:`mailfile`,
        and then :meth:`seek` to return to the original pointer position we
        were at before this method was called.

        :rtype: str
        :returns: The entire contents of the :cvar:`mailfile`.
        """
        pointer = self.mailfile.tell()
        self.mailfile.seek(0)
        contents = self.mailfile.read()
        self.mailfile.seek(pointer)
        return contents

    def rewind(self):
        """Rewind to the very beginning of the :cvar:`mailfile`."""
        self.seek(0)

    def write(self, line):
        """Any **line** written to me will have ``'\r\n'`` appended to it."""
        self.mailfile.write(self._buff(line + '\r\n'))
        self.mailfile.flush()

    def writelines(self, lines):
        """Calls :meth:`write` for each line in **lines**."""
        if isinstance(lines, basestring):
            for ln in lines.split('\n'):
                self.write(ln)
        elif isinstance(lines, (list, tuple,)):
            for ln in lines:
                self.write(ln)

    def writeHeaders(self, fromAddress, toAddress, subject=None,
                     inReplyTo=None, includeMessageID=True,
                     contentType='text/plain; charset="utf-8"', **kwargs):
        """Write all headers into the response email.

        :param str fromAddress: The email address for the ``From:`` header.
        :param str toAddress: The email address for the ``To:`` header.
        :type subject: None or str
        :param subject: The ``Subject:`` header.
        :type inReplyTo: None or str
        :param inReplyTo: If set, an ``In-Reply-To:`` header will be
            generated. This should be set to the ``Message-ID:`` header from
            the client's original request email.
        :param bool includeMessageID: If ``True``, generate and include a
            ``Message-ID:`` header for the response.
        :param str contentType: The ``Content-Type:`` header.
        :kwargs: If given, the key will become the name of the header, and the
            value will become the Contents of that header.
        """
        self.write("From: %s" % fromAddress)
        self.write("To: %s" % toAddress)
        if includeMessageID:
            self.write("Message-ID: %s" % smtp.messageid())
        if inReplyTo:
            self.write("In-Reply-To: %s" % inReplyTo)
        self.write("Content-Type: %s" % contentType)
        self.write("Date: %s" % smtp.rfc822date())

        if not subject:
            subject = '[no subject]'
        if not subject.lower().startswith('re'):
            subject = "Re: " + subject
        self.write("Subject: %s" % subject)

        if kwargs:
            for headerName, headerValue in kwargs.items():
                headerName = headerName.capitalize()
                headerName = headerName.replace(' ', '-')
                headerName = headerName.replace('_', '-')
                self.write("%s: %s" % (headerName, headerValue))

        # The first blank line designates that the headers have ended:
        self.write("\r\n")

    def writeBody(self, body):
        """Write the response body into the :cvar:`mailfile`.

        If ``MailResponse.gpgContext`` is set, and signing is configured, the
        **body** will be automatically signed before writing its contents into
        the ``mailfile``.

        :param str body: The body of the response email.
        """
        if self.gpgContext:
            body, _ = gpgSignMessage(self.gpgContext, body)
        self.writelines(body)

    # The following methods implement the IMessage interface.

    def lineReceived(self, line):
        """Called when we receive a line from an underlying transport."""
        self.write(line)

    def eomRecieved(self):
        """Called when we receive an EOM.

        :rtype: :api:`twisted.internet.defer.Deferred`
        :returns: A ``Deferred`` which has already been callbacked with the
            entire response email contents retrieved from
            :meth:`readContents`.
        """
        contents = self.readContents()
        if not self.closed:
            self.connectionLost()
        return defer.succeed(contents)

    def connectionLost(self):
        """Called if we die partway through reading a message.

        Truncate the :cvar:`mailfile` to null length, then close it.
        """
        self.mailfile.truncate(0)
        self.mailfile.close()

class MailMessage(object):
    """Plugs into the Twisted Mail and receives an incoming message.

    :ivar list lines: A list of lines from an incoming email message.
    :ivar int nBytes: The number of bytes received thus far.
    :ivar bool ignoring: If ``True``, we're ignoring the rest of this message
        because it exceeded :ivar:`MailContext.maximumSize`.
    """
    implements(smtp.IMessage)

    def __init__(self, context, fromCanonical=None):
        """Create a new MailMessage from a MailContext.

        :type context: :class:`MailContext`
        :param context: The configured context for the email server.
        :type canonicalFrom: str or None
        :param canonicalFrom: The canonical domain which this message was
            received from. For example, if ``'gmail.com'`` is the configured
            canonical domain for ``'googlemail.com'`` and a message is
            received from the latter domain, then this would be set to the
            former.
        """
        self.context = context
        self.fromCanonical = fromCanonical
        self.lines = []
        self.nBytes = 0
        self.ignoring = False

    def lineReceived(self, line):
        """Called when we get another line of an incoming message."""
        self.nBytes += len(line)
        if self.nBytes > self.context.maximumSize:
            self.ignoring = True
        else:
            self.lines.append(line)
        if not safelog.safe_logging:
            logging.debug("> %s", line.rstrip("\r\n"))

    def eomReceived(self):
        """Called when we receive the end of a message."""
        if not self.ignoring:
            self.reply()
        return defer.succeed(None)

    def connectionLost(self):
        """Called if we die partway through reading a message."""
        pass

    def getIncomingMessage(self):
        """Create and parse an :rfc:`2822` message object for all ``lines``
        received thus far.

        :rtype: :api:`twisted.mail.smtp.rfc822.Message`
        :returns: A ``Message`` comprised of all lines received thus far.
        """
        rawMessage = io.StringIO()
        rawMessage.writelines([unicode('{0}\n'.format(ln)) for ln in self.lines])
        rawMessage.seek(0)
        return smtp.rfc822.Message(rawMessage)

    def getClientAddress(self, incoming):
        """Attempt to get the client's email address from an incoming email.

        :type incoming: :api:`twisted.mail.smtp.rfc822.Message`
        :param incoming: An incoming ``Message``, i.e. as returned from
            :meth:`getIncomingMessage`.
        :rtype: ``None`` or :api:`twisted.mail.smtp.Address`
        :returns: The client's email ``Address``, if it originated from a
            domain that we accept and the address was well-formed. Otherwise,
            returns ``None``.
        """
        addrHeader = None
        try: fromAddr = incoming.getaddr("From")[1]
        except (IndexError, TypeError, AttributeError): pass
        else: addrHeader = fromAddr

        if not addrHeader:
            logging.warn("No From header on incoming mail.")
            try: senderHeader = incoming.getaddr("Sender")[1]
            except (IndexError, TypeError, AttributeError): pass
            else: addrHeader = senderHeader
        if not addrHeader:
            logging.warn("No Sender header on incoming mail.")
        else:
            try:
                client = smtp.Address(addr.normalizeEmail(
                    addrHeader,
                    self.context.domainMap,
                    self.context.domainRules))
            except (UnsupportedDomain, BadEmail, smtp.AddressError) as error:
                logging.warn(error)
            else:
                return client

    def getRecipient(self, incoming):
        """Find our address in the recipients list of the **incoming** message.

        :type incoming: :api:`twisted.mail.smtp.rfc822.Message`
        :param incoming: An incoming ``Message``, i.e. as returned from
            :meth:`getIncomingMessage`.
        :rtype: str
        :return: Our address from the recipients list. If we can't find it
            return our default ``SMTP_FROM_ADDRESS`` from the config file.
        """
        address = self.context.fromAddr
        addressList = incoming.getaddrlist("To")

        try:
            ours = smtp.Address(address)
        except smtp.AddressError as error:
            logging.warn("Our address seems invalid: %r" % address)
            logging.warn(error)
        else:
            for _, addr in addressList:
                try:
                    maybeOurs = smtp.Address(addr)
                except smtp.AddressError:
                    pass
                else:
                    # See if the user looks familiar. We do a 'find' instead of
                    # compare because we might have a '+' address here.
                    if maybeOurs.local.find(ours.local) != -1:
                        return '@'.join([maybeOurs.local, maybeOurs.domain])
        return address

    def getCanonicalDomain(self, domain):
        try:
            canonical = canonicalizeEmailDomain(domain, self.context.canon)
        except (UnsupportedDomain, BadEmail) as error:
            logging.warn(error)
        else:
            return canonical

    def reply(self):
        """Reply to an incoming email. Maybe.

        If no `response` is returned from :func:`createMailResponse`, then the
        incoming email will not be responded to at all. This can happen for
        several reasons, for example: if the DKIM signature was invalid or
        missing, or if the incoming email came from an unacceptable domain, or
        if there have been too many emails from this client in the allotted
        time period.

        :rtype: :api:`twisted.internet.defer.Deferred`
        :returns: A ``Deferred`` which will callback when the response has
            been successfully sent, or errback if an error occurred while
            sending the email.
        """
        logging.info("Got an email; deciding whether to reply.")

        def _replyEB(fail):
            """Errback for a :api:`twisted.mail.smtp.SMTPSenderFactory`.

            :param fail: A :api:`twisted.python.failure.Failure` which occurred during
            the transaction.
            """
            logging.debug("_replyToMailEB() called with %r" % fail)
            error = fail.getTraceback() or "Unknown"
            logging.error(error)

        d = defer.Deferred()
        d.addErrback(_replyEB)

        incoming = self.getIncomingMessage()
        recipient = self.getRecipient(incoming)
        client = self.getClientAddress(incoming)

        if not client:
            return d

        if not self.fromCanonical:
            self.fromCanonical = self.getCanonicalDomain(client.domain)
        rules = self.context.domainRules.get(self.fromCanonical, [])
        if not checkDKIM(incoming, rules):
            return d

        clientAddr = '@'.join([client.local, client.domain])
        messageID = incoming.getheader("Message-ID", None)
        subject = incoming.getheader("Subject", None)

        # Look up the locale part in the 'To:' address, if there is one and
        # get the appropriate Translation object:
        lang = translations.getLocaleFromPlusAddr(recipient)
        logging.info("Client requested email translation: %s" % lang)

        body = createResponseBody(self.lines, self.context, client, lang)
        if not body: return d  # The client was already warned.

        response = generateResponse(self.context.fromAddr, clientAddr, body,
                                    subject, messageID, self.context.gpgContext)
        if not response: return d

        logging.info("Sending reply to %s" % client)
        factory = smtp.SMTPSenderFactory(self.context.smtpFromAddr, clientAddr,
                                         response, d, retries=0, timeout=30)
        reactor.connectTCP(self.context.smtpServerIP,
                           self.context.smtpServerPort,
                           factory)
        return d

class MailDelivery(object):
    """Plugs into Twisted Mail and handles SMTP commands."""
    implements(smtp.IMessageDelivery)

    def setBridgeDBContext(self, context):
        self.context = context
        self.fromCanonical = None

    def receivedHeader(self, helo, origin, recipients):
        """Create the ``Received:`` header for an incoming email.

        :type helo: tuple
        :param helo: The lines received during SMTP client HELO.
        :type origin: :api:`twisted.mail.smtp.Address`
        :param origin: The email address of the sender.
        :type recipients: list
        :param recipients: A list of :api:`twisted.mail.smtp.User` instances.
        """
        cameFrom = "%s (%s [%s])" % (helo[0] or origin, helo[0], helo[1])
        cameFor = ', '.join(["<{0}>".format(recp.dest) for recp in recipients])
        hdr = str("Received: from %s for %s; %s"
                  % (cameFrom, cameFor, smtp.rfc822date()))
        return hdr

    def validateFrom(self, helo, origin):
        try:
            logging.debug("ORIGIN: %r" % repr(origin.addrstr))
            canonical = canonicalizeEmailDomain(origin.domain,
                                                self.context.canon)
        except UnsupportedDomain as error:
            logging.info(error)
            raise smtp.SMTPBadSender(origin.domain)
        except Exception as error:
            logging.exception(error)
        else:
            logging.debug("Got canonical domain: %r" % canonical)
            self.fromCanonical = canonical
        return origin  # This method *cannot* return None, or it'll cause a 503.

    def validateTo(self, user):
        """If the local user that was addressed isn't our configured local user
        or doesn't contain a '+' with a prefix matching the local configured
        user: Yell.
        """
        u = user.dest.local
        # Hasplus? If yes, strip '+foo'
        idx = u.find('+')
        if idx != -1:
            u = u[:idx]
        if u != self.context.username:
            raise smtp.SMTPBadRcpt(user)
        return lambda: MailMessage(self.context, self.fromCanonical)

class MailFactory(smtp.SMTPFactory):
    """Plugs into Twisted Mail; creates a new MailDelivery whenever we get
       a connection on the SMTP port."""

    def __init__(self, context=None, **kw):
        smtp.SMTPFactory.__init__(self, **kw)
        self.delivery = MailDelivery()
        if context:
            self.setBridgeDBContext(context)

    def setBridgeDBContext(self, context):
        self.context = context
        self.delivery.setBridgeDBContext(context)

    def buildProtocol(self, addr):
        p = smtp.SMTPFactory.buildProtocol(self, addr)
        p.delivery = self.delivery
        return p

def addServer(config, distributor, schedule):
    """Set up a SMTP server for responding to requests for bridges.

    :param config: A configuration object from Main. We use these
        options::
            EMAIL_BIND_IP
            EMAIL_PORT
            EMAIL_N_BRIDGES_PER_ANSWER
            EMAIL_DOMAIN_RULES
    :type distributor: :class:`bridgedb.Dist.EmailBasedDistributor`
    :param dist: A distributor which will handle database interactions, and
        will decide which bridges to give to who and when.
    :type schedule: :class:`bridgedb.schedule.ScheduledInterval`
    :param schedule: The schedule. XXX: Is this even used?
    """
    context = MailContext(config, distributor, schedule)
    factory = MailFactory(context)

    addr = config.EMAIL_BIND_IP or ""
    port = config.EMAIL_PORT

    reactor.listenTCP(port, factory, interface=addr)

    # Set up a LoopingCall to run every 30 minutes and forget old email times.
    lc = LoopingCall(distributor.cleanDatabase)
    lc.start(1800, now=False)

    return factory


#!/usr/bin/env python
from multiprocessing import Process, JoinableQueue

# Messy, but acceptable config.
NUMBER_OF_CONSUMERS = 2

def put_in_numbers(queue):
    """
    The producer method, if you passed in another argument,
    like... a url this could run your scraping.
    """
    for i in range(100):
        queue.put(i)

    for i in range(NUMBER_OF_CONSUMERS):
        queue.put(None)

    queue.close()
    return

def get_number(queue):
    """
    The consumer method, if you put links in the queue
    these could do the downloading....
    """
    while True:
        number = queue.get(True)
        if number is None:
            ## End of the queue
            queue.task_done()
            return
        print(number * number)
        queue.task_done()

def main():
    '''
    The main function definition.
    '''

    queue = JoinableQueue()
    # Producer...
    # To fill the queue
    producer = Process(target=put_in_numbers, args=(queue,))
    producer.start()
    # Workers to work on the queue.
    workers = []
    for i in range(NUMBER_OF_CONSUMERS):
        p = Process(target=get_number, args=(queue,))
        p.start()
        workers.append(p)

    # and wait for everyone to finish
    # If the producer is done...
    producer.join()
    for worker in workers:
        # and the workers...
        worker.join()

    # And the queue no longer has any jobs....
    queue.join()

    print("Done")

if __name__ == '__main__':
    '''
    If this is the file being run...
    run main.
    '''
    main()


from enum import Enum
import re

class TokenizeError(Exception):
    pass

class TokenType(Enum):
    PLUS = 1
    MINUS = 2
    MUL = 3
    DIV = 4
    LPAR = 5
    RPAR = 6
    NUM = 7
    EOF = 8

class Token:
    def __init__(self, type: TokenType, value: str):
        self.type = type
        self.value = value

    def __repr__(self):
        """repr function is using for tests (like __str__)"""
        return f'token({self.type.name}, {self.value})'

    def __eq__(self, other):
        """ Makes possible to compare tokens with == """
        return self.type == other.type and self.value == other.value

    def __ne__(self, other):
        return not self.__eq__(other)

def tokenize(input: str):
    whitespaces=re.compile(r'^\s')     # ^ position 0, ^s+ whitespace 1 or more times
    num = re.compile(r'^\d+')
    result = []
    position = 0

    while position < len(input):
        current_char = input[position]
        if current_char == '+':
            result.append(Token(TokenType.PLUS, current_char))
            position += 1
        elif current_char == '-':
            result.append(Token(TokenType.MINUS, current_char))
            position += 1
        elif current_char == '*':
            result.append(Token(TokenType.MUL, current_char))
            position += 1
        elif current_char == '/':
            result.append(Token(TokenType.DIV, current_char))
            position += 1
        elif current_char == '(':
            result.append(Token(TokenType.LPAR, current_char))
            position += 1
        elif current_char == ')':
            result.append(Token(TokenType.RPAR, current_char))
            position += 1
        # elif current_char == ' ':
        #     result.append(Token(TokenType., current_char))
        #     position += 1
        elif whitespaces.match(current_char):
            position += 1
        else:
            match = num.match(input[position:])
            if match:
                num_literal = match.group(0)
                result.append(Token(TokenType.NUM, num_literal))
                position += len(num_literal)
            else:
                raise TokenizeError(f'Unexpected character at position {position}')

    result.append(Token(TokenType.EOF, ''))

    return result

# TESTS #

import unittest

class Tests(unittest.TestCase):
    def test_string_tokenizing(self):
        input = '3 * 8 + ( 24 / 12 ) - 4'
        expected = [Token(TokenType.NUM, '3'),
                    Token(TokenType.MUL, '*'),
                    Token(TokenType.NUM, '8'),
                    Token(TokenType.PLUS, '+'),
                    Token(TokenType.LPAR, '('),
                    Token(TokenType.NUM, '24'),
                    Token(TokenType.DIV, '/'),
                    Token(TokenType.NUM, '12'),
                    Token(TokenType.RPAR, ')'),
                    Token(TokenType.MINUS, '-'),
                    Token(TokenType.NUM, '4'),
                    Token(TokenType.EOF, '')]
        self.assertEqual(expected, tokenize(input))

    def test_invalid_input(self):
        input = '3* CHEESE + 18'
        self.assertRaises(TokenizeError, tokenize, input)


from direct.showbase.ShowBase import ShowBase
from direct.interval.IntervalGlobal import LerpFunc
from direct.gui.DirectGui import DirectButton
from direct.gui.DirectGui import DGG

from stageflow import Flow
from stageflow import Stage
from stageflow.panda3d import Cutscene
from stageflow.prefab import Quit

ShowBase()
base.disable_mouse()

class StartupSplashes(Cutscene):
    def setup_credits(self, data):
        base.cam.set_pos(0, -10, 0)
        base.cam.look_at(0, 0, 0)
        self.ball = base.loader.load_model("models/smiley")
        self.ball.reparent_to(base.render)
        return LerpFunc(
            self.run_credits,
            fromData=0,
            toData=1,
            duration=5.0,
            blendType='noBlend',
            extraArgs=[],
            name=None,
        )

    def run_credits(self, t):
        self.ball.set_h(t*360*5)

    def destroy_credits(self):
        self.ball.remove_node()

class MainMenu(Stage):
    def enter(self, data):
        self.btn_quit = DirectButton(
            text=(
                "Quit",
                "Quit!",
                "Quit?",
                "(Quit)",
            ),
            text_pos=(0, -0.7),
            text_scale=0.2,
            frameSize=(-1, 1, -0.8, -0.5),
            borderWidth=(0.01, 0.01),
            command=self.quit,
        )
        self.btn_credits = DirectButton(
            text=(
                "Credits",
                "Credits!",
                "Credits?",
                "(Credits)",
            ),
            text_pos=(0, -0.3),
            text_scale=0.2,
            frameSize=(-1, 1, -0.4, -0.1),
            borderWidth=(0.01, 0.01),
            command=self.credits,
        )
        self.btn_main_game = DirectButton(
            text=(
                "Main Game Loop",
                "Main Game Loop!",
                "Main Game Loop?",
                "(Main Game Loop)",
            ),
            text_pos=(0, 0.6),
            text_scale=0.2,
            frameSize=(-1, 1, 0.5, 0.8),
            borderWidth=(0.01, 0.01),
            command=self.main_game_loop,
        )
        self.buttons = [self.btn_quit, self.btn_credits, self.btn_main_game]

    def exit(self, data):
        for btn in self.buttons:
            btn.destroy()
        return data

    def exit_to_substage(self, substage, data):
        for btn in self.buttons:
            btn["state"] = DGG.DISABLED
        return data

    def reenter_from_substage(self, substage, data):
        for btn in self.buttons:
            btn["state"] = DGG.NORMAL
        if substage == 'are_you_sure':
            question, i_am_sure = data
            if question == 'quit' and i_am_sure:
                base.flow.transition('quit')

    def main_game_loop(self):
        base.flow.transition('main_game_loop')

    def credits(self):
        base.flow.transition('main_credits')

    def quit(self):
        base.flow.push_substage('are_you_sure', 'quit')

class MainGameLoop(Stage):
    def enter(self, data):
        self.btn_menu = DirectButton(
            text=(
                "Ingame Menu",
                "Ingame Menu",
                "Ingame Menu",
                "(Ingame Menu)",
            ),
            text_pos=(0, -0.05),
            text_scale=0.2,
            frameSize=(-1, 1, -0.15, 0.15),
            borderWidth=(0.01, 0.01),
            command=self.ingame_menu,
        )

    def exit(self, data):
        self.btn_menu.destroy()
        return data

    def exit_to_substage(self, substage, data):
        for btn in [self.btn_menu]:
            btn["state"] = DGG.DISABLED
        return data

    def reenter_from_substage(self, substage, data):
        for btn in [self.btn_menu]:
            btn["state"] = DGG.NORMAL
        if data == 'main_menu':
            base.flow.transition('main_menu')
        if data == 'quit':
            base.flow.transition('quit')

    def ingame_menu(self):
        base.flow.push_substage('ingame_menu')

class AreYouSure(Stage):
    def enter(self, data):
        self.btn_yes = DirectButton(
            text=("Yes", "Yes", "Yes", "Yes"),
            text_pos=(-0.6, -0.05),
            text_scale=0.2,
            frameSize=(-1, -0.2, -0.2, 0.2),
            borderWidth=(0.01, 0.01),
            command=self.yes,
        )
        self.btn_no = DirectButton(
            text=("No", "No", "No", "No"),
            text_pos=(0.6, -0.05),
            text_scale=0.2,
            frameSize=(0.2, 1, -0.2, 0.2),
            borderWidth=(0.01, 0.01),
            command=self.no,
        )
        self.data = data

    def exit(self, data):
        self.btn_yes.destroy()
        self.btn_no.destroy()
        return (self.data, data)

    def yes(self):
        base.flow.pop_substage(True)

    def no(self):
        base.flow.pop_substage(False)

class IngameMenu(Stage):
    def enter(self, data):
        self.btn_quit = DirectButton(
            text=(
                "Quit",
                "Quit!",
                "Quit?",
                "(Quit)",
            ),
            text_pos=(0, -0.3),
            text_scale=0.2,
            frameSize=(-1, 1, -0.4, -0.1),
            borderWidth=(0.01, 0.01),
            command=self.quit,
        )
        self.btn_main = DirectButton(
            text=(
                "Main Menu",
                "Main Menu!",
                "Main Menu?",
               "(Main Menu)",
            ),
            text_pos=(0, 0.1),
            text_scale=0.2,
            frameSize=(-1, 1, 0.0, 0.3),
            borderWidth=(0.01, 0.01),
            command=self.main,
        )
        self.btn_back = DirectButton(
            text=(
                "Back",
                "Back!",
                "Back?",
                "(Back)",
            ),
            text_pos=(0, -0.7),
            text_scale=0.2,
            frameSize=(-1, 1, -0.8, -0.5),
            borderWidth=(0.01, 0.01),
            command=self.back,
        )
        self.buttons = [self.btn_main, self.btn_quit, self.btn_back]

    def exit(self, data):
        for btn in self.buttons:
            btn.destroy()
        return data

    def exit_to_substage(self, substage, data):
        for btn in self.buttons:
            btn["state"] = DGG.DISABLED
        return data

    def reenter_from_substage(self, substage, data):
        for btn in self.buttons:
            btn["state"] = DGG.NORMAL
        if substage == 'are_you_sure':
            question, i_am_sure = data
            if question == 'quit' and i_am_sure:
                base.flow.pop_substage('quit')
            if question == 'main' and i_am_sure:
                base.flow.pop_substage('main_menu')

    def main(self):
        base.flow.push_substage('are_you_sure', 'main')

    def quit(self):
        base.flow.push_substage('are_you_sure', 'quit')

    def back(self):
        base.flow.pop_substage()

base.flow = Flow(
    stages=dict(
        splashes=StartupSplashes(exit_stage='main_menu'),
        main_menu=MainMenu(),
        main_game_loop=MainGameLoop(),
        main_credits=StartupSplashes(exit_stage='main_menu'),
        quit=Quit(),
    ),
    substages=dict(
        are_you_sure=AreYouSure(),
        ingame_menu=IngameMenu(),
    ),
    initial_stage='splashes',
)
## Alternative to the above:
#base.flow = Flow()
#base.flow.add_stage('splashes', StartupSplashes(exit_stage='quit'))
#base.flow.add_stage('quit', Quit())
#base.flow.transition('splashes', None)
base.run()


# -*- coding:utf-8 -*-
import pandas as pd
import numpy as np
from sklearn.tree import DecisionTreeClassifier
from lib.execute import Executor
from tools.mylogger import logger
from lib.select_funcs import drop_useless

class myExecutor(Executor):
    def feature_select(self, sub_train_set, y):
        return drop_useless(sub_train_set, 'pre_apply_no', 'book_date', 'book_mon')

def main():
    df = pd.read_csv("data/hl_test_clean.csv", encoding="utf8")
    logger.info("============================Data is ready!============================")
    clf = DecisionTreeClassifier(
        max_features=1,
        min_weight_fraction_leaf=0.05,
        min_samples_split=0.05,
        criterion="entropy",
        max_leaf_nodes=5
    )
    myexe = myExecutor(df, "fpd", clf)
    myexe.train_all()

if __name__ == '__main__':
    main()


import jieba.posseg
import re
jieba.load_userdict("LDA/data/person.txt")

STOP_WORDS = set([w.strip for w in open("LDA/data/stopwords.txt", "r", encoding="UTF-8").readlines()])

class MyChapters(object):
    def __init__(self, chapter_list):
        self.chapter_list = chapter_list

    def __iter__(self):
        for chapter in self.chapter_list:
            yield cut_words_with_pos(chapter)

def split_by_chapter(filepath):
    text = open(filepath, "r", encoding="UTF-8").read()
    chapter_list = re.split(r'第.{1,3}章\n', text)[1:]
    return chapter_list

def cut_words_with_pos(text):
    seg = jieba.posseg.cut(text)
    res = []
    for i in seg:
        if i.flag in ["a", "v", "x", "n", "an", "vn", "nz", "nt", "nr"] and is_fine_word(i.word):
            res.append(i.word)

    return list(res)

# 过滤词长，过滤停用词，只保留中文
def is_fine_word(word, min_length=2):
    rule = re.compile(r"^[\u4e00-\u9fa5]+$")
    if len(word) >= min_length and word not in STOP_WORDS and re.search(rule, word):
        return True
    else:
        return False

import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
import lda
import matplotlib.pyplot as plt
import seaborn as sns

def get_lda_input(chapters):
    corpus = [" ".join(word_list) for word_list in chapters]
    vectorizer = CountVectorizer()
    X = vectorizer.fit_transform(corpus)
    return X.toarray(), vectorizer

def lda_train(weight, vectorizer):
    model = lda.LDA(n_topics=20, n_iter=1000, random_state=1)
    model.fit(weight)

    doc_num = len(weight)
    topic_word = model.topic_word_
    vocab = vectorizer.get_feature_names()
    titles = ["第{}章".format(i) for i in range(1, doc_num+1)]

    n_top_words = 20
    for i, topic_dist in enumerate(topic_word):
        topic_words = np.array(vocab)[np.argsort(topic_dist)][:-(n_top_words+1):-1]
        print('Topic {}: {}'.format(i, ' '.join(topic_words)))

    doc_topic = model.doc_topic_
    print(doc_topic, type(doc_topic))
    plot_topic(doc_topic)

    for i in range(doc_num):
        print('{} (top topic:{})'.format(titles[i],np.argsort(doc_topic[i])[:-4:-1]))

def main():
    chapter_list = split_by_chapter("LDA\data\芳华-严歌苓.txt")
    chapters = MyChapters(chapter_list)
    weight, vectorizer = get_lda_input(chapters)
    lda_train(weight, vectorizer)

def plot_topic(doc_topic):
    f, ax = plt.subplots(figsize=(10, 4))
    cmap = sns.cubehelix_palette(start=1, rot=3, gamma=0.8, as_cmap=True)
    sns.heatmap(doc_topic, cmap=cmap, linewidths=0.05, ax=ax)
    ax.set_title("proportion pre topic in every chapter")
    ax.set_xlabel('topic')
    ax.set_ylabel('chapter')
    plt.show()

    f.savefig("LDA/data/topic_heatmap1.jpg", bbox_inches='tight')

if __name__ == '__main__':
    main()


# This is the main.py script
import pygame
import os
import random
pygame.font.init()

WIDTH, HEIGHT = 750, 750
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Space Invaders")
pygame.mixer.init()

# Load images
RED_SPACE_SHIP = \
pygame.image.load(os.path.join("assets","pixel_ship_red_small.png"))
GREEN_SPACE_SHIP = \
pygame.image.load(os.path.join("assets","pixel_ship_green_small.png"))
BLUE_SPACE_SHIP = \
pygame.image.load(os.path.join("assets","pixel_ship_blue_small.png"))

# Player ship
YELLOW_SPACE_SHIP = \
pygame.image.load(os.path.join("assets","pixel_ship_yellow.png"))

# Lasers
RED_LASER = pygame.image.load(os.path.join("assets","pixel_laser_red.png"))
GREEN_LASER = pygame.image.load(os.path.join("assets","pixel_laser_green.png"))
BLUE_LASER = pygame.image.load(os.path.join("assets","pixel_laser_blue.png"))
YELLOW_LASER = pygame.image.load(os.path.join("assets","pixel_laser_yellow.png"))

# MediKit
MEDIKIT = pygame.transform.scale(
    pygame.image.load(os.path.join("assets","healthpack.png")),
    (75, 75)
)

# Background
BG = pygame.transform.scale(
    pygame.image.load(os.path.join("assets","background-black.png")), # image
    (WIDTH, HEIGHT) # new size
)

# Load music and sounds
pygame.mixer.music.load(
    os.path.join('assets','wav','score.wav')
)

SOUNDS = {
    'DirectHit':pygame.mixer.Sound(
        os.path.join('assets','wav','DirectHit.ogg')
    ),
    'HealthPickup':pygame.mixer.Sound(
        os.path.join('assets','wav','HealthPickupBb.ogg')
    ),
    'YouGotHit':[
        pygame.mixer.Sound(
            os.path.join('assets','wav','YouTookDamage.ogg')
        ),
        pygame.mixer.Sound(
            os.path.join('assets','wav','YouTookDamage2.ogg')
        )
    ],
    'GameOver':pygame.mixer.Sound(
        os.path.join('assets','wav','Bamboozled.ogg')
    ),
    'PlayerShoots':pygame.mixer.Sound(
        os.path.join('assets','wav','Shoot.ogg')
    )
}

world_state = {
            'Player': None,
            'Enemies': [],
            'PlayerLasers': [],
            'EnemyLasers': [],
            'MediKits': []
        }

## START CLASS DEFINITIONS

class Actions:
    @staticmethod
    def collision(obj1, obj2):
        '''Detect collision between two objects'''
        offset_x = obj2.x - obj1.x
        offset_y = obj2.y - obj1.y
        return obj1.mask.overlap(obj2.mask, (offset_x, offset_y)) != None

    @staticmethod
    def move(obj, velocity, direction):
        '''Move an object up down left or right with certain velocity'''
        if direction == 'up':
            obj.y -= velocity
        elif direction == 'down':
            obj.y += velocity
        elif direction == 'left':
            obj.x -= velocity
        elif direction == 'right':
            obj.x += velocity
        else:
            pass

    @staticmethod
    def offscreen_x(obj, width):
        '''Determine if obj is offscreen in the x direction'''
        return obj.x > width or obj.x < 0

    @staticmethod
    def offscreen_y(obj, height):
        '''Determine if obj is offscreen in the y direction'''
        return obj.y > height

    @staticmethod
    def is_offscreen(obj, width, height):
        '''Determine if obj is offscreen in either direction'''
        return Actions.offscreen_x(obj, width) or Actions.offscreen_y(obj,
                                                                      height
                                                                     )
    @staticmethod
    def make_wave(wave_length=5):
        if len(world_state['Enemies']) == 0:
            level += 1
            wave_length += 5
            for i in range(wave_length):
                enemy = Enemy(
                    random.randrange(50, WIDTH - 100),
                    random.randrange(-1500, -100),
                    health=100
                    )
                world_state['Enemies'].append(enemy)
        else:
            pass

class Ship:
    def __init__(self, x, y, health):
        self.x = x
        self.y = y
        self.health = health
        self.ship_img = None
        self.laser_img = None
        self.cooldown_counter = 0
        self.cooldown_limit = 30

    def draw(self, window):
        '''Draw the ship_img at ship's current position (x, y)'''
        window.blit(self.ship_img, (self.x, self.y))

    def width(self):
        '''Get the ship's width'''
        return self.ship_img.get_width()

    def height(self):
        '''Get the ship's height'''
        return self.ship_img.get_height()

    def cooldown(self):
        '''Return True if cooled down, False if not'''
        if 1 <= self.cooldown_counter < self.cooldown_limit:
            self.cooldown_counter += 1
            return False
        elif self.cooldown_counter >= self.cooldown_limit:
            self.cooldown_counter = 0
            return True
        elif self.cooldown_counter == 0:
            return True

class Player(Ship):
    def __init__(self, x, y, health=100):
        super().__init__(x, y, health)
        self.ship_img = YELLOW_SPACE_SHIP
        self.laser_img = YELLOW_LASER
        self.mask = pygame.mask.from_surface(self.ship_img)
        self.max_health = health
        self.cooldown_counter = 0
        self.cooldown_limit = 20

    def health_bar(self, window):
        pygame.draw.rect(
            window,
            (255,0,0), # red
            (self.x, self.y + self.ship_img.get_height() + 10, \
             self.ship_img.get_width(), 10)
        )

        curr_health_pct = self.health / 100

        pygame.draw.rect(
            window,
            (0,255,0), # green
            (self.x, self.y + self.ship_img.get_height() + 10, \
             self.ship_img.get_width() * curr_health_pct, 10)
        )

    def draw(self, window):
        super().draw(window)
        self.health_bar(window)

    def shoot(self):
        '''Fire a Player Laser'''
        if self.cooldown():
            laser = Laser(
                self.x,
                self.y - 10,
                self.laser_img
            )
            world_state['PlayerLasers'].append(laser)
            self.cooldown_counter = 1
        else:
            pass

class Enemy(Ship):
    COLOR_MAP = {
        'red': (RED_SPACE_SHIP, RED_LASER),
        'green': (GREEN_SPACE_SHIP, GREEN_LASER),
        'blue': (BLUE_SPACE_SHIP, BLUE_LASER)
    }

    def __init__(self, x, y, health):
        super().__init__(x, y, health)
        self.ship_img, self.laser_img = Enemy.COLOR_MAP[random.choice(['red','green','blue'])]
        self.mask = pygame.mask.from_surface(self.ship_img)
        self.max_health = health
        self.cooldown_counter = 0
        self.cooldown_limit = 30

    def shoot(self):
        if self.cooldown():
            laser = Laser(
                self.x + random.randrange(-10,10),
                self.y,
                self.laser_img
            )
            world_state['EnemyLasers'].append(laser)
            self.cooldown_counter = 1
        else:
            pass

class Laser:
    def __init__(self, x, y, img):
        self.x = x
        self.y = y
        self.img = img
        self.mask = pygame.mask.from_surface(self.img)

    def draw(self, window):
        window.blit(self.img, (self.x, self.y))

class Medikit:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.img = MEDIKIT
        self.mask = pygame.mask.from_surface(self.img)
        self.cooldown_counter = 0
        self.cooldown_limit = 300 # five seconds

    def draw(self, window):
        '''Draw the healthpack at position (x, y)'''
        window.blit(self.img, (self.x, self.y))

## END CLASS DEFINITIONS

def main():
    run = True
    FPS = 60
    clock = pygame.time.Clock()
    level = 0
    lives = 5
    main_font = pygame.font.SysFont("arial", 50)
    lost_font = pygame.font.SysFont("comicsans", 60)
    player_vel = 5
    lost = False
    lost_count = 0
    world_state['Player'] = Player(300, 530)
    wave_length = 5
    enemy_vel = 1
    laser_velocity = 10
    pygame.mixer.music.play(-1)

    def redraw_window():
        WIN.blit(BG, (0,0)) # Draw background

        # Draw text
        lives_label = main_font.render(f"Lives: {lives} ", 1, (255,255,255))
        level_label = main_font.render(f"Level: {level} ", 1, (255,255,255))
        WIN.blit(lives_label, (10,10))
        WIN.blit(level_label, (WIDTH - level_label.get_width() - 10, 10))

        # Draw enemies
        for enemy in world_state['Enemies']:
            enemy.draw(WIN)

        # Draw player
        world_state['Player'].draw(WIN)

        # Draw enemy lasers
        for laser in world_state['EnemyLasers']:
            laser.draw(WIN)

        # Draw player lasers
        for laser in world_state['PlayerLasers']:
            laser.draw(WIN)

        # Draw medikits
        for medikit in world_state['MediKits']:
            medikit.draw(WIN)

        if lost:
            lost_label = lost_font.render("You lost!!!", 1, (255,255,255))
            WIN.blit(lost_label, (WIDTH/2 - lost_label.get_width()/2, 250))

    while run:
        # Game Loop
        clock.tick(FPS)
        redraw_window()

        # Game over test and counter
        if lives <= 0 or world_state['Player'].health <= 0:
            lost = True
            lost_count += 1
            SOUNDS['GameOver'].play()

        if lost:
            if lost_count > FPS * 3: # wait 3 seconds
                run = False
            else:
                pass

        pygame.display.update()

        # New wave of enemies if none are left
        if len(world_state['Enemies']) == 0:
            level += 1
            wave_length += 5
            for i in range(wave_length):
                enemy = Enemy(
                    random.randrange(50, WIDTH - 100),
                    random.randrange(-1500, -100),
                    health=100
                    )
                world_state['Enemies'].append(enemy)
        else:
            pass

        # Check for user events
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
            else:
                pass

        # Read inputs and move player
        keys = pygame.key.get_pressed()
        if keys[pygame.K_a] and ((world_state['Player'].x - player_vel) > 0): # left
            Actions.move(world_state['Player'], player_vel, 'left')
        if keys[pygame.K_d] and ((world_state['Player'].x + player_vel + world_state['Player'].width()) < WIDTH): # right
            Actions.move(world_state['Player'], player_vel, 'right')
        if keys[pygame.K_w] and ((world_state['Player'].y - player_vel) > 0): # up
            Actions.move(world_state['Player'], player_vel, 'up')
        if keys[pygame.K_s] and ((world_state['Player'].y + player_vel + world_state['Player'].height()) + 10 < HEIGHT):
            Actions.move(world_state['Player'], player_vel, 'down')
        if keys[pygame.K_SPACE]:
            world_state['Player'].shoot()
            SOUNDS['PlayerShoots'].play()

        world_state['Player'].cooldown()

        # Move enemies and let them shoot
        for enemy in world_state['Enemies']:
            enemy.cooldown()
            Actions.move(enemy, enemy_vel, 'down')
            if random.randrange(0, 600) == 1:
                enemy.shoot()
            if Actions.collision(world_state['Player'], enemy):
                # print('Enemy collided with Player!')
                world_state['Player'].health -= 10
                world_state['Enemies'].remove(enemy)
            elif enemy.y + enemy.height() > HEIGHT:
                lives -= 1
                world_state['Enemies'].remove(enemy)

        # Throw in a medikit
        if len(world_state['MediKits']) <= 3:
            if random.randrange(0, 600) == 1: # circa once in 30 seconds
                medikit = Medikit(
                    x=random.randrange(200, WIDTH - 200),
                    y=random.randrange(200, HEIGHT - 200)
                )
                world_state['MediKits'].append(medikit)
        for medikit in world_state['MediKits'][:]:
            medikit.cooldown_counter += 1
            if Actions.collision(world_state['Player'],medikit):
                world_state['Player'].health += 10
                world_state['MediKits'].remove(medikit)
                SOUNDS['HealthPickup'].play()
            elif medikit.cooldown_counter >= medikit.cooldown_limit:
                world_state['MediKits'].remove(medikit)

        # Move Player lasers and detect collisions
        for laser in world_state['PlayerLasers']:
            Actions.move(laser, laser_velocity, 'up')
            for enemy in world_state['Enemies']: # Detect collision
                if Actions.collision(laser, enemy):
                    # print("Player hit an Enemy!")
                    world_state['PlayerLasers'].remove(laser)
                    world_state['Enemies'].remove(enemy)
                    SOUNDS['DirectHit'].play()
                    continue
            if laser.y <= 0:
                # print('One of the Players Lasers is off-screen!')
                try:
                    world_state['PlayerLasers'].remove(laser)
                except:
                    pass

        # Move Enemy lasers
        for laser in world_state['EnemyLasers']:
            Actions.move(laser, laser_velocity, 'down')
            if Actions.collision(laser, world_state['Player']):
                # print("Player-Laser collision detected!")
                world_state['Player'].health -= 10
                world_state['EnemyLasers'].remove(laser)
                SOUNDS['YouGotHit'][random.randint(0,1)].play()
            elif laser.y >= HEIGHT:
                # print("Enemy Laser off screen")
                world_state['EnemyLasers'].remove(laser)

def main_menu():
    title_font = pygame.font.SysFont("comicsans", 70)
    run = True
    while run:
        WIN.blit(BG, (0,0))
        title_label = title_font.render(
            "Press the mouse button to begin",
            1,
            (255,255,255)
        )

        WIN.blit(title_label, (WIDTH/2 - title_label.get_width()/2, 350))

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
            if event.type == pygame.MOUSEBUTTONDOWN:
                main()
    pygame.quit()

main_menu()