# -*- coding: utf-8 -*-
# /***************************************************************************/
# * __________________________________
# * METIS CYBERSPACE TECHNOLOGY S.A.
# * www.metis.tech
# * __________________________________
# * [2019] All Rights Reserved.
# *
# * NOTICE:  All information contained herein is, and remains
# * the property of Metis CyberSpace Technology and its suppliers,
# * if any.  The intellectual and technical concepts contained
# * herein are proprietary to METIS CYBERSPACE TECHNOLOGY
# * and its suppliers and may be covered by European and Foreign Patents,
# * patents in process, and are protected by trade secret or copyright law.
# * Dissemination of this information or reproduction of this material
# * is strictly forbidden unless prior written permission is obtained
# * from Metis Cyberspace Technology.
#
# /***************************************************************************/
#
# Created Date: Friday April 5th 2019
# Author: Vassilis Lemonidis
"""Module that holds class that fixes document orientation
"""

import cv2
import numpy as np
from ImageProcessing import IMPROC_CONFIG
from ImageProcessing import DEBUG_CONFIG
import ImageProcessing.Debugging.operations as dbg
from ImageProcessing.GeometricalTransformations.operations import rotate
from Model.BasicObjects import GrayscaleGraphic

class RotationCanceller:
    '''
    Fixes given image rotation
    '''

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.min_angle = IMPROC_CONFIG['min_accepted_angle']

    def run(self, struct):  # @IgnorePep8 pylint: disable=unused-argument
        '''
        Rotates image based on each contents orientation
        '''
        _, contours, _ = cv2.findContours(struct.binary.any.astype(np.uint8),
                                          cv2.RETR_EXTERNAL,
                                          cv2.CHAIN_APPROX_SIMPLE)
        if not contours:
            return struct.img, 0
        massive_contour = np.array([point for contour in contours for
                                    point in contour])
        hull = cv2.convexHull(massive_contour)
        rect = cv2.minAreaRect(
            hull)
        (p_x, p_y), _, angle = rect
        if DEBUG_CONFIG.visualize_rotation_canceller:
            img = np.zeros_like(struct.binary.any).astype(np.uint8)
            cv2.drawContours(img, [hull], 0, 1, 3)

            box = cv2.boxPoints(rect)
            box = np.int0(box)
            box_img = np.zeros_like(struct.binary.any).astype(np.uint8)
            cv2.drawContours(box_img, [box],0, 1 , 3)
            dbg.imshow(np.concatenate((struct.binary.any.astype(np.uint8)[:, :, None],
                                       img[:, :, None],
                                       box_img[:, :, None]), axis=2),
                                       'Image with convex hull used to cancel rotation')

        if angle < -45:
            angle = 90 + angle
        elif angle > 45:
            angle = angle - 90
        if abs(angle) < self.min_angle:
            return struct.img, 0
        return GrayscaleGraphic(rotate(struct.binary.all, angle, (p_x, p_y))), angle


vowels = "aiueo"
ip_str = "Halo nama saya Seviko Attalarik Pramayudha Handoko saya sedang belajar python"
ip_str = ip_str.casefold()

count = {}.fromkeys(vowels, 0)

for char in ip_str :
    if char in count:
        count[char] += 1

print(count)


"""Tests for Crossref.licenses"""
import os
import vcr
from habanero import Crossref

cr = Crossref()

@vcr.use_cassette("test/vcr_cassettes/licenses.yaml")
def test_licenses():
    "licenses - basic test"
    res = cr.licenses()
    assert dict == res.__class__
    assert 130 < len(res["message"]["items"])

@vcr.use_cassette("test/vcr_cassettes/licenses_query.yaml")
def test_licenses_query():
    "licenses - param: query - doesn't do anything without works"
    res = cr.licenses(query="aps")
    assert {u"search-terms": u"aps", u"start-index": 0} == res["message"]["query"]


from flask import Flask, request, abort, jsonify
from linebot import (LineBotApi, WebhookHandler)
from linebot.exceptions import (InvalidSignatureError)
from linebot.models import (MessageEvent, TextMessage, TextSendMessage,)
from flask.logging import create_logger
import requests
import json
import datetime, pytz
tz = pytz.timezone('Asia/Bangkok')

app = Flask(__name__)
LOG = create_logger(app)

line_bot_api = LineBotApi('THIS IS A SECRET')
handler = WebhookHandler('THIS IS A SECRET')

@app.route("/")
def hello():
    return "Hello World"

def date_now():
    now1 = datetime.datetime.now(tz)
    month_name = 'x มกราคม กุมภาพันธ์ มีนาคม เมษายน พฤษภาคม มิถุนายน กรกฎาคม สิงหาคม กันยายน ตุลาคม พฤศจิกายน ธันวาคม'.split()[now1.month]
    thai_year = now1.year + 543
    time_str = now1.strftime('%H:%M:%S')
    return "%d %s %d %s"%(now1.day, month_name, thai_year, time_str) # 30 ตุลาคม 2560 20:45:30

# for test
@app.route("/test")
def test():
    r = requests.get(
      'https://bx.in.th/api/')
    data = r.json()
    command = "acn"
    today = date_now()
    message = "ข้อมูลปัจจุบัน ณ เวลา " + today + "\n"
    if command == "tcn":
        filterData = [v for v in data.values() if "THB" in v.values()]
        for value in sorted(filterData, key = lambda name: name['pairing_id']):
            message += str(value['pairing_id']) + ": " + value['primary_currency'] + " to " + value['secondary_currency'] + " = " + str(value['last_price']) + "\n"
    elif command == "acn":
        for value in sorted(data.values(), key = lambda name: name['pairing_id']):
            message += str(value['pairing_id']) + ": " + value['primary_currency'] + " to " + value['secondary_currency'] + " = " + str(value['last_price']) + "\n"
    # for key, value in sort_data:
    # return jsonify(r.json())
    print(message)
    return "ok"

@app.route("/webhook", methods=['POST'])
def webhook():
    # get X-Line-Signature header value
    signature = request.headers['X-Line-Signature']

    # get request body as text
    body = request.get_data(as_text=True)
    LOG.debug("Request body: " + body)

    # handle webhook body
    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        abort(400)

    return 'OK'

@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    r = requests.get(
      'https://bx.in.th/api/')
    data = r.json()
    command = event.message.text
    today = date_now()
    message = "ข้อมูลปัจจุบัน ณ เวลา " + today + "\n"
    if command == "tcn":
        filterData = [v for v in data.values() if "THB" in v.values()]
        for value in sorted(filterData, key = lambda name: name['pairing_id']):
            message += str(value['pairing_id']) + ": " + value['primary_currency'] + " to " + value['secondary_currency'] + " = " + str(value['last_price']) + "\n"
    elif command == "acn":
        for value in sorted(data.values(), key = lambda name: name['pairing_id']):
            message += str(value['pairing_id']) + ": " + value['primary_currency'] + " to " + value['secondary_currency'] + " = " + str(value['last_price']) + "\n"
    elif command == "รักเค้าไหม":
        message = "รักดิมากด้วย <3"
    elif command == "ตอแหลไหม":
        message = "มากที่สุดเหมือนกัน :)"
    else:
        message = "ไม่มีคำสั่งที่คุณพิมพ์มาตอนนี้เรามีแค่\n1.acn (all crypto now)\n2.tcn(thai crypto now)"
    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=message))

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


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

from __future__ import print_function

import uuid
import pytest
from conditional import conditional
from mock import call, MagicMock

from mlt.commands.deploy import DeployCommand
from test_utils.io import catch_stdout

@pytest.fixture
def sleep(patch):
    return patch('time.sleep')

@pytest.fixture
def call_logs(patch):
    return patch('log_helpers.call_logs')

@pytest.fixture
def fetch_action_arg(patch):
    return patch('files.fetch_action_arg', MagicMock(return_value='output'))

@pytest.fixture
def kube_helpers(patch):
    return patch('kubernetes_helpers')

@pytest.fixture
def json_mock(patch):
    return patch('json')

@pytest.fixture
def open_mock(patch):
    return patch('open')

# PROCESS_HELPERS MOCKS

@pytest.fixture(autouse=True)
def process_helpers_mock(patch):
    # mock every outside process generally, specific mocks below
    return patch('process_helpers')

@pytest.fixture
def run_popen_mock(patch):
    run_popen_mock = MagicMock()
    run_popen_mock.return_value.poll.return_value = 0
    return patch('process_helpers.run_popen', run_popen_mock)

@pytest.fixture
def process_helpers_run_mock(patch):
    run_mock = MagicMock(side_effect=SystemExit)
    # want to test that kubectl apply failed
    return patch('process_helpers.run', run_mock)

# END PROCESS_HELPERS MOCKS

@pytest.fixture
def progress_bar(patch):
    progress_mock = MagicMock()
    progress_mock.duration_progress.side_effect = lambda x, y, z: print(
        'Pushing ')
    return patch('progress_bar', progress_mock)

@pytest.fixture
def template(patch):
    return patch('Template')

@pytest.fixture
def verify_build(patch):
    return patch('build_helpers.verify_build')

@pytest.fixture
def verify_init(patch):
    return patch('config_helpers.load_config')

@pytest.fixture
def subprocess_mock(patch):
    return patch('check_output')

@pytest.fixture
def walk_mock(patch):
    return patch('os.walk', MagicMock(return_value=['foo', 'bar']))

@pytest.fixture
def yaml(patch):
    return patch('yaml.load')

@pytest.fixture
def get_sync_spec_mock(patch):
    return patch('sync_helpers.get_sync_spec')

@pytest.fixture
def is_custom_mock(patch):
    return patch('files.is_custom')

def deploy(no_push, skip_crd_check, interactive, extra_config_args, retries=5,
           template='test', logs=False, verbose=False, catch_exception=None):
    deploy = DeployCommand(
        {'deploy': True, '--no-push': no_push,
         '--skip-crd-check': skip_crd_check,
         '--interactive': interactive, '--retries': retries,
         '--logs': logs, '--verbose': verbose})
    deploy.config = {'name': 'app',
                     'namespace': 'namespace',
                     'template': template}

    deploy.config.update(extra_config_args)

    with catch_stdout() as caught_output:
        with conditional(catch_exception, pytest.raises(catch_exception)):
            deploy.action()
        output = caught_output.getvalue()
    return output

def verify_successful_deploy(output, did_push=True, interactive=False,
                             pod_count=2, verbose=False):
    """assert pushing, deploying, then objs created, then pushed"""
    pushing = output.find('Pushing ')
    push_skip = output.find('Skipping image push')
    deploying = output.find('Deploying ')
    inspecting = output.find('Inspect created objects by running:\n')
    pushed = output.find('Pushed app to ')
    if pod_count == 1:
        pod_connect = output.find('Connecting to pod...')
    else:
        pod_connect = output.find('watch until pods are `Running`')

    if did_push:
        # we don't print `pushing ####` stuff in `verbose` mode
        if not verbose:
            assert all(var >= 0 for var in (
                deploying, inspecting, pushing, pushed))
            assert deploying < inspecting, pushing < pushed
        else:
            assert all(var >= 0 for var in (
                deploying, inspecting, pushed))
            assert deploying < inspecting, pushed < deploying
    else:
        assert all(var == -1 for var in (pushing, pushed))
        assert all(var >= 0 for var in (deploying, inspecting, push_skip))
        assert push_skip < deploying, deploying < inspecting

    if interactive:
        assert pod_connect > inspecting

@pytest.mark.parametrize("sync_spec", [
    None, 'hello-world'])
@pytest.mark.parametrize("registry", [
    'gcr://projectfoo', 'dockerhub'])
@pytest.mark.parametrize("skip_crd_check", [
    True, False])
@pytest.mark.parametrize("logs", [
    True, False])
@pytest.mark.parametrize("verbose", [
    True, False])
def test_deploy(walk_mock, call_logs, progress_bar, run_popen_mock, open_mock,
                template, kube_helpers, verify_build,
                verify_init, fetch_action_arg, json_mock, get_sync_spec_mock,
                sync_spec, registry, skip_crd_check, logs, verbose):
    """Tests a successful deploy with and without sync_spec, 2 different
       registry types, skipping and not skipping crd_check, and log tailing
    """
    get_sync_spec_mock.return_value = sync_spec
    json_mock.load.return_value = {
        'last_remote_container': 'gcr.io/app_name:container_id',
        'last_push_duration': 0.18889}
    output = deploy(
        no_push=False, skip_crd_check=skip_crd_check,
        interactive=False, logs=logs, verbose=verbose,
        extra_config_args={'registry': registry})
    verify_successful_deploy(output, verbose=verbose)

def test_deploy_without_push(walk_mock, progress_bar, run_popen_mock,
                             open_mock, template, kube_helpers,
                             verify_build, verify_init, fetch_action_arg,
                             json_mock):
    json_mock.load.return_value = {
        'last_remote_container': 'gcr.io/app_name:container_id',
        'last_push_duration': 0.18889}
    output = deploy(
        no_push=True, skip_crd_check=True,
        interactive=False,
        extra_config_args={'registry': 'gcr://projectfoo'})
    verify_successful_deploy(output, did_push=False)

def test_deploy_interactive_one_file(walk_mock, progress_bar, run_popen_mock,
                                     open_mock, template, kube_helpers,
                                     verify_build,
                                     verify_init, fetch_action_arg, sleep,
                                     yaml, json_mock):
    walk_mock.return_value = ['foo']
    yaml.return_value = {
        'template': {'foo': 'bar'}, 'containers': [{'foo': 'bar'}]}
    json_mock.loads.return_value = {'status': {'phase': 'Running'}}
    output = deploy(
        no_push=False, skip_crd_check=True,
        interactive=True,
        extra_config_args={'registry': 'dockerhub'})
    verify_successful_deploy(output, interactive=True, pod_count=1)

    # verify that kubectl commands are specifying namespace
    for call_args in run_popen_mock.call_args_list:
        assert isinstance(call_args, type(call))
        assert isinstance(call_args[0], tuple)
        assert len(call_args[0]) > 0
        command = call_args[0][0]
        if command[0] == "kubectl":
            assert "--namespace" in command

def test_deploy_interactive_two_files(walk_mock, progress_bar, run_popen_mock,
                                      open_mock, template, kube_helpers,
                                      verify_build,
                                      verify_init, fetch_action_arg, sleep,
                                      yaml, json_mock):
    json_mock.loads.return_value = {'status': {'phase': 'Running'}}
    yaml.return_value = {
        'template': {'foo': 'bar'}, 'containers': [{'foo': 'bar'}]}
    output = deploy(
        no_push=False, skip_crd_check=True,
        interactive=True,
        extra_config_args={'registry': 'dockerhub'})
    verify_successful_deploy(output, interactive=True)

def test_deploy_interactive_pod_not_run(walk_mock, progress_bar,
                                        run_popen_mock,
                                        process_helpers_run_mock,
                                        open_mock, template, kube_helpers,
                                        verify_build,
                                        verify_init, fetch_action_arg, sleep,
                                        yaml, json_mock):
    json_mock.loads.return_value = {'status': {'phase': 'Error'}}
    yaml.return_value = {
        'template': {'foo': 'bar'}, 'containers': [{'foo': 'bar'}]}
    with pytest.raises(SystemExit):
        deploy(
            no_push=False, skip_crd_check=True,
            interactive=True,
            extra_config_args={'registry': 'dockerhub'})

def test_deploy_update_app_run_id(open_mock, json_mock):
    run_id = str(uuid.uuid4())
    json_mock_data = {
        'last_remote_container': 'gcr.io/app_name:container_id',
        'last_push_duration': 0.18889}
    json_mock.load.return_value = json_mock_data

    DeployCommand._update_app_run_id(run_id)

    assert json_mock_data['app_run_id'] == run_id

def test_image_push_error(walk_mock, progress_bar, run_popen_mock, open_mock,
                          template, kube_helpers,
                          verify_build, verify_init, fetch_action_arg,
                          json_mock):
    json_mock.load.return_value = {
        'last_remote_container': 'gcr.io/app_name:container_id',
        'last_push_duration': 0.18889}

    # setup mock to induce and error during the deploy
    run_popen_mock.return_value.poll.return_value = 1
    output_str = "normal output..."
    error_str = "error message..."
    build_output = MagicMock()
    build_output.decode.return_value = output_str
    error_output = MagicMock()
    error_output.decode.return_value = error_str
    run_popen_mock.return_value.communicate.return_value = (build_output,
                                                            error_output)

    output = deploy(
        no_push=False, skip_crd_check=True, interactive=False,
        extra_config_args={'registry': 'gcr://projectfoo'},
        catch_exception=SystemExit)

    # assert that we got the normal output, followed by the error message
    output_location = output.find(output_str)
    error_location = output.find(error_str)
    assert all(var >= 0 for var in (output_location, error_location))
    assert output_location < error_location

def test_no_image_found_error(walk_mock, progress_bar, run_popen_mock,
                              open_mock, template, kube_helpers,
                              verify_build, verify_init, fetch_action_arg,
                              json_mock):
    """if we don't have remote_container_name during deploy_new_container
       then throw ValueError
    """
    get_sync_spec_mock.return_value = None
    fetch_action_arg.side_effect = [None, None, None]
    json_mock.load.return_value = {
        'last_remote_container': 'gcr.io/app_name:container_id',
        'last_push_duration': 0.18889}
    deploy(
        no_push=True, skip_crd_check=True, interactive=False,
        extra_config_args={'registry': 'gcr://projectfoo'},
        catch_exception=ValueError)

def test_deploy_custom_deploy(walk_mock, progress_bar, run_popen_mock,
                              open_mock, template, kube_helpers,
                              subprocess_mock, verify_build, is_custom_mock,
                              verify_init, fetch_action_arg, json_mock, ):
    json_mock.load.return_value = {
        'last_remote_container': 'gcr.io/app_name:container_id',
        'last_push_duration': 0.18889}
    expected_output = "Updating configmaps\n" \
                      "Creating non-existent configmaps\n" \
                      "Updating services\n" \
                      "Creating non-existent services\n" \
                      "Updating serviceaccounts\n" \
                      "Creating non-existent serviceaccounts\n" \
                      "Updating clusterrolebindings\n" \
                      "Creating non-existent clusterrolebindings\n" \
                      "Updating pods\n" \
                      "Creating non-existent pods\n"
    subprocess_mock.return_value.decode.return_value = expected_output
    is_custom_mock.return_value = True
    output = deploy(
        no_push=False, skip_crd_check=True,
        interactive=False,
        extra_config_args={'registry': 'gcr://projectfoo',
                           "template_parameters": {
                               "gpus": 0,
                               "num_workers": 1}})
    verify_successful_deploy(output)
    assert expected_output in output

def test_deploy_custom_deploy_interactive(walk_mock, progress_bar,
                                          run_popen_mock, open_mock, template,
                                          kube_helpers, subprocess_mock,
                                          verify_build, is_custom_mock,
                                          verify_init, fetch_action_arg,
                                          json_mock, yaml):
    json_mock.load.return_value = {
        'last_remote_container': 'gcr.io/app_name:container_id',
        'last_push_duration': 0.18889}
    is_custom_mock.return_value = True
    json_mock.loads.return_value = {'status': {'phase': 'Running'}}
    yaml.return_value = {
        'template': {'foo': 'bar'}, 'containers': [{'foo': 'bar'}]}
    output = deploy(
        no_push=False, skip_crd_check=True,
        interactive=True,
        extra_config_args={'registry': 'gcr://projectfoo',
                           "template_parameters": {
                               "gpus": 0,
                               "num_workers": 1}})
    verify_successful_deploy(output, interactive=True)


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

# In[2]:

import torch

# # Neural Networks

# * El uso de funciones de activacion no lineares como la diferencia clave entre modelos lineales
# * Los diferentes tipos de funciones de activacion
# * El modulo `nn` de PyTorch que contiene los bloques para construir NNs
# * Resolver un problema simple de un _fit_ lineal con una NN

# ## Neuronas artificiales
#
# * Neural networks: entidades matematicas capaces de representar funciones complicadas a traves de una composicion de funciones mas simples.
# * Originalmente inspiradas por la forma en la que funciona nuestro cerebro.
# * El bloque de construccion basico es una neurona:
#     * Esencialmente una transformacion linear del input (e.g. multiplicacion del input por un numero, el _weight_, y la suma de una constante, el _bias_.
#     * Seguido por la aplicacion de una funcion no lineal (referida como la funcion de activacion)
#     * $o = f(w x + b)$
#     * x es nuestro input, w el _weight_ y b el _bias_. $f$ es la funcion de activacion.
#     * x puede ser un escalar o un vector de valores, w puede ser un escalar o una matriz, mientras que b es un escalar o un vector.
# * La expresion $o = f(w x + b)$ es una capa de neuronas, ya que representa varias neuronas a traves de los _weights_ y _bias_ multidimensionales

# $x_1 = f(w_0 x_0 + b_0)$
#
# $x_2 = f(w_1 x_1 + b_1)$
#
# $...$
#
# $y = f(w_n x_n + b_n)$

# ### **dibujos**

# ## Funciones de activacion

# * Nuestro modelo anterior ya tenia una operacion lineal. Eso era el modelo entero.
# * El rol de la funcion de activacion es concentrar los _outputs_ de la operacion lineal precedente a un rango dado.
# * Si queremos asignar un _score_ al output del modelo necesitamos limitar el rango de numeros posibles para ese _score_
#     * `float32`
#     * $\sum wx + b$

# ### Que opciones tenemos?

# * Una opcion seria ponerle un limite a los valores del _output_.
#     * Cualquier cosa debajo de cero seria cero
#     * cualquier cosa arriba de 10 seria 10
#     * `torch.nn.Hardtanh`

# In[3]:

import math

math.tanh(-2.2) # camion

# In[4]:

math.tanh(0.1) # oso

# In[5]:

math.tanh(2.5) # perro

# ![Funciones de activacion](../assets/activaciones.png)

# * Hay muchas funciones de activacion.
# * Por definicion, las funciones de activacion:
#     * Son no lineales. Aplicaciones repetidas de $wx+b$ sin una funcion de activacion resultan en una polinomial. La no linealidad permite a la red aproximar funciones mas complejas.
#     * Son diferenciables, para poder calcular las gradientes a traves de ellas. Discontinuidades de punto como en `Hatdtanh` o `ReLU` son validas.
# * Sin esto, las redes caen a ser polinomiales complicadas o dificiles de entrenar.
# * Adicionalmente, las funciones:
#     * Tienen al menos un rango sensible, donde cambios no triviales en el input resultan en cambio no trivial correspondiente en el output
#     * Tienen al menos un rango no sensible (o saturado), donde cambios al input resultan en poco o ningun cambio en el output.
# * Por utlimo, las fuciones de activacion tienen al menos una de estas:
#     * Un limite inferior que se aproxima (o se encuentra) mientras el input tiende a negativo infinito.
#     * Un limite superior similar pero inverso para positivo infinito.
# * Dado lo que sabemos de como funciona back-propagation
#     * Sabemos que los errores se van a propagar hacia atras a traves de la activacion de manera mas efectiva cuando los inputs se encuentran dentro del rango de respuesta.
#     * Por otro lado, los errores no van a afectar a las neuornas para cuales el _input_ esta saturado debido a que la gradiente estara cercana a cero.

# ### En conclusion
#
# * En una red hecha de unidades lineales + activaciones, cuando recibe diferentes _inputs_:
#     * diferentes unidades van a responder en diferentes rangos para los mismos inputs
#     * los errores asociados a esos inputs van a afectar a las neuronas operancio en el rango sensible, dejando a las otras unidades mas o menos igual en el proceso de aprendizaje.
# * Juntar muchas operaciones lineales + unidades de activacion en paralelo y apilandolas una sobre otra nos provee un objeto matematico capaz de aproximar funciones complicadas.
# * Diferentes combinaciones de unidades van a responder a inputs en diferentes rangos
#     * Esos parametros son relativamente faciles de optimizar a traves de SGD

# ### Dibujo graficas computacionales separadas

# In[7]:

import torch.nn as nn

linear_model = nn.Linear(1, 1)
linear_model(val_t_un)

# Todas las subclases de `nn.Module` tienen un metodo `call` definido. Esto permite crear una instancia de `nn.Linear` y llamarla como si fuera una funcion.
#
# Llamar una instancia de `nn.Module` con un conjunto de argumetnos termina llamando un metodo llamado `forward` con esos mismos argumentos

# ### Implementacion de `Module.call`
#
# (simplificado para claridad)

# In[8]:

def __call__(self, *input, **kwargs):
    for hook in self._forward_pre_hooks.values():
        hook(self, input)

    result = self.forward(*input, **kwargs)

    for hook in self._forward_hooks.values():
        hook_result = hook(self, input, result)
        # ...

    for hook in self._backward_hooks.values():
        # ...

        return result

# ### De regreso al modelo lineal

# In[9]:

import torch.nn as nn

linear_model = nn.Linear(1, 1)
linear_model(val_t_un)

# `nn.Linear` acepta tres argumentos:
# * el numero de input features: size del input = 1
# * numero de output features: size del outpu = 1
# * si incluye un bias o no (por default es `True`)

# In[10]:

linear_model.weight

# In[11]:

linear_model.bias

# In[12]:

x = torch.ones(1)
linear_model(x)

# * Nuestro modelo toma un input y produce un output
# * `nn.Module` y sus subclases estan diseniados para hacer eso sobre multiples muestras al mismo tiempo
# * Para acomodar multiples muestras los modulos esperan que la dimension 0 del input sea el numero de muestras en un _batch_
# * Cualquier module en `nn` esta hecho para producir outputs para un _batch_ de multiples inputs al mismo tiempo.
# * B x Nin
#     * B es el tamanio del _batch_
#     * Nin el numero de input features

# In[13]:

x = torch.ones(10, 1)
linear_model(x)

# Para un dataset de imagenes:
# * BxCxHxW

# In[14]:

t_c.size()

# In[6]:

t_c = [0.5, 14.0, 15.0, 28.0, 11.0, 8.0, 3.0, -4.0, 6.0, 13.0, 21.0] # Temperatura en grados celsios
t_u = [35.7, 55.9, 58.2, 81.9, 56.3, 48.9, 33.9, 21.8, 48.4, 60.4, 68.4] # Unidades desconocidas
t_c = torch.tensor(t_c).unsqueeze(1) # Agregamos una dimension para tener B x N_inputs
t_u = torch.tensor(t_u).unsqueeze(1) # Agregamos una dimension para tener B x N_inputs

n_samples = t_u.shape[0]
n_val = int(0.2 * n_samples)

shuffled_indices = torch.randperm(n_samples)

train_indices = shuffled_indices[:-n_val]
val_indices = shuffled_indices[-n_val:]

train_t_u = t_u[train_indices]
train_t_c = t_c[train_indices]

val_t_u = t_u[val_indices]
val_t_c = t_c[val_indices]

train_t_un = 0.1 * train_t_u
val_t_un = 0.1 * val_t_u

# In[15]:

import torch.nn as nn
import torch.optim as optim

params_old = torch.tensor([1.0, 0.0], requires_grad=True)
learning_rate_old = 1e-1
optimizer_old = optim.Adam([params_old], lr=learning_rate_old)

linear_model = nn.Linear(1, 1)
optimizer = optim.SGD(
    linear_model.parameters(), # reemplazamos [params] con este metodo
    lr=1e-2)

# ### linear_model.parameters()

# In[16]:

list(linear_model.parameters())

# In[17]:

def training_loop(model, n_epochs, optimizer, loss_fn, train_x, val_x, train_y, val_y):
    for epoch in range(1, n_epochs + 1):
        train_t_p = model(train_x) # ya no tenemos que pasar los params
        train_loss = loss_fn(train_t_p, train_y)

        with torch.no_grad(): # todos los args requires_grad=False
            val_t_p = model(val_x)
            val_loss = loss_fn(val_t_p, val_y)

        optimizer.zero_grad()
        train_loss.backward()
        optimizer.step()

        if epoch == 1 or epoch % 1000 == 0:
            print(f"Epoch {epoch}, Training loss {train_loss}, Validation loss {val_loss}")

# In[18]:

linear_model = nn.Linear(1, 1)
optimizer = optim.SGD(linear_model.parameters(), lr=1e-2)

training_loop(
    n_epochs=3000,
    optimizer=optimizer,
    model=linear_model,
    loss_fn=nn.MSELoss(), # Ya no estamos usando nuestra loss function hecha a mano
    train_x = train_t_un,
    val_x = val_t_un,
    train_y = train_t_c,
    val_y = val_t_c)

print()
print(linear_model.weight)
print(linear_model.bias)

# ## Finalmente un Neural Network

# * Ultimo paso: reemplazar nuestro modelo lineal
# * No va a ser mejor
# * Lo unico que vamos a cambiar va a ser el modelo
# * Un simple NN:
#     * Una capa lineal
#     * Activacion
#     * "hidden layers"

# In[19]:

seq_model = nn.Sequential(
                nn.Linear(1, 13), # El 13 es arbitrario
                nn.Tanh(),
                nn.Linear(13, 1) # Este 13 debe hacer match con el primero
            )

seq_model

# * El resultado final es un modelo que toma los inputs esperados por el primer modulo (_layer_)
# * Pasa los outputs intermedios al resto de los modulos
# * Produce un output retornado por el ultimo modulo

# In[20]:

[param.size() for param in seq_model.parameters()]

# * Estos son los parametros que el optimizador va a recibir
# * Al llamar `backward()` todos los parametros se van a llenar con su `grad`
# * El optimizador va a actualizar el valor de `grad` durante `optimizer.step()`

# In[21]:

for name, param in seq_model.named_parameters():
    print(name, param.size())

# In[22]:

from collections import OrderedDict

named_seq_model = nn.Sequential(OrderedDict([
        ('hidden_linear', nn.Linear(1, 8)),
        ('hidden_activation', nn.Tanh()),
        ('output_linear', nn.Linear(8, 1))
]))

seq_model

# In[23]:

for name, param in named_seq_model.named_parameters():
    print(name, param.size())

# In[24]:

named_seq_model.output_linear.bias

# Util para inspeccionar parametros o sus gradientes.

# In[ ]:

optimizer = optim.SGD(seq_model.parameters(), lr=1e-3)

training_loop(
    n_epochs=5000,
    optimizer=optimizer,
    model=seq_model,
    loss_fn=nn.MSELoss(), # Ya no estamos usando nuestra loss function hecha a mano
    train_x = train_t_un,
    val_x = val_t_un,
    train_y = train_t_c,
    val_y = val_t_c)

print('output', seq_model(val_t_un))
print('answer', val_t_c)
print('hidden', seq_model.hidden_linear.weight.grad)

start = torch.cuda.Event(enable_timing=True)
end = torch.cuda.Event(enable_timing=True)

start.record()
z = x + y
end.record()

# Waits for everything to finish running
torch.cuda.synchronize()

print(start.elapsed_time(end))

# Tambien podemos evaluar el modelo en toda la data y ver que tan diferente es de una linea:

# In[26]:

from matplotlib import pyplot as plt

t_range = torch.arange(20., 90.).unsqueeze(1)

fig = plt.figure(dpi=600)
plt.xlabel("Fahrenheit")
plt.ylabel("Celsius")
plt.plot(t_u.numpy(), t_c.numpy(), 'o')
plt.plot(t_range.numpy(), seq_model(0.1 * t_range).detach().numpy(), 'c-')
plt.plot(t_u.numpy(), seq_model(0.1 * t_u).detach().numpy(), 'kx')
plt.show()

# ## Subclassing nn.Module
#
# * sublcassing `nn.Module` nos da mucha mas flexibilidad.
# * La interface especifica que como minimo debemos definir un metodo `forward` para la subclase
#     * `forward` toma el input al model y regresa el output
# * Si usamos las operaciones de `torch`, `autograd` se encarga de hacer el `backward` pass de forma automatica
#
# * Normalmente vamos a definir los submodulos que usamos en el metodo `forward` en el constructor
#     * Esto permite que sean llamados en `forward` y que puedan mantener sus parametros a durante la existencia de nuestro modulo

# In[27]:

class SubclassModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.hidden_linear = nn.Linear(1, 13)
        self.hidden_activation = nn.Tanh()
        self.output_linear = nn.Linear(13, 1)

    def forward(self, input):
        hidden_t = self.hidden_linear(input)
        activated_t = self.hidden_activation(hidden_t)
        #activated_t = self.hidden_activation(hidden_t) if random.random() > 0.5 else hidden_t
        output_t = self.output_linear(activated_t)

        return output_t

subclass_model = SubclassModel()
subclass_model

# * Nos permite manipular los outputs de forma directa  y transformarlo en un tensor BxN
# * Dejamos la dimension de batch como -1 ya que no sabemos cuantos inputs van a venir por batch

# * Asignar una instancia de `nn.Module` a un atributo en un `nn.Module` registra el modulo como un submodulo.
# * Permite a `Net` acceso a los `parameters` de sus submodulos sin necesidad de hacerlo manualmente

# In[28]:

numel_list = [p.numel() for p in subclass_model.parameters()]
sum(numel_list), numel_list

# **Lo que paso**
#
# * `parameters()` investiga todos los submodulos asignados como atributos del constructor y llama `parameters` de forma recursiva.
# * Al accesar su atributo `grad`, el cual va a ser llenado por el `autograd`, el optimizador va a saber como cambiar los parametros para minimizar el _loss_

# In[29]:

for type_str, model in [('seq', seq_model), ('named_seq', named_seq_model), ('subclass', subclass_model)]:
    print(type_str)
    for name_str, param in model.named_parameters():
        print("{:21} {:19} {}".format(name_str, str(param.shape), param.numel()))

    print()

# In[30]:

class SubclassFunctionalModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.hidden_linear = nn.Linear(1, 14)
        self.output_linear = nn.Linear(14, 1)

    def forward(self, input):
        hidden_t = self.hidden_linear(input)
        activated_t = torch.tanh(hidden_t)
        output_t = self.output_linear(activated_t)

        return output_t

func_model = SubclassFunctionalModel()
func_model

# ## Ejercicios

# * Experimenten con el numero de neuronas en el modelo al igual que el learning rate.
#     * Que cambios resultan en un output mas lineal del modelo?
#     * Pueden hacer que el modelo haga un overfit obvio de la data?
#
# * Cargen la [data de vinos blancos](https://archive.ics.uci.edu/ml/datasets/wine+quality) y creen un modelo con el numero apropiado de inputs
#     * Cuanto tarda en entrenar comparado al dataset que hemos estado usando?
#     * Pueden explicar que factores contribuyen a los tiempos de entrenamiento?
#     * Pueden hacer que el _loss_ disminuya?
#     * Intenten graficar la data

# In[84]:

import time

start = time.time()
seq_model = nn.Sequential(
                nn.Linear(1, 3000),
                nn.Tanh(),
                nn.Linear(3000, 1) #
            )

optimizer = optim.SGD(seq_model.parameters(), lr=1e-4)

training_loop(
    n_epochs=9000,
    optimizer=optimizer,
    model=seq_model,
    loss_fn=nn.MSELoss(), # Se utiliza la función pytorch, no la generada manualmente
    train_x = train_t_un,
    val_x = val_t_un,
    train_y = train_t_c,
    val_y = val_t_c)

end = time.time()
print(end - start)

# # Experimentando con el numero de neuronas en el modelo al igual que el learning rate.
# ### Que cambios resultan en un output mas lineal del modelo?
#
# A un mayor número de repeticiones y neuronas la función de perdida reduce su tamaño, para lo cual se le atribuye mayor exactitud a un aumento del número de neuronas. Un numero de learning rate muy pequeño puede no implicar mejoras significativas, sin embargo el mejor resultado en la función loss se observa en el nivel 1e-4 debido a que cualquier denotación mayor no implicaba un aporte al modelo.
#
#
#
# ### Pueden hacer que el modelo haga un overfit obvio de la data?
#
# Un overfit obvio se puede generar al crear demasiadas neuronas y al fijar el learning rate en el monto más alto permitido
#

# In[62]:

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split

# In[63]:

whine_df = pd.read_csv("winequality-white.csv", sep=";")
whine_df.head()

# In[65]:

corr = whine_df.corr()

corr

# In[74]:

X = whine_df['alcohol']
y = whine_df['quality']

# In[75]:

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=42)

# In[76]:

X_train = np.array(X_train)
X_test = np.array(X_test)
y_train = np.array(y_train)
y_test = np.array(y_test)

X_train = torch.tensor(X_train).unsqueeze(1)
X_test = torch.tensor(X_test).unsqueeze(1)
y_train = torch.tensor(y_train).unsqueeze(1)
y_test = torch.tensor(y_test).unsqueeze(1)

# In[83]:

import time

start = time.time()
seq_model = nn.Sequential(
                nn.Linear(1, 1000),
                nn.Tanh(),
                nn.Linear(1000, 1)
            )

optimizer = optim.SGD(seq_model.parameters(), lr=1e-4)

training_loop(
    n_epochs=5000,
    optimizer=optimizer,
    model=seq_model,
    loss_fn=nn.MSELoss(),
    train_x = X_train.float(),
    val_x = X_test.float(),
    train_y = y_train.float(),
    val_y = y_test.float())

end = time.time()
print(end - start)

# ## Cuanto tarda en entrenar comparado al dataset que hemos estado usando?
#
# #### Este dataset considerablemente toma más tiempo en entrenarse, se utilizo la función time.time para evaluar el tiempo elapsado y principalmente puedo atribuirlo al número de datos implicados en este set y la exactitud requerida. El primero modelo se entreno en 11 segundos mientras que el segundo demostro 422 segundos
#
#
# ## Pueden explicar que factores contribuyen a los tiempos de entrenamiento?
#
# #### Los factores que explican el tiempo de entrenamiento son el numero de neuronas implicado en la red neuronal predominantemente, el tamaño del learning rate planteado y el número de repeticiones o epochs. Todas estas variables implican un aumento en la exactitud.
#
# ## Pueden hacer que el loss disminuya?
#
# #### Al involucrar en el modelo las variables más correlacionadas como el alcohol para predecir la calidad del vino se reduce la función de perdida, al igual que al aumentar el learning rate al máximo disponible.
#
# ## Intenten graficar la data
#

# In[ ]:

get_ipython().system('jupyter nbconvert --to script Juarez_Boris_Tarea4_neural_networks.ipynb')


r"""
A module for calculating Resonant Relaxation diffusion coefficients
"""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import multiprocessing as mp
from ast import literal_eval as make_dict
from builtins import range
from builtins import super
from builtins import zip
from collections import namedtuple
from functools import lru_cache

import h5py
import numpy as np
# noinspection PyPackageRequirements
import progressbar
import vegas
from numba import jit
from numpy import mod
from numpy import sqrt
from scipy import special

from . import Cusp

Res = namedtuple('Res', ('l', 'n', 'np', 'neval'))

class DRR(Cusp):
    r"""
    Resonant relaxation diffusion coefficient (DRR).
    Assuming a power law stellar cusp around a massive black hole (MBH).
    The cusp is assumed to have an isotropic distribution function
    :math:`f(E) \propto |E|^p` corresponding ro a stellar density
    :math:`n(r) \propto r^{-\gamma}` where :math:`\gamma = \tfrac{3}{2} + p`

    Parameters
    ----------
    sma : float
       The semi-mahor axis along which DRR will be computed

    gamma : float, int, optional
        The slope of the density profile.
        Default: 7/4 (Bahcall wolf cusp)
    mbh_mass : float, int, optional
        Mass of the MBH [solar mass].
        Default: :math:`4.3 \times 10^6` (Milky Way MBH)
    star_mass : float, int, optional
        Mass of individual stars [solar mass].
        Default: 1.0
    rh : float, int, optional
        Radius of influence [pc].
        Define as the radius in which the velocity
        dispersion of the stellar cusp :math:`\sigma` is equal to the
        Keplerian velocity due to the MBH
        :math:`\sigma(r_\mathrm{h})^2 = G M_{\bullet} / r_\mathrm{h}`.
        Default: 2.0
    """

    def __init__(self, sma, gamma=1.75, mbh_mass=4e6, star_mass=1.0,
                 j_grid_size=128, rh=2.0, seed=None):

        super().__init__(gamma=gamma,
                         mbh_mass=mbh_mass,
                         star_mass=star_mass,
                         rh=rh)
        self.sma = sma
        self.gr_factor = 1.0
        self.j = np.logspace(np.log10(self.jlc(self.sma)), 0,
                             j_grid_size + 1)[:-1]
        if seed is None:
            self.seed = np.random.randint(int(1e8))
        else:
            self.seed = seed

        np.random.seed(self.seed)

        self.seeds = np.random.randint(int(1e8), size=self.j.size)

    @property
    def omega(self):
        try:
            return self._omega
        except AttributeError:
            self._omega = self.nu_p(self.sma, self.j)
            return self._omega

    @omega.setter
    def omega(self, omega):
        self._omega = omega

    @lru_cache()
    def _res_intrp(self, ratio):
        return ResInterp(self, self.omega * ratio, self.gr_factor)

    def _integrand(self, j, sma_p, j_p, lnnp, true_anomaly):
        d_nu_p = abs(self.d_nu_p(sma_p, j_p))
        a2_int = a2_integrand(self.sma, j, sma_p, j_p, lnnp, true_anomaly)
        return j_p * a2_int / d_nu_p

    def __call__(self, l_max, neval=1e3, threads=1,
                 progress_bar=True, seed=None):
        r"""
        Returns the RR diffusion coefficient :math:`D_{JJ}/J_{\mathrm{c}}^2` [1/yr].

        Parameters
        ----------
        l_max : int
            Maximal order of spherical harmonics to compute
        neval : int
            The maximum number of integrand evaluations
            in each iteration of the `vegas` algorithm.
            Default: 1000
        threads : int
            Number of parallel threads to use.
            Default: 1 (no parallelization)
        progress_bar : bool
            Show progress bar.
            Default: ``True``
        """

        # Get all non-vanishing resonances up to l=l_max
        lnnp = [(l, n, n_p)
                for l in range(1, l_max + 1)
                for n in range(1, l + 1)
                for n_p in range(-l - 1, l + 1)
                if (not mod(l + n, 2) + mod(l + n_p, 2)) and n_p != 0
                ]

        if progress_bar:
            pbar = progressbar.ProgressBar()(range(len(lnnp)))
        else:
            pbar = range(len(lnnp))

        for i in pbar:
            self._drr_lnnp(*lnnp[i], neval=neval, threads=threads)

        drr = np.vstack([self._drr_lnnp(*lnnp, neval=neval, threads=threads)[0]
                         for lnnp in lnnp])

        # Remove non-physical values
        drr[drr < 0] = 0

        # sum all resonances
        drr = drr.sum(axis=0)

        drr_err = sqrt(sum(self._drr_lnnp(*lnnp, neval=neval,
                                          threads=threads)[-1] ** 2
                           for lnnp in lnnp))
        return drr, drr_err

    def _drr_lnnp(self, l, n, n_p, neval=1e3, threads=1):
        r"""
        Calculates the :math:`(l,n,n_p)` term of the diffusion coefficient
        """
        neval = int(neval)

        # Pre compute the resonance interpolation grid
        try:
            drr, drr_err = self._drr_lnnp_cache[Res(l, n, n_p, neval)]

            return drr, drr_err
        except AttributeError:
            self._drr_lnnp_cache = {}
        except KeyError:
            pass

        ratio = n / n_p
        self._res_intrp(ratio)

        if threads > 1:
            queue = mp.Queue()

            def parallel_drr(pos, j_s, omega_s, seed_s):
                _results = [
                    self._drr(j, omega, (l, n, n_p), neval=neval, seed=seed)
                    for j, omega, seed in zip(j_s, omega_s, seed_s)
                ]
                _drr = [result[0] for result in _results]
                _drr_err = [result[-1] for result in _results]
                queue.put((pos, (_drr, _drr_err)))

            js = [self.j[i::threads] for i in range(threads)]
            omegas = [self.omega[i::threads] for i in range(threads)]
            seeds = [self.seeds[i::threads] for i in range(threads)]

            processes = [
                mp.Process(target=parallel_drr, args=(i, j_s, omega_s, seed_s))
                for i, (j_s, omega_s, seed_s) in
                enumerate(zip(js, omegas, seeds))]
            for process in processes:
                process.start()
            for process in processes:
                process.join()

            drr, drr_err = zip(*[(drr, drr_err)
                                 for (i, (drr, drr_err)) in
                                 sorted(map(queue.get, processes))])
            drr, drr_err = (np.concatenate(list(zip(*drr))),
                            np.concatenate(list(zip(*drr_err))))

        else:
            results = [self._drr(j, omega, (l, n, n_p), neval=neval, seed=seed)
                       for j, omega, seed in
                       zip(self.j, self.omega, self.seeds)]

            drr, drr_err = np.array(list(zip(*results)))

        self._drr_lnnp_cache[Res(l, n, n_p, neval)] = (drr, drr_err)

        return drr, drr_err

    def _drr(self, j, omega, lnnp, neval=1e3, seed=None):
        l, n, n_p = lnnp
        ratio = n / n_p
        get_jf = self._res_intrp(ratio)(omega * ratio)
        if seed is not None:
            # make a unique seed
            np.random.seed([seed, l, n, 2 * l + n_p])

        pi = np.pi

        @vegas.batchintegrand
        def c_lnnp(x):
            true_anomaly = x[:, :-1].T * pi
            sma_f = self.inverse_cumulative_a(x[:, -1])
            jf = get_jf(sma_f)
            res = np.zeros(x.shape[0], float)
            ix = np.where(jf > 0)[0]
            if len(ix) > 0:
                res[ix] = self._integrand(j, sma_f[ix], jf[ix], lnnp,
                                          true_anomaly[:, ix])
            return res

        self.c_lnnp = c_lnnp
        integ = vegas.Integrator(5 * [[0, 1]])

        if get_jf is None:
            result = np.zeros(2)
        else:
            result = np.array(integrate(c_lnnp, integ, neval))

        return result * (8 * pi * n ** 2 / abs(n_p) *
                         _a2_norm_factor(*lnnp) *
                         self.nu_r(self.sma) ** 2 / self.mass_ratio ** 2 *
                         self.total_number_of_stars)

    @property
    def l_max(self):
        try:
            return max([key.l
                        for key in self._drr_lnnp_cache.keys()])
        except AttributeError:
            pass

    @property
    def neval(self):
        try:
            return max([key.neval
                        for key in self._drr_lnnp_cache.keys()])
        except AttributeError:
            pass

    def save(self, file_name):
        r"""
        Save the current instance to an hdf5 file.

        Example
        -------
        >>> drr = DRR(0.1, j_grid_size=32)
        >>> d, d_err = drr(l_max=3)
        >>> drr.save('example.hdf5')
        >>> drr = DRR.from_file('example.hdf5')
        >>> d, d_err = drr(l_max=drr.l_max, neval=drr.neval)
        """
        with h5py.File(file_name, 'w') as h5:
            drr_lnnp_cache = h5.create_group("_drr_lnnp_cache")
            for key, value in self._drr_lnnp_cache.items():
                drr_lnnp_cache[str(dict(key._asdict()))] = value
            for key, value in self.__dict__.items():
                try:
                    h5[key] = value
                except TypeError:
                    pass

    def _read(self, file_name):
        r"""
        Read the cached data from an hdf5 file
        """
        with h5py.File(file_name, 'r') as h5:

            for key, value in h5['_drr_lnnp_cache'].items():
                try:
                    self._drr_lnnp_cache[Res(**make_dict(key))] = value.value
                except AttributeError:
                    self._drr_lnnp_cache = {Res(**make_dict(key)): value.value}

            for key, value in h5.items():
                if key != '_drr_lnnp_cache':
                    setattr(self, key, value.value)

    @classmethod
    def from_file(cls, file_name):
        r"""
        Load from file and return an instance

        Example
        -------
        >>> drr = DRR(0.1, j_grid_size=32)
        >>> d, d_err = drr(l_max=3)
        >>> drr.save('example.hdf5')
        >>> drr = DRR.from_file('example.hdf5')
        >>> d, d_err = drr(l_max=drr.l_max, neval=drr.neval)
        """
        drr = cls(1.0)
        drr._read(file_name)
        return drr

def integrate(func, integ, neval=1e4):
    integ(func, nitn=10, neval=neval)
    result = integ(func, nitn=10, neval=neval)
    try:
        res, err = np.array([[r.val, np.sqrt(r.var)] for r in result]).T
    except TypeError:
        res, err = result.val, np.sqrt(result.var)
    return res, err

@jit(nopython=True)
def a2_integrand(sma, j, sma_p, j_p, lnnp, true_anomaly):
    r"""
    Returns the :math:`|a_{\ell n n^{\prime}}|^{2}` integrand to use in the MC integration
    """
    l, n, n_p = lnnp
    cnnp = np.cos(true_anomaly.T * np.array([n, n, n_p, n_p])).T
    cnnp = cnnp[0] * cnnp[1] * cnnp[2] * cnnp[3]
    j2 = j ** 2
    j_p2 = j_p ** 2
    ecc, eccp = np.sqrt(1 - j2), np.sqrt(1 - j_p2)
    r12 = (sma * j2 / (1 - ecc * np.cos(true_anomaly[:2])))
    rp12 = (sma_p * j_p2 / (1 - eccp * np.cos(true_anomaly[2:])))
    r_1, r_2 = r12[0], r12[-1]
    rp1, rp2 = rp12[0], rp12[-1]
    return (cnnp / j2 / j_p2 / sma ** 2 / sma_p ** 4 *
            (np.minimum(r_1, rp1) * np.minimum(r_2, rp2)) ** (2 * l + 1) /
            (r_1 * r_2 * rp1 * rp2) ** (l - 1))

@lru_cache()
def _a2_norm_factor(l, n, n_p):
    r"""
    Normalization factor for :math:`|a_{\ell n n^{prime}} |^{2}`
    """

    return (abs(special.sph_harm(n, l, 0, np.pi / 2)) ** 2 *
            abs(special.sph_harm(n_p, l, 0, np.pi / 2)) ** 2 *
            (4 * np.pi / (2 * l + 1)) ** 2) / (2 * l + 1)

class ResInterp(object):
    r"""
    Generates an interpolation function :math:`j^{\prime} (a^{\prime})` where :math:`j^{\prime}`
    satisfies the resonant condition: :math:`\nu^{\prime} (a^{\prime}, j^{\prime}) == \omega`

    Parameters
    ----------
    cusp : a `Cusp` instance
    omega : ndarray
          The resonance frequencies

    Example
    -------
    >>> from scrrpy import Cusp
    >>> from scrrpy.drr import ResInterp
    >>> import numpy as np
    >>> cusp = Cusp(gamma=1.75, mbh_mass=4e6, rh=2.0)
    >>> j = np.logspace(-2, 0, 11)[:-1]
    >>> omega = cusp.nu_p(a=0.1, j=j)
    >>> resint = ResInterp(cusp, omega)
    >>> jf = np.array([resint(o)(0.1) for o in omega])
    >>> abs(1 - jf/j).max() < 1e-4
    True
    """

    def __init__(self, cusp, omega, gr_factor=1.0):
        r"""
        """
        self._cusp = cusp
        self.size = 1000
        self._cusp.gr_factor = gr_factor
        self.omega = omega
        self._af = np.logspace(np.log10(16 * self._cusp.rg),
                               np.log10(self._cusp.rh),
                               1001)[1:]
        self.x = np.logspace(-5, 0, self.size + 1)[:-1][::-1]
        self.j_grid = self.make_grid()

    def __call__(self, omega):
        log_ap, jp = self.j_grid[omega]
        if jp.size == 0:
            return
        return lambda af: np.interp(np.log(af), log_ap, jp, left=0, right=0)

    def make_grid(self):
        j_grid = []
        for af in self._af:
            jlc = self._cusp.jlc(af)
            j = (1 - jlc) * self.x + jlc
            nup = self._cusp.nu_p(af, j)
            j_grid.append(np.exp(np.interp(self.omega, nup, np.log(j),
                                           left=-np.inf, right=-np.inf)))
        j_grid = np.array(list(zip(*j_grid)))
        return dict((omega, (np.log(self._af[j > 0]), j[j > 0]))
                    for omega, j in zip(self.omega, j_grid))


import numpy as np
import gym
import os

enviroment = 'CartPole-v1'
env = gym.make(enviroment)
Q = np.zeros((1, 1))
states = []

for i_episode in range(200):
    observation = env.reset()
    reward = 0
    done = False
    steps = 0
    while not done:
        env.render()
        action = env.action_space.sample()
        observation, reward, done, info = env.step(action)

        if not any((observation == x).all() for x in states):
            states.append(observation)

        os.system('clear')
        print(f'Reward: {reward}')
        print(f'Episode: {i_episode}')
        print(f'Done: {done}')
        print(f'Steps: {steps}')
        steps += 1

print(f"Number of states: {len(states)}")
print()

env.close()


"""
Author: Sam McGrath
Class: CS 450
Instructor: Br. Burton
"""
import numpy as np
import pandas as pd
from scipy import stats

def get_iris():
    headers = [
        'sepal length',
        'sepal width',
        'petal length',
        'petal width',
        'class'
    ]

    classObj = {
        'Iris-setosa': 1,
        'Iris-versicolor': 2,
        'Iris-virginica': 3
    }

    df = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data",
                    header=None, names=headers)

    df.replace(classObj, inplace=True)

    return stats.zscore(df.as_matrix(columns=headers[:-1])), \
            df.as_matrix(columns=headers[-1:]), \
            ["Iris-setosa", "Iris-versicolor", "Iris-virginica"]


"""alphastoka URL Configuration

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

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^mgmt/create', views.mgmt_create),
    url(r'^mgmt/murder/([^\s]+)', views.mgmt_murder),
    url(r'^mgmt/jail/([^\s]+)', views.mgmt_jail),
    url(r'^mgmt/release/([^\s]+)', views.mgmt_release),
    url(r'^results/export', views.results_export),
    url(r'^results', views.results),
    url(r'^categorization', views.categorization),
    url(r'^processors', views.processors),
    # default first view
    url(r'^$', views.index)
]

@register.filter
def get_item(dictionary, key):
    return dictionary.get(key)

@register.filter
def add_int(v, b):
    return int(v) + int(b)

@register.filter
def unixtime(intTime):
    that = datetime.fromtimestamp(int(intTime))
    total_time=(datetime.now() - that)

    return str(total_time).split(".")[0]


from nsepy import get_history
from datetime import date, timedelta
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import nsepy
from matplotlib import style
style.use('fivethirtyeight')

#TICKER NAME
ticker = "SBIN"
#TIME PERIOD, 15 days in this case
end_day = date.today()
start_day = end_day - timedelta(200)

#Fetch ticker data from nsepy
df = get_history(symbol=ticker, start=start_day, end=end_day)
data=df[['Open', 'High', 'Low', 'Close', 'Volume']]
data['15d']= np.round(data['Close'].rolling(window=15).mean(),2)
data['40d']= np.round(data['Close'].rolling(window=40).mean(),2)

data[['Close','15d','40d']].plot(grid=True, figsize=(30,30))
# plt.show()

data['15d-40d']=data['15d']-data['40d']
x=30
data['Stance']=np.where(data['15d-40d']>x,1,0)
data['Stance']=np.where(data['15d-40d']<x,-1,data['Stance'])
# print(data['Stance'].value_counts())
data['Stance'].value_counts()
data['Stance'].plot(lw=2,ylim=[-1.1,1.1])
plt.show()

data['Stock_Returns']=np.log(data['Close']/data['Close'].shift(1))
data['SMAC_Strategy']=data['Stock_Returns']*data['Stance'].shift(1)
data[['Stock_Returns','SMAC_Strategy']].plot(grid=True,figsize=(10,6))
plt.show()

# check for SettingWithCopyWarning. https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy


# -*- coding: utf-8 -*-
from odoo import fields, models, api

class DocumentType(models.Model):
    _name = 'ln10_co_intello.documenttype'
    _description = "Colombian Document Type"

    key_dian = fields.Integer(required=True, string="DIAN Key")
    name = fields.Char(required=True, index=True, string="Name")
    with_digit = fields.Boolean(default=False, string="With Verification Digit")

    _sql_constraints = [('keyDian_uniq', 'UNIQUE(key_dian)', 'Duplicate Key DIAN value is not allowed!'),
                        ('name_uniq', 'UNIQUE(name)', 'Duplicate Name is not allowed!')]

class DianCodes(models.Model):
    _name = 'ln10_co_intello.diancodes'
    _description = "Colombian DIAN Codes"

    key_dian = fields.Char(required=True, string="DIAN Key")
    name = fields.Char(required=True, index=True, string="Name")
    type = fields.Selection([('persontype', 'Person Type'),
                             ('fiscalregime', 'Fiscal Regime'),
                             ('fiscalresponsibility', 'Fiscal Responsibility'),
                             ('paymentmethod', 'Payment Method'),
                             ('representation', 'Representation'),
                             ('customs', 'Customs'),
                             ('establishment', 'Establishment')],
                            required=True, string="Code Type")

    '''
    _sql_constraints = [('keyDian_uniq', 'UNIQUE(type,key_dian)', 'Duplicate Key DIAN value is not allowed!')]
    ,('name_uniq', 'UNIQUE(type,name)', 'Duplicate Name is not allowed!')]
    '''

class CIIUCodes(models.Model):
    _name = 'ln10_co_intello.ciiucodes'
    _description = "Colombian CIIU Codes"

    code = fields.Char(required=True, string="Code")
    name = fields.Char(required=True, index=True, string="Name")
    industry_id = fields.Many2one('res.partner.industry', 'Industry')

    _sql_constraints = [('code_uniq', 'UNIQUE(code)', 'Duplicate Code value is not allowed!'),
                        ('name_uniq', 'UNIQUE(name)', 'Duplicate Name value is not allowed!')]

class NomenclatureDIAN(models.Model):
    _name = 'ln10_co_intello.nomenclaturedian'
    _description = "Colombian DIAN Nomenclature"

    abbreviation = fields.Char(required=True, string="Abbreviation")
    name = fields.Char(required=True, index=True, string="Name")
    type = fields.Selection([('principal', 'Principal'),
                             ('qualifiying', 'Qualifiying'),
                             ('additional', 'Additional')], string="Nomenclature Type")

    _sql_constraints = [('abbreviation_uniq', 'UNIQUE(abbreviation)', 'Duplicate Abbreviation value is not allowed!'),
                        ('name_uniq', 'UNIQUE(name)', 'Duplicate Name value is not allowed!')]

'''
    @api.multi
    def name_get(self, context=None):
        if context is None:
            context = {}
        res = []
        if context.get('display_code', False):
            for record in self:
                res.append(record.code)
        else:
            # Do a for and set here the standard display name, for example if the standard display name were name, you should do the next for
            for record in self:
                res.append(record.name)
        return res
'''
'''
    @api.multi
    def name_get(self):
        result = []
        for record in self:
            record_name = record.movie + ' - ' + record.seat_number
            result.append((record.id, record_name))
        return result

    def name_get(self, cr, uid, ids, context=None):
        if u'compute_name' in context:
            # check value from frontend and call custom method
            return getattr(self, context[u'compute_name'])(cr, uid, ids, context)
        else:
            # call base method
            return super(TestProject, self).name_get(cr, uid, ids, context=context)

    def _get_my_name(self, cr, uid, ids, context):
        res = []
        for record in self.browse(cr, uid, ids, context=context):
            res.append((record.id, record.prj_id.name))
        return res
'''
'''
class PersonType(models.Model):
    _name = 'ln10_co_intello.persontype'

    key_dian = fields.Integer(required=True, string="DIAN Key")
    name = fields.Char(required=True, index=True, string="Name")

    _sql_constraints = [('keyDian_uniq', 'UNIQUE(key_dian)', 'Duplicate Key DIAN value is not allowed!'),
                        ('name_uniq', 'UNIQUE(name)', 'Duplicate Name is not allowed!')]

class FiscalRegime(models.Model):
    _name = 'ln10_co_intello.fiscalregime'

    key_dian = fields.Char(required=True, string="DIAN Key")
    name = fields.Char(required=True, index=True, string="Name")

    _sql_constraints = [('keyDian_uniq', 'UNIQUE(key_dian)', 'Duplicate Key DIAN value is not allowed!'),
                        ('name_uniq', 'UNIQUE(name)', 'Duplicate Name is not allowed!')]

class FiscalResponsibility(models.Model):
    _name = 'ln10_co_intello.fiscalresponsibility'

    key_dian = fields.Char(required=True, string="DIAN Key")
    name = fields.Char(required=True, index=True, string="Name")
    active = fields.Boolean(default=True)

    _sql_constraints = [('keyDian_uniq', 'UNIQUE(key_dian)', 'Duplicate Key DIAN value is not allowed!'),
                        ('name_uniq', 'UNIQUE(name)', 'Duplicate Name is not allowed!')]
'''


import numpy as np
import matplotlib.pyplot as plt
import utils

def computeGaussian(value, mean, var):
    """This function is compute log of Gaussian distribution, because original multiply values will become smaller and smaller."""
    return np.log(1.0 / (np.sqrt(2.0 * np.pi * var))) - ((value - mean) ** 2.0 / (2.0 * var))

def checkResult(prediction, answer):
    # prediction = np.argmin(probability)
    # print("Prediction: ", prediction, ", Ans: ", answer)
    if prediction == answer:
        return 0
    else:
        return 1

def normalization(probability, class_num):
    """This function is used to normalize the probability."""
    temp = 0
    for j in range(class_num):
        temp += probability[j]
    for j in range(class_num):
        probability[j] /= temp
    return probability

def train(train_x, train_y, class_num):
    """This function is training stage of naive-bayes classifier."""
    # print("train x shape : {}".format(train_x.shape))
    # print("train y shape : {}".format(train_y.shape))
    prior = np.zeros((class_num), dtype = float)
    train_square = np.zeros((class_num, train_x.shape[1]), dtype = float)
    train_mean = np.zeros((class_num, train_x.shape[1]), dtype = float)
    train_var = np.zeros((class_num, train_x.shape[1]), dtype = float)

    for data_idx in range(train_x.shape[0]):
        label = train_y[data_idx]
        prior[label] += 1
        for feature_idx in range(train_x.shape[1]):
            train_square[label][feature_idx] += (train_x[data_idx][feature_idx] ** 2)
            train_mean[label][feature_idx] += train_x[data_idx][feature_idx]
    #Calculate mean and standard deviation
    for label in range(class_num):
        for feature_idx in range(train_x.shape[1]):
            train_mean[label][feature_idx] = float(train_mean[label][feature_idx] / prior[label])
            train_var[label][feature_idx] = float(train_square[label][feature_idx] / prior[label]) - float(train_mean[label][feature_idx] ** 2)
            # psuedo count for variance
            if train_var[label][feature_idx] == 0:
                train_var[label][feature_idx] = 1e-6
    prior = prior / train_x.shape[0]
    prior = np.log(prior)
    return prior, train_mean, train_var

def test(test_x, test_y, prior, train_mean, train_var, class_num, filename, model_name, testing=False):
    """This function is testing stage of naive-bayes classifier."""
    # print("test_x shape : {}".format(test_x.shape))
    # print("test_y shape : {}".format(test_y.shape))
    error = 0
    predict_list = []
    total_probability = [0 for _ in range(test_x.shape[0])]
    multi_class = []
    for data_idx in range(test_x.shape[0]):
        probability = np.zeros((class_num), dtype = float)
        for label in range(class_num):
            probability[label] += prior[label]
            for feature_idx in range(test_x.shape[1]):
                predict_value = computeGaussian(test_x[data_idx][feature_idx], train_mean[label][feature_idx], train_var[label][feature_idx])
                probability[label] += predict_value
        probability = normalization(probability, class_num)
        total_probability[data_idx] = probability[1]            # Select class 1
        multi_class.append(probability)
        prediction = np.argmin(probability)
        predict_list.append(prediction)
        error += checkResult(prediction, test_y[data_idx])
    accuracy = (test_x.shape[0] - error) / test_x.shape[0]
    print("Error : {}. Accuracy {}".format(error, accuracy))

    #Plot ROC curve
    FA_PD = []
    if class_num == 2:
        slices = 50
        low = min(total_probability)
        high = max(total_probability)
        step = (abs(low) + abs(high)) / slices
        thresholds = np.arange(low-step, high+step, step)
        for threshold in thresholds:
            FA_PD.append(utils.computeConfusionMatrix(total_probability, test_y, class_num, model_name, threshold))
        FA = [row[0] for row in FA_PD]
        PD = [row[1] for row in FA_PD]
        FA_x = np.linspace(0.0, 1.0, slices)
        PD_interp = np.interp(FA_x, FA, PD)
        # Plot ROC curve of testing data
        if testing is True:
            utils.computeConfusionMatrix(multi_class, test_y, class_num, model_name)
            fig = plt.figure()
            plt.plot(FA_x, PD_interp)
            plt.xlabel('FA')
            plt.ylabel('PD')
            fig.savefig('plotting/' + filename + '_' + model_name + '_roc_testing.png')
        return accuracy, FA_x, PD_interp
    else:
        utils.computeConfusionMatrix(multi_class, test_y, class_num, model_name)
        return accuracy


from flask import Flask, render_template, request, jsonify
from textblob import TextBlob
from textblob import Word
from spell import correction, words, candidates
import random
import nltk
from nltk.tokenize import word_tokenize
from nltk.tag import pos_tag
#import json
import os
#synonym checking implemented
#sentiment analysis implemented
#POS tagging implemented - synergizes with sentiment analysis
#REFERENCES: https://stevenloria.com/wordnet-tutorial/
#https://medium.com/@gianpaul.r/tokenization-and-parts-of-speech-pos-tagging-in-pythons-nltk-library-2d30f70af13b
#https://www.geeksforgeeks.org/part-speech-tagging-stop-words-using-nltk-python/
#https://www.geeksforgeeks.org/twitter-sentiment-analysis-using-python/

os.environ['NLTK_DATA'] = '~/nltk_data'
GREETING_KEYWORDS = ("yo", "hey", "hello", "hi", "greetings", "sup", "what's up", "hi there", "good evening", "wuzzup my homie")
GREETING_RESPONSES = ["What can I get you?", "Hello stranger, what can I serve up for you?", "Hey there! Need a drink?", "Hi, hope you're thirsty. What can I get you?", "Welcome! What'll it be today?"]
GOODBYE_KEYWORDS = ("bye", "good bye", "goodbye", "see ya")
GOODBYE_RESPONSES = ["Have a good night", "Drive safe!", "Until next time"]
MEALS = ["steak", "hamburger", "fish and chips", "blt", "spaghetti", "hot dog", ]
HEDGE_RESPONSES = ["I have no idea what you're asking", "I'm not sure", "Can you re-phrase that?", "Pardon?", "Sorry I can't do that", "I'm confused"]
DRINKS = ("vodka", "beer", "whiskey", "wine", "sex on the beach", "screwdriver", "green fairy", "whiskey", "absinthe", "acapulco gold", "amaretto", "bacardi", "baileys" "budweiser", "champagne", "daiquiri", "goldschlager" "guinness", "grey goose", "hootch", "jack daniels", "jagermeister", "limoncello", "mezcal", "moonshine", "martini", "pina colada", "tequila", "vodka", "zinfandel", "raki", "long island iced tea"  )
DRINKSTYLE = ("on the rocks", "neat")#ask this after they request a drink
YES_KEYWORDS = ("good", "yes", "that's good", "yeah", "certainly", "true", "yep", "yea", "okay", "exactly", "gladly")
YES_RESPONSES = ["Okay", "Sounds good", "I like it", "Thats great!", "Exciting!"]
NO_KEYWORDS = ("no", "nah", "negative", "not really", "never", "false", "nope")
NO_RESPONSES = ["That's too bad", "Suit yourself", "If you say so", "I insist"]
chat_log = {}
GRATITUDE = ["thanks", "thank you", "much obliged", "thanks a bunch"]

#testing section for determining synonyms
#synonym tested words are: grub, alcohol, booze, nothing, dandy, goodbye, hello all at [0]
# testword = Word("milk")
# bev = testword.synsets[0]
print(candidates("grub"))
# print(bev.lemma_names())

def createMessage(input):
    '''Takes json facebook input and creates the message to return to facebook'''
    #input_msg = TextBlob(input['text'])

    spellingcheck = str(input).split()
    counter = 0
    for x in spellingcheck:

        if x not in candidates(x) and x not in Word("grub").synsets[0].lemma_names() and x not in Word("booze").synsets[0].lemma_names() and x not in MEALS and x not in DRINKS:
            spellingcheck[counter] = correction(x)
            print(spellingcheck[counter])
        counter += 1
    spell_checked_word = " ".join(spellingcheck)
    print(spell_checked_word)
    input_msg = TextBlob(spell_checked_word)

    senderId = 0
    data = buildMessage(input_msg, senderId)

    return str(data)  #this will return the wanted message back out to messenger

def checkForFeedback(words): #for checking sentiment behind response
    analysis = TextBlob(str(words))
    if analysis.sentiment.polarity > 0:
        return 'positive'
    elif analysis.sentiment.polarity == 0:
        return 'neutral'
    else:
        return 'negative'

def buildMessage(input_msg, senderId):
    '''Core Logic to build the message.
    If unsure how to reply, will respond with a hedge'''
    tokenform = nltk.word_tokenize(str(input_msg)) #pos tagging form of sentence
    #initializes switch for feedback

    if tokenform[0] in GRATITUDE:
        return "You're welcome!"

    # Clears the user session to start over new
    if input_msg.lower() == 'clear':
        clearSession(senderId)
        return "Session cleared"

    times_con = howManyMessages(senderId)
    # If the user is greeting, respond with a greeting
    if CheckForGreeting(input_msg):
        return random.choice(GREETING_RESPONSES)

    # If the user is greeting, respond with a greeting
    if CheckForGoodbye(input_msg):

        #the user will give an impression with their farewell which the bartender will respond to
        #setGoodByeTrue()
        if checkForFeedback(tokenform) == 'positive':
            clearSession(senderId)

            return "Happy to hear that!  " + random.choice(GOODBYE_RESPONSES)
        elif checkForFeedback(tokenform) == 'negative':
            clearSession(senderId)

            return "I'm sorry to hear that. " + random.choice(GOODBYE_RESPONSES)
        else:
            clearSession(senderId)

            return random.choice(GOODBYE_RESPONSES)

    # Break the message into parts
    pronoun, noun, adjective, verb = getSpeechParts(input_msg)
    num_drinks = chat_log[senderId]['drinks_served']

    # Search for a drink in the user input and respond as well as we can
    drink = noun #pass the noun through spell check
    if noun not in DRINKS:
        drink = searchForDrink(input_msg)
    if len(input_msg.words) == 1:
        drink = input_msg
    if drink in DRINKS:
        if tokenform[0] == 'can' or tokenform[0] == 'may': #pos tagging to specify
            return "you sure "+ tokenform[0] + "! here's your {0}".format(drink)
        if num_drinks == 1:

            return "Here's your {0}. How are you enjoying your drink so far?"
        if num_drinks > 3:
            return "You are too drunk I am unable to serve you any more drinks. You can type 'clear' to tell me that you're sober again"
        #increment drink counter
        chat_log[senderId]['drinks_served'] = num_drinks + 1
        if num_drinks <= 1:
            return "One {0} coming right up!".format(drink)
        if num_drinks == 2:
            return "{0} for you, enjoy.".format(drink)
        else:
            return "Here is your {0}! Wow you've already had {1} drinks!".format(drink, num_drinks)

    # Look for yes or no responses and respond with a weak hedge
    if checkForYes(input_msg):
        return random.choice(YES_RESPONSES)
    if checkForNo(input_msg):
        return random.choice(NO_RESPONSES)

    # If someone doesn't want anything
    if noun == Word("nothing").synsets[0].lemma_names():
        return "There isn't anything I can get for you? I have a vast knowledge of drinks. I'm sure you'll like something we have in stock."
    # If the noun is a meal:
    meal = noun
    if noun not in MEALS:
        meal = searchForMeal(input_msg)
    if len(input_msg.words) == 1:
        meal = input_msg
    if meal in MEALS:
        if tokenform[0] == 'can' or tokenform[0] == 'may': #pos tagging to specify
            return "you sure "+ tokenform[0] + "! here's your {0}".format(meal)
        if num_drinks == 1:

            return "Here's your {0}. How are you enjoying your food so far?".format(meal)
        else:
            return "Alright, here's your {0}, bon appetite".format(meal)
    #If we have a noun but no drink, we don't know what they want, so we answer with a question
    for x in tokenform:
        print(str(x))
        if str(x) in Word("grub").synsets[0].lemma_names():
            return "Sounds good. What would you like to eat?"
    for x in tokenform:
        print(str(x))
        if str(x) == "drink" or x in Word("booze").synsets[0].lemma_names():
            return "One drink coming up. What's your fancy?"
    if noun:
        if checkForFeedback(tokenform) == 'positive':
            return "Happy to hear that!  "
        elif checkForFeedback(tokenform) == 'negative':
            return "Oh that's no good. I'm sure we can fix that"
        else:
            return "well, can't say I understood that, I'll assume it was positive!"
    #If nothing caught, return a hedge
    return random.choice(HEDGE_RESPONSES)

def createChatLog(senderId):
    '''Keeps track of each session ID in a dictionary'''
    log = {'times_contacted': 1, 'context': None, 'drinks_served': 0}
    chat_log[senderId] = log

def howManyMessages(senderId):
    '''Check the chat log for number of messages and increment accordinly.'''
    if senderId not in chat_log:
        createChatLog(senderId)
        #return value is number of messages received
        return 1
    else:
        times_con = chat_log[senderId]['times_contacted'] + 1
        chat_log[senderId]['times_contacted'] = times_con
        return times_con

def clearSession(senderId):
    '''Delete any data from the user session log'''
    chat_log[senderId]['times_contacted'] = 0
    chat_log[senderId]['drinks_served'] = 0

def CheckForGreeting(sentence):
    '''Return boolean if the user sentence contains a greeting'''
    for word in sentence.words:
        if word.lower() in GREETING_KEYWORDS or word.lower() in Word("hello").synsets[0].lemma_names():
            return True
    return False

def CheckForGoodbye(sentence):
    '''Return boolean if the user wants to leave/end the sesion'''
    for word in sentence.words:
        if word.lower() in GOODBYE_KEYWORDS or word.lower() in Word("goodbye").synsets[0].lemma_names():
            return True
    return False

def checkForYes(sentence):
    '''Return boolean if the user indicated a yes/true reply'''
    for word in sentence.words:
        if word.lower() in YES_KEYWORDS or word.lower() in Word("yes").synsets[0].lemma_names():
            return True
    return False

def checkForNo(sentence):
    '''Return boolean if the user indicated a no/false reply'''
    for word in sentence.words:
        if word.lower() in NO_KEYWORDS or word.lower() in Word("no").synsets[0].lemma_names():
            return True
    return False

def searchForDrink(sentence):
    '''Return boolean if the user sentence contains a drink'''
    for word in sentence.words:
        if word.lower() in DRINKS: #or word.lower in Word(word).synsets[0].lemma_names():
            return word
    return None

def searchForMeal(sentence):
    '''Return boolean if the user sentence contains a drink'''
    for word in sentence.words:
        if word.lower() in MEALS: # or word.lower in Word(word).synsets[0].lemma_names():
            return word
    return None

def getSpeechParts(input_msg):
    '''Use natural language processing to find and categorize each part of the sentance'''
    pronoun = None
    noun = None
    adjective = None
    verb = None
    for s in input_msg.sentences:
        pronoun = findPronoun(s)
        noun = findNoun(s)
        adjective = findAdjective(s)
        verb = findVerb(s)
    return pronoun, noun, adjective, verb

def findPronoun(sent):
    '''Return pronoun (I or You). Determins if the user is talking about
    themselves or the bot.
    Pronoun is represented as PRP in NLTK'''
    pronoun = None
    for word, part_of_speech in sent.pos_tags:
        if part_of_speech == 'PRP' and word.lower() == 'you':
            pronoun = 'I'
        elif part_of_speech == 'PRP' and word == 'I' or word == 'i':
            pronoun = 'You'
    return pronoun

def findVerb(sent):
    '''Return verb represended as VB in NLTK'''
    verb = None
    pos = None
    for word, part_of_speech in sent.pos_tags:
        if part_of_speech.startswith('VB'):  # This is a verb
            verb = word
            pos = part_of_speech
            break
    return verb, pos

def findNoun(sent):
    '''Return noun represended as NN in NLTK'''
    noun = None
    if not noun:
        for w, p in sent.pos_tags:
            if p == 'NN' and w != 'i':  # This is a noun
                #textblob detecting 'i' as a noun
                noun = w
                break
    return noun

def findAdjective(sent):
    '''Return adjective represended as JJ in NLTK'''
    adj = None
    for w, p in sent.pos_tags:
        if p == 'JJ':  # This is an adjective
            adj = w
            break
    return adj

def startsWithVowel(word):
    '''Used to check if a noun starts with a vowel
    then we can assign the proper pronoun'''
    return True if word[0] in 'aeiou' else False

#all code above this created API
app = Flask(__name__) #create the app server to recieve json
@app.route("/")
def root():
    return render_template('chat.html')

@app.route("/chat", methods=['POST','GET'])
def chat():
    content = str(request.form['chatmessage'])
    if content == "quit":
        exit()
        return jsonify({"status":"ok", "answer":"exit Thank You"})
    else:
        message = createMessage(content)
        return jsonify({'status':'OK','answer':message})

app.run(host = '127.0.0.1', port = 8090)


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

import os
import sys

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

readme = open('README.rst').read()
history = open('HISTORY.rst').read().replace('.. :changelog:', '')

if sys.argv[-1] == 'publish':
    os.system('python setup.py sdist upload')
    sys.exit()

with open("smartystreets/__init__.py", "r") as module_file:
    for line in module_file:
        if line.startswith("__version__"):
            version_string = line.split("=")[1]
            version = version_string.strip().replace("'", "")

requirements = [
    'requests>=2.0.0',
]

test_requirements = [
    'mock>=1.0.0',
    'responses==0.3.0',
]

# grequests isn't available on python 3, unfortunately, but make it a testing requirement
# if we are on python 2.
if int(sys.version[0]) == 2:
    test_requirements.append('grequests')

setup(
    name='smartystreets.py',
    version=version,
    description='A wrapper for the SmartyStreets address validation and geolocation API"',
    long_description=readme + '\n\n' + history,
    author='Ben Lopatin',
    author_email='ben@wellfire.co',
    url='https://github.com/bennylope/smartystreets.py',
    packages=[
        'smartystreets',
    ],
    package_dir={'smartystreets':
                 'smartystreets'},
    include_package_data=True,
    install_requires=requirements,
    license="BSD",
    zip_safe=False,
    keywords='smarty streets',
    classifiers=[
        'Development Status :: 3 - Alpha',
        'Intended Audience :: Developers',
        'License :: OSI Approved :: BSD License',
        'Natural Language :: English',
        "Programming Language :: Python :: 2",
        'Programming Language :: Python :: 2.7',
        'Programming Language :: Python :: 3',
        'Programming Language :: Python :: 3.3',
        'Programming Language :: Python :: 3.4',
    ],
    test_suite='tests',
    tests_require=test_requirements,
)


#!/usr/bin/env python3
"""downstream jobs are delegated in pipeline_runs collection
"""
# standard library imports
import logging
import sys
import os
import argparse
import getpass
import glob
from collections import namedtuple

#--- third party imports
#
import requests
import pymongo
#--- project specific imports
#
# add lib dir for this pipeline installation to PYTHONPATH
LIB_PATH = os.path.abspath(
    os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", "lib"))
if LIB_PATH not in sys.path:
    sys.path.insert(0, LIB_PATH)
from services import rest_services
from mongodb import mongodb_conn
from pipelines import generate_window, send_mail, get_site
from pipelines import get_machine_run_flowcell_id, generate_timestamp
from pipelines import is_devel_version
from readunits import key_for_read_unit

ReadUnit = namedtuple('ReadUnit', ['run_id', 'flowcell_id', 'library_id',
                                   'lane_id', 'rg_id', 'fq1', 'fq2'])

__author__ = "Lavanya Veeravalli"
__email__ = "veeravallil@gis.a-star.edu.sg"
__copyright__ = "2016 Genome Institute of Singapore"
__license__ = "The MIT License (MIT)"

OUTDIR_BASE = {
    'GIS': {
        'devel': '/mnt/projects/rpd/testing/output/downstream',
        'production': '/mnt/projects/userrig/solexa/downstream'},
    'NSCC': {
        'devel': '/seq/astar/gis/rpd/testing/output/downstream/',
        'production': '/seq/astar/gis/seq/downstream'}
}
PRODUCTION_PIPELINE_VERSION = {
    'GIS': {
        'production': '/mnt/projects/rpd/pipelines/current',
        'devel': 'devel'},
    'NSCC': { ###FIXME for the correct path
        'devel': '/seq/astar/gis/rpd/pipelines.git/',
        'production': 'devl'}
}

# global logger
logger = logging.getLogger(__name__)
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter(
    '[{asctime}] {levelname:8s} {filename} {message}', style='{'))
logger.addHandler(handler)

def get_downstream_outdir(requestor, pipeline_version, pipeline_name, site=None, basedir_map=OUTDIR_BASE, base_pipelinedir_map=PRODUCTION_PIPELINE_VERSION):
    """generate downstream output directory
    """
    if not site:
        site = get_site()
    if site not in basedir_map:
        raise ValueError(site)
    if site not in base_pipelinedir_map:
        raise ValueError(site)
    if is_devel_version():
        basedir = basedir_map[site]['devel']
        if not pipeline_version:
            pipeline_version = base_pipelinedir_map[site]['devel']
    else:
        basedir = basedir_map[site]['production']
        if not pipeline_version:
            pipeline_version = os.readlink(base_pipelinedir_map[site]['production'])
    outdir = "{basedir}/{requestor}/{pversion}/{pname}/{ts}".format(
        basedir=basedir, requestor=requestor, pversion=pipeline_version, pname=pipeline_name,
        ts=generate_timestamp())
    return outdir

def check_fastq(fastq_data_dir, libid, laneId):
    """Check if fastq data available for library
    """
    fastq_list = (os.path.join(fastq_data_dir, "*libid", "*fastq.gz")).replace("libid", libid)
    fastq_data = glob.glob(fastq_list)
    if len(fastq_data) > 0:
        for file in fastq_data:
            base = os.path.basename(file)
            if "L00laneId_R1_".replace("laneId", laneId) in base:
                fq1 = file
            elif "L00laneId_R2_".replace("laneId", laneId) in base:
                fq2 = file
            else:
                fq2 = None
        return (True, fq1, fq2)
    else:
        return (False, None)

def mongodb_update_runcomplete(run_num_flowcell, analysis_id, mux_id, insert_id, connection):
    """Change the status to DELEGATED in runcomplete collection of MongoDB
    """
    try:
        db = connection.gisds.runcomplete
        db.update({"run": run_num_flowcell, \
            'analysis.analysis_id' : analysis_id, \
            'analysis.per_mux_status.mux_id' : mux_id}, \
            {"$set": {insert_id: "DELEGATED", }})
    except pymongo.errors.OperationFailure:
        logger.fatal("MongoDB OperationFailure")
        return False
    else:
        return True

def mongodb_insert_libjob(lib_info, connection):
    """Insert records into pipeline_runs collection of MongoDB
    """
    try:
        db = connection.gisds.pipeline_runs
        db.insert_one(lib_info)
    except pymongo.errors.OperationFailure:
        logger.fatal("mongoDB OperationFailure")
        return False
    else:
        return True

def mongodb_remove_muxjob(mux_id, run_id, ctime, connection):
    """Delete libraries from MUX, runID and ctime
    """
    try:
        db = connection.gisds.runcomplete
        db.remove({"run_id": run_id, "mux_id": mux_id, "ctime": ctime})
    except pymongo.errors.OperationFailure:
        logger.fatal("mongoDB OperationFailure")
        sys.exit(1)

def get_lib_details(run_num_flowcell, mux_list, testing):
    """Lib info collection from ELM per run
    """
    _, run_num, flowcellid = get_machine_run_flowcell_id(run_num_flowcell)
    # Call rest service to get component libraries
    if testing:
        print(run_num)
        rest_url = rest_services['run_details']['testing'].replace("run_num", run_num)
        logger.info("development server")
    else:
        rest_url = rest_services['run_details']['production'].replace("run_num", run_num)
        logger.info("production server")
    response = requests.get(rest_url)
    if response.status_code != requests.codes.ok:
        response.raise_for_status()
    rest_data = response.json()
    logger.debug("rest_data from %s: %s", rest_url, rest_data)
    sample_info = {}
    if rest_data.get('runId') is None:
        logger.info("JSON data is empty for run num %s", run_num)
        return sample_info
    for mux_id, out_dir in mux_list:
        fastq_data_dir = os.path.join(out_dir[0], 'out', "Project_"+mux_id)
        if os.path.exists(fastq_data_dir):
            for rows in rest_data['lanes']:
                if mux_id in rows['libraryId']:
                    if "MUX" in rows['libraryId']:
                        for child in rows['Children']:
                            if child['Analysis'] != "Sequence only":
                                ctime, _ = generate_window(1)
                                sample_dict = {}
                                sample = child['libraryId']
                                sample_dict['requestor'] = rows['requestor']
                                sample_dict['ctime'] = ctime
                                sample_dict['pipeline_name'] = child['Analysis']
                                if 'pipeline_version' in rows:
                                    sample_dict['pipeline_version'] = child['pipeline_version']
                                else:
                                    sample_dict['pipeline_version'] = None
                                sample_dict['pipeline_params'] = 'params'
                                sample_dict['site'] = get_site()
                                out_dir = get_downstream_outdir(sample_dict['requestor'], \
                                    sample_dict['pipeline_version'], sample_dict['pipeline_name'])
                                sample_dict['out_dir'] = out_dir
                                readunits_dict = {}
                                status, fq1, fq2 = check_fastq(fastq_data_dir, child['libraryId'],\
                                    rows['laneId'])
                                if status:
                                    ru = ReadUnit(run_num_flowcell, flowcellid, child['libraryId'],\
                                        rows['laneId'], None, fq1, fq2)
                                    k = key_for_read_unit(ru)
                                    readunits_dict[k] = dict(ru._asdict())
                                    sample_dict['readunits'] = readunits_dict
                                    if sample_info.get(sample, {}).get('readunits'):
                                        sample_info[sample]['readunits'].update(readunits_dict)
                                    else:
                                        sample_info[sample] = sample_dict
                    else:
                        if rows['Analysis'] != "Sequence only":
                            sample = rows['libraryId']
                            status, fq1, fq2 = check_fastq(fastq_data_dir, rows['libraryId'], \
                                rows['laneId'])
                            if status:
                                ctime, _ = generate_window(1)
                                sample_dict = {}
                                readunits_dict = {}
                                ru = ReadUnit(run_num_flowcell, flowcellid, rows['libraryId'], \
                                    rows['laneId'], None, fq1, fq2)
                                k = key_for_read_unit(ru)
                                readunits_dict[k] = dict(ru._asdict())
                                sample_dict['readunits'] = readunits_dict
                                sample_info[sample] = sample_dict
    return sample_info

def main():
    """main function
    """
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('-n', "--dry-run", action='store_true',
                        help="Don't run anything")
    parser.add_argument('-t', "--testing", action='store_true',
                        help="Use MongoDB test-server here and when calling bcl2fastq wrapper (-t)")
    default = 14
    parser.add_argument('-w', '--win', type=int, default=default,
                        help="Number of days to look back (default {})".format(default))
    parser.add_argument('-v', '--verbose', action='count', default=0,
                        help="Increase verbosity")
    parser.add_argument('-q', '--quiet', action='count', default=0,
                        help="Decrease verbosity")
    args = parser.parse_args()

    # Repeateable -v and -q for setting logging level.
    # See https://www.reddit.com/r/Python/comments/3nctlm/what_python_tools_should_i_be_using_on_every
    # and https://gist.github.com/andreas-wilm/b6031a84a33e652680d4
    # script -vv -> DEBUG
    # script -v -> INFO
    # script -> WARNING
    # script -q -> ERROR
    # script -qq -> CRITICAL
    # script -qqq -> no logging at all
    logger.setLevel(logging.WARN + 10*args.quiet - 10*args.verbose)

    user_name = getpass.getuser()
    if user_name != "userrig":
        logger.warning("Not a production user. Skipping MongoDB update")
        sys.exit(0)

    connection = mongodb_conn(args.testing)
    if connection is None:
        sys.exit(1)
    db = connection.gisds.runcomplete
    epoch_present, epoch_back = generate_window(args.win)
    results = db.find({"analysis.per_mux_status" : {"$exists": True},
                       "timestamp": {"$gt": epoch_back, "$lt": epoch_present}})
    logger.info("Found %s runs", results.count())
    run_list = {}
    mongo_db_ref = {}
    for record in results:
        run_number = record['run']
        print(run_number)
        mux_list = {}
        for (analysis_count, analysis) in enumerate(record['analysis']):
            analysis_id = analysis['analysis_id']
            per_mux_status = analysis.get("per_mux_status", None)
            if per_mux_status is None:
                continue
            for (mux_count, mux_status) in enumerate(per_mux_status):
                # sanity checks against corrupted DB entries
                if mux_status is None or mux_status.get('mux_id') is None:
                    logger.warning("mux_status is None or incomplete for run %s analysis %s."
                                   " Requires fix in DB. Skipping entry for now.", \
                                    run_number, analysis_id)
                    continue
                if mux_status.get('Status', None) != "SUCCESS":
                    logger.info("MUX %s from %s is not SUCCESS. Skipping downstream analysis",
                                mux_status['mux_id'], run_number)
                    continue
                mux_id = mux_status['mux_id']
                out_dir = analysis['out_dir']
                mux_db_id = "analysis.{}.per_mux_status.{}.DownstreamSubmission".format(
                    analysis_count, mux_count)
                if mux_status.get('Status') == "SUCCESS" and \
                    mux_status.get('DownstreamSubmission', None) == "TODO":
                    mongo_list = (mux_id, mux_db_id, analysis_id)
                    mongo_db_ref.setdefault(run_number, []).append(mongo_list)
                    mux_list.setdefault(mux_id, []).append(out_dir)
        for mux_id, out_dir in mux_list.items():
            mux_list_success = mux_list[mux_id]
            #Check if MUX has been analyzed more then 1 time successfully
            if len(mux_list_success) > 1:
                body = "{} has been analyzed more than 1 time successfully..".format(mux_id) \
                    + "delegator is skipping the downstream analysis under {}. Please" \
                    "check the results.".format(mux_list_success)
                subject = "Downstream delegator skipped job submission for {}".format(mux_id)
                if args.testing:
                    subject += " (testing)"
                send_mail(subject, body, toaddr='veeravallil', ccaddr=None)
                continue
            mux_info = (mux_id, out_dir)
            run_list.setdefault(run_number, []).append(mux_info)
    for run_num_flowcell, mux_list in run_list.items():
        update_status = True
        pipeline_params_dict = get_lib_details(run_num_flowcell, mux_list, args.testing)
        if not bool(pipeline_params_dict):
            logger.warning("pipeline_paramas_dict is empty for run num %s", run_num_flowcell)
            continue
        for lib, lib_info in pipeline_params_dict.items():
            readunits_list = list()
            for outer_key in lib_info:
                if outer_key == 'readunits':
                    for inner_key in lib_info[outer_key]:
                        readunits_list.append(inner_key)
            lib_info['samples'] = {}
            lib_info['samples'][lib] = readunits_list
            if args.dry_run:
                logger.warning("Skipping job delegation for %s", \
                    lib)
                continue
            res = mongodb_insert_libjob(lib_info, connection)
            if not res:
                logger.critical("Skipping rest of analysis job submission" \
                     "for %s from %s", lib, lib_info.run_id)
                subject = "Downstream delegator failed job submission for" \
                    "{}".format(lib)
                if args.testing:
                    subject += " (testing)"
                body = "Downstream delegator failed to insert job submission for" \
                    "{}".format(lib)
                send_mail(subject, body, toaddr='veeravallil', ccaddr=None)
                update_status = False
                logger.warning("Clean up the database for mux %s from run %s and ctime %s", \
                    lib_info.mux_id, lib_info.run_id, lib_info.ctime)
                mongodb_remove_muxjob(lib_info.mux_id, lib_info.run_id, \
                    lib_info.ctime, connection)
                break
        if not args.dry_run and update_status:
            value = mongo_db_ref[run_num_flowcell]
            for mux_id, insert_id, analysis_id in value:
                logger.info("Update mongoDb runComplete for %s and runnumber is %s" \
                    "and id is %s and analysis_id %s", run_num_flowcell, mux_id, \
                    insert_id, analysis_id)
                res = mongodb_update_runcomplete(run_num_flowcell, analysis_id, mux_id, \
                    insert_id, connection)
                if not res:
                    logger.critical("Skipping rest of analysis job submission for %s" \
                        "from %s", mux_id, run_num_flowcell)
                    subject = "Downstream delegator failed job submission for {}" \
                        .format(mux_id)
                    if args.testing:
                        subject += " (testing)"
                    body = "Downstream delegator failed to insert job submission for" \
                        "{}".format(mux_id)
                    send_mail(subject, body, toaddr='veeravallil', ccaddr=None)
                    update_status = False
                    break
    connection.close()

if __name__ == "__main__":
    logger.info("Send email to Users and NGSP")
    main()