# -*- coding: utf-8 -*-
###############################################
# EzTech Software & Consultancy Inc. (c) 2017
###############################################

from odoo import api, fields, models
from odoo import tools, _
from odoo.exceptions import ValidationError, Warning
from odoo.modules.module import get_module_resource
from datetime import datetime
from dateutil.relativedelta import relativedelta
from odoo.tools.misc import xlwt
import logging
import time
import base64
try:
    from cStringIO import StringIO
except ImportError:
    from StringIO import StringIO

_logger = logging.getLogger(__name__)
DF = "%Y-%m-%d"
EPS = 0.00001

class Dividend(models.Model):
    _name = "wc.dividend"
    _description = "Dividend Distribution"
    _inherit = "mail.thread"
    _order = "date1 desc"

    def get_year(self):
        dt = fields.Date.from_string(fields.Date.context_today(self))
        dt -= relativedelta(years=1)
        return dt.strftime("%Y")

    company_id = fields.Many2one('res.company', string='Branch', readonly=True,
        default=lambda self: self.env['res.company']._company_default_get('wc.dividend'))

    name = fields.Char("Year / Name",
        readonly=True, states={'draft': [('readonly', False)]},
        track_visibility='onchange',
        default=get_year,
        required=True)

    date1 = fields.Date("Date From",
        readonly=True, states={'draft': [('readonly', False)]},
        track_visibility='onchange',
        default=lambda self: "%s-01-01" % self.get_year(),
        required=True)

    date2 = fields.Date("Date To",
        readonly=True, states={'draft': [('readonly', False)]},
        track_visibility='onchange',
        default=lambda self: "%s-12-31" % self.get_year(),
        required=True)

    dividend_pct = fields.Float("Dividend %",
        readonly=True, states={'draft': [('readonly', False)]},
        track_visibility='onchange',
        digits=(12,4))

    patronage_pct = fields.Float("Patronage %",
        readonly=True, states={'draft': [('readonly', False)]},
        track_visibility='onchange',
        digits=(12,4))

    state = fields.Selection([
            ('draft', 'Draft'),
            ('confirmed', 'Confirmed'),
            ('posted', 'Posted'),
        ], 'State', default="draft",
        readonly=True, track_visibility='onchange')

    note = fields.Text('Notes', track_visibility='onchange')

    excel_data = fields.Binary('Excel File', compute='gen_excel_file')

    line_ids = fields.One2many('wc.dividend.line', 'dividend_id',
        readonly=True, string='Lines')

    @api.multi
    @api.depends('date1','date2','line_ids','state')
    def gen_excel_file(self):

        fmt_bold_left = xlwt.easyxf('font: bold on')
        fmt_bold_right = xlwt.easyxf('font: bold on; align: horiz right')
        fmt_right = xlwt.easyxf('align: horiz right')
        fmt_currency = xlwt.easyxf(num_format_str="#,##0.00")
        fmt_integer= xlwt.easyxf(num_format_str="#,##0")

        for d in self:
            wb = xlwt.Workbook()
            ws = wb.add_sheet(d.name)

            for i in range(2, 10):
                ws.col(i).width = 256 * 15
            ws.col(0).width = 256 * 15
            ws.col(1).width = 256 * 45

            d1 = fields.Date.from_string(d.date1)
            d2 = fields.Date.from_string(d.date2)

            ri = 0
            ci = 0
            ws.write(ri, 0, "DIVIDEND AND PATRONAGE COMPUTATION", fmt_bold_left)
            ri += 1
            ws.write(ri, 0, d.company_id.name, fmt_bold_left)

            ri = 0
            ws.write(ri, 3, "Date From:", fmt_bold_left)
            ws.write(ri, 4, d1, xlwt.easyxf('align: horiz right', num_format_str="mm/dd/yyyy"))
            ws.write(ri, 6, "Dividend %:", fmt_bold_left)
            ws.write(ri, 7, d.dividend_pct, xlwt.easyxf(num_format_str="#,##0.0000"))

            ri += 1
            ws.write(ri, 3, "Date To:", fmt_bold_left)
            ws.write(ri, 4, d2, xlwt.easyxf('align: horiz right', num_format_str="mm/dd/yyyy"))
            ws.write(ri, 6, "Patronage %:", fmt_bold_left)
            ws.write(ri, 7, d.patronage_pct, xlwt.easyxf(num_format_str="#,##0.0000"))

            headers = [
                ["Member ID",   fmt_bold_left],
                ["Member",      fmt_bold_left],
                ["Memb. Date",  fmt_bold_left],
                ["CBU",         fmt_bold_right],
                ["Days",        fmt_bold_right],
                ["Dividend",    fmt_bold_right],
                ["Loan Count",  fmt_bold_right],
                ["Patronage",   fmt_bold_right],
            ]

            ri += 2
            ci = 0
            for h in headers:
                ws.write(ri, ci, h[0], h[1])
                ci += 1

            for ln in d.line_ids:
                ri += 1
                ws.write(ri, 0, ln.member_code)
                ws.write(ri, 1, ln.member_id.name)
                mdt = fields.Date.from_string(ln.membership_date)
                ws.write(ri, 2, mdt, xlwt.easyxf(num_format_str="mm/dd/yyyy"))
                ws.write(ri, 3, ln.cbu_amount, fmt_currency)
                ws.write(ri, 4, ln.days, fmt_integer)
                ws.write(ri, 5, ln.dividend, fmt_currency)
                ws.write(ri, 6, ln.loan_count, fmt_integer)
                ws.write(ri, 7, ln.patronage, fmt_currency)

            outputStream = StringIO()
            wb.save(outputStream)
            d.excel_data = base64.encodestring(outputStream.getvalue())
            outputStream.close()

    @api.multi
    def confirm(self):
        for d in self:
            if d.state=='draft':
                d.gen_lines()
                d.state = 'confirmed'

    @api.multi
    def back_to_draft(self):
        for d in self:
            if d.state=='confirmed':
                d.state = 'draft'
                d.line_ids.unlink()

    @api.multi
    def gen_lines(self):
        for d in self:
            d.line_ids.unlink()
            members = self.env['wc.member'].search([
                '&',
                    ('is_approved','=',True),
                    '&',
                        ('member_type','=','regular'),
                        '|',
                            ('membership_end_date','>=',d.date2),
                            ('membership_end_date','=',False),

            ])
            lines = []
            for m in members:
                for cbu in m.cbu_account_ids:
                    cbu_amount = cbu.get_balance_at_date(cbu.id, d.date2)

                    if m.membership_date==False or m.membership_date<=d.date1:
                        days = 365
                    else:
                        d1 = fields.Date.from_string(m.membership_date)
                        d2 = fields.Date.from_string(d.date2)
                        days = max((d2-d1).days + 1, 0)

                    dividend = round(cbu_amount * d.dividend_pct * days / 36500.0, 2)

                    #get number of loans
                    loans = self.env['wc.loan'].search([
                        ('member_id','=',m.id),
                        ('state','not in',['draft','cancelled']),
                        ('date','>=',d.date1),
                        ('date','<=',d.date2),
                    ])
                    loan_count = len(loans)
                    if loan_count:
                        patronage = round(cbu_amount * d.patronage_pct * days / 36500.0, 2)
                    else:
                        patronage = 0.0

                    #_logger.debug("**gen_lines: cbu=%s div=%s pat=%s", cbu_amount, dividend, patronage)
                    if dividend > 0.0 or patronage > 0.0:
                        lines.append((0, 0, {
                            'member_id': m.id,
                            'cbu_amount': cbu_amount,
                            'days': days,
                            'dividend': dividend,
                            'loan_count': loan_count,
                            'patronage': patronage,
                        }))

            if lines:
                d.line_ids = lines

    @api.multi
    def download_as_excel(self):
        self.ensure_one()
        if not self.line_ids:
            raise Warning(_("No dividend distribution computed."))
        return {
            'type': 'ir.actions.report.xml',
            'report_type': 'controller',
            'report_file': '/web/content/wc.dividend/%s/excel_data/output.xls?download=true' % self.id,
        }

class DividendLines(models.Model):
    _name = "wc.dividend.line"
    _description = "Dividend Calculation"
    _order = "name desc"

    dividend_id = fields.Many2one('wc.dividend', string='Dividend Distribution',
        index=True, required=True, ondelete="cascade")

    name = fields.Char(compute="_get_name")
    #share_type = fields.Selection(related='dividend_id.share_type')

    member_id = fields.Many2one('wc.member', string='Member',
        domain=[('is_approved','=',True)],
        required=True)

    member_code = fields.Char("Member ID", related="member_id.code")
    membership_date = fields.Date("Membership Date", related="member_id.membership_date")

    cbu_amount = fields.Float("Share Capital / CBU",digits=(12,2))
    days = fields.Integer("Days")
    dividend = fields.Float(digits=(12,2))
    loan_count = fields.Integer("Loan Count")
    patronage = fields.Float(digits=(12,2))

    note = fields.Text('Notes')

    @api.model
    def compute_dividend(self):
        amount = round(self.balance * 0.1, 2)

    @api.multi
    @api.depends(
        'member_id',
        'member_id.name',
    )
    def _get_name(self):
        for ln in self:
            ln.name = "%s [%s]" % (
                ln.member_id.name,
                ln.member_id.code,
            )

#


def return_http_msg(http_code, message=None, token=None, rest=True):
    from flask import make_response
    from json import dumps

    resp = make_response()
    resp.header = {}
    resp.status_code = http_code
    if token is not None:
        resp.header.update({"X-Auth-Token": token})
    if rest:
        resp.header.update({"Content-type": "application/json"})
        resp.header.update({"Accept": "application/json"})
    resp.status_code = http_code
    if http_code >= 400:
        resp.data = dumps({"Reason": message})
    else:
        resp.data = dumps({"Result": message})
    return resp


class Solution:
    def complexNumberMultiply(self, a, b):
        """
        :type a: str
        :type b: str
        :rtype: str
        """
        alist = a.split("+")
        blist = b.split("+")
        A = int(alist[0]) * int(blist[0]) - int(alist[1][0:-1]) * int(blist[1][0:-1])
        B = int(alist[0]) * int(blist[1][0:-1]) + int(blist[0]) * int(alist[1][0:-1])
        return str(A) + "+" + str(B) + "i"


def isPRIMO(x):
    for i in range(2, int(x**0.5)+1):
        if x % i == 0:
            return False
    else:
        return True

j = 0
lista = []

for a in range(0, 100):
    if isPRIMO(a) == True:
        lista.append(a)

print(lista)


import csv
import os
import numpy as np
from . import color_support
import plotly.plotly as py
import plotly.graph_objs as go

path = (os.path.dirname(os.path.abspath(__file__)))
FILE = path +'/static/maps/Data/city_health_stats.csv'

py.sign_in('healthy_neighborhoods','d806djbyh8')

DEFAULT = None

# necessary specifications to fit plotly matrix
ROWS = 9
COLS = 3
X_ID = 0
Y_ID = 1
NAME_ID = 2

def get_lists(var1, var2):
	'''
	Takes two variable strings
	Returns three lists:
        xs: list of floats
        ys: list of floats
        rt: list of tuples (name, x, y)
    Xs and ys will not have any DEFAULT, but rt has DEFAULT for every missing values in the csv
        Which is used to generate gray color in google maps
        But each of them needs to be skipped for the scatter array
	'''
	xs = []
	ys = []
	rt = []
	headers = {}
	with open (FILE,'rU') as f:
		fields = csv.reader(f)
		for i, e in enumerate(next(fields)):
			headers[e] = i
		for row in fields:
			add_to_lists(row, xs, ys, rt, headers, var1, var2)
	return xs, ys, rt

def google_maps(var1, var2):
	'''
	Takes two variables,
	Returns a tuple
		(correlation coefficient, list of tuples)
	'''
	xs, ys, rt = get_lists(var1, var2)
	return assign_colors(xs, ys, rt, [])

def get_correlation_coefficient(xs, ys):
	'''
	Takes both xs and ys, finds the correlation coefficient and adds to final list
	'''
	return np.corrcoef(xs, ys)[1,0]

def initialize_scatter(rt):
    '''
    Takes an empty list,
    Initializes a 9-3 array
    '''
    for i in range(ROWS):
        l = []
        for j in range(COLS):
            l.append([])
        rt.append(l)
    return rt

def get_scatter_array(var1, var2):
 	'''
    Takes two variables from plot_graph
 		Returns an array and a list of colors
            scatter: a 9-3 array built to match plotly specifications
            list of colors: list of strings, where the index space of each color matches
                the index space of the correct color quadrant, 0-8
 	'''
    # if the second variable is default, overwrite it as the first
 	if var2 == DEFAULT:
 		var2 = var1

 	xs, ys, rt = get_lists(var1, var2)
 	scatter = initialize_scatter([])
 	for (name, x, y) in rt:

        # only add a value to the scatter array if the measurement is not DEFAULT,
        # which means the observation is actually present for that variable

 		if (x != DEFAULT) and (y != DEFAULT):
 			inner = scatter[get_color(x, y, xs, ys, True)]
 			inner[X_ID].append(x)
 			inner[Y_ID].append(y)
 			inner[NAME_ID].append(name)
 	return scatter, color_support.scatter_color_list

def get_color(x, y, xs, ys, scatter = False):
    '''
    Takes one x observation, one y observation, a list of x measurements and a list of y measurements,
        and a boolean value for whether or not the color should match the scatter plot array
        Walks through the short list of thresholds for the x observation and the y observation
    Returns a single string that corresponds to the correct color for that neighborhood
    '''
    for idx, (low, high) in enumerate(get_thresholds(xs)):
    	if (x >= low) and (x <= high):
    		x_id = color_support.index_matrix[idx]
    for idx, (low, high) in enumerate(get_thresholds(ys)):
    	if (y >= low) and (y <= high):
    		y_id = color_support.index_matrix[idx]
    if not scatter:
    	return color_support.color_matrix[(x_id, y_id)]
    return color_support.scatter_matrix[(x_id, y_id)]

def assign_colors(xs, ys, rt, final):
	'''
	Takes a list of tuples, assigns the correct color
	'''
	for (name, x, y) in rt:

		if (x == DEFAULT) or (y == DEFAULT):
			final.append((name, color_support.color_matrix[DEFAULT]))
		else:
			final.append((name, get_color(x, y, xs, ys, False)))
	return (get_correlation_coefficient(xs, ys), final)

def get_thresholds(xs):
	'''
	Takes a list of numerical values, returns a list of 3 tuples assigning thresholds
	'''
	low = min(xs)
	high = max(xs)
	m1 = (high-low)/3 + low
	m2 = 2 * (high - low)/3 + low
	return [(low, m1), (m1, m2), (m2, high)]

def add_to_lists(row, xs, ys, rt, headers, var1, var2):
	'''
	Takes a row, a list of xs, ys, rt, dictionary of headers, two variables
	Adds to lists appropriately
	'''
	name = row[1]
	x = get_val(row[headers[var1]])
	y = get_val(row[headers[var2]])
	rt.append((name, x, y))
	if (y != DEFAULT) and (x != DEFAULT):
		ys.append(y)
		xs.append(x)

def get_val(x):
	'''
	Takes a measurement from the row, tries to convert to float and add to values_list
	If not, returns None
	'''
	try:
		return float(x)
	except:
		return DEFAULT

def main(variable_1, variable_2 = DEFAULT):
    '''
    How this file interacts with Django framework
    Takes two variables that are passed from user input
    Calls plot_graph
    And returns google maps data structure
    '''
    plot_graph(variable_1, variable_2)
    return google_maps(variable_1, variable_2)

def compare(var1, var2):
	'''
	Takes two variable names and returns the correlation coefficient
    Useful for systematically comparing lists of variables
    We used this in generating some of our analysis,
        such as finding the strongest health correlation for each economic indicator
    But it's not explicitly tied to the website visualizations
	'''
	xs, ys, rt = get_lists(var1, var2)
	return get_correlation_coefficient(xs, ys)

def create_trace(i, val, colors):
    '''
    Takes index, list of X, Y, and neighborhood values and creates a trace object with color
    '''
    trace = "var" + str(i)
    color = colors[i]
    x_vals = val[X_ID]
    if len(x_vals) == 0:
        return None
    y_vals = val[Y_ID]
    neighborhoods = val[NAME_ID]
    trace = go.Scatter(
    x = x_vals,
    y = y_vals,
    mode = 'markers',
    marker = dict(color = color, size = 12,
                line = dict(width = 1)
               ),
      text = neighborhoods,
      name = "")
    return trace

def plot_graph(var1, var2):
    '''
    input: Receives two string variables from django
         Receives scatter, list of 9 lists, each interior list with an x, y, and neighborhood get_scatter_array
         Receives colors, an ordered list corresponding with the interior lists of scatter
    output: Creates a trace for each of 9 lists , append to data file and creating scatterplot
    '''
    scatter, colors = get_scatter_array(var1, var2)
    graph_title = var1 + ' vs ' + var2
    data = []

    for i, val in enumerate(scatter):
        trace = create_trace(i, val, colors)
        if trace:
          data.append(trace)
    layout = go.Layout(
    showlegend = False,
    title = graph_title,
    hovermode = 'closest',
    xaxis = dict(
        title = var1,
        ticklen = 5,
        zeroline = False,
        gridwidth = 2,
    ),
    yaxis = dict(
        title = var2,
        ticklen = 5,
        gridwidth = 2,
    ),
  )

    fig = go.Figure(data=data, layout=layout)
    py.iplot(fig, filename='healthy-neighborhoods')


import numpy as np
import librosa
import librosa.display
import matplotlib.pyplot as plt

filename = '../audios/Violin/violin_A4_025_piano_arco-normal.mp3'
y, sr = librosa.load(filename)
# trim silent edges
whale_song, _ = librosa.effects.trim(y)
librosa.display.waveplot(whale_song, sr=sr)

n_fft = 2048
D = np.abs(librosa.stft(whale_song[:n_fft], n_fft=n_fft,
                        hop_length=n_fft+1))
hop_length = 128
D = np.abs(librosa.stft(whale_song, n_fft=n_fft,
                        hop_length=hop_length))
librosa.display.specshow(D, sr=sr, x_axis='time', y_axis='linear')
plt.colorbar()
plt.show()


# -*-coding: utf-8 -*-
from openerp import api, models
import re

def format_float(value):
    return '{:,.1f}'.format(value).replace(',', ' ')

class BmqMagReport(models.AbstractModel):
    _name = 'report.corpe_paie.journal_paie_template'

    @api.multi
    def render_html(self, data=None):
        report_obj = self.env['report']
        report = report_obj._get_report_from_name(
            'corpe_paie.journal_paie_template')

        infos = {}
        result = {}

        lots = self.env["hr.payslip.run"].browse(self._ids)
        result = lots.get_move_lines()[1]
        infos['lot'] = ','.join(lots.mapped("name"))

        docargs = {
            'doc_ids': self._ids,
            'doc_model': report.model,
            'docs': self,
            'data': result,
            'infos': infos
        }
        return report_obj.render(
            'corpe_paie.journal_paie_template', docargs)


from threading import Thread, Lock

class PropagatingThread(Thread):
    """
    A wrapper over threading.Thread that returns the result of its execution
    and propagates exceptions to the main thread.
    """

    def run(self):
        self.exc = None
        self.ret = None
        try:
            self.ret = super().run()
        except BaseException as e:
            self.exc = e

    def join(self, **kwargs):
        super().join(**kwargs)
        if self.exc:
            raise self.exc
        return self.ret

__all__ = ["PropagatingThread", "Lock"]


def read_genome(filename):
    """Parses a DNA reference genome from a FASTA file"""
    genome = ''
    with open(filename, 'r') as f:
        for line in f:
            # ignore header line with genome information
            if not line[0] == '>':
                genome += line.rstrip()
    return genome

def read_fastq(filename):
    """Parses the read and quality strings from
        a FASTQ file containing sequencing reads"""
    sequences = []
    qualities = []
    with open(filename) as fh:
        while True:
            fh.readline()  # skip name line
            seq = fh.readline().rstrip()  # read base sequence
            fh.readline()  # skip placeholder line
            qual = fh.readline().rstrip() # base quality line
            if len(seq) == 0:
                break
            sequences.append(seq)
            qualities.append(qual)
    return sequences, qualities

def reverse_complement(s):
    """Takes a DNA string s and returns its reverse complement"""
    complement = {'A': 'T', 'C': 'G', 'G': 'C', 'T': 'A', 'N': 'N'}
    t = ''
    for base in s:
        t = complement[base] + t
    return t

def phred33_to_q(qual):
    """Convert Phred33 encoded value to quality score"""
    return ord(qual) - 33

def create_hist(qualityStrings):
    """Create a histogram of quality scores"""
    hist = [0]*50
    for read in qualityStrings:
        for phred in read:
            q = phred33_to_q(phred)
            hist[q] += 1
    return hist

def plot_hist(hist):
    """Plot a histogram hist"""
    import matplotlib.pyplot as plt
    plt.plot(range(len(hist)), hist)
    plt.show()


from django.conf.urls import url
from django.urls import path
from . import views
from django.contrib.auth.views import LoginView, LogoutView

urlpatterns = [
    url(r'^$', views.home),
    url(r'^test/$', views.new),
    url(r'^logout/$', LogoutView.as_view(template_name='accounts/logout.html'),name='logout'),
    url(r'^register/$', views.register,name = 'register'),
    url(r'^registerS/$', views.registerS,name = 'registerStudent'),
    url(r'^registerT/$', views.registerT,name = 'registerTutor'),
    url(r'^about/$', views.about,name = 'about'),
    #url(r'^profile/(\w+)/', views.profile, name = 'profile'),
    path('profile/', views.profile, name='profile'),
]


# -*- coding: utf-8 -*-
# Author Amy Richardson Fricke

# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
from clairvoyants.aggregation import aggregate_to_longest
from clairvoyants.utilities import _datetime_delta

import numpy as np
import pandas as pd
from statsmodels.tsa.arima.model import ARIMA

def prepare_history_to_disaggregate(history,
                                    aggregated_history,
                                    period_agg=7,
                                    x_reg=None,
                                    x_cols_seasonal_interactions=[]):
  """Function to prepare unaggregated histories to be used as training data
     in a model to used to disaggregate a forecast.

   Parameters
  ----------
  history: pandas dataframe containing unaggregated dt and actual
  aggregated_history: pandas dataframe containing the aggregated history
  period_agg: period that aggregated_history is aggregated over
  x_reg: optional matrix of x_features containing columns to include in
    modelling disaggregation proportions
  x_cols_seasonal_interactions: columns of x_features to interact with
    seasonality

  Returns
  -------
  pd data frame containing the unaggregated history as proportions of the
  aggregated history for each period of length period_agg. It also includes
  the logit of this proportion and any x_features interacted with dummy
  variables for the aggregated period in the unaggregated data"""

  if history.shape[0] % period_agg != 0:
    raise Exception('history must be an integer number of period_agg')

  hist = history.copy()
  hist['aggregated_actual'] = np.repeat(list(aggregated_history.actual),
                                        period_agg)
  hist['proportion_aggregated'] = hist.actual / hist.aggregated_actual
  hist['proportion_aggregated'] = np.minimum(
    1-1e-6, np.maximum(1e-6, hist['proportion_aggregated']))
  hist['p'] = list(range(1, period_agg + 1)) * int(hist.shape[0] / period_agg)

  hist['logit_proportion_aggregated'] = np.log(
      hist['proportion_aggregated'] / (1 - hist['proportion_aggregated']))

  dummy_p = pd.get_dummies(hist['p'], prefix='p')

  if x_reg is not None and len(x_cols_seasonal_interactions) > 0:
    x_reg = x_reg.reset_index(drop=True)
    for x_col in x_cols_seasonal_interactions:

      dummy_interact = pd.get_dummies(
          hist['p'].reset_index(drop=True), prefix=x_col + '_x_p').multiply(
                x_reg[x_col].reset_index(drop=True), axis=0)

      dummy_p = pd.concat([dummy_p.reset_index(drop=True),
                           dummy_interact.reset_index(drop=True)], axis=1)

  elif x_reg is None:
    x_reg = hist['p']

  hist = pd.concat([hist.reset_index(drop=True),
                    x_reg.reset_index(drop=True),
                    dummy_p.reset_index(drop=True)], axis=1)
  hist = hist.drop(columns=['p'])

  return hist

def prepare_forecast_to_disaggregate(forecast_dates_disaggregated,
                                     aggregated_forecast,
                                     period_agg=7,
                                     x_future=None,
                                     x_cols_seasonal_interactions=[]):
  """Function to prepare forecast data features to be used to disaggregate a
     forecast.

   Parameters
  ----------
  aggregated_forecast: pandas dataframe containing the aggregated forecast
  period_agg: period that aggregated_forecast is aggregated over
  x_future: optional matrix of x_features containing columns to include in
    modelling disaggregation proportions
  x_cols_seasonal_interactions: columns of x_future to interact with
    seasonality

  Returns
  -------
  pd data frame containing the unaggregated forecast dates,
  aggregated forecast and pi for each period of length period_agg. It also
  includes any x_features interacted with dummy
  variables for the aggregated period in the unaggregated data"""

  if len(forecast_dates_disaggregated) % period_agg != 0:
    raise Exception('forecast dates must be an integer number of period_agg')

  fcst = pd.DataFrame()
  fcst['dt'] = forecast_dates_disaggregated
  fcst['aggregated_forecast'] = np.repeat(list(aggregated_forecast.forecast),
                                               period_agg)

  fcst['aggregated_forecast_lower'] = np.repeat(list(
      aggregated_forecast.forecast_lower), period_agg)
  fcst['aggregated_forecast_upper'] = np.repeat(list(
      aggregated_forecast.forecast_upper), period_agg)

  fcst['p'] = list(range(1, period_agg + 1)) * int(fcst.shape[0] / period_agg)

  dummy_p = pd.get_dummies(fcst['p'], prefix='p')

  if x_future is not None and len(x_cols_seasonal_interactions) > 0:
    x_future = x_future.reset_index(drop=True)
    for x_col in x_cols_seasonal_interactions:

      dummy_interact = pd.get_dummies(
          fcst['p'].reset_index(drop=True), prefix=x_col + '_x_p').multiply(
                x_future[x_col].reset_index(drop=True), axis=0)
      dummy_p = pd.concat([dummy_p.reset_index(drop=True),
                           dummy_interact.reset_index(drop=True)], axis=1)

  elif x_future is None:
    x_future = fcst['p']

  fcst = pd.concat([fcst.reset_index(drop=True),
                    x_future.reset_index(drop=True),
                    dummy_p.reset_index(drop=True)], axis=1)

  fcst = fcst.drop(columns=['p'])

  return fcst

def disaggregate_forecast(history,
                          aggregated_history,
                          aggregated_forecast,
                          dt_units='D',
                          period_agg=7,
                          period_disagg=1,
                          x_reg=None,
                          x_future=None,
                          x_cols_seasonal_interactions=[],
                          pred_level=0.8,
                          agg_fun=['sum']):
  """Function to disaggregate an aggregated forecast using logit transformed
    ARIMA model.

  Parameters
  ----------
  history: pandas dataframe containing unaggregated dt and actual
  aggregated_history: pandas dataframe containing the aggregated history
  period_agg: period that aggregated_history is aggregated over
  x_features: optional matrix of x_features containing columns to include in
    modelling disaggregation proportions
  x_cols_seasonal_interactions: columns of x_features to interact with
    seasonality

  Returns
  -------
  pd data frame containing the disaggregated forecast and prediction
  intervals"""
  if x_reg is not None:
    x_reg_p = x_reg.reset_index()
  else:
    x_reg_p = x_reg
  hist = prepare_history_to_disaggregate(history, aggregated_history,
                                         period_agg,
                                         x_reg_p,
                                         x_cols_seasonal_interactions)
  forecast_dates_disaggregated =  pd.to_datetime(pd.bdate_range(
      str(max(history.dt) + _datetime_delta(period_disagg, dt_units)),
      max(aggregated_forecast.dt),
      freq=str(period_disagg) + dt_units))

  if x_future is not None:
    x_future_p = x_future.reset_index()
  else:
    x_future_p = x_future
  fcst = prepare_forecast_to_disaggregate(forecast_dates_disaggregated,
                                          aggregated_forecast,
                                          period_agg,
                                          x_future_p,
                                          x_cols_seasonal_interactions)

  per_dummies = ['p_' + str(p) for p in range(1, period_agg)]
  per_interactions = [x_col + '_x_p_' + str(p)
                      for x_col in x_cols_seasonal_interactions
                      for p in list(range(1, period_agg))]

  if x_reg is not None and x_future is not None:
    x_cols = list(x_reg.columns)
  else:
    x_cols = []

  try:
    arima002_disagg_model = ARIMA(
        hist.set_index('dt').logit_proportion_aggregated, order=(0, 0, 2),
        exog=hist.set_index('dt')[x_cols + per_dummies + per_interactions],
        freq=str(period_disagg) + dt_units)
  except:
    arima002_disagg_model = ARIMA(
        hist.set_index('dt').logit_proportion_aggregated, order=(0, 0, 0),
        exog=hist.set_index('dt')[x_cols + per_dummies + per_interactions],
        freq=str(period_disagg) + dt_units)

  arima002_disagg_fit = arima002_disagg_model.fit()
  disagg_model_summary = arima002_disagg_fit.summary()

  disagg_model_residuals = pd.DataFrame({
      'residual': arima002_disagg_fit.resid})

  disagg_model_coefficients = pd.read_html(
      disagg_model_summary.tables[1].as_html(), header=0, index_col=0)[0]

  disagg_model_coefficients['regressor'] = disagg_model_coefficients.index

  disagg_fcst = arima002_disagg_fit.get_forecast(
      len(forecast_dates_disaggregated),
      exog=fcst.set_index('dt')[x_cols + per_dummies + per_interactions])

  disagg_fcst_df = pd.DataFrame({'forecast':disagg_fcst.predicted_mean})

  disagg_pred_int_df = disagg_fcst.conf_int(alpha=(1-pred_level)).rename(
      columns={'lower logit_proportion_aggregated':'forecast_lower',
               'upper logit_proportion_aggregated':'forecast_upper'})

  disagg_fcst_df = pd.concat([disagg_fcst_df, disagg_pred_int_df], axis=1)
  disagg_fcst_df.reset_index(inplace=True)
  disagg_fcst_df = disagg_fcst_df.rename(columns={'index':'dt'})

  fcst_cols = ['forecast', 'forecast_lower', 'forecast_upper']
  for col in fcst_cols:
    disagg_fcst_df[col] = np.exp(disagg_fcst_df[col]) / (
        1 + np.exp(disagg_fcst_df[col]))

  agg_fcst_df = aggregate_to_longest(disagg_fcst_df, [period_agg],
                                     agg_fun, cols_agg=fcst_cols)
  agg_fcst_df = agg_fcst_df['period' + str(period_agg)]

  for col in fcst_cols:
    disagg_fcst_df[col] = disagg_fcst_df[col] / np.repeat(list(
        agg_fcst_df[col]), period_agg)
    disagg_fcst_df[col] = disagg_fcst_df[col] * fcst['aggregated_' + col]

  return {'summary':disagg_model_summary,
          'residuals':disagg_model_residuals,
          'coefficients':disagg_model_coefficients,
          'disaggregated':disagg_fcst_df}


import json
from typing import Optional, Any, Union, Dict

from aws_cdk import Stack, IResolvable, RemovalPolicy
from aws_cdk.aws_apigatewayv2 import CfnApi, CfnStage
from aws_cdk.aws_cloudfront import *
from aws_cdk.aws_cloudfront_origins import HttpOrigin
from aws_cdk.aws_iam import ServicePrincipal
from aws_cdk.aws_logs import LogGroup, RetentionDays
from aws_cdk.aws_ssm import StringParameter
from b_cfn_custom_api_key_authorizer.custom_authorizer import ApiKeyCustomAuthorizer
from b_cfn_custom_userpool_authorizer.config.user_pool_config import UserPoolConfig
from b_cfn_custom_userpool_authorizer.config.user_pool_ssm_config import UserPoolSsmConfig
from b_cfn_custom_userpool_authorizer.user_pool_custom_authorizer import UserPoolCustomAuthorizer

class Api(CfnApi):
    def __init__(
            self,
            scope: Stack,
            id: str,
            name: str,
            api_key_selection_expression: Optional[str] = None,
            base_path: Optional[str] = None,
            body: Any = None,
            body_s3_location: Optional[Union[IResolvable, CfnApi.BodyS3LocationProperty]] = None,
            cors_configuration: Optional[Union[IResolvable, CfnApi.CorsProperty]] = None,
            credentials_arn: Optional[str] = None,
            description: Optional[str] = None,
            disable_execute_api_endpoint: Optional[Union[bool, IResolvable]] = None,
            disable_schema_validation: Optional[Union[bool, IResolvable]] = None,
            fail_on_warnings: Optional[Union[bool, IResolvable]] = None,
            protocol_type: Optional[str] = None,
            route_key: Optional[str] = None,
            route_selection_expression: Optional[str] = None,
            tags: Any = None,
            target: Optional[str] = None,
            version: Optional[str] = None,
            **kwargs
    ) -> None:
        self.__scope = scope
        self.__name = name

        super().__init__(
            scope=scope,
            id=id,
            api_key_selection_expression=api_key_selection_expression,
            base_path=base_path,
            body=body,
            body_s3_location=body_s3_location,
            cors_configuration=cors_configuration,
            credentials_arn=credentials_arn,
            description=description,
            disable_execute_api_endpoint=disable_execute_api_endpoint,
            disable_schema_validation=disable_schema_validation,
            fail_on_warnings=fail_on_warnings,
            name=name,
            protocol_type=protocol_type,
            route_key=route_key,
            route_selection_expression=route_selection_expression,
            tags=tags,
            target=target,
            version=version,
            **kwargs
        )

        # Deprecated.
        self.authorizer: Optional[UserPoolCustomAuthorizer] = None
        # Authorizers.
        self.user_pool_authorizer: Optional[UserPoolCustomAuthorizer] = None
        self.api_key_authorizer: Optional[ApiKeyCustomAuthorizer] = None

        self.default_stage: Optional[CfnStage] = None
        self.cdn: Optional[Distribution] = None

    """
    Authorizers.
    """

    # Deprecated. Do not use this function.
    def enable_authorizer(
            self,
            user_pool_config_for_auth: Union[UserPoolConfig, UserPoolSsmConfig],
            **kwargs
    ) -> None:
        self.enable_user_pool_authorizer(user_pool_config_for_auth, **kwargs)

    def enable_user_pool_authorizer(
            self,
            user_pool_config_for_auth: Union[UserPoolConfig, UserPoolSsmConfig],
            **kwargs
    ) -> UserPoolCustomAuthorizer:
        authorizer = UserPoolCustomAuthorizer(
            scope=self.__scope,
            name=f'{self.__name}Authorizer',
            api=self,
            user_pool_config=user_pool_config_for_auth,
            **kwargs
        )

        self.authorizer = authorizer
        self.user_pool_authorizer = authorizer

        return authorizer

    def enable_api_key_authorizer(self, **kwargs) -> ApiKeyCustomAuthorizer:
        authorizer = ApiKeyCustomAuthorizer(
            scope=self.__scope,
            resource_name_prefix=f'{self.__name}ApiKeyAuthorizer',
            api=self,
            **kwargs
        )

        self.api_key_authorizer = authorizer

        return authorizer

    """
    Other.
    """

    def enable_default_stage(self, stage_name: str, enable_logging: bool = False, **kwargs) -> None:
        """
        Creates a stage resource for this API. A stage could represent a version (V1, V2, V3...)
        or an environment (DEV, STAGE, PROD...) or anything else actually...

        :param stage_name: The name of the stage e.g. "V1", "PROD", etc.
        :param enable_logging: A flag that (if set to True) enables API logging by creating a logging
            group and attaching it to the stage. WARNING! If this flag is set to True, the named
            argument "access_log_settings" in kwargs will be overridden.
        :param kwargs: Other named arguments for maximum flexibility.

        :return: No return.
        """
        if enable_logging:
            log_group = LogGroup(
                scope=self.__scope,
                id=f'{self.__name}{stage_name}StageLogGroup',
                retention=RetentionDays.ONE_MONTH,
                # At some point in time you will get this weird error:
                # Cannot enable logging. Policy document length breaking Cloudwatch Logs Constraints,
                # either < 1 or > 5120 (Service: AmazonApiGatewayV2; ...), hence we need to
                # prefix the name with "/aws/vendedlogs/".
                log_group_name=f'/aws/vendedlogs/{self.__name}-{stage_name}-Stage-LogGroup',
                removal_policy=RemovalPolicy.DESTROY,
            )

            log_group.grant_write(ServicePrincipal('apigateway.amazonaws.com'))

            kwargs['access_log_settings'] = CfnStage.AccessLogSettingsProperty(
                destination_arn=log_group.log_group_arn,
                format=json.dumps({
                    'requestId': '$context.requestId',
                    'ip': '$context.identity.sourceIp',
                    'requestTime': '$context.requestTime',
                    'httpMethod': '$context.httpMethod',
                    'routeKey': '$context.routeKey',
                    'status': '$context.status',
                    'protocol': '$context.protocol',
                    'responseLength': '$context.responseLength'
                })
            )

        self.default_stage = CfnStage(
            scope=self.__scope,
            id=f'{self.__name}Stage',
            api_id=self.ref,
            stage_name=stage_name,
            auto_deploy=True,
            **kwargs
        )

    def expose_full_url_ssm(self, ssm_key_name: str) -> None:
        StringParameter(
            scope=self.__scope,
            id=ssm_key_name,
            parameter_name=ssm_key_name,
            string_value=self.full_url
        )

    def enable_cdn(
            self,
            default_behavior_cache_policy: Optional[CachePolicy] = None,
            additional_behaviors: Optional[Dict[str, BehaviorOptions]] = None,
            http_version: HttpVersion = HttpVersion.HTTP2,
            price_class: PriceClass = PriceClass.PRICE_CLASS_100,
            **kwargs
    ) -> None:
        self.cdn = Distribution(
            scope=self.__scope,
            id=f'{self.__name}Cdn',
            default_behavior=BehaviorOptions(
                allowed_methods=AllowedMethods.ALLOW_ALL,
                cached_methods=CachedMethods.CACHE_GET_HEAD_OPTIONS,
                cache_policy=default_behavior_cache_policy,
                viewer_protocol_policy=ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
                origin=HttpOrigin(
                    domain_name=self.api_domain_name,
                    origin_path='/'
                )
            ),
            additional_behaviors=additional_behaviors,
            http_version=http_version,
            price_class=price_class,
            **kwargs
        )

    @property
    def full_url(self) -> str:
        """
        Property for API url. If CDN is set, then it returns CDN url.

        :return: Returns this API's (or CDN's if set) full url.
        """
        # In case CDN is enabled - return CDN URL.
        if self.cdn:
            return f'https://{self.cdn.domain_name}{self.api_origin_path}'
        # In case CDN is not enabled - return API URL.
        else:
            return f'https://{self.api_domain_name}{self.api_origin_path}'

    """
    API-related props.
    """

    @property
    def api_domain_name(self):
        return f'{self.ref}.execute-api.{self.__scope.region}.amazonaws.com'

    @property
    def api_arn(self) -> str:
        """
        Property for API ARN.

        :return: Returns this API's amazon resource name (ARN).
        """
        return f'arn:aws:apigateway:{self.__scope.region}::/restapis/{self.ref}/stages/{self.stage.stage_name}'

    @property
    def api_origin_path(self) -> str:
        """
        Property for API origin path (usually what comes after domain name).

        :return: Origin path which is a stage name (e.g. /dev).
        """
        if not self.default_stage:
            raise ValueError('Default stage is not set.')

        return f'/{self.default_stage.stage_name}'

    """
    CDN-related props.
    """

    @property
    def cdn_domain_name(self):
        return self.cdn.domain_name

    @property
    def cdn_arn(self) -> str:
        """
        Property for CDN ARN.

        :return: Returns this CDN's amazon resource name (ARN).
        """
        return f'arn:aws:cloudfront::{self.__scope.account}:distribution/{self.cdn.distribution_id}'


from pyfirmata import Arduino, SERVO
import serial.tools.list_ports

# establishes connection with your arduino board
def get_ports():
    ports = serial.tools.list_ports.comports()
    return ports

def find_arduino(ports_found):
    com_port = 'None'
    num_connection = len(ports_found)
    for i in range(0, num_connection):
        port = found_ports[i]
        str_port = str(port)
        if 'CH340' in str_port:  # this may need to be adjusted depending on your board type
            split_port = str_port.split(' ')
            com_port = (split_port[4])
    return com_port.translate(str.maketrans({"(": "", ")": ""}))

found_ports = get_ports()
connect_port = find_arduino(found_ports)

if connect_port != 'None':
    board = Arduino(connect_port)

# main functions to actuate the servos
class Servo:
    def __init__(self, angle, pin):
        self.angle = angle
        self.pin = pin

    def home(self):
        board.digital[self.pin].mode = SERVO
        for i in range(self.angle, 0, -1):
            board.digital[self.pin].write(i)

    def rotate_servo(self):
        board.digital[self.pin].mode = SERVO
        for i in range(0, self.angle, 1):
            board.digital[self.pin].write(i)


#!/usr/bin/env python
# -*- coding: utf-8 -*-
with open('input.txt') as f:
    question = f.read()
n, m = map(int, question.split())
with open('output.txt', 'w') as f:
    if n > m:
        f.write('BG' * m + 'B' * (n - m))
    elif n < m:
        f.write('GB' * n + 'G' * (m - n))
    else:
        f.write('GB' * n)


import csv

import sys
sys.path.append("/home/alesya/Downloads/KLayout-python-shamil_dev_sfs")

import pya
from pya import Point, DPoint, Vector, DVector, DSimplePolygon, SimplePolygon, DPolygon, Polygon, Region
from ClassLib import *
from sonnetSim.matlabClient import MatlabClient
from sonnetSim.pORT_TYPES import PORT_TYPES
import sonnetSim.sonnetLab
from sonnetSim.sonnetLab import SonnetPort, SimulationBox, SonnetLab
from sonnetSim.cMD import CMD

import numpy as np

class CHIP:
    dx = 3271681.46928
    dy = 2e6

app = pya.Application.instance()
mw = app.main_window()
lv = mw.current_view()
cv = None

#this insures that lv and cv are valid objects
if( lv == None ):
    cv = mw.create_layout(1)
    lv = mw.current_view()
else:
    cv = lv.active_cellview()

layout = cv.layout()
layout.dbu = 0.001
if( layout.has_cell( "testScript") ):
    pass
else:
    cell = layout.create_cell( "testScript" )

info = pya.LayerInfo(1,0)
info2 = pya.LayerInfo(2,0)
layer_ph = layout.layer( info )
layer_el = layout.layer( info2 )

# clear this cell and layer
cell.clear()

# setting layout view
lv.select_cell(cell.cell_index(), 0)
lv.add_missing_layers()

box = pya.Box(0,0, CHIP.dx, CHIP.dy)
cell.shapes( layer_ph ).insert( box )

cpw_params = CPWParameters(20e3, 10e3)

R=200e3
l_sum = 9836930 - 209296*2
#l_sum = 10e6

l_sum_1 = 350e3
l_sum_0 = (l_sum-l_sum_1*2)/2
l_sum_2 = l_sum_0/2

l_s_0 = l_sum_0 + 2*R - np.pi*R
l_s_1 = l_sum_1 + R - np.pi/2*R
l_s_2 = l_sum_2 + 2*R - np.pi/2*R

segment_lengths = [l_s_1, l_s_2] + [l_s_0]*1 + [l_s_2, l_s_1]
#print(segment_lengths)

feedline = CPW_RL_Path(DPoint(0, CHIP.dy/2), "LRLRRLRRLRL", cpw_params, R,
      segment_lengths, [-pi/2, pi/2] + [pi/2, -pi/2, -pi/2, pi/2]*1)
feedline.place(cell, layer_ph)

ports = [SonnetPort(feedline.start, PORT_TYPES.BOX_WALL),
         SonnetPort(feedline.end, PORT_TYPES.BOX_WALL)]

lv.zoom_fit()


# coding: utf-8

"""
    WEX REST APIs

    Authentication methods - Basic Auth - JSON Web Token   - [POST /api/v1/usermgmt/login](#!/User/signinUser)   - [POST /api/v1/usermgmt/logout](#!/User/doLogout) - Python client sample [Download](/docs/wex-python-api.zip)

    OpenAPI spec version: 12.0.2.417

    Generated by: https://github.com/swagger-api/swagger-codegen.git
"""

from pprint import pformat
from six import iteritems
import re

class WordType(object):
    """
    NOTE: This class is auto generated by the swagger code generator program.
    Do not edit the class manually.
    """

    """
    Attributes:
      swagger_types (dict): The key is attribute name
                            and the value is attribute type.
      attribute_map (dict): The key is attribute name
                            and the value is json key in definition.
    """
    swagger_types = {
        'ftr': 'list[ValType]',
        'lemma': 'ValType',
        'mtime': 'int',
        'pos': 'str',
        'surface': 'list[ValType]'
    }

    attribute_map = {
        'ftr': 'ftr',
        'lemma': 'lemma',
        'mtime': 'mtime',
        'pos': 'pos',
        'surface': 'surface'
    }

    def __init__(self, ftr=None, lemma=None, mtime=None, pos=None, surface=None):
        """
        WordType - a model defined in Swagger
        """

        self._ftr = None
        self._lemma = None
        self._mtime = None
        self._pos = None
        self._surface = None

        if ftr is not None:
          self.ftr = ftr
        if lemma is not None:
          self.lemma = lemma
        if mtime is not None:
          self.mtime = mtime
        if pos is not None:
          self.pos = pos
        self.surface = surface

    @property
    def ftr(self):
        """
        Gets the ftr of this WordType.

        :return: The ftr of this WordType.
        :rtype: list[ValType]
        """
        return self._ftr

    @ftr.setter
    def ftr(self, ftr):
        """
        Sets the ftr of this WordType.

        :param ftr: The ftr of this WordType.
        :type: list[ValType]
        """

        self._ftr = ftr

    @property
    def lemma(self):
        """
        Gets the lemma of this WordType.

        :return: The lemma of this WordType.
        :rtype: ValType
        """
        return self._lemma

    @lemma.setter
    def lemma(self, lemma):
        """
        Sets the lemma of this WordType.

        :param lemma: The lemma of this WordType.
        :type: ValType
        """

        self._lemma = lemma

    @property
    def mtime(self):
        """
        Gets the mtime of this WordType.

        :return: The mtime of this WordType.
        :rtype: int
        """
        return self._mtime

    @mtime.setter
    def mtime(self, mtime):
        """
        Sets the mtime of this WordType.

        :param mtime: The mtime of this WordType.
        :type: int
        """

        self._mtime = mtime

    @property
    def pos(self):
        """
        Gets the pos of this WordType.

        :return: The pos of this WordType.
        :rtype: str
        """
        return self._pos

    @pos.setter
    def pos(self, pos):
        """
        Sets the pos of this WordType.

        :param pos: The pos of this WordType.
        :type: str
        """

        self._pos = pos

    @property
    def surface(self):
        """
        Gets the surface of this WordType.

        :return: The surface of this WordType.
        :rtype: list[ValType]
        """
        return self._surface

    @surface.setter
    def surface(self, surface):
        """
        Sets the surface of this WordType.

        :param surface: The surface of this WordType.
        :type: list[ValType]
        """
        if surface is None:
            raise ValueError("Invalid value for `surface`, must not be `None`")

        self._surface = surface

    def to_dict(self):
        """
        Returns the model properties as a dict
        """
        result = {}

        for attr, _ in iteritems(self.swagger_types):
            value = getattr(self, attr)
            if isinstance(value, list):
                result[attr] = list(map(
                    lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
                    value
                ))
            elif hasattr(value, "to_dict"):
                result[attr] = value.to_dict()
            elif isinstance(value, dict):
                result[attr] = dict(map(
                    lambda item: (item[0], item[1].to_dict())
                    if hasattr(item[1], "to_dict") else item,
                    value.items()
                ))
            else:
                result[attr] = value

        return result

    def to_str(self):
        """
        Returns the string representation of the model
        """
        return pformat(self.to_dict())

    def __repr__(self):
        """
        For `print` and `pprint`
        """
        return self.to_str()

    def __eq__(self, other):
        """
        Returns true if both objects are equal
        """
        if not isinstance(other, WordType):
            return False

        return self.__dict__ == other.__dict__

    def __ne__(self, other):
        """
        Returns true if both objects are not equal
        """
        return not self == other


# Import the dependencies.
import numpy as np
import pandas as pd
import datetime

import sqlalchemy
from sqlalchemy.ext.automap import automap_base
from sqlalchemy.orm import Session
from sqlalchemy import create_engine, func

from flask import Flask, jsonify

#################################################
# Database Setup
#################################################
engine = create_engine("sqlite:///../Resources/hawaii.sqlite")

# reflect an existing database into a new model
Base = automap_base()

# reflect the tables
Base.prepare(autoload_with=engine)

# Save references to each table
Measurement = Base.classes.measurement
Station = Base.classes.station

# Create our session (link) from Python to the DB
session = Session(engine)

#################################################
# Flask Setup
#################################################
app = Flask(__name__)

#################################################
# Flask Routes
#################################################
@app.route("/")
def homepage():
    #List all routes
    return (
        f"Available Routes:
"
        f"/api/v1.0/precipitation
"
        f"/api/v1.0/stations
"
        f"/api/v1.0/tobs
"
        f"/api/v1.0/<start>
"
        f"/api/v1.0/<start>/<end>
"
    )

#Convert the query results from your precipitation analysis (i.e. retrieve only the last 12 months of data) to a dictionary using date as the key and prcp as the value.
@app.route("/api/v1.0/precipitation")
def precipitation():
    # Create our session (link) from Python to the DB
    session = Session(engine)

    # Query precipitation
    oneyearback = datetime.date(2017, 8, 23) - datetime.timedelta(days=365)
    results = session.query(Measurement.date, Measurement.prcp).filter(Measurement.date >= oneyearback).all()
    session.close()

    # Convert list of tuples into normal list
    all_data = []

    for date, prcp in results:
        precip_dict = {}
        precip_dict["Date"] = date
        precip_dict["Precipitation"] = prcp
        all_data.append(precip_dict)

    return jsonify(all_data)

#Return a JSON list of stations from the dataset.
@app.route("/api/v1.0/stations")
def stations():
    # Create our session (link) from Python to the DB
    session = Session(engine)

    # Query precipitation
    results = session.query(Station.station).all()
    session.close()

    # Convert list of tuples into normal list
    all_names = list(np.ravel(results))

    return jsonify(all_names)

#Query the dates and temperature observations of the most-active station for the previous year of data.
#Return a JSON list of temperature observations for the previous year.
@app.route("/api/v1.0/tobs")
def tobs():
    # Create our session (link) from Python to the DB
    session = Session(engine)

    # Query precipitation
    oneyearback = datetime.date(2017, 8, 23) - datetime.timedelta(days=365)
    results = session.query(Measurement.station, Measurement.date, Measurement.tobs)\
        .filter(Measurement.station == 'USC00519281', Measurement.date >= oneyearback)\
        .all()

    session.close()

    # Convert list of tuples into normal list
    one_year_tobs_data = []

    for station, date, tobs in results:
        tobs_dict = {}
        tobs_dict["Station"] = station
        tobs_dict["Date"] = date
        tobs_dict["Tobs"] = tobs
        one_year_tobs_data.append(tobs_dict)

    return jsonify(one_year_tobs_data)

#Return a JSON list of the minimum temperature, the average temperature, and the maximum temperature for a specified start or start-end range.
#For a specified start, calculate TMIN, TAVG, and TMAX for all the dates greater than or equal to the start date.
@app.route("/api/v1.0/<start>")
def startdata(start):
    # Create our session (link) from Python to the DB
    session = Session(engine)

    # Query and error checking
    try:
        date = datetime.datetime.strptime(start, "%Y-%m-%d").date()
    except ValueError:
        date = datetime.datetime.strptime(start, "%y-%m-%d").date()

    results = session.query(func.min(Measurement.tobs).label("Min"),func.max(Measurement.tobs).label("Max"),func.avg(Measurement.tobs).label("Avg")).filter(Measurement.date >= date).first()

    session.close()

    #Labels the future JSON info

    start_date_data = {
        "Min": results[0],
        "Max": results[1],
        "Avg": results[2]
    }

    return jsonify(start_date_data)

#For a specified start date and end date, calculate TMIN, TAVG, and TMAX for the dates from the start date to the end date, inclusive.
@app.route("/api/v1.0/<start>/<end>")
def startenddata(start,end):
    # Create our session (link) from Python to the DB
    session = Session(engine)

    # Query and error checking
    try:
        date = datetime.datetime.strptime(start, "%Y-%m-%d").date()
        date2 = datetime.datetime.strptime(end, "%Y-%m-%d").date()
    except ValueError:
        date = datetime.datetime.strptime(start, "%y-%m-%d").date()
        date2 = datetime.datetime.strptime(end, "%y-%m-%d").date()

    results = session.query(func.min(Measurement.tobs).label("Min"),func.max(Measurement.tobs).label("Max"),func.avg(Measurement.tobs).label("Avg")).filter(Measurement.date >= date, Measurement.date <= date2).first()

    session.close()

    #Labels the future JSON info
    start_date_data = {
        "Min": results[0],
        "Max": results[1],
        "Avg": results[2]
    }
    return jsonify(start_date_data)

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

#datetime string convert: https://stackoverflow.com/questions/53460391/passing-a-date-as-a-url-parameter-to-a-flask-route
#fixing my datetime.datetime.strptime() https://stackoverflow.com/questions/12070193/why-does-trying-to-use-datetime-strptime-result-in-module-object-has-no-at


#!/usr/bin/env python

from __future__ import print_function

import argparse
import torch
import torch.nn.functional as F
from torch.nn import Parameter
from nn.conv import HGATConv
from utils import parse_feat

class UnsupervisedHGAT(torch.jit.ScriptModule):

    def __init__(self, in_u_dim, in_i_dim, u_embedding_dim, i_embedding_dim,
                 u_field_num, i_field_num, hidden, out_dim, heads, dropout,
                 negative_size, encode):
        super(UnsupervisedHGAT, self).__init__()
        # bipartite graph, two types of nodes, namely u,i. Edges: (u, i)

        self.user_input_dim = in_u_dim
        self.item_input_dim = in_i_dim
        self.user_embedding_dim = u_embedding_dim
        self.item_embedding_dim = i_embedding_dim
        self.user_field_num = u_field_num
        self.item_field_num = i_field_num
        self.heads = heads
        self.dropout = dropout
        self.negative_size = negative_size
        self.encode = encode

        # the transformed dense feature dimension for user and item
        in_u_dim = u_embedding_dim * u_field_num if u_embedding_dim > 0 else in_u_dim
        in_i_dim = i_embedding_dim * i_field_num if i_embedding_dim > 0 else in_i_dim

        self.convs_u = torch.nn.ModuleList()
        self.convs_i = torch.nn.ModuleList()

        # u-i-u
        self.convs_u.append(HGATConv(hidden, hidden, hidden, heads=heads, dropout=dropout))
        self.convs_u.append(HGATConv(hidden * self.heads, hidden * self.heads,
                                     hidden, heads=heads, dropout=dropout, act=True))

        # i-u-i
        self.convs_i.append(HGATConv(hidden, hidden, hidden, heads=heads, dropout=dropout))
        self.convs_i.append(HGATConv(hidden * self.heads, hidden * self.heads,
                                     hidden, heads=heads, dropout=dropout, act=True))

        # weight
        self.weight_u1 = Parameter(torch.zeros(in_u_dim, hidden))
        self.weight_i1 = Parameter(torch.zeros(in_i_dim, hidden))

        self.weight_u2 = Parameter(torch.zeros(hidden + hidden * self.heads * 2, out_dim))
        self.weight_i2 = Parameter(torch.zeros(hidden + hidden * self.heads * 2, out_dim))

        self.weight = Parameter(torch.zeros(out_dim, 2))
        self.bias = Parameter(torch.zeros(2))

        self.reset_parameters()

    def reset_parameters(self):
        torch.nn.init.xavier_uniform_(self.weight_u1)
        torch.nn.init.xavier_uniform_(self.weight_i1)
        torch.nn.init.xavier_uniform_(self.weight_u2)
        torch.nn.init.xavier_uniform_(self.weight_i2)
        torch.nn.init.xavier_uniform_(self.weight)
        if self.bias.dim() > 1:
            torch.nn.init.xavier_uniform_(self.bias)

    @torch.jit.script_method
    def forward_(self, pos_u, pos_i, first_u_edge_index, second_u_edge_index,
                 first_i_edge_index, second_i_edge_index,
                 u_batch_ids=torch.Tensor([]), i_batch_ids=torch.Tensor([]),
                 u_field_ids=torch.Tensor([]), i_field_ids=torch.Tensor([])):

        # encode u, i feat
        pos_u, pos_i = self.encode_feat(pos_u, pos_i, u_batch_ids,
                                        i_batch_ids, u_field_ids, i_field_ids)

        pos_u_embedding = self.embedding__(pos_u, pos_i,
                                           first_u_edge_index,
                                           first_i_edge_index,
                                           "u")
        pos_i_embedding = self.embedding__(pos_i, pos_u,
                                           second_u_edge_index,
                                           second_i_edge_index,
                                           "i")

        u_index, i_index = first_u_edge_index[0], first_u_edge_index[1]

        u_emb, i_emb = pos_u_embedding[u_index], pos_i_embedding[i_index]

        # out size: (edge_num, out_dim)
        return u_emb, i_emb

    @torch.jit.script_method
    def encode_feat(self, u, i,
                    u_batch_ids=torch.Tensor([]), i_batch_ids=torch.Tensor([]),
                    u_field_ids=torch.Tensor([]), i_field_ids=torch.Tensor([])):

        if self.user_field_num > 0:
            u = parse_feat(u, u_batch_ids, u_field_ids, self.user_field_num, self.encode)
            i = parse_feat(i, i_batch_ids, i_field_ids, self.item_field_num, self.encode)

        u = torch.matmul(u, self.weight_u1)
        i = torch.matmul(i, self.weight_i1)

        return u, i

    @torch.jit.script_method
    def loss(self, pos_u, pos_i):
        # (edge_num, out_dim)
        i_emb_origin = pos_i.repeat(1, 1)
        i_emb = pos_i
        # ((edge_num * (negative_size + 1)), out_dim)
        u_emb = pos_u.repeat(self.negative_size + 1, 1)

        for _ in range(self.negative_size):
            neg_index = torch.randperm(i_emb_origin.size(0)).view(-1).to(torch.long)
            neg_sample_emb = torch.index_select(i_emb_origin, 0, neg_index)
            i_emb = torch.cat([i_emb, neg_sample_emb], dim=0)

        # ((edge_num * (negative_size + 1)), 1)
        prod = torch.sum(torch.mul(u_emb, i_emb), 1, True) / 0.05

        # (edge_num, (negative_size + 1))
        logits = torch.transpose(torch.transpose(prod, 0, 1)
                                 .reshape(self.negative_size + 1, -1), 0, 1)

        true_label = torch.zeros(pos_u.size(0)).view(-1).to(torch.long)

        loss = F.cross_entropy(logits, true_label)

        acc_per_example = torch.eq(
            torch.argmax(logits, dim=1),
            torch.zeros([pos_u.size(0)], dtype=torch.int64)).view(-1).to(torch.float)

        loss1 = loss.mean()
        accuracy = acc_per_example.mean()
        print("loss: ", loss1, ", acc: ", accuracy)

        return loss

    @torch.jit.script_method
    def embedding__(self, u, i, first_u_edge_index, first_i_edge_index, conv="u"):
        # type: (Tensor, Tensor, Tensor, Tensor, str) -> Tensor

        # gat conv encode
        graph_user_emb = self.encode_conv(u, i, first_u_edge_index, first_i_edge_index, conv)

        user_emb = torch.cat([u[0: graph_user_emb.size(0)], graph_user_emb], dim=1)

        # conv for u, i
        if conv == "u":
            user_emb = torch.matmul(user_emb, self.weight_u2)
        else:
            user_emb = torch.matmul(user_emb, self.weight_i2)

        user_emb = F.normalize(user_emb, p=2.0)

        # out size: (node_num, out_dim)
        return user_emb

    @torch.jit.script_method
    def encode_conv(self, u, i, first_edge_index, second_edge_index, conv):
        # type: (Tensor, Tensor, Tensor, Tensor, str) -> Tensor

        # convs = self.convs_u
        if conv == "u":
            convs = self.convs_u
            z1 = convs[0](i, u, second_edge_index)
            z2 = convs[0](u, i, first_edge_index)
            z3 = convs[1](z2, z1, first_edge_index)
        else:
            convs = self.convs_i
            z1 = convs[0](i, u, second_edge_index)
            z2 = convs[0](u, i, first_edge_index)
            z3 = convs[1](z2, z1, first_edge_index)

        midh0 = torch.cat([z2, z3], dim=1)

        # out size: (node_num, (hidden * heads * 2))
        return midh0

    @torch.jit.script_method
    def user_embedding_(self, u, i, first_u_edge_index, first_i_edge_index,
                        u_batch_ids=torch.Tensor([]), i_batch_ids=torch.Tensor([]),
                        u_field_ids=torch.Tensor([]), i_field_ids=torch.Tensor([])):

        if self.user_field_num > 0:
            u, i = self.encode_feat(u, i, u_batch_ids, i_batch_ids, u_field_ids, i_field_ids)

        user_emb = self.embedding__(u, i, first_u_edge_index, first_i_edge_index, "u")

        # out size: (node_num, out_dim)
        return user_emb

    @torch.jit.script_method
    def item_embedding_(self, u, i, first_u_edge_index, first_i_edge_index,
                        u_batch_ids=torch.Tensor([]), i_batch_ids=torch.Tensor([]),
                        u_field_ids=torch.Tensor([]), i_field_ids=torch.Tensor([])):

        if self.user_field_num > 0:
            u, i = self.encode_feat(u, i, u_batch_ids, i_batch_ids, u_field_ids, i_field_ids)

        item_emb = self.embedding__(i, u, first_u_edge_index, first_i_edge_index, "i")

        # out size: (node_num, out_dim)
        return item_emb

FLAGS = None

def main():
    bisage = UnsupervisedHGAT(FLAGS.input_user_dim, FLAGS.input_item_dim,
                              FLAGS.input_user_embedding_dim,
                              FLAGS.input_item_embedding_dim,
                              FLAGS.input_user_field_num,
                              FLAGS.input_item_field_num,
                              FLAGS.hidden_dim, FLAGS.output_dim,
                              FLAGS.heads, FLAGS.dropout, FLAGS.negative_size,
                              FLAGS.encode)
    bisage.save(FLAGS.output_file)

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--input_user_dim",
        type=int,
        default=-1,
        help="input dimention of user node features")
    parser.add_argument(
        "--input_item_dim",
        type=int,
        default=-1,
        help="input dimention of item node features")
    parser.add_argument(
        "--input_user_embedding_dim",
        type=int,
        default=-1,
        help="embedding dim of user node features")
    parser.add_argument(
        "--input_item_embedding_dim",
        type=int,
        default=-1,
        help="embedding dim of item node features")
    parser.add_argument(
        "--input_user_field_num",
        type=int,
        default=-1,
        help="field num of user node features")
    parser.add_argument(
        "--input_item_field_num",
        type=int,
        default=-1,
        help="field num of item node features")
    parser.add_argument(
        "--hidden_dim",
        type=int,
        default=-1,
        help="hidden dimension of bipartite graphsage convolution layer")
    parser.add_argument(
        "--output_dim",
        type=int,
        default=-1,
        help="output embedding dimension")
    parser.add_argument(
        "--heads",
        type=int,
        default=1,
        help="the number of heads")
    parser.add_argument(
        "--dropout",
        type=float,
        default=0.0,
        help="the percentage of dropout")
    parser.add_argument(
        "--negative_size",
        type=int,
        default=1,
        help="the negative sample size")
    parser.add_argument(
        "--encode",
        type=str,
        default="dense",
        help="data encode, could be one-hot, multi-hot or dense")
    parser.add_argument(
        "--output_file",
        type=str,
        default="unsupervised_bipartite_graphsage.pt",
        help="output file name")
    FLAGS, unparsed = parser.parse_known_args()
    main()


import os
from typing import Optional, List

from langchain.chains import MultiRetrievalQAChain
from langchain.document_loaders import TextLoader, PyPDFLoader, Docx2txtLoader
from langchain.document_loaders.base import BaseLoader
from langchain.embeddings import OpenAIEmbeddings
from langchain.schema import Document
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores.qdrant import Qdrant
from qdrant_client import QdrantClient

def create_vs_from_docs(base_dir) -> Qdrant:
    print(f'create vectorstore from docs: base_dir = {base_dir}')
    documents = []
    loader: Optional[BaseLoader] = None
    print(f"开始读取文件夹:{os.path.abspath(base_dir)}")
    for file in os.listdir(base_dir):
        file_path = os.path.join(base_dir, file)
        if file.endswith('.pdf'):
            loader = PyPDFLoader(file_path)
        elif file.endswith('.docx') or file.endswith('.doc'):
            loader = Docx2txtLoader(file_path)
        elif file.endswith('.txt'):
            loader = TextLoader(file_path)
        if loader is not None:
            documents.extend(loader.load())
    print("开始分割文档")
    text_splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=0)
    all_splits = text_splitter.split_documents(documents)
    print("开始创建矢量DB")
    vectorstore = Qdrant.from_documents(
        documents=all_splits,
        embedding=OpenAIEmbeddings(),
        # location=":memory:",
        path="./db",
        collection_name="my_documents",
    )
    return vectorstore

def create_vs_from_exist() -> Optional[Qdrant]:
    print(f'create_vs_from_exist: ')
    client = QdrantClient(path="./db")
    collections = client.get_collections().collections
    if len(collections) == 0:
        return None
    collection_name = collections[0].name
    return Qdrant(client=client,
                  collection_name=collection_name,
                  embeddings=OpenAIEmbeddings(),
                  )

qdrant: Qdrant = create_vs_from_exist()
if not qdrant:
    qdrant = create_vs_from_docs('./OneFlower')

result: list[Document] = qdrant.similarity_search('总经理说了什么')
for d in result:
    print(d)

MultiRetrievalQAChain()


try:
    import cPickle # Python 2
except:
    import pickle as cPickle # Python 3

import os
import numpy as np
import json
from prev_ob_models.Birgiolas2020.isolated_cells import *
from blenderneuron.nrn.neuronnode import NeuronNode
from olfactorybulb.database import Odor, OdorGlom, CellModel, database
from math import pow
from LFPsimpy import LfpElectrode
import sys
from heapq import *
from matplotlib import pyplot as plt
from hashlib import sha1
from random import random, seed

from olfactorybulb.paramsets.base import *
from olfactorybulb.paramsets.case_studies import *
from olfactorybulb.paramsets.sensitivity import *

class OlfactoryBulb:
    """
    The main class used to build and simulate the olfactory bulb network model.
    """

    def __init__(self, params="ParameterSetBase", autorun=True):
        """
        :param params: The name of the class defined in olfactorybulb.paramsets that defines the network parameters
        :param autorun: When true, after the network model is built, starts the simulation
        """

        if type(params) == str:
            params = eval(params)()

        self.params = params

        self.rnd_seed = params.rnd_seed

        self.slice_dir = os.path.abspath(os.path.join(params.slice_dir, params.slice_name))
        self.cells = {}
        self.inputs = []

        self.gj_source_gids = set()
        self.gjs = []

        # Just use the BlenderNEURON package functions (e.g. no server/client)
        self.bn_server = NeuronNode(server_end='Package')

        from neuron import h, load_mechanisms
        self.h = h
        self.pc = h.ParallelContext()
        self.mpimap = {}
        self.nranks = int(self.pc.nhost())
        self.mpirank = self.pc.id()

        # Keep track of rank complexities with a min-heap
        self.rank_complexities = [(0, r) for r in range(self.nranks)]

        self.t_vec = h.Vector()
        self.t_vec.record(h._ref_t, params.recording_period)
        self.v_vectors = {}
        self.input_vectors = []

        for cell_type in ['MC', 'GC', 'TC']:
            self.load_cells(cell_type)

        if self.mpirank == 0:
            complexities = np.array([c[0] for c in self.rank_complexities])
            min = np.min(complexities)
            max = np.max(complexities)
            mean = np.mean(complexities)

            print('Rank Complexity min: %s, mean: %s, max: %s' % (min, mean, max))

        for synapse_set in ['GCs__MCs', 'GCs__TCs']:
            self.load_synapse_set(synapse_set)

        # Load glom->cell links
        self.load_glom_cells()

        # Create gap junctions between MC and TC tufts
        for cell_type, g_gap in params.gap_juction_gmax.items():
            self.add_gap_junctions(cell_type, g_gap)

        # Set synapse parameters
        for syn_mech, syn_values in params.synapse_properties.items():
            if hasattr(h, syn_mech):
                for syn_attrib, attrib_value in syn_values.items():
                    [setattr(s, syn_attrib, attrib_value) for s in getattr(h, syn_mech)]

        # Add glomerular inputs
        for time, odor_info in params.input_odors.items():
            self.add_inputs(odor=odor_info["name"], t=time, rel_conc=odor_info["rel_conc"])

        # LFP
        self.electrode = self.create_lfp_electrode(*params.lfp_electrode_location,
                                                   sampling_period=params.recording_period)

        self.setup_status_reporter()

        for cell_type in params.record_from_somas:
            self.record_from_somas(cell_type)

        if self.mpirank == 0 and self.nranks == 1:
            from neuron import gui
            # h.load_file('1x1x1-testbed.ses')

            h.newPlotI()
            [g for g in h.Graph][-1].addvar('LfpElectrode[0].value')

        if autorun:
            self.run(params.tstop)

            if self.mpirank == 0:
                self.results_dir = os.path.join('results', params.name)
                if not os.path.exists(self.results_dir):
                    os.makedirs(self.results_dir)

            self.save_recorded_vectors()

            if self.mpirank == 0:
                t, lfp = self.get_lfp()

            # Cleanup on MPI
            if self.nranks > 1:
                database.close()
                self.h.quit()

    def stim_glom_segments(self, time, input_segs, intensity):
        """
        Adds input synapses onto glomerular tufts at specified start time and intensity

        The inhalation part of a sniff cycle is modeled as a gaussian probability that is centered at
        the midpoint of the inhalation onset and end. The probability is translated into spikes. The spikes
        then trigger the excitatory synapses placed at the mitral/tufted cell tufts.

        Intensity regulates how many spikes to pick from the gaussian.

        :param time: the inhalation onset time in ms

        :param input_segs: a list containing tuples of:
            a) The name of the segment to stimulate as it appears on the current MPI rank
            b) segment gid
            c) segment name as it appears when there is only one rank. If not using MPI a) and c) are same.
        :param intensity: 0-1 representing odor intensity

        :return: None
        """

        h = self.h

        inhale_duration = self.params.inhale_duration

        # ORN firing rate
        max_firing_rate = self.params.max_firing_rate

        # Translate intensity to number of spikes per inhalation
        spike_count = int(round(max_firing_rate * intensity * (inhale_duration / 1000.0)))

        for seg_name, seg_gid, single_rank_seg_name in input_segs:
            # Randomize spikes to each tufted segment
            seed_source = "%s|%s|%s|%s" % (self.rnd_seed, time, single_rank_seg_name, intensity)
            np.random.seed(self.stable_hash(seed_source))

            # Odor is modeled as a gaussian spike train representing OSN spikes during inhalation
            # exhalation is assumed to not generate OSN spikes
            spike_times = self.get_gaussian_spike_train(spike_count, time, inhale_duration)

            # Create synapse point process
            seg = eval(seg_name.replace('(1)', '(.999)'))
            syn = h.Exp2Syn(seg)
            syn.tau1 = self.params.input_syn_tau1
            syn.tau2 = self.params.input_syn_tau2

            if "MC" in seg_name:  # MCs
                delay = self.params.mc_input_delay
                weight = self.params.mc_input_weight

            else:  # "TC"
                delay = self.params.tc_input_delay
                weight = self.params.tc_input_weight

            # VecStim will deliver events to synapse at vector times
            ns = h.VecStim()
            ns.play(h.Vector(spike_times + delay))

            # Netcon to trigger the synapse
            netcon = h.NetCon(
                ns,
                syn,
                0,  # thresh
                0,  # delay
                weight  # weight uS
            )

            # Record odor input events
            input_vec = h.Vector()
            netcon.record(input_vec)
            self.input_vectors.append((single_rank_seg_name, input_vec))

            self.inputs.append((syn, ns, netcon))

    def stable_hash(self, source, digits=9):
        """
        Creates a hash code of digits long that is stable across different machines.

        :param source: The string to hash, in this case a section name
        :param digits: The number of digits to keep of the hash
        :return: The hash code as an integer
        """

        return int(sha1(source.encode()).hexdigest(), 16) % (10 ** digits)

    def run(self, tstop):
        """
        Runs the NEURON simulation until the specified stop time

        :param tstop: Simulation stop time
        """

        if self.mpirank == 0:
            print('Starting simulation...')

        h = self.h
        h.dt = self.params.sim_dt
        h.tstop = tstop

        if self.nranks == 1:
            h.cvode_active(0)
            h.cvode.cache_efficient(1)
            h.run()

        else:
            self.pc.setup_transfer()
            self.pc.timeout(1)
            # h.cvode.cache_efficient(0) # This line causes gap junction Seg Faults
            h.cvode_active(0)
            self.pc.set_maxstep(1)
            h.stdinit()
            self.pc.psolve(h.tstop)

        # Clear status updater line
        if self.mpirank == 0:
            print('')

    def print_status(self):
        """
        Prints the current simulation time on the same line (no new line)
        """

        sys.stdout.write("\rTime: %s ms" % self.h.t)
        sys.stdout.flush()

    def setup_status_reporter(self):
        """
        Sets up the NEURON simulation to report the simulation time
        """

        if self.mpirank == 0:
            h = self.h

            collector_stim = h.NetStim(0.5)
            collector_stim.start = 0
            collector_stim.interval = 1
            collector_stim.number = 1e9
            collector_stim.noise = 0

            collector_con = h.NetCon(collector_stim, None)
            collector_con.record(self.print_status)

            self.collector_stim = collector_stim
            self.collector_con = collector_con

    def create_lfp_electrode(self, x, y, z, sampling_period, method='Line'):
        """
        Uses the LFPsimpy package to add an LFP electrode at the specified x,y,z location

        See `LFPsimpy package <https://github.com/justasb/LFPsimpy>`_.

        :param x: y, z coordinates in um
        :param sampling_period: How often to compute the LFP signal in ms
        :param method: One of 'Line', 'Point', or 'RC'.
        :return: an LFPsimpy LfpElectrode object
        """

        return LfpElectrode(x, y, z, sampling_period, method)

    def get_lfp(self):
        """
        Returns the LFP signal in nV

        :return: a tuple of LFP times, and voltages (nV)
        """

        if self.electrode is None or not any(self.electrode.times):
            raise Exception('Run simulation first to get the LFP')

        t = self.electrode.times
        lfp = self.electrode.values

        with open(os.path.join(self.results_dir, 'lfp.pkl'), 'wb') as f:
            cPickle.dump((t, lfp), f)

        return t, lfp

    def get_model_inputsegs(self):
        """
        Queries the model database to get the 'root' segments of the tufted dendrites
        of the mitral and tufted cells

        :return: A dict that maps the cell model's class name to the name of the root tufted dendrite section
        """

        # Get all the different cell models used in the slice
        input_models = set()
        for cells in self.glom_cells.values():
            for cell in cells:
                input_models.add(cell[:cell.find('[')])

        # Get each model's input segments (in the tuft)
        model_inputsegs = {m.class_name: m.tufted_dend_root
                           for m in CellModel \
                               .select(CellModel.class_name, CellModel.tufted_dend_root) \
                               .where(CellModel.class_name.in_(list(input_models)))}

        return model_inputsegs

    def add_gap_junctions(self, in_name, g_gap):
        """
        Adds gap junctions between tufted dendrites of specified cells

        :param in_name: A part of a cell class name (e.g. 'Mitral') used to select a cell to which the GJ is added
        :param g_gap: The conductance of the gap junctions
        """

        model_inputsegs = self.get_model_inputsegs()

        for glom_id, cells in self.glom_cells.items():

            input_segs = []
            for cell in cells:
                if in_name not in cell:
                    continue

                model_class = cell[:cell.find('[')]
                input_seg = model_inputsegs[model_class]

                single_rank_address = 'h.' + cell + '.' + input_seg
                single_rank_gid = self.stable_hash(single_rank_address)

                rank_cell = self.bn_server.rank_section_name(cell)

                if rank_cell is not None:
                    seg_address = 'h.' + rank_cell + '.' + input_seg
                else:
                    seg_address = None

                input_segs.append((seg_address, single_rank_gid))

            if len(input_segs) > 0:
                self.create_gap_junctions_between(input_segs, g_gap)

        self.pc.setup_transfer()

    def create_gap_junctions_between(self, input_segs, g_gap):
        """
        Creates gap junctions between a list of specified segments. GJs are connected in a chain
        (e.g. Seg1 <-GJ1-> Seg2 <-GC2-> Seg3)

        :param input_segs: List of segments to connect by gap junctions
        :param g_gap: Gap junction conductance
        """

        count = len(input_segs)

        if count < 2:
            return

        h = self.h

        first_seg = input_segs[0]
        last_seg = input_segs[-1]

        if count > 2:
            for i, seg in enumerate(input_segs[:-1]):
                next_seg = input_segs[i + 1]

                self.create_gap_junction(seg, next_seg, g_gap)

        self.create_gap_junction(first_seg, last_seg, g_gap)

    def create_gap_junction(self, seg_1_info, seg_2_info, g_gap):
        """
        Creates a gap junction between two segments

        :param seg_1_info: Tuple of the name and gid of the first segment
        :param seg_2_info: Tuple of the name and gid of the second segment
        :param g_gap: Gap junction conductance
        """

        h = self.h

        seg_1_name, seg_1_gid = seg_1_info
        seg_2_name, seg_2_gid = seg_2_info

        if seg_1_name is not None:
            seg1 = eval(seg_1_name.replace('(1)', '(.999)'))

            if seg_1_gid not in self.gj_source_gids:
                self.pc.source_var(seg1._ref_v, seg_1_gid, sec=seg1.sec)
                self.gj_source_gids.add(seg_1_gid)

            gap1 = h.GapJunction(seg1.x, sec=seg1.sec)
            gap1.g = g_gap
            self.pc.target_var(gap1._ref_v_other, seg_2_gid)
            self.gjs.append(gap1)

        if seg_2_name is not None:
            seg2 = eval(seg_2_name.replace('(1)', '(.999)'))

            if seg_2_gid not in self.gj_source_gids:
                self.pc.source_var(seg2._ref_v, seg_2_gid, sec=seg2.sec)
                self.gj_source_gids.add(seg_2_gid)

            gap2 = h.GapJunction(seg2)
            gap2.g = g_gap
            self.pc.target_var(gap2._ref_v_other, seg_1_gid)
            self.gjs.append(gap2)

    def add_inputs(self, odor, t, rel_conc):
        """
        Add odor stimulation to the tufts of the principal cells

        :param odor: The name of the odor
        :param t: Onset time
        :param rel_conc: Relative concentration 0-1
        """

        model_inputsegs = self.get_model_inputsegs()

        # Get input odor glomeruli
        glom_intensities = {g.glom_id: g.intensity
                            for g in OdorGlom
                                .select(OdorGlom.glom_id, OdorGlom.intensity)
                                .join(Odor)
                                .where(Odor.name == odor)}

        for glom_id, cells in self.glom_cells.items():
            glom_id = int(glom_id)

            input_segs = []
            for cell in cells:
                rank_cell = self.bn_server.rank_section_name(cell)

                # Add inputs only to cells that are on this rank
                if rank_cell is None:
                    continue

                model_class = rank_cell[:rank_cell.find('[')]
                input_seg = model_inputsegs[model_class]
                seg_address = 'h.' + rank_cell + '.' + input_seg

                single_rank_address = 'h.' + cell + '.' + input_seg
                single_rank_gid = int(sha1(single_rank_address.encode()).hexdigest(), 16) % (10 ** 9)

                input_segs.append((seg_address, single_rank_gid, single_rank_address))

            if len(input_segs) > 0:
                glom_intensity = glom_intensities[glom_id] * rel_conc
                self.stim_glom_segments(t, input_segs, glom_intensity)

    def load_glom_cells(self):
        """
        Loads a dict that maps glomeruli ids to cells that are attached to each glomerulus
        """

        with open(os.path.join(self.slice_dir, 'glom_cells.json')) as f:
            self.glom_cells = json.load(f)

    def get_gaussian_spike_train(self, spikes=50, start_time=100, duration=10):
        """
        Gets a spike train from a gaussian probability distribution whose 99% range starts
        at the specified time and lasts for the specified duration.

        :param spikes: The number of spikes to generate
        :param start_time: The onset time of the gaussian
        :param duration: The duration of the gaussian
        :return: A numpy array of spike times in chronological order
        """

        # Create a gaussian whose 99% range starts at start_time
        # and ends at start_time + duration
        normal_stdev = duration / (2.576 * 2)

        times = np.random.normal(start_time + (duration / 2.0), normal_stdev, spikes)

        # Remove any spikes outside this range
        times = times[np.where((times > start_time) & (times < start_time + duration))]
        times.sort()

        return times

    def load_cells(self, cell_type):
        """
        Load the cells of the specified type onto least busy MPI ranks.

        'Busyness' of a rank is the sum of all cell complexities on that rank, as measured by the number
        of segments of each cell.

        :param cell_type: One of 'MC', 'GC', 'TC'
        """

        # Load the cell json file
        path = os.path.join(self.slice_dir, cell_type + 's.json')

        with open(path, 'r') as f:
            group_dict = json.load(f)

        # Count how many of each cell model will be on each rank
        rank_cell_counts = {r: {} for r in range(self.nranks)}

        for ri, root in enumerate(group_dict['roots']):
            # Get the least loaded rank
            min_complexity, min_complexity_rank = heappop(self.rank_complexities)

            # Cell nseg count is used as a proxy for complexity
            nsegs = self.get_nseg_count(root)

            # Add to rank complexity and push back onto the heap
            heappush(self.rank_complexities, (min_complexity + nsegs, min_complexity_rank))

            # Assign cell to least busy rank
            cell_rank = min_complexity_rank

            name = root['name']
            name = name[0:name.find('[')]

            count = rank_cell_counts[cell_rank].get(name, 0)

            self.mpimap[root['name'][:root['name'].find(']') + 1]] = {
                'name': name + '[' + str(count * 2) + ']',
                'rank': cell_rank
            }

            count += 1
            rank_cell_counts[cell_rank][name] = count

        # Load that many base instances of each model
        self.cells[cell_type] = []
        for cell_model_name, count in rank_cell_counts[self.mpirank].items():
            cell_models = [eval(cell_model_name + '()') for _ in range(count)]
            self.cells[cell_type].extend(cell_models)

        # Update section index with the new cells
        self.bn_server.update_section_index()

        # Apply the cell json file onto the base instances
        self.bn_server.init_mpi(self.pc, self.mpimap)
        self.bn_server.update_groups([group_dict])

    def record_from_somas(self, cell_type):
        """
        Adds NEURON vector recorders to the somas of the specified cell types

        :param cell_type: One of 'MC', 'GC', 'TC'
        """

        h = self.h

        for cell_model in self.cells[cell_type]:
            v_vec = h.Vector()
            v_vec.record(cell_model.soma(0.5)._ref_v, self.params.recording_period)
            self.v_vectors[str(cell_model.soma)] = v_vec

    def save_recorded_vectors(self):
        """
        Saves soma voltage traces and odor input spike times to Pickle files for later processing

        Saves to the results directory as 'soma_vs.pkl' and 'input_times.pkl'
        """

        # Gather cell voltage vectors
        all_v_vecs = self.pc.py_gather(self.v_vectors, 0)

        if all_v_vecs is not None:
            t = self.t_vec.to_python()
            result = []
            for rank_v_vecs in all_v_vecs:
                for cell, v_vec in rank_v_vecs.items():
                    result.append((cell, t, v_vec.to_python()))

            with open(os.path.join(self.results_dir, 'soma_vs.pkl'), 'wb') as f:
                cPickle.dump(result, f)

        # Gather input event time vectors
        all_input_vecs = self.pc.py_gather(self.input_vectors, 0)

        if all_input_vecs is not None:
            result = []
            for rank_input_vecs in all_input_vecs:
                for seg_name, t_vec in rank_input_vecs:
                    result.append((seg_name, t_vec.to_python()))

            with open(os.path.join(self.results_dir, 'input_times.pkl'), 'wb') as f:
                cPickle.dump(result, f)

    def get_nseg_count(self, root_dict):
        """
        Recursively counts the number of segments of a cell provided its BlenderNEURON root segment dict

        :param root_dict: The root segment dict of a cell as saved by BlenderNEURON
        :return: The total number of segments of the cell
        """

        count = root_dict["nseg"]

        for child_dict in root_dict['children']:
            count += self.get_nseg_count(child_dict)

        return count

    def load_synapse_set(self, synapse_set):
        """
        Uses BlenderNEURON to load a previously saved set of synapses between a population of cells

        :param synapse_set: One of 'GCs__MCs' or 'GCs__TCs' as seen in the olfactorybulb.slices.DorsalColumnSlice folder.
        """

        path = os.path.join(self.slice_dir, synapse_set + '.json')

        with open(path, 'r') as f:
            synapse_set_dict = json.load(f)

        self.bn_server.create_synapses(synapse_set_dict)


import sys
import imdb

from keras.preprocessing import sequence
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras.layers import Embedding
from keras.layers import Conv1D, Flatten, MaxPooling1D
from sklearn.metrics import accuracy_score
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import f1_score
import wandb
from wandb.keras import WandbCallback
from keras.preprocessing import text
import numpy as np

def main():
    # Download and Extract IMDB dataset archive
    imdb.download_and_extract_imdb()

    #
    wandb.init()
    config = wandb.config

    # set parameters:
    config.vocab_size = 1000
    config.maxlen = 1000
    config.batch_size = 30
    config.embedding_dims = 10
    config.filters = 16
    config.kernel_size = 3
    config.hidden_dims = 256
    config.epochs = 10

    (X_train, y_train), (X_test, y_test) = imdb.load_imdb()

    print("===Train===")
    print(f"X_train shape: {len(X_train)}")
    print(f"y_train shape: {len(y_train)}")

    print("===Test===")
    print(f"X_test shape: {len(X_test)}")
    print(f"y_test shape: {len(y_test)}")

    tokenizer = text.Tokenizer(num_words=config.vocab_size)
    tokenizer.fit_on_texts(X_train)
    X_train = tokenizer.texts_to_matrix(X_train)
    X_test = tokenizer.texts_to_matrix(X_test)

    X_train = sequence.pad_sequences(X_train, maxlen=config.maxlen)
    X_test = sequence.pad_sequences(X_test, maxlen=config.maxlen)

    model = Sequential()
    model.add(Embedding(config.vocab_size,
                        config.embedding_dims,
                        input_length=config.maxlen))
    model.add(Dropout(0.5))
    model.add(Conv1D(config.filters,
                    config.kernel_size,
                    padding='valid',
                    activation='relu'))
    model.add(MaxPooling1D())
    model.add(Conv1D(config.filters,
                    config.kernel_size,
                    padding='valid',
                    activation='relu'))
    model.add(MaxPooling1D())
    model.add(Flatten())
    model.add(Dense(config.hidden_dims, activation='relu'))
    model.add(Dropout(0.5))
    model.add(Dense(1, activation='sigmoid'))

    print("===Summary===")
    model.summary()

    model.compile(loss='binary_crossentropy',
                optimizer='adam',
                metrics=['accuracy'])

    model.fit(X_train, y_train,
            batch_size=config.batch_size,
            epochs=config.epochs,
            validation_data=(X_test, y_test), callbacks=[WandbCallback()])

    # predict probabilities for test set
    yhat_probs = model.predict(X_test, verbose=0)
    yhat_probs = yhat_probs[:, 0]
    # predict crisp classes for test set
    yhat_classes = np.rint(yhat_probs)

    print(f"yhat_probs: {yhat_probs}")

    print(f"yhat_classes: {yhat_classes}")

    # accuracy: (tp + tn) / (p + n)
    accuracy = accuracy_score(y_test, yhat_classes)
    print('Accuracy: %f' % accuracy)
    # precision tp / (tp + fp)
    precision = precision_score(y_test, yhat_classes)
    print('Precision: %f' % precision)
    # recall: tp / (tp + fn)
    recall = recall_score(y_test, yhat_classes)
    print('Recall: %f' % recall)
    # f1: 2 tp / (2 tp + fp + fn)
    f1 = f1_score(y_test, yhat_classes)
    print('F1 score: %f' % f1)

if __name__ == "__main__":
    sys.exit(main())


# Dictionaries

phonebook = {
    'John': 993298329,
    'Dave': 372937299,
    'Gary': 327932932
}

print(phonebook)

for name, number in phonebook.items():
    print("Phone number of %s is %d" %(name, number))

phonebook.pop("John")
print(phonebook)