from PyQt5.QtWidgets import QWidget, QPushButton, QGridLayout,QLineEdit
from PyQt5.QtWidgets import QHBoxLayout,QLabel,QComboBox
from PyQt5.QtGui import QFont

class User_informent_win(QWidget):
    def __init__(self):
        super(User_informent_win, self).__init__()
        self.sure = QPushButton("确认")
        self.chang_image = QPushButton("换头像")
        self.name = QLabel("姓名:")
        self.year = QLabel("出生年月")
        self.yearcb = QComboBox()
        self.monthcb = QComboBox()
        self.sex = QLabel("性别:")
        self.sexcb = QComboBox()
        self.school = QLabel("学校:")
        self.grade = QLabel("选择年级")
        self.gradecb = QComboBox()
        self.nameEdit = QLineEdit()
        self.tupian = QLabel()
        self.schoolEiit = QLineEdit()
        self.devise_Ui()

    def devise_Ui(self):
        self.horizontalLayout = QHBoxLayout(self)
        self.layout = QGridLayout()
        self.win = QWidget()
        self.win.setLayout(self.layout)  # 设置顶级布局管理器
        self.horizontalLayout.addWidget(self.win)
        self.win.setMouseTracking(True)  # 设置widget鼠标跟踪
        self.layout.setContentsMargins(100, 0, 0, 0)
        yearnb = []
        for i in range(1980, 2020):
            yearnb.append(str(i))
        monthmb = []
        for i in range(1, 13):
            monthmb.append(str(i))
        grade = ['一年级', '二年级', '三年级', '四年级', '五年级', '六年级',
                 '初一', '初二', '初三',
                 '高一', '高二', '高三']
        self.sex.setStyleSheet("QLabel{color:rgb(0,0,0);font-size:22px;font-weight:Bold;font-family:Arial;}")
        self.chang_image.setStyleSheet(
            "QLabel{color:rgb(0,0,0);font-size:22px;font-weight:Bold;font-family:Arial;}")
        self.school.setStyleSheet("QLabel{color:rgb(0,0,0);font-size:22px;font-weight:Bold;font-family:Arial;}")
        self.grade.setStyleSheet("QLabel{color:rgb(0,0,0);font-size:22px;font-weight:Bold;font-family:Arial;}")
        self.name.setStyleSheet("QLabel{color:rgb(0,0,0);font-size:22px;font-weight:Bold;font-family:Arial;}")
        self.year.setStyleSheet("QLabel{color:rgb(0,0,0);font-size:22px;font-weight:Bold;font-family:Arial;}")
        self.sure.setStyleSheet("QPushButton{ font-family:'宋体';font-size:22px;color:rgb(0,0,0);}\
                                 QPushButton{background-color:rgb(170,200, 50)}\
                                 QPushButton:hover{background-color:rgb(50, 170, 200)}")
        self.nameEdit.setPlaceholderText("请输入姓名")
        self.schoolEiit.setPlaceholderText("请输入学校名称")
        self.nameEdit.setFont(QFont("宋体", 14))  # 设置QLineEditn 的字体及大小
        self.schoolEiit.setFont(QFont("宋体", 14))  # 设置QLineEditn 的字体及大小
        self.name.setMaximumSize(50, 40)
        self.chang_image.setMaximumSize(90, 40)
        self.school.setMaximumSize(50, 40)
        self.year.setMaximumSize(95, 40)
        self.sex.setMaximumSize(50, 40)
        self.grade.setMaximumSize(95, 40)
        self.nameEdit.setMaximumSize(420, 40)
        self.schoolEiit.setMaximumSize(420, 40)
        self.sure.setMaximumSize(420, 40)
        self.sexcb.setMaximumSize(420, 40)
        self.gradecb.setMaximumSize(420, 40)
        self.yearcb.setMaximumSize(220, 40)
        self.monthcb.setMaximumSize(175, 40)
        self.tupian.setMaximumSize(250, 250)
        self.sexcb.setStyleSheet("QComboBox{font-family:'宋体';font-size: 18px;}")
        self.yearcb.setStyleSheet("QComboBox{font-family:'宋体';font-size: 18px;}")
        self.monthcb.setStyleSheet("QComboBox{font-family:'宋体';font-size: 18px;}")
        self.gradecb.setStyleSheet("QComboBox{font-family:'宋体';font-size: 18px;}")
        self.sexcb.addItems(['男', '女'])
        self.yearcb.addItems(yearnb)
        self.monthcb.addItems(monthmb)
        self.gradecb.addItems(grade)
        self.layout.addWidget(self.tupian, 1, 1, 4, 4)
        self.layout.addWidget(self.chang_image, 4, 2, 1, 2)
        self.layout.addWidget(self.name, 1, 6, 1, 1)
        self.layout.addWidget(self.nameEdit, 1, 8, 1, 8)
        self.layout.addWidget(self.sex, 2, 6, 1, 1)
        self.layout.addWidget(self.sexcb, 2, 8, 1, 8)
        self.layout.addWidget(self.year, 3, 6, 1, 1)
        self.layout.addWidget(self.yearcb, 3, 8, 1, 4)
        self.layout.addWidget(self.monthcb, 3, 11, 1, 7)
        self.layout.addWidget(self.school, 4, 6, 1, 1)
        self.layout.addWidget(self.schoolEiit, 4, 8, 1, 8)
        self.layout.addWidget(self.grade, 5, 6, 1, 1)
        self.layout.addWidget(self.gradecb, 5, 8, 1, 8)
        self.layout.addWidget(self.sure, 6, 8, 1, 8)


import sys
import csv

run_times = [100000]
with open("osg_timing.txt") as f_in:
    for line in f_in:
        run_time = [entry for entry in line.split(' ') if entry]
        run_times.append(run_time[3])

with open("time__osg.csv", "w") as f_out:
    writer = csv.writer(f_out)
    writer.writerow(run_times)


"""
:class:`OTF` is the on-the-fly training module for ASE, WITHOUT molecular dynamics engine.
It needs to be used adjointly with ASE MD engine.
"""
import os
import sys
import inspect
from time import time
from copy import deepcopy

import numpy as np
from ase.md.npt import NPT
from ase.md.nvtberendsen import NVTBerendsen
from ase.md.nptberendsen import NPTBerendsen
from ase.md.verlet import VelocityVerlet
from ase.md.langevin import Langevin
from ase import units

from flare.otf import OTF
from flare.utils.learner import is_std_in_bound

from flare.ase.atoms import FLARE_Atoms
from flare.ase.calculator import FLARE_Calculator
import flare.ase.dft as dft_source

class ASE_OTF(OTF):

    """
    On-the-fly training module using ASE MD engine, a subclass of OTF.

    Args:
        atoms (ASE Atoms): the ASE Atoms object for the on-the-fly MD run,
            with calculator set as FLARE_Calculator.
        timestep: the timestep in MD. Please use ASE units, e.g. if the
            timestep is 1 fs, then set `timestep = 1 * units.fs`
        number_of_steps (int): the total number of steps for MD.
        dft_calc (ASE Calculator): any ASE calculator is supported,
            e.g. Espresso, VASP etc.
        md_engine (str): the name of MD thermostat, only `VelocityVerlet`,
            `NVTBerendsen`, `NPTBerendsen`, `NPT` and `Langevin` are supported.
        md_kwargs (dict): Specify the args for MD as a dictionary, the args are
            as required by the ASE MD modules consistent with the `md_engine`.
        trajectory (ASE Trajectory): default `None`, not recommended,
            currently in experiment.

    The following arguments are for on-the-fly training, the user can also
    refer to :class:`OTF`

    Args:
        prev_pos_init ([type], optional): Previous positions. Defaults
            to None.
        rescale_steps (List[int], optional): List of frames for which the
            velocities of the atoms are rescaled. Defaults to [].
        rescale_temps (List[int], optional): List of rescaled temperatures.
            Defaults to [].

        calculate_energy (bool, optional): If True, the energy of each
            frame is calculated with the GP. Defaults to False.
        write_model (int, optional): If 0, write never. If 1, write at
            end of run. If 2, write after each training and end of run.
            If 3, write after each time atoms are added and end of run.

        std_tolerance_factor (float, optional): Threshold that determines
            when DFT is called. Specifies a multiple of the current noise
            hyperparameter. If the epistemic uncertainty on a force
            component exceeds this value, DFT is called. Defaults to 1.
        skip (int, optional): Number of frames that are skipped when
            dumping to the output file. Defaults to 0.
        init_atoms (List[int], optional): List of atoms from the input
            structure whose local environments and force components are
            used to train the initial GP model. If None is specified, all
            atoms are used to train the initial GP. Defaults to None.
        output_name (str, optional): Name of the output file. Defaults to
            'otf_run'.
        max_atoms_added (int, optional): Number of atoms added each time
            DFT is called. Defaults to 1.
        freeze_hyps (int, optional): Specifies the number of times the
            hyperparameters of the GP are optimized. After this many
            updates to the GP, the hyperparameters are frozen.
            Defaults to 10.

        n_cpus (int, optional): Number of cpus used during training.
            Defaults to 1.
    """

    def __init__(
        self,
        atoms,
        timestep,
        number_of_steps,
        dft_calc,
        md_engine,
        md_kwargs,
        trajectory=None,
        **otf_kwargs
    ):

        self.atoms = FLARE_Atoms.from_ase_atoms(atoms)
        self.md_engine = md_engine

        if md_engine == "VelocityVerlet":
            MD = VelocityVerlet
        elif md_engine == "NVTBerendsen":
            MD = NVTBerendsen
        elif md_engine == "NPTBerendsen":
            MD = NPTBerendsen
        elif md_engine == "NPT":
            MD = NPT
        elif md_engine == "Langevin":
            MD = Langevin
        else:
            raise NotImplementedError(md_engine + " is not implemented in ASE")

        self.md = MD(
            atoms=self.atoms, timestep=timestep, trajectory=trajectory, **md_kwargs
        )

        force_source = dft_source
        self.flare_calc = self.atoms.calc

        # Convert ASE timestep to ps for the output file.
        flare_dt = timestep / (units.fs * 1e3)

        super().__init__(
            dt=flare_dt,
            number_of_steps=number_of_steps,
            gp=self.flare_calc.gp_model,
            force_source=force_source,
            dft_loc=dft_calc,
            dft_input=self.atoms,
            **otf_kwargs
        )

    def get_structure_from_input(self, prev_pos_init):
        self.structure = self.atoms
        if prev_pos_init is None:
            self.atoms.prev_positions = np.copy(self.atoms.positions)
        else:
            assert len(self.atoms.positions) == len(
                self.atoms.prev_positions
            ), "Previous positions and positions are not same length"
            self.atoms.prev_positions = prev_pos_init

    def initialize_train(self):
        super().initialize_train()

        if self.md_engine == "NPT":
            if not self.md.initialized:
                self.md.initialize()
            else:
                if self.md.have_the_atoms_been_changed():
                    raise NotImplementedError(
                        "You have modified the atoms since the last timestep."
                    )

    def compute_properties(self):
        """
        Compute energies, forces, stresses, and their uncertainties with
            the FLARE ASE calcuator, and write the results to the
            OTF structure object.
        """

        # Reset FLARE calculator if necessary.
        if not isinstance(self.atoms.calc, FLARE_Calculator):
            self.atoms.set_calculator(self.flare_calc)

        self.atoms.calc.calculate(self.atoms)

    def md_step(self):
        """
        Get new position in molecular dynamics based on the forces predicted by
        FLARE_Calculator or DFT calculator
        """
        # Update previous positions.
        self.structure.prev_positions = np.copy(self.structure.positions)

        # Take MD step.
        self.md.step()

        # Update the positions and cell of the structure object.
        self.structure.cell = np.copy(self.atoms.cell)
        self.structure.positions = np.copy(self.atoms.positions)

    def update_positions(self, new_pos):
        # call OTF method
        super().update_positions(new_pos)

        # update ASE atoms
        if self.curr_step in self.rescale_steps:
            rescale_ind = self.rescale_steps.index(self.curr_step)
            temp_fac = self.rescale_temps[rescale_ind] / self.temperature
            vel_fac = np.sqrt(temp_fac)
            curr_velocities = self.atoms.get_velocities()
            self.atoms.set_velocities(curr_velocities * vel_fac)

    def update_temperature(self):
        self.KE = self.atoms.get_kinetic_energy()
        self.temperature = self.atoms.get_temperature()

        # Convert velocities to Angstrom / ps.
        self.velocities = self.atoms.get_velocities() * units.fs * 1e3

    def update_gp(self, train_atoms, dft_frcs):
        super().update_gp(train_atoms, dft_frcs)

        if self.flare_calc.use_mapping:
            self.flare_calc.mgp_model.build_map(self.flare_calc.gp_model)


#This script grabs data from the internet for a given ticker price
#It allows the user to store the data as a CSV for later user
#It allows the user to plot the data and apply functions to the data generating new columns

import datetime as dt
import matplotlib.pyplot as plt
from matplotlib import style
import pandas as pd
import pandas_datareader.data as web

style.use('ggplot')

#start at 1/1/00
start = dt.datetime(2015,1,1)
#end at 12/31/16
end = dt.datetime(2016,12,31)

#grab data from yahoo finance for the given ticker over period of start to end
df = web.DataReader('CAT', 'yahoo', start, end)

#prints first 5 rows of data that was grabbed
print(df.head())

#convert collected data into csv and saves data in given file name
df.to_csv('cat.csv')

#reads csv file into data frame parsed by date
#df = pd.read_csv('cat.csv', parse_dates=True, index_col=0)

#plots the data
df.plot()
plt.show()

#plots desired entry
df['Volume'].plot()

#how to address individual columns
print(df[['Open','High']])

#adds 100 day moving average to data frame
df['100movAvg'] = df['Adj Close'].rolling(window=100).mean()

print(df.tail())


# -*- coding: utf-8 -*-
import setuptools

with open("README.md", "r", encoding="utf-8") as fh:
    long_description = fh.read()

setuptools.setup(
    name="mrt-nist", # Replace with your own username
    version="0.0.1",
    author="Jaden Pieper",
    author_email="jaden.pieper@nist.gov",
    description="Modified Rhyme Test Speech Intelligibility Graphical User Interface",
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="https://github.com/usnistgov/mrt",
    packages=setuptools.find_packages(),
    use_scm_version={'write_to' : 'mrt/version.py'},
    setup_requires = ['setuptools_scm'],
    classifiers=[
        "Programming Language :: Python :: 3",
        "License :: Public Domain",
        "Operating System :: OS Independent",
    ],
    include_package_data = True,
    package_data={'':['audio_check.wav']},
    install_requires=[
        'numpy',
        'scipy',
        'sounddevice',
        'appdirs',
    ],
    entry_points={
        'console_scripts':[
            'mrt-gui=mrt.MRT:main',
        ],
    },
    python_requires='>=3.6',
)


"""Discord.py Bot hooks that add a logger to Context.

Messages can be added to the log with a function, and are all sent once
the command has finished executing.
"""
from discord.ext import commands

class Logger:
    """A simple logger for Discord.py commands."""

    def __init__(self, ctx: commands.Context):
        """Set up the logger."""
        self.messages = []
        self.ctx = ctx

    def log(self, message: str):
        """Log a message."""
        self.messages.append(message)

    async def send(self):
        """Send all messages remaining in the logs."""
        if self.messages:
            await self.ctx.send('\n'.join(self.messages))
            self.messages = []

async def before_invoke(ctx: commands.Context):
    """Add a logger to the context."""
    ctx.logger = Logger(ctx)

async def after_invoke(ctx: commands.Context):
    """Output from the logger if anything is there."""
    await ctx.logger.send()

def setup(bot: commands.Bot):
    """Add the hooks to the bot."""
    bot.before_invoke(before_invoke)
    bot.after_invoke(after_invoke)


# Dynamic, isotropic Mooney Rivlin, mixed formulation (Taylor-Hood)
#
#
import numpy as np
import sys, os

# Define number of elements
# The number of nodes in (2*nx+1) x (2*ny+1) x (2*nz+1) because we have a quadratic mesh
# z axis is pointing upwards
# y axis is pointing in moving direction
nx = 4
ny = 2
nz = 6

# set up Dirichlet boundary condition values (indexing is for quadratic elements)
dirichlet_bc = {}
xpos = 0.0
ypos = 0.0
zpos = 0.0

# Fix top plane, set y velocity to 0
for j in range(0,2*ny+1):
  for i in range(0,2*nx+1):
    k = 2*nz
    dirichlet_bc[k*(2*nx+1)*(2*ny+1) + j*(2*nx+1) + i] = [xpos, ypos, zpos, None, 0.0, None]   # displacements [ux,uy,uz] and velocity [vx,vy,vz]

# Function to update dirichlet boundary conditions over time
# This function returns "dirichlet_bc". Only those entries can be updated that were also initially set.
def update_dirichlet_boundary_conditions(t):

  # parameters for movement
  duration = 5.0
  amplitude = 1.0

  # define movement in y-direction
  def y(t):
    t *= np.pi/duration
    if t > np.pi:
      return 2*amplitude
    return (1 + np.cos(t - np.pi))*amplitude

  # define velocity of movement, dy(t)/dt
  def dydt(t):
    t *= np.pi/duration
    if t > np.pi:
      return 0
    return -np.sin(t - np.pi)*amplitude

  # set d
  for j in range(0,2*ny+1):
    for i in range(0,2*nx+1):
      k = 2*nz
      dirichlet_bc[k*(2*nx+1)*(2*ny+1) + j*(2*nx+1) + i] = [xpos, ypos+y(t), zpos, None, dydt(t), None]  # displacements [ux,uy,uz] and velocity [vx,vy,vz]

  return dirichlet_bc

# Function to postprocess the output
# This function gets periodically called by the running simulation.
# It provides all current variables for each node: geometry (position), u, v, stress
def postprocess(result):
  result = result[0]
  # print result for debugging
  #print(result)

  # get current time
  current_time = result["currentTime"]
  timestep_no = result["timeStepNo"]

  # parse variables
  field_variables = result["data"]

  # output all field variables for debugging
  for i,f in enumerate(field_variables):
    print(i,field_variables[i]["name"])

  # field_variables[0] is the geometry
  # field_variables[1] is the displacements u
  # field_variables[2] is the velocities v
  # field_variables[3] is the PK2-Stress (Voigt)
  # field_variables[4] is the material traction

  traction_components = field_variables[3]["components"]

  # traction values contains the traction vector in reference configuration
  traction1_values = traction_components[0]["values"]   # traction in x-direction
  traction2_values = traction_components[1]["values"]   # traction in y-direction
  traction3_values = traction_components[2]["values"]   # traction in z-direction

  # Integrate total forces, e.g. Fx = ∫∫ S_11(x,y) • ϕ(x,y) dxdy. The integration domain is the top layer of the geometry.
  # The result corresponds to the bearing forces.
  # Integration is done by adding the values with factors

  # Integration stencils for ∫∫ ϕ_i dxdy with ϕ quadratic Lagrange function
  # nodes i of a single quadratic 2D element:
  #   1/36  1/9  1/36      primary   secondary  primary
  #   1/9   4/9  1/9   =   secondary tertiary   secondary
  #   1/36  1/9  1/36      primary   secondary  primary
  #
  # values in total mesh:
  # interior primary node: 4*1/36 = 1/9, interior secondary node: 2*1/9 = 2/9, interior tertiary node: 4/9
  # edge primary node: 2*1/36 = 1/18, edge secondary node: 1/9
  # corner primary node: 1/36

  # store all factors
  factors = [1./9. for _ in range((2*nx+1) * (2*ny+1))]

  # set factors for secondary nodes
  for j in range(2*ny+1):
    for i in range(2*nx+1):
      if (i+j) % 2 == 1:
        factors[j * (2*nx+1) + i] = 2./9.

  # set factors for tertiary nodes
  for j in range(1,2*ny+1,2):
    for i in range(1,2*nx+1,2):
      factors[j * (2*nx+1) + i] = 4./9.

  # edges, primary nodes
  for i in range(0,2*nx+1,2):
    factors[(2*ny) * (2*nx+1) + i] = 1./18.
    factors[i] = 1./18.
  for j in range(0,2*ny+1,2):
    factors[j * (2*nx+1) + 0] = 1./18.
    factors[j * (2*nx+1) + (2*nx)] = 1./18.

  # edges, secondary nodes
  for i in range(1,2*nx+1,2):
    factors[(2*ny) * (2*nx+1) + i] = 1./9.
    factors[i] = 1./9.
  for j in range(1,2*ny+1,2):
    factors[j * (2*nx+1) + 0] = 1./9.
    factors[j * (2*nx+1) + (2*nx)] = 1./9.

  # corners
  factors[0] = 1./36
  factors[2*nx] = 1./36
  factors[(2*ny) * (2*nx+1) + 0] = 1./36
  factors[(2*ny) * (2*nx+1) + (2*nx)] = 1./36

  # output factors for debugging
  if True:
    print("factors = 1/36 * ")
    for j in range(0,2*ny+1):
      for i in range(0,2*nx+1):
        print("{}".format(36*factors[j * (2*nx+1) + i]),end =" ")
      print("")

  # integrate force values
  total_force_x = 0
  total_force_y = 0
  total_force_z = 0

  # loop over nodes on top layer of geometry
  for j in range(0,2*ny+1):
    for i in range(0,2*nx+1):
      k = 2*nz+1-1
      factor = factors[j * (2*nx+1) + i]

      index = k*(2*nx+1)*(2*ny+1) + j*(2*nx+1) + i

      total_force_x += factor * traction1_values[index]
      total_force_y += factor * traction2_values[index]
      total_force_z += factor * traction3_values[index]

  # output values
  print("t: {}, force: {},{},{}".format(current_time, total_force_x, total_force_y, total_force_z))

dt = 0.5
end_time = 100
output_interval = dt

neumann_bc = []

config = {
  "scenarioName": "3d_box",               # specifier to find simulation run in log file
  "logFormat":    "csv",                  # "csv" or "json", format of the lines in the log file, csv gives smaller files
  "solverStructureDiagramFile":     "solver_structure.txt",     # output file of a diagram that shows data connection between solvers
  "mappingsBetweenMeshesLogFile": "mappings_between_meshes_log.txt",    # log file for mappings
  "DynamicHyperelasticitySolver": {
    #"numberTimeSteps": 1,
    "endTime": end_time,                  # end time of simulation
    "timeStepWidth": dt,                  # time step width
    "durationLogKey": "nonlinear",        # key to find duration of this solver in the log file
    "timeStepOutputInterval": 1,          # how often the current time step should be printed to console

    #"materialParameters": [1.5,2.0],
    "materialParameters": [0.0,1.0],      # material parameters of the Mooney-Rivlin material
    "density": 1.0,                       # density of the material
    "displacementsScalingFactor": 1.0,    # scaling factor for displacements, only set to sth. other than 1 only to increase visual appearance for very small displacements
    "residualNormLogFilename": "log_residual_norm.txt",   # log file where residual norm values of the nonlinear solver will be written
    "useAnalyticJacobian": True,          # whether to use the analytically computed jacobian matrix in the nonlinear solver (fast)
    "useNumericJacobian": False,          # whether to use the numerically computed jacobian matrix in the nonlinear solver (slow), only works with non-nested matrices, if both numeric and analytic are enable, it uses the analytic for the preconditioner and the numeric as normal jacobian

    "dumpDenseMatlabVariables": False,    # whether to have extra output of matlab vectors, x,r, jacobian matrix (very slow)
    # if useAnalyticJacobian,useNumericJacobian and dumpDenseMatlabVariables all all three true, the analytic and numeric jacobian matrices will get compared to see if there are programming errors for the analytic jacobian

    # mesh
    "nElements": [nx, ny, nz],            # number of elements in x,y and z direction
    "inputMeshIsGlobal": True,            # if all indices are global (set to True)
    "physicalExtent": [nx, ny, nz],       # physical size in [m]
    "physicalOffset": [0, 0, 0],          # bottom front left position of the mesh

    # nonlinear solver
    "relativeTolerance":          1e-10,                        # 1e-10 relative tolerance of the linear solver
    "absoluteTolerance":          1e-10,                        # 1e-10 absolute tolerance of the residual of the linear solver
    "solverType":                 "preonly",                    # type of the linear solver: cg groppcg pipecg pipecgrr cgne nash stcg gltr richardson chebyshev gmres tcqmr fcg pipefcg bcgs ibcgs fbcgs fbcgsr bcgsl cgs tfqmr cr pipecr lsqr preonly qcg bicg fgmres pipefgmres minres symmlq lgmres lcd gcr pipegcr pgmres dgmres tsirm cgls
    "preconditionerType":         "lu",                         # type of the preconditioner
    "maxIterations":              1e4,                          # maximum number of iterations in the linear solver
    "snesMaxFunctionEvaluations": 1e8,                          # maximum number of function iterations
    "snesMaxIterations":          10,                           # maximum number of iterations in the nonlinear solver
    "snesRelativeTolerance":      1e-5,                         # relative tolerance of the nonlinear solver
    "snesLineSearchType":         "l2",                         # type of linesearch, possible values: "bt" "nleqerr" "basic" "l2" "cp" "ncglinear"
    "snesAbsoluteTolerance":      1e-5,                         # absolute tolerance of the nonlinear solver
    "snesRebuildJacobianFrequency": 10,                         # how often the jacobian should be recomputed, -1 indicates NEVER rebuild, 1 means rebuild every time the Jacobian is computed within a single nonlinear solve, 2 means every second time the Jacobian is built etc. -2 means rebuild at next chance but then never again

    "dumpFilename": "",                                         # filename of vector and matrix dump, "" means disabled
    "dumpFormat": "matlab",                                     # format of vector and matrix dump

    #"loadFactors":                [0.5, 1.0],                   # load factors for every timestep
    "loadFactors":                [],                           # no load factors, solve problem directly
    "loadFactorGiveUpThreshold": 0.1,                           # if the adaptive time stepping produces a load factor smaller than this value, the solution will be accepted for the current timestep, even if it did not converge fully to the tolerance
    "nNonlinearSolveCalls":       1,                            # how often the nonlinear solve should be called

    # boundary and initial conditions
    "dirichletBoundaryConditions": dirichlet_bc,                        # the initial Dirichlet boundary conditions that define values for displacements u and velocity v
    "neumannBoundaryConditions":   neumann_bc,                          # Neumann boundary conditions that define traction forces on surfaces of elements
    "divideNeumannBoundaryConditionValuesByTotalArea": True,            # if the given Neumann boundary condition values under "neumannBoundaryConditions" are total forces instead of surface loads and therefore should be scaled by the surface area of all elements where Neumann BC are applied

    "updateDirichletBoundaryConditionsFunction":  update_dirichlet_boundary_conditions,  # function that updates the Dirichlet BCs while the simulation is running
    "updateDirichletBoundaryConditionsFunctionCallInterval": 1,                          # every which step the update function should be called, 1 means every time step
    "updateNeumannBoundaryConditionsFunction":    None,                                  # function that updates the Neumann BCs while the simulation is running
    "updateNeumannBoundaryConditionsFunctionCallInterval": 1,                            # every which step the update function should be called, 1 means every time step

    "initialValuesDisplacements": [[0.0,0.0,0.0] for _ in range((2*nx+1) * (2*ny+1) * (2*nz+1))],     # the initial values for the displacements, vector of values for every node [[node1-x,y,z], [node2-x,y,z], ...]
    "initialValuesVelocities":    [[0.0,0.0,0.0] for _ in range((2*nx+1) * (2*ny+1) * (2*nz+1))],     # the initial values for the velocities, vector of values for every node [[node1-x,y,z], [node2-x,y,z], ...]
    "extrapolateInitialGuess":     True,                                # if the initial values for the dynamic nonlinear problem should be computed by extrapolating the previous displacements and velocities
    "constantBodyForce": (0,0,-1e-1),                 # a constant force that acts on the whole body, e.g. for gravity

    "dirichletOutputFilename":     "out/dirichlet_boundary_conditions",                                # filename for a vtp file that contains the Dirichlet boundary condition nodes and their values, set to None to disable

    # define which file formats should be written
    # 1. main output writer that writes output files using the quadratic elements function space. Writes displacements, velocities and PK2 stresses.
    "OutputWriter" : [

      # Paraview files
      {"format": "Paraview", "outputInterval": 1, "filename": "out/u", "binary": False, "fixedFormat": False, "onlyNodalValues":True, "combineFiles":True, "fileNumbering": "incremental"},

      # Python callback function "postprocess" (at the top of this scritpt)
      {"format": "PythonCallback", "outputInterval": 1, "callback": postprocess, "onlyNodalValues":True, "filename": "", "fileNumbering": "incremental"},
    ],
    # 2. additional output writer that writes also the hydrostatic pressure
    "pressure": {   # output files for pressure function space (linear elements), contains pressure values, as well as displacements and velocities
      "OutputWriter" : [
        #{"format": "Paraview", "outputInterval": 1, "filename": "out/p", "binary": False, "fixedFormat": False, "onlyNodalValues":True, "combineFiles":True, "fileNumbering": "incremental"},
      ]
    },
    # 3. additional output writer that writes virtual work terms
    "dynamic": {    # output of the dynamic solver, has additional virtual work values
      "OutputWriter" : [   # output files for displacements function space (quadratic elements)
        #{"format": "Paraview", "outputInterval": int(output_interval/dt), "filename": "out/dynamic", "binary": False, "fixedFormat": False, "onlyNodalValues":True, "combineFiles":True, "fileNumbering": "incremental"},
        #{"format": "Paraview", "outputInterval": 1, "filename": "out/dynamic", "binary": False, "fixedFormat": False, "onlyNodalValues":True, "combineFiles":True, "fileNumbering": "incremental"},
      ],
    },
    # 4. output writer for debugging, outputs files after each load increment, the geometry is not changed but u and v are written
    "LoadIncrements": {
      "OutputWriter" : [
        #{"format": "Paraview", "outputInterval": 1, "filename": "out/load_increments", "binary": False, "fixedFormat": False, "onlyNodalValues":True, "combineFiles":True, "fileNumbering": "incremental"},
      ]
    },
  }
}


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu May 14 23:51:27 2020

@author: halowin
"""

import numpy as np
import matplotlib.pyplot as plt
time = 100
beta = 0.3
gamma = 0.05
population = np.zeros((100,100))
outbreak = np.random.choice(range(100), 2)
#0=S 1=I 2=R
population[outbreak[0], outbreak[1]] = 1
plt.figure(figsize =(6,4) , dpi =150)
plt.imshow(population, cmap='viridis', interpolation= 'nearest')
plt.show()

count = 0
while count != 100:
    infectedIndex = np.where(population == 1)
    for i in range(len(infectedIndex[0])):
        x = infectedIndex[0][i]
        y = infectedIndex[1][i]
        for xNeighbour in (x - 1, x + 1):
            for yNeighbour in (y - 1, y + 1):
                if xNeighbour != -1 and yNeighbour != -1 and xNeighbour != 100 and yNeighbour != 100 and  population[xNeighbour, yNeighbour] == 0:
                    population[xNeighbour, yNeighbour] = np.random.choice(range(2), 1, p=[1 - beta, beta])[0]
        population[x, y] = np.random.choice((1,2), 1, p=[1-gamma,gamma])[0]
    plt.imshow(population, cmap='viridis', interpolation='nearest')
    plt.show()
    plt.close()


#!/usr/bin/env python3
###
###
###
### Jesse Leigh Patsolic
### 2017 <jpatsol1@jhu.edu>
### S.D.G
#
import argparse
from intern.remote.boss import BossRemote
from intern.resource.boss.resource import *
from intern.utils.parallel import block_compute
import configparser
import requests
import numpy as np
from numpy import genfromtxt
import shutil
import blosc
from IPython.core.debugger import set_trace
import h5py
import sys
import os
import itertools
from scipy.stats import multivariate_normal
from functools import partial
from multiprocessing import Pool
from multiprocessing.dummy import Pool as ThreadPool
from multiprocessing import cpu_count
import csv
import datetime

def getAnnoData(di):
    data = di['rem'].get_cutout(di['ch_rsc'], di['res'], di['xrng'],
          di['yrng'] ,di['zrng'])
    out = np.multiply(data, di['mask'])
    return(out)

def getMaskData(di):
    data = di['rem'].get_cutout(di['ch_rsc'], di['res'], di['xrng'],
          di['yrng'] ,di['zrng'])
    out = np.multiply(data, di['mask'])
    return(out)

def getMaskDataT(di):
    data = di['rem'].get_cutout(di['ch_rsc'], di['res'], di['xrng'],
          di['yrng'] ,di['zrng'])
    out = np.multiply(data, di['mask']).astype(data.dtype)
    return(out)

def getCube(di):
    data = di['rem'].get_cutout(di['ch_rsc'], di['res'], di['xrng'],
          di['yrng'] ,di['zrng'])
    return(data)

def getWCube(di):
    data = di['rem'].get_cutout(di['ch_rsc'], di['res'], di['xrng'],
          di['yrng'] ,di['zrng'])
    y = np.multiply(data, di['w'])
    return(y)

def getCentroid(box):
    m = np.asarray(box == True)
    avg = np.int(np.round(np.mean(m,1)))
    return(avg)

def weightCubes(cubes, w):
    c = np.float32(cubes)
    for i in range(c.shape[0]):
        for j in range(c.shape[1]):
            tmp = np.multiply(c[i,j,::], w)
            c[i,j,::] = tmp
    return(c)

def distMat2(bf):
    A = np.reshape(np.array([np.sqrt((i-(bf+1))**2 + (j-(bf+1))**2)
    for i in range(1, 2*bf+2)
    for j in range(1, 2*bf+2)]), (2*bf+1, 2*bf+1))
    A[np.where(A == 0)] = 1
    return(A)

def distMat3(bf):
    A = np.reshape(
        np.array([np.sqrt((i-(bf+1))**2 + (j-(bf+1))**2 + (k-(bf+1))**2)\
        for i in range(1, 2*bf+2)\
        for j in range(1, 2*bf+2)\
        for k in range(1, 2*bf+2)]),(2*bf+1, 2*bf+1, 2*bf+1))
    #A[np.where(A == 0)] = 1
    return(A)

def F0(cubes):
    print(cubes.shape)
    f0 = [[np.sum(cubes[i,j,:,:,:]) for j in range(cubes.shape[1])] for i in range(cubes.shape[0])]
    #f0 = np.sum(cube)
    return(f0)

def oob():

    return(None)

def gaussian3dMask(mean, sd, x,y,z,bf):
    def mvn(x, m = [0,0,0], sigma = [1,1,1]):
            y = multivariate_normal.pdf(x, mean = m, cov = sigma)
            return(y)

    mask = np.array([0 for i in range(x*y*z)], dtype = np.float32).reshape(x,y,z)
    for i in range(x):
      for j in range(y):
        for k in range(z):
          mask[i,j,k] = mvn(x = [i - bf[0], j - bf[1], k - bf[2]])
    return(mask)

def toh5(EXP_NAME, outfile, CHAN_NAMES, cubes, loc, F0 = None, w = None):
    hf = h5py.File(outfile, 'w')
    hf.create_dataset(EXP_NAME + "_cubes", data = cubes)
    hf.create_dataset("Locations", data = np.transpose(loc))
    hf.create_dataset("Channels", data = np.string_(CHAN_NAMES))
    if F0 is not None:
        hf.create_dataset("F0", data = F0)
    if w is not None:
        hf.create_dataset("w", data = w)

    hf.close()
    return(None)

def mainOUT(F0, head, outfile):

    with open(outfile, 'w') as f1:
        wt = csv.writer(f1)
        wt.writerow(head)
        wt.writerows(np.transpose(np.asarray(F0)))

    return(None)


import exchangelayer
import genconfig
import genutils
import loggerdb
import simulator
import strategies

SimCurrency = genconfig.Simulator.Currency
SimAsset = genconfig.Simulator.Asset

def SimPrint():
  Worth = (loggerdb.price_list[-1] * SimAsset) + SimCurrency
  print('[SIMULATOR] Asset:', SimAsset, genconfig.API.Asset, 'Currency:', SimCurrency,
        genconfig.API.Currency, 'Net Worth:', Worth, genconfig.API.Currency)

def SimulateFromStrategy():
  # Is external, otherwise on each function call we clear content
  TradeCurrency = (
      strategies.Trade_dict['TradeVolume'] / 100) * simulator.SimCurrency
  TradeAsset = (
      strategies.Trade_dict['TradeVolume'] / 100) * simulator.SimAsset
  if strategies.Trade_dict['Order'] == 'Buy':
    # Get fresh ask price
    MarketAskPrice = exchangelayer.GetMarketPrice('ask')
    BidTradeAmount = TradeCurrency / MarketAskPrice
    if BidTradeAmount > genconfig.API.AssetTradeMin:
      if len(str(BidTradeAmount).split('.')[1]) > 3:
        BidTradeAmount = round(BidTradeAmount, 3)
      simulator.SimAsset += BidTradeAmount
      simulator.SimCurrency -= BidTradeAmount * MarketAskPrice
      print('[SIMULATOR] BUYING', BidTradeAmount, genconfig.API.Asset, 'at',
            MarketAskPrice, genconfig.API.Currency)
      if not genconfig.Simulator.Verbose:
        SimPrint()
      if genconfig.TradeRecorder.Enabled:
        genutils.RecordTrades('BOUGHT', MarketAskPrice, BidTradeAmount)
    elif BidTradeAmount < genconfig.API.AssetTradeMin:
      print('[SIMULATOR] Wanted to BUY', BidTradeAmount, genconfig.API.Asset,
            'at', MarketAskPrice, 'but needed more', genconfig.API.Currency)
  elif strategies.Trade_dict['Order'] == 'Sell':
    # Get fresh bid price
    MarketBidPrice = exchangelayer.GetMarketPrice('bid')
    if TradeAsset > genconfig.API.AssetTradeMin:
      if len(str(TradeAsset).split('.')[1]) > 3:
        TradeAsset = round(TradeAsset, 3)
      simulator.SimAsset -= TradeAsset
      simulator.SimCurrency += TradeAsset * MarketBidPrice
      print('[SIMULATOR] SELLING', TradeAsset, genconfig.API.Asset, 'at',
            MarketBidPrice, genconfig.API.Currency)
      if not genconfig.Simulator.Verbose:
        SimPrint()
      if genconfig.TradeRecorder.Enabled:
        genutils.RecordTrades('SOLD', MarketBidPrice, TradeAsset)
    elif TradeAsset < genconfig.API.AssetTradeMin:
      print('[SIMULATOR] Wanted to SELL', TradeAsset, genconfig.API.Asset, 'at',
            MarketBidPrice, 'but needed more', genconfig.API.Asset)
  if genconfig.Simulator.Verbose:
    SimPrint()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat Mar 24 18:57:59 2018

@author: huihsuan
"""
from dataset import MultiNli
from tqdm import tqdm

import tensorflow as tf
from time import ctime
import numpy as np

from nn import embedded, mask, highway_network, multihead_attention, normalize

######parameters

keep_prob = 1
learning_rate = 0.00005 #peter: 0.001 -> 0.5 -> 0.00005 (20180628)
batch_num = 256
max_len = 100
num_heads = 5 #for transformer
hidden_dim = 300 #a dim reduction after highway network

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

mnli = MultiNli("glove.txt.gz", "./DIIN/data/multinli_0.9",
                max_len = max_len,
                batch=batch_num,
                train_epoch=1,
                dev_epoch=1,
                char_emb_dim=8,
                all_printable_char=True,
                #trainfile="multinli_0.9_train_5000.jsonl",
)

weights =mnli.embedding

sentence1 = mnli.sentence1
sentence2 = mnli.sentence2

sent1_mask = tf.cast(tf.sign(sentence1), dtype=tf.float32)
sent2_mask = tf.cast(tf.sign(sentence2), dtype=tf.float32)
sent1_len = tf.reduce_sum(sent1_mask, -1)
sent2_len = tf.reduce_sum(sent2_mask, -1)

antonym1  = tf.expand_dims(mnli.antonym1, -1)
antonym2  = tf.expand_dims(mnli.antonym2, -1)
exact1to2 = tf.expand_dims(mnli.exact1to2, -1)
exact2to1 = tf.expand_dims(mnli.exact2to1, -1)
synonym1  = tf.expand_dims(mnli.synonym1, -1)
synonym2  = tf.expand_dims(mnli.synonym2, -1)
sent1char = mnli.sent1char
sent2char = mnli.sent2char

with tf.variable_scope("word_embedding"):
    glove_embedding = embedded(mnli.embedding)
    embedding_pre = glove_embedding(sentence1)
    embedding_hyp = glove_embedding(sentence2)

# with tf.variable_scope("char_embedding"):
#     char_embedding = embedded(mnli.char_embedding, name="char")
#     char_embedding_pre = char_embedding(sent1char)
#     char_embedding_hyp = char_embedding(sent2char)

#     with tf.variable_scope("conv") as scope:
#         conv_pre = char_conv(char_embedding_pre)
#         scope.reuse_variables()
#         conv_hyp = char_conv(char_embedding_hyp)

# embed_pre = tf.concat((embedding_pre, antonym1, exact1to2, synonym1, conv_pre), -1)
# embed_hyp = tf.concat((embedding_hyp, antonym2, exact2to1, synonym2, conv_hyp), -1)

embed_pre = tf.concat((embedding_pre, antonym1, exact1to2, synonym1), -1)
embed_hyp = tf.concat((embedding_hyp, antonym2, exact2to1, synonym2), -1)

hout_pre = highway_network(embed_pre, 2, [tf.nn.sigmoid] * 2, "premise")
hout_hyp = highway_network(embed_hyp, 2, [tf.nn.sigmoid] * 2, "hypothesis")

#peter: dim reduction
hout_pre = normalize(tf.layers.dense(hout_pre, hidden_dim, activation=tf.nn.sigmoid))
hout_hyp = normalize(tf.layers.dense(hout_hyp, hidden_dim, activation=tf.nn.sigmoid))

hout_pre = mask(hout_pre, sent1_mask)
hout_hyp = mask(hout_hyp, sent2_mask)

pre_atten = multihead_attention(hout_pre,
                                hout_pre,
                                hout_pre,
                                scope="pre_atten"
)

hyp_atten = multihead_attention(hout_hyp,
                                hout_hyp,
                                hout_hyp,
                                scope="hyp_atten"
)

p2h_atten = multihead_attention(hout_pre,
                                hout_hyp,
                                hout_hyp,
                                scope="p2h_atten"
)

h2p_atten = multihead_attention(hout_hyp,
                                hout_pre,
                                hout_pre,
                                scope="h2p_atten"
)

##concat the output of hw &attention

#[B, L, 300+300]
concatP =tf.concat(values = [hout_pre, pre_atten],axis = 2, name='concatP')
concatH =tf.concat(values = [hout_hyp, hyp_atten],axis = 2, name='concatH')

#[B, L, 300]
mulP =tf.multiply(hout_pre, pre_atten)
mulH =tf.multiply(hout_hyp, hyp_atten)

#[B, L, 300]
subP =tf.abs(tf.subtract(hout_pre, pre_atten))
subH =tf.abs(tf.subtract(hout_hyp, hyp_atten))

#[B, L, 600+300+300]
P_ = tf.concat([concatP, mulP, subP], axis=2)
H_ = tf.concat([concatH, mulH, subH], axis=2)

# P_ = mask(P_)
# H_ = mask(H_)

concatP2H =tf.concat(values = [hout_pre, p2h_atten],axis = 2, name='concatP2H')
concatH2P =tf.concat(values = [hout_hyp, h2p_atten],axis = 2, name='concatH2P')

#[B, L, 300]
mulP2H =tf.multiply(hout_pre, p2h_atten)
mulH2P =tf.multiply(hout_hyp, h2p_atten)

#[B, L, 300]
subP2H =tf.abs(tf.subtract(hout_pre, p2h_atten))
subH2P =tf.abs(tf.subtract(hout_hyp, h2p_atten))

#[B, L, 600+300+300]
PH_ = tf.concat([concatP2H, mulP2H, subP2H], axis=2)
HP_ = tf.concat([concatH2P, mulH2P, subH2P], axis=2)

# PH_ = mask(P_)
# HP_ = mask(H_)

P_ = tf.concat([P_, PH_], 2)
H_ = tf.concat([H_, HP_], 2)

def mulph(p, h):  # [b, L, d]

    PL = tf.shape(p)[1]
    HL = tf.shape(h)[1]
    p_aug = tf.tile(tf.expand_dims(p, 2), [1, 1, HL, 1])
    h_aug = tf.tile(tf.expand_dims(h, 1), [1, PL, 1, 1])  # [N, PL, HL, 2d]    h_mask_aug = tf.reduce_any(tf.cast(tf.tile(tf.expand_dims(h_mask, 1), [1, PL
    ph = p_aug * h_aug

    return ph

ph_ = mulph(P_,H_)
pl_ave_pool = tf.reduce_mean(ph_, 1)
hl_ave_pool = tf.reduce_mean(ph_, 2)
pl_max_pool = tf.reduce_max(ph_, 1)
hl_max_pool = tf.reduce_max(ph_, 2)

pl_ = tf.concat([pl_ave_pool, pl_max_pool, P_], axis = 2)
hl_ = tf.concat([hl_ave_pool, hl_max_pool, H_], axis = 2)

pl_ = tf.layers.dense(pl_, hidden_dim)
hl_ = tf.layers.dense(hl_, hidden_dim)

#[B, L, 1200]
ph = tf.concat([P_,H_], axis=1)

###baseline:dynamic_rnn
rnn_cell = tf.nn.rnn_cell.GRUCell(num_units=128)
_outputs, state = tf.nn.dynamic_rnn(rnn_cell, ph,
                                    dtype=tf.float32)
outputs = state

# 'state' is a tensor of shape [batch_size, cell_state_size]
#dynmic_rnn output: [B, L, 128]

y = tf.layers.dense(outputs, 3)

###labels
labels = mnli.label

# # training
loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(labels=labels,
                                                                     logits=y))
l2_loss = tf.add_n([tf.nn.l2_loss(v) for v in tf.trainable_variables()])
loss += l2_loss * 9e-5

optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
train_op = optimizer.minimize(loss)

##evaluate

# current accuracy
predictlabel = tf.argmax(y, axis=1)
correctlabel = tf.cast(tf.equal(predictlabel, labels), dtype=tf.float32)
correctnumber = tf.reduce_sum(correctlabel)
correntPred = tf.reduce_mean(correctlabel)

init = tf.global_variables_initializer()
saver = tf.train.Saver()

sess_config = tf.ConfigProto()
sess_config.gpu_options.allow_growth = True
sess = tf.Session(config=sess_config)
sess.run(init)

# saver.save(sess, "model/basemodel_v1")
#saver.restore(sess, "model/htg")

para_num = sum([np.prod(sess.run(tf.shape(v))) for v in tf.trainable_variables()])
print(f"parameters num : {para_num}")

def run(init, e=1, train=False, name="", printnum=500):
    for epoch in range(e):
        total_loss = 0.
        batch_number = 0
        total_pred = 0.  # total_pred for one epoch
        local_pred = 0.
        local_loss = 0.

        # init_trainset
        init(sess)
        while True:
            try:
                if train:
                    _, loss_value, pred = sess.run((train_op, loss, correntPred))
                else:
                    loss_value, pred = sess.run((loss, correntPred))
                total_loss += loss_value
                local_loss += loss_value
                total_pred += pred
                local_pred += pred
                batch_number += 1
                # bc+=8
                if batch_number % printnum == 0:
                    print(f"{ctime()}: {name}> average_loss:{local_loss/printnum}, local_accuracy:{local_pred/printnum}")
                    local_pred = 0.
                    local_loss = 0.
            except tf.errors.OutOfRangeError:
                break
        print(f"{ctime()}: {name}> total_loss:{total_loss/batch_number}, total_accuracy:{total_pred/batch_number}")

for i in tqdm(range(1000)):
    print(f"train epoch: {i}")
    run(mnli.train, train=True, name="train")
    print(f"evaluate on dev_matched")
    run(mnli.dev_matched, name="matched")
    print(f"evaluate on dev_mismatched")
    run(mnli.dev_mismatched, name="mismatched")

print("done!")


import configparser

# CONFIG
config = configparser.ConfigParser()
config.read('dwh.cfg')

# DROP TABLES

staging_events_table_drop = "DROP TABLE IF EXISTS staging_events"
staging_songs_table_drop = "DROP TABLE IF EXISTS staging_songs"
songplay_table_drop = "DROP TABLE IF EXISTS fact_songplays"
user_table_drop = "DROP TABLE IF EXISTS dim_users"
song_table_drop = "DROP TABLE IF EXISTS dim_songs"
artist_table_drop = "DROP TABLE IF EXISTS dim_artists"
time_table_drop = "DROP TABLE IF EXISTS dim_time"

# CREATE TABLES

staging_events_table_create= ("""
CREATE TABLE IF NOT EXISTS staging_events
(
    artist VARCHAR(255),
    auth VARCHAR(255),
    firstName VARCHAR(255),
    gender CHAR,
    itemInSession INT,
    lastName VARCHAR(255),
    length decimal,
    level VARCHAR(255),
    location VARCHAR(255),
    method VARCHAR(255),
    page VARCHAR(255),
    registration FLOAT,
    sessionId INT,
    song VARCHAR(255),
    status INT,
    ts BIGINT,
    userAgent VARCHAR(255),
    userId INT
)
""")

staging_songs_table_create = ("""
CREATE TABLE IF NOT EXISTS staging_songs
(
    num_songs INT,
    artist_id VARCHAR(255),
    artist_latitude decimal,
    artist_longitude decimal,
    artist_location VARCHAR(255),
    artist_name VARCHAR(255),
    song_id VARCHAR(255),
    title VARCHAR(255),
    duration decimal,
    year INT
)
""")

songplay_table_create = ("""
CREATE TABLE IF NOT EXISTS fact_songplays
(
songplay_id int IDENTITY(0,1) PRIMARY KEY,
start_time timestamp,
user_id int,
level varchar(255),
song_id varchar(255),
artist_id varchar(255),
session_id int,
location varchar(255),
user_agent varchar(255)
);
""")

user_table_create = ("""
CREATE TABLE IF NOT EXISTS dim_users
(
user_id int PRIMARY KEY NOT NULL,
first_name varchar(255),
last_name varchar(255),
gender char,
level varchar(255)
);
""")

song_table_create = ("""
CREATE TABLE IF NOT EXISTS dim_songs
(
song_id varchar(255) PRIMARY KEY NOT NULL,
title varchar(255),
artist_id varchar(255),
year int,
duration float
);
""")

artist_table_create = ("""
CREATE TABLE IF NOT EXISTS dim_artists
(
artist_id varchar(255) PRIMARY KEY NOT NULL,
name varchar(255),
location varchar(255),
latitude decimal,
longitude decimal
);
""")

time_table_create = ("""
CREATE TABLE IF NOT EXISTS dim_time
(
ts timestamp,
hour int,
day int,
week int,
month int,
year int,
weekday int
);
""")

# STAGING TABLES

staging_events_copy = \
    (
    """
    COPY staging_events FROM {}
     iam_role {} FORMAT AS JSON 'auto' COMPUPDATE OFF REGION 'us-west-2';
    """
).format(config.get("S3", "LOG_DATA"), config.get("IAM_ROLE", "ARN"))

staging_songs_copy = (
    """
    COPY staging_songs FROM {}
     iam_role {} FORMAT AS JSON 'auto' COMPUPDATE OFF REGION 'us-west-2';
    """
).format(config.get("S3", "SONG_DATA"), config.get("IAM_ROLE", "ARN"))

# FINAL TABLES

songplay_table_insert = (
    """
    INSERT INTO fact_songplays(start_time, user_id, level, song_id, artist_id, session_id, location, user_agent)
    (SELECT timestamp 'epoch' + cast(ts as bigint)/1000 * interval '1 second' AS converted_timestamp, userid, level, s.song_id, s.artist_id, sessionid, location, useragent FROM staging_events AS e
        LEFT OUTER JOIN staging_songs AS s ON e.song = s.title)
    """
)

user_table_insert = (
    """
    INSERT INTO dim_users(user_id, first_name, last_name, gender, level)
    (SELECT DISTINCT userid, firstname, lastname, gender, level FROM staging_events WHERE userid IS NOT NULL)
    """
)

song_table_insert = (
    """
    INSERT INTO dim_songs(song_id, title, artist_id, year, duration)
    (SELECT DISTINCT song_id, title, artist_id, year, duration from staging_songs)
    """
)

artist_table_insert = (
    """
    INSERT INTO dim_artists(artist_id, name, location, latitude, longitude)
    (SELECT DISTINCT artist_id, artist_name, artist_location, artist_latitude, artist_longitude from staging_songs)
    """
)

time_table_insert = (
    """
    INSERT INTO dim_time(ts)
    (SELECT timestamp 'epoch' + cast(ts as bigint)/1000 * interval '1 second' AS converted_timestamp from staging_events)
    """
)

time_table_full_insert = ('INSERT INTO dim_time(ts, hour, day, week, month, year, weekday) VALUES(%s,%s,%s,%s,%s,%s,%s);')
select_time_table = ('SELECT ts FROM dim_time')
truncate_time_table = ('TRUNCATE TABLE dim_time')

# QUERY LISTS

create_table_queries = [songplay_table_create, user_table_create, song_table_create, artist_table_create, time_table_create, staging_events_table_create, staging_songs_table_create]
drop_table_queries = [
 #    staging_events_table_drop, staging_songs_table_drop,
     songplay_table_drop, user_table_drop, song_table_drop, artist_table_drop, time_table_drop]
copy_table_queries = [staging_events_copy, staging_songs_copy]
insert_table_queries = [user_table_insert, artist_table_insert, song_table_insert, time_table_insert, songplay_table_insert]


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
        ('ds9s', '0018_auto_20141210_2334'),
    ]

    operations = [
        migrations.AlterModelOptions(
            name='analysis',
            options={'permissions': (('view_allAnalysis', 'Can see all analysis'),)},
        ),
        migrations.AlterModelOptions(
            name='identifications',
            options={'permissions': (('view_allIdentifications', 'Can see all identifications'),)},
        ),
    ]


#Ramo: IA (ICI5240-1)
#Integrantes: Andres Gonzalez - Jorge Montiel - Bruno Rezzio

def datos_diff(primero, segundo):
    if primero == '...' or segundo == '...':
        return False

    if not type(primero) == type(segundo):
        print("Los tipos no coinciden:")
        print(primero)
        print(segundo)
        return True

    elif isinstance(primero, dict):
        for k in primero:
            if datos_diff(primero[k], segundo[k]):
                return True
        for k in segundo:
            if datos_diff(primero[k], segundo[k]):
                return True

    elif isinstance(primero, list):
        if len(primero) != len(segundo):
            print("Las longitudes de lista no coinciden:")
            print(primero)
            print(segundo)
            return True
        for i, v in enumerate(primero):
            if datos_diff(v, segundo[i]):
                return True
    else:
#        if (isinstance(primero, unicode) and primero[0] == '$') or (isinstance(primero, unicode) and segundo[0] == '$'):
#            return False
#        else:
        if primero != segundo:
            print("Los valores no coinciden:")
            print(primero)
            print(segundo)
        return primero != segundo
    return False

if __name__ == "__main__":
    import doctest
    doctest.testmod()


import logging
from .colorformatter import ColorFormatter

def getLogger(name=None, level=logging.DEBUG, fmt=None, **kwargs):
    '''
    Description:
        simple wrapper around logging.getLogger that creates a console handler and
        attaches the ColorFormatter as the default formatter for console logging

    Input:
        *args, **kwargs: passed directly to logging.getLogger() as is.
    '''
    logger = logging.getLogger(name, **kwargs)
    logger.setLevel(level)
    color_formatter = ColorFormatter(fmt=fmt)
    console_handler = logging.StreamHandler()
    console_handler.setFormatter(color_formatter)
    logger.addHandler(console_handler)

    return logger


from django.db import models
from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
from django import forms
from django.conf import settings
from django.db.models import get_model

from trapper.apps.storage.models import Resource
from trapper.apps.research.models import Project as RProject, ProjectCollection as RProjectCollection
from django_select2.fields import AutoModelSelect2Field

from django_hstore import hstore

import json
from operator import itemgetter
from collections import OrderedDict

class Project(models.Model):
    """Describes a single classification project existing withing the system
    """

    name = models.CharField(max_length=255)
    research_project = models.ForeignKey(RProject, related_name='classification_projects')
    collections = models.ManyToManyField(RProjectCollection, through='ProjectCollection', blank=True, null=True, related_name="classifications")
    """Collections assigned to the project"""
    createdby = models.ForeignKey(User, null=True, blank=True)
    created = models.DateTimeField(auto_now_add=True, default='2014-01-01 12:00:00')
    sequencing_enabled = models.BooleanField("Sequences", default=True, help_text="Enable sequencing interface")
    cs_enabled = models.BooleanField(default=True)
    """Is crowd-sourcing enabled for the project ?"""

    def __unicode__(self):
        return unicode(self.name)

    def get_all_cs_resources(self):
        """Returns a list of crowd-sourcing enabled resources for given project."""

        resources = []

        if not self.cs_enabled:
            return resources

        for c in self.projectcollection_set.filter(cs_enabled=True):
            new = [r for r in c.collection.resources.all()]
            resources.extend(new)
        return list(set(resources))

    def is_project_admin(self, user):
        role = self.cproject_roles.filter(user=user)
        return len(role) > 0 and role[0].name == 'A'

    # TODO: given user can have only one role in a project; rewrite tests below
    def determine_roles(self, user):
        """Returns a tuple of project roles for given user.

        :param user: user for which the roles are determined
        :type user: :py:class:`django.contrib.auth.models.User`
        :return: list of role names of given user withing the project
        :rtype: str
        """

        return [r.name for r in self.cproject_roles.filter(user=user)]

    def can_update(self, user):
        """Determines whether given user can update the project.

        :param user: user for which the test is made
        :type user: :py:class:`django.contrib.auth.models.User`
        :return: True if user can edit the project, False otherwise
        :rtype: bool
        """

        return self.cproject_roles.filter(user=user, name__in=ProjectRole.ROLE_EDIT).count() > 0

    def can_detail(self, user):
        """Determines whether given user can see the details of a project.

        :param user: user for which the check is made
        :type user: :py:class:`django.contrib.auth.models.User`
        :return: True if user can see the details of the project, False otherwise
        :rtype: bool
        """

        return self.cproject_roles.filter(user=user).count() > 0

    def get_absolute_url(self):
        return reverse('media_classification:project_detail', kwargs={'pk':self.pk})

class ProjectCollection(models.Model):
    """Many-To-Many model for Project-Collection relationship."""

    project = models.ForeignKey(Project)
    collection = models.ForeignKey(RProjectCollection)
    active = models.BooleanField("Active", default=True)
    """Is collection "active" within the project at given moment ?"""
    group_by_location = models.BooleanField("Group resources by location", default=False)
    """Should resources for this collection be grouped by location in classification view?"""
    sequencing_experts = models.BooleanField("Sequences editable by experts", default=True, help_text="Allow experts to create and edit sequences")
    cs_enabled = models.BooleanField("Crowd-Sourcing", default=True, help_text="Enable Crowd-Sourcing")
    """Is collection available for the crowd-sourcing ?"""

    def __unicode__(self):
        return unicode("%s" % self.collection)

    def get_resources(self):
        return self.collection.collection.resources.all().order_by('date_recorded', 'name')

    def get_resources_with_status(self):
        resources = self.get_resources()
        resources_pks = resources.values_list('pk', flat=True)
        status_list = Classification.objects.filter(
            project__pk=1, resource__pk__in=resources_pks
        ).values_list('approved', flat=True).order_by('resource__date_recorded', 'resource__name')
        return zip(resources, status_list)

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

class AttributeSet(models.Model):
    """Defined group of attributes describing given classification form.
    Such set is defined per-resource type, and is defined in given classification project.
    """

    CUSTOM_ATTRS_FIELDS = {
        'B': forms.BooleanField,
        'F': forms.FloatField,
        'I': forms.IntegerField,
        'S': forms.CharField,
    }

    name = models.CharField(max_length=255)
    project = models.OneToOneField(Project, verbose_name='Media classification project', null=True, blank=True, related_name="attributeset")
    predefined_attrs = hstore.DictionaryField(null=True, blank=True)
    custom_attrs = hstore.DictionaryField(null=True, blank=True)
    dynamic_attrs_order = models.TextField(null=True, blank=True)
    static_attrs_order = models.TextField(null=True, blank=True)
    owner = models.ForeignKey(User, null=True, blank=True, related_name='owned_attsets')

    objects = hstore.HStoreManager()

    def __unicode__(self):
        return unicode("Name: %s | Project: %s" % (self.name, self.project.name))

    def get_absolute_url(self):
        return reverse('media_classification:attributeset_detail', kwargs={'pk':self.pk})

    def can_edit(self, user):
        return self.owner == user

    def get_pre_attrs_names(self):
        return settings.PREDEFINED_ATTRIBUTES_SIMPLE.keys() + settings.PREDEFINED_ATTRIBUTES_MODELS.keys()

    def get_active_pre_attrs_names(self):
        config = self.get_pre_attrs_names()
        active = []
        for attr in config:
            if self.predefined_attrs[attr] == 'true':
                active.append(attr)
        return active

    def get_all_attrs_names(self):
        all = [[],[]] # [[dynamic_form], [static_form]]
        for at in self.get_active_pre_attrs_names():
            if self.predefined_attrs['target_%s' % at] == 'D':
                all[0].append(at)
            else:
                all[1].append(at)
        for at in self.custom_attrs.keys():
            if json.loads(self.custom_attrs[at])['target'] == 'D':
                all[0].append(at)
            else:
                all[1].append(at)
        return all

    def get_dynamic_attrs_order(self):
        try:
            return self.dynamic_attrs_order.split(',')
        except:
            return []

    def get_static_attrs_order(self):
        try:
            return self.static_attrs_order.split(',')
        except:
            return []

    def update_attrs_order(self):
        all_attrs_names = self.get_all_attrs_names()
        dynamic_attrs_order = self.get_dynamic_attrs_order()
        static_attrs_order = self.get_static_attrs_order()
        ordered_attrs = []
        new_attrs = []
        for at in all_attrs_names[0]: # dynamic_form
            if not at in dynamic_attrs_order:
                dynamic_attrs_order.append(at)
        for at in dynamic_attrs_order:
            if not at in all_attrs_names[0]:
                del dynamic_attrs_order[dynamic_attrs_order.index(at)]
        for at in all_attrs_names[1]: # static_form
            if not at in static_attrs_order:
                static_attrs_order.append(at)
        for at in static_attrs_order:
            if not at in all_attrs_names[1]:
                del static_attrs_order[static_attrs_order.index(at)]
        self.dynamic_attrs_order = ','.join(dynamic_attrs_order)
        self.static_attrs_order = ','.join(static_attrs_order)
        self.save()

    def parse_hstore_values(self, field, attr=None):
        parsed_values = {}
        # if attr not specified parse all
        if not attr:
            items = getattr(self, field).items()
        else:
            items = [(attr, getattr(self, field)[attr], ),]
        for k,v in items:
            try:
                parsed_values[k] = json.loads(v)
            except ValueError:
                # if it is not a json it must be a simple string so just add it to a parsed_values dict
                parsed_values[k] = v
        return parsed_values

    def prepare_class_form_fields_defs(self):
        # parsed custom attributes
        ca = self.parse_hstore_values('custom_attrs')
        # parsed predefined attributes
        pa = self.parse_hstore_values('predefined_attrs')
        form_fields = OrderedDict()
        form_fields['D'] = OrderedDict() # "D" -> dynamic form
        form_fields['S'] = OrderedDict() # "S" -> dynamic form
        # first prepare predefined attributes:
        pas = settings.PREDEFINED_ATTRIBUTES_SIMPLE
        pam = settings.PREDEFINED_ATTRIBUTES_MODELS
        for key in pas.keys():
            if pa.get(key):
                if pas[key].get('widget'):
                    widget = pas[key]['widget']
                    formfield = pas[key]['formfield'](required=pa['required_%s' % key] ,widget=widget)
                else:
                    formfield = pas[key]['formfield'](required=pa['required_%s' % key])
                form_fields[pa['target_%s' % key]][key] = formfield
        for key in pam.keys():
            if pa.get(key):
                model = get_model(pam[key]['app'], key)
                if pa['selected_%s' % key]:
                    query = model.objects.filter(pk__in=pa['selected_%s' % key])
                    choices = query.values_list(pam[key]['choices_labels'], pam[key]['choices_labels'])
                    formfield = forms.ChoiceField(choices=choices, required=pa['required_%s' % key])
                    form_fields[pa['target_%s' % key]][key] = formfield
                else:
                    formfield = AutoModelSelect2Field(
                        queryset = model.objects,
                        search_fields = pam[key]['search_fields'],
                        required = pa['required_%s' % key],
                    )
                    form_fields[pa['target_%s' % key]][key] = formfield
        # next prepare custom attributes:
        for key in ca.keys():
            if ca[key]['values']:
                # values have been already checked during a form validation so just split them
                splitted_values = ca[key]['values'].split(',')
                choices = zip(splitted_values, splitted_values)
                formfield = forms.ChoiceField(choices=choices, required=ca[key]['required'], initial=ca[key]['initial'])
                form_fields[ca[key]['target']][key] = formfield
            else:
                formfield = self.CUSTOM_ATTRS_FIELDS[ca[key]['at_type']](required=ca[key]['required'], initial=ca[key]['initial'],)
                form_fields[ca[key]['target']][key] = formfield
        return form_fields

#---------------------------------------------------------------#
# CLASSIFICATION MODELS (expert decisions)
#---------------------------------------------------------------#

# helper function, move to tools module
def get_ordered_values(keys_list, d):
    return [d.get(k) for k in keys_list]

class Classification(models.Model):
    """The result of classification process for given resource.
    .. seealso::
        * :class:`ClassificationUser`
    """

    resource = models.ForeignKey(Resource)
    project = models.ForeignKey(Project)
    pcollection = models.ForeignKey(ProjectCollection)
    approved = models.BooleanField(default=False)
    """is this classification approved by admins of classification project?"""
    classified_by = models.ForeignKey(User, null=True, blank=True, related_name='+')
    approved_by = models.ForeignKey(User, null=True, blank=True, related_name='+')
    approved_date = models.DateTimeField(null=True, blank=True)
    modified_by = models.ForeignKey(User, null=True, blank=True, related_name='+')
    modified_date = models.DateTimeField(null=True, blank=True)
    data_static_form = hstore.DictionaryField(null=True, blank=True)

    objects = hstore.HStoreManager()

    def __unicode__(self):
        return unicode("Classification: %s, Resource: %s" % (self.pk, self.resource))

    def get_attset(self):
        return self.project.attributeset

    def get_users_class(self):
        return self.users_classifications.all().order_by('modified')

    def get_approved_static_values(self):
        static_order = self.get_attset().get_static_attrs_order()
        return get_ordered_values(static_order, self.approved_data_static_form)

    def get_approved_dynamic_rows(self):
        values_list = []
        dynamic_order = self.get_attset().get_dynamic_attrs_order()
        for row in self.data_dynamic_form_rows.values_list('data_dynamic_form_row', flat=True):
            values_list.append(
                get_ordered_values(dynamic_order, row)
            )
        return values_list

class ClassificationDynamicFormRow(models.Model):
    classification = models.ForeignKey(Classification, related_name='data_dynamic_form_rows')
    data_dynamic_form_row = hstore.DictionaryField(null=True, blank=True)

    objects = hstore.HStoreManager()

class ClassificationUser(models.Model):
    """A model to store classifications made by users.
    .. note::
    """

    classification = models.ForeignKey(Classification, related_name="users_classifications")
    data_static_form = hstore.DictionaryField(null=True, blank=True)
    user = models.ForeignKey(User)
    classified = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now_add=True)

    objects = hstore.HStoreManager()

    def __unicode__(self):
        return unicode("%s | User: %s" % (self.classification, self.user.username))

    def get_static_values(self):
        static_order = self.classification.get_attset().get_static_attrs_order()
        return get_ordered_values(static_order, self.data_static_form)

    def get_dynamic_rows(self):
        values_list = []
        dynamic_order = self.classification.get_attset().get_dynamic_attrs_order()
        for row in self.data_dynamic_form_rows.values_list('data_dynamic_form_row', flat=True):
            values_list.append(
                get_ordered_values(dynamic_order, row)
            )
        return values_list

    def get_user_role(self):
        return self.classification.project.cproject_roles.get(user=self.user)

class ClassificationUserDynamicFormRow(models.Model):
    classification_user = models.ForeignKey(ClassificationUser, related_name='data_dynamic_form_rows')
    data_dynamic_form_row = hstore.DictionaryField()

    objects = hstore.HStoreManager()

class Sequence(models.Model):
    """Sequence of resources identified by an expert (ADMIN or EXPERT in a project)."""

    name = models.CharField(max_length=50)
    description = models.TextField(max_length=1000, null=True, blank=True)
    collection = models.ForeignKey(ProjectCollection)
    """ProjectCollection"""
    resources = models.ManyToManyField(Resource)
    created = models.DateTimeField(auto_now_add=True)
    user = models.ForeignKey(User, null=True, blank=True)

    def __unicode__(self):
        return unicode("Sequence %s defined by %s" % (self.name, self.user))

    def get_absolute_url(self):
        return reverse('media_classification:sequence_detail', kwargs={'pk':self.pk})

class ProjectRole(models.Model):
    """Model describing the user's role withing given :class:`.Project`"""

    ROLE_PROJECT_ADMIN = "A"
    ROLE_EXPERT = "E"
    ROLE_COLLABORATOR = "C"

    ROLE_ANY = (ROLE_PROJECT_ADMIN, ROLE_EXPERT, ROLE_COLLABORATOR, )
    ROLE_EDIT = (ROLE_PROJECT_ADMIN, ROLE_EXPERT, )

    ROLE_CHOICES = (
        (ROLE_PROJECT_ADMIN, "Admin"),
        (ROLE_EXPERT, "Expert"),
        (ROLE_COLLABORATOR, "Collaborator"),
    )

    user = models.ForeignKey(User)
    """User for which the role is defined"""

    name = models.CharField(max_length=1, choices=ROLE_CHOICES)
    """Role name"""

    project = models.ForeignKey(Project, related_name="cproject_roles")
    """Project for which the role is defined"""

    def __unicode__(self):
        return unicode("%s | Project: %s | Role: %s " % (self.user.username, self.project.name, self.get_name_display()))


class Solution:
    def luckyNumbers (self, matrix):
        m=len(matrix)
        n=len(matrix[0])
        max_row=[0 for i in range(n)]
        for i in range(m):
            for j in range(n):
                if matrix[i][j]>max_row[j]:
                    max_row[j]=matrix[i][j]
        lucky=[]
        for i in range(m):
            min_val=min(matrix[i])
            min_ind=matrix[i].index(min_val)
            if min_val>=max_row[min_ind]:
                lucky.append(min_val)
        return lucky

a=Solution()

print(a.luckyNumbers( [[3,7,8],[9,11,13],[15,16,17]]))


from django.contrib.auth import (
    login as django_login,
    logout as django_logout,
    get_user_model)
from django.core.exceptions import ObjectDoesNotExist
from django.conf import settings
from django.shortcuts import render

from rest_framework.response import Response
from rest_framework import status
from rest_framework.authtoken.models import Token
from rest_framework.decorators import action
from rest_framework import viewsets, mixins
from rest_framework.permissions import AllowAny, IsAuthenticated

# Create your views here.
from accounts.models import User, PhoneConfirm, Profile
from accounts.serializers import LoginSerializer, SignupSerializer, CredentialException, NicknameSerializer, \
    ResetPasswordSerializer, UserInfoSerializer, ProfileSerializer, GCMCreateSerializer
from accounts.sms.signature import simple_send
from accounts.sms.utils import SMSV2Manager, SMSManager
from accounts.utils import create_token, set_random_nickname
from mypage.models import DeliveryPolicy

from push_notifications.models import GCMDevice

class AccountViewSet(viewsets.GenericViewSet, mixins.CreateModelMixin):
    permission_classes = [AllowAny, ]
    queryset = User.objects.filter(is_active=True)
    token_model = Token

    def get_serializer_class(self):
        if self.action == 'signup':
            serializer = SignupSerializer
        elif self.action == 'reset_pw':
            serializer = ResetPasswordSerializer
        elif self.action == 'login':
            serializer = LoginSerializer
        elif self.action == 'check_userinfo':
            serializer = UserInfoSerializer
        elif self.action == 'profile':
            return ProfileSerializer
        elif self.action == 'gcm':
            return GCMCreateSerializer
        else:
            serializer = super(AccountViewSet, self).get_serializer_class()
        return serializer

    @action(methods=['get'], detail=False)
    def check_userinfo(self, request):
        """
        스플래시 화면에서 유저가 자동로그인이 가능하도록 해당 유저가 가지고 있는 토큰의 유효성을 판단하는 API
        추가로 유저의 환불계좌 입력 유무에 따라 업로드 시 client 에서 띄워주는 페이지가 다름
        api: POST accounts/v1/check_userinfo/
        :param request: header token or not
        :return: id, seller_registered, token
        200 : 해당 토큰을 가진 유저가 존재할 때
        401 : 해당 토큰을 가진 유저가 존재하지 않거나 토큰을 담아서 주지 않았을 때
        """
        if request.user.is_anonymous:
            return Response(status=status.HTTP_401_UNAUTHORIZED)
        user = request.user
        serializer = self.get_serializer(user)

        return Response(serializer.data, status=status.HTTP_200_OK)

    @action(methods=['post'], detail=False, permission_classes=[IsAuthenticated,])
    def gcm(self, request):
        """
        signup을 하거나 login 후의 받은 token과 reg_id를 함꼐 보내 User에 얽혀있는 registeration_id 를 update 합니다.
        api : POST accounts/v1/gcm/
        :param request: header token
        data = { "registration_id" : String }
        :return: status
        """
        reg_id = request.data.get('registration_id')
        if GCMDevice.objects.filter(registration_id=reg_id).exists():
            reg_obj = GCMDevice.objects.get(registration_id=reg_id)
            serializer = self.get_serializer(reg_obj, data=request.data)
        else:
            serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(status=status.HTTP_201_CREATED)

    @action(methods=['post'], detail=False)
    def signup(self, request, *args, **kwargs):
        """
        회원가입시 사용하는 api 입니다.
        sms 인증이 완료될 때 return 된 phone, temp_key에 + password 을 입력받습니다.
        temp_key를 활용하여 외부 api로 signup을 방지하였습니다.
        nickname의 경우 자동으로 random nickname이 부여되고, 회원가입 이후 nickname을 입력하면 update가 됩니다.
        api: POST accounts/v1/signup/

        :return:
        400 : bad request
        400 : temp_key가 유효하지 않을 때
        201 : created
        """
        data = request.data.copy()

        # check is confirmed (temp key로서 외부의 post 막음)
        temp_key = data.get('temp_key')
        if not temp_key:
            return Response("No temp key", status=status.HTTP_400_BAD_REQUEST)
        temp_key = data.pop('temp_key')
        phone_confirm = PhoneConfirm.objects.get(temp_key=temp_key)
        if not phone_confirm.is_confirmed:
            return Response("Unconfirmed Phone number", status=status.HTTP_400_BAD_REQUEST)
        if phone_confirm.phone != data.get("phone"):
            return Response("Not match phone number & temp key", status=status.HTTP_400_BAD_REQUEST)

        # user 생성
        serializer = self.get_serializer(data=data)
        serializer.is_valid(raise_exception=True)
        user = serializer.save()

        # default random nickname
        user.nickname = set_random_nickname(get_user_model())
        user.save()

        # default info create
        Profile.objects.get_or_create(user=user)
        DeliveryPolicy.objects.get_or_create(user=user)

        serializer = UserInfoSerializer(user)

        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def _login(self):
        user = self.serializer.validated_data['user']
        setattr(user, 'backend', 'django.contrib.auth.backends.ModelBackend')
        django_login(self.request, user)
        # loginlog_on_login(request=self.request, user=user)

    @action(methods=['post'], detail=False)
    def login(self, request, *args, **kwargs):
        """
        api: POST accounts/v1/login/

        """
        try:
            self.serializer = self.get_serializer(data=request.data)
            self.serializer.is_valid(raise_exception=True)
            self._login()
            user = self.serializer.validated_data['user']
        except CredentialException:
            return Response({"non_field_errors": ['Unable to log in with provided credentials.']},
                            status=status.HTTP_400_BAD_REQUEST)
        serializer = UserInfoSerializer(user)
        return Response(serializer.data, status=status.HTTP_200_OK)

    @action(methods=['post'], detail=False, url_name='logout')
    def logout(self, request):
        """
        api: POST accounts/v1/logout/
        data = { "registration_id" : string }
        :return: code, status
        """
        try:
            device = GCMDevice.objects.get(user=request.user,
                                           registration_id=request.data.get('registration_id'))
            device.user = None
            device.save()
            request.user.auth_token.delete()
        except (AttributeError, ObjectDoesNotExist):
            key = request.headers['Authorization']
            if key:
                token = Token.objects.get(key=key.split(' ')[1])
                token.delete()
        if getattr(settings, 'REST_SESSION_LOGIN', True):
            django_logout(request)

        return Response(status=status.HTTP_200_OK)

    @action(methods=['post'], detail=False)
    def reset_pw(self, request, *args, **kwargs):
        """
        비밀번호 재설정에 사용하는 api 입니다.
        sms 인증이 완료될 때 return 된 phone, temp_key에 + password 을 입력받습니다.
        temp_key를 활용하여 외부 api로 signup을 방지하였습니다.
        nickname의 경우 자동으로 random nickname이 부여되고, 회원가입 이후 nickname을 입력하면 update가 됩니다.

        api: POST accounts/v1/reset_pw/

        :return:
        400 : bad request
        400 : temp_key가 유효하지 않을 때
        201 : created
        """
        data = request.data.copy()

        # check is confirmed (temp key로서 외부의 post 막음)
        temp_key = data.get('temp_key')
        if not temp_key:
            return Response("No temp key", status=status.HTTP_400_BAD_REQUEST)

        temp_key = data.pop('temp_key')
        phone_confirm = PhoneConfirm.objects.get(temp_key=temp_key)
        if not phone_confirm.is_confirmed:
            return Response("Unconfirmed phone number", status=status.HTTP_400_BAD_REQUEST)
        if phone_confirm.phone != data.get("phone"):
            return Response("Not match phone number & temp key", status=status.HTTP_400_BAD_REQUEST)

        phone = data.pop('phone')
        user = User.objects.filter(phone=phone, is_active=True)

        if user.count() == 0:
            return Response("User does not exist", status=status.HTTP_400_BAD_REQUEST)

        user = user.last()

        # password reset(update) 생성
        serializer = self.get_serializer(user, data=data, partial=True)
        serializer.is_valid(raise_exception=True)
        user = serializer.save()

        serializer = UserInfoSerializer(user)
        return Response(serializer.data, status=status.HTTP_206_PARTIAL_CONTENT)

    @action(methods=['post'], detail=False, permission_classes=[IsAuthenticated, ])
    def profile(self, request, *args, **kwargs):
        """
        api: POST accounts/v1/profile/

        data = {profile_img: image file}
        """
        user = request.user
        profile = user.profile
        serializer = self.get_serializer(profile, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(status=status.HTTP_206_PARTIAL_CONTENT)

class NicknameViewSet(viewsets.GenericViewSet, mixins.UpdateModelMixin):
    permission_classes = [IsAuthenticated, ]
    serializer_class = NicknameSerializer
    queryset = User.objects.filter(is_active=True)

    @action(methods=['post'], detail=False)
    def register(self, request, *args, **kwargs):
        """
        User 회원가입시 nickname을 자동 생성 한 이후, NicknameViewSet 을 사용하여 nickname을 update 합니다.
        My page 에서 닉네임 업데이트시에도 사용합니다.

        api: POST accounts/v1/nickname/register/
        """
        user = request.user

        nickname = request.data.get('nickname')
        if nickname is None or len(nickname) < 2:
            return Response(status=status.HTTP_400_BAD_REQUEST)

        # check duplicate nickname
        if User.objects.filter(nickname=nickname).exists():
            return Response(status=status.HTTP_409_CONFLICT)

        # nickname save
        serializer = self.get_serializer(user, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        return Response(status=status.HTTP_206_PARTIAL_CONTENT)

    @action(['get'], detail=False, permission_classes=[AllowAny])
    def random(self, request, *args, **kwargs):
        """
        [PEPUP-226] 2020.06.11 기획이후 랜덤하게 설정하는 api 입니다.
        api: GET accounts/v1/nickname/random/
        """
        nickname = set_random_nickname(get_user_model())
        return Response({'nickname': nickname})

class SMSViewSet(viewsets.GenericViewSet):
    permission_classes = [AllowAny, ]
    serializer_class = None

    @action(methods=['post'], detail=False)
    def signup(self, request, *args, **kwargs):
        """
        회원가입 시 인증번호를 받는 api 입니다.
        body 에 phone 을 담아 보내주기만 하면 됩니다.

        api: POST accounts/v1/send_sms/signup/

        :return : temp_key (이를 활용하여 재발급에 사용)
        400 : bad request -> phone 을 보내지 않았을 때
        400 : 강제 밴 처리 당한 유저
        409 : 이미 가입 내역이 존재
        500 : (1) client에서 data 양식에 맞지 않게 요청시, (2) send error
        """
        data = request.data.copy()
        phone = data.get('phone')

        if not phone:
            return Response("No phone number", status=status.HTTP_400_BAD_REQUEST)

        if User.objects.filter(phone=phone, is_banned=True).exists():
            return Response("User is banned", status=status.HTTP_400_BAD_REQUEST) # banned user
        elif User.objects.filter(phone=phone, is_active=True).exists():
            return Response("Phone number already exists", status=status.HTTP_409_CONFLICT) # already exists

        # sms_manager = SMSManager()
        sms_manager = SMSV2Manager()
        sms_manager.set_content()
        sms_manager.create_instance(phone=phone, kind=PhoneConfirm.SIGN_UP)
        print(sms_manager.temp_key)
        if not sms_manager.send_sms(phone=phone):
            return Response("Failed send sms", status=status.HTTP_410_GONE)

        return Response({'temp_key': sms_manager.temp_key}, status=status.HTTP_200_OK)

    @action(methods=['post'], detail=False)
    def reset_pw(self, request, *args, **kwargs):
        """
        비밀번호 재설정시 인증번호를 받는 api 입니다.
        body 에 phone 을 담아 보내주기만 하면 됩니다.

        api: POST accounts/v1/send_sms/reset_pw/

        :return : temp_key (이를 활용하여 재발급에 사용)
        400 : bad request -> phone 을 보내지 않았을 때
        400 : 강제 밴 처리 당한 유저
        204 : 가입 내역이 없음
        500 : (1) client에서 data 양식에 맞지 않게 요청시, (2) send error
        """
        data = request.data.copy()
        phone = data.get('phone')

        if not phone:
            return Response({'temp_key': ""}, status=status.HTTP_400_BAD_REQUEST)

        if User.objects.filter(phone=phone, is_banned=True).exists():
            return Response({'temp_key': ""}, status=status.HTTP_400_BAD_REQUEST)  # banned user
        elif not User.objects.filter(phone=phone, is_active=True).exists():
            return Response({'temp_key': ""}, status=status.HTTP_204_NO_CONTENT)  # no user

        # sms_manager = SMSManager()
        sms_manager = SMSV2Manager()
        sms_manager.set_content()
        sms_manager.create_instance(phone=phone, kind=PhoneConfirm.RESET_PASSWORD)
        if not sms_manager.send_sms(phone=phone):
            return Response({'temp_key': ""}, status=status.HTTP_410_GONE)

        return Response({'temp_key': sms_manager.temp_key}, status=status.HTTP_200_OK)

    @action(methods=['post'], detail=False)
    def resend(self, request, *args, **kwargs):
        """
        인증번호 재발급에 사용하는 api 입니다.
        body 에 temp_key를 담아 보내주기만 하면 됩니다.

        api: POST accounts/v1/send_sms/resend/

        :return
        400 : bad request -> temp_key 에 데이터가 존재하지 않을 때
        404 : not found -> 잘못된 temp_key를 보냈을 때
        500 :  (1) client에서 data 양식에 맞지 않게 요청시, (2) send error
        """
        data = request.data.copy()
        temp_key = data.get('temp_key')

        if not temp_key:
            return Response("No temp key", status=status.HTTP_400_BAD_REQUEST)

        if not PhoneConfirm.objects.filter(temp_key=temp_key).exists():
            return Response("Invalid temp key", status=status.HTTP_404_NOT_FOUND)

        obj = PhoneConfirm.objects.filter(temp_key=temp_key).last()
        certification_number = obj.certification_number
        phone = obj.phone

        if not simple_send(certification_number, phone):
            return Response("Failed send sms", status=status.HTTP_410_GONE)

        return Response(status=status.HTTP_200_OK)

    @action(methods=['post'], detail=False)
    def confirm(self, request, *args, **kwargs):
        """
        인증번호를 확인하는 api 입니다.
        body 에 phone 과 key 를 담아 보내야 합니다.
        return 400 시 재전송이 아닌, 이전페이지(핸드폰 번호 입력)로 이동하여 새로운 코드를 발급해야 합니다.

        api: POST accounts/v1/send_sms/confirm/

        :return : phone, temp_key
        400 : bad request -> (1) phone 또는 key 가 없을 때, (2) 해당 key가 이미 인증에 사용된 key 일 때
        404 : not found -> key 가 맞지 않을 때
        """
        data = request.data.copy()
        phone = data.get('phone')
        key = str(data.get('key'))  # certification number

        if not phone or not key:
            return Response("No phone number or No key", status=status.HTTP_400_BAD_REQUEST)

        obj = PhoneConfirm.objects.filter(phone=phone).last()
        if obj.is_confirmed:  # already used key
            return Response("Invalid key: Already used to confirm", status=status.HTTP_400_BAD_REQUEST)

        if obj.certification_number != key:
            return Response("Not match key & server key", status=status.HTTP_404_NOT_FOUND)
        obj.is_confirmed = True
        obj.save()

        return Response({'phone': obj.phone, 'temp_key': obj.temp_key}, status=status.HTTP_200_OK)

def search_address_page(request):
    return render(request, 'address.html')


# _*_ coding: UTF-8 _*_
# 开发团队   :  未来科技
# 开发人员   :  ww
# 开发时间   :  2019-10-23 12:14
# 文件名称   :  MemberService.py
# 开发工具   :  PyCharm
# 功能描述   :  MemberService
import requests, json
from config import Config

class MemberService():

    @staticmethod
    def getWeChatOpenId(code):
        url = ("https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&"
               "js_code={2}&grant_type=authorization_code".format(Config.AppID, Config.AppSecret, code))
        r = requests.get(url)
        res = json.loads(r.text)
        openid = None
        if 'openid' in res:
            openid = res['openid']
        return openid


from django.db.models import TextChoices
from json import JSONDecodeError

from .client import Client

from grades.models import Semester, Course, Grade

"""
API documentation can be found at:
https://dbh.nsd.uib.no/dbhvev/dokumenter/api/api_dokumentasjon.pdf

Or table documentation found at:
https://dbh.hkdir.no/datainnhold/tabell-dokumentasjon
"""

class FilterType(TextChoices):
    TOP = "top", "Topp"
    ALL = "all", "Alle"
    ITEM = "item", "Enkelt enhet"
    BETWEEN = "between", "Mellom"
    LIKE = "like", "Lik"
    LESSTHAN = "lessthan", "Mindre enn"

class NSDGradeClient(Client):
    base_url = "https://dbh.hkdir.no"
    api_version = 1
    table_id = 308
    status_line = False  # Should extra information about the API response be included?
    code_text = True  # Should names of related resources be included?
    decimal_separator = "."
    institution_id = 1150  # ID for NTNU in NSD databases

    def __init__(self):
        super().__init__()
        self.session.headers.update({"Content-type": "application/json"})

    def get_json_table_url(self):
        return f"{self.base_url}/api/Tabeller/hentJSONTabellData"

    def create_filter(self, name: str, filter_type: FilterType, values):
        return {
            "variabel": name,
            "selection": {"filter": filter_type, "values": values, "exclude": [""],},
        }

    def get_semester_id(self, semester: Semester):
        lookup = {
            Semester.SPRING: 1,
            Semester.SUMMER: 2,  # NSD does not actually work for SUMMER semester!
            Semester.AUTUMN: 3,
        }
        return lookup[semester]

    def get_semester_filter(self, semester: Semester):
        semester_id = self.get_semester_id(semester)
        return self.create_filter(
            name="Semester", filter_type=FilterType.ITEM, values=[semester_id]
        )

    def get_institution_filter(self):
        return self.create_filter(
            name="Institusjonskode",
            filter_type=FilterType.ITEM,
            values=[str(self.institution_id)],
        )

    def get_department_filter(self):
        return self.create_filter(
            name="Avdelingskode", filter_type=FilterType.ALL, values=["*"]
        )

    def get_course_filter(self, course_code: str):
        # Filter course code by SQL 'like' since course codes in NSD include a version number in the string.
        course_code_likeness = f"{course_code}-%"
        return self.create_filter(
            name="Emnekode", filter_type=FilterType.LIKE, values=[course_code_likeness]
        )

    def get_year_filter(self, year: int):
        return self.create_filter(
            name="Årstall", filter_type=FilterType.ITEM, values=[str(year)]
        )

    def get_field_of_study_filter(self):
        return self.create_filter(
            name="Studieprogramkode", filter_type=FilterType.ITEM, values=["*"]
        )

    def get_filters(self, course_code: str, year: int, semester: Semester):
        return [
            self.get_semester_filter(semester),
            self.get_institution_filter(),
            self.get_department_filter(),
            self.get_course_filter(course_code),
            self.get_year_filter(year),
            self.get_field_of_study_filter(),
        ]

    def build_query(self, course_code: str, year: int, semester: Semester, limit=1000):
        filters = self.get_filters(course_code, year, semester)
        query = {
            "tabell_id": self.table_id,
            "api_versjon": self.api_version,
            "statuslinje": "J" if self.status_line else "N",
            "begrensning": str(limit),
            "kodetekst": "J" if self.code_text else "N",
            "desimal_separator": self.decimal_separator,
            "groupBy": ["Institusjonskode", "Avdelingskode", "Emnekode", "Karakter"],
            "sortBy": ["Institusjonskode", "Avdelingskode"],
            "variabler": ["*"],
            "filter": filters,
        }
        return query

    def resolve_result_for_grade(self, results, letter: str):
        grade_results = [
            result for result in results if result.get("Karakter") == letter
        ]
        if len(grade_results) == 0:
            return 0
        elif len(grade_results) > 1:
            raise Exception("Found more than a single grade entry for a course")

        grade_result = grade_results[0]
        return int(grade_result.get("Antall kandidater totalt"))

    def build_grade_data_from_results(
        self, results, course_code: str, year: int, semester: Semester
    ):
        passed = self.resolve_result_for_grade(results, "G")
        failed = self.resolve_result_for_grade(results, "H")
        a = self.resolve_result_for_grade(results, "A")
        b = self.resolve_result_for_grade(results, "B")
        c = self.resolve_result_for_grade(results, "C")
        d = self.resolve_result_for_grade(results, "D")
        e = self.resolve_result_for_grade(results, "E")
        f = self.resolve_result_for_grade(results, "F")

        student_count = a + b + c + d + e + f

        is_pass_fail = any(map(lambda number: number != 0, [passed, failed]))
        is_graded = any(map(lambda number: number != 0, [a, b, c, d, e, f]))

        if is_pass_fail and is_graded:
            raise Exception("Course is both pass/fail and graded by letters")

        if is_pass_fail:
            data = {
                "passed": passed,
                "f": failed,
                "average_grade": 0,
            }
        else:
            average_grade = (a * 5.0 + b * 4 + c * 3 + d * 2 + e) / student_count
            data = {
                "a": a,
                "b": b,
                "c": c,
                "d": d,
                "e": e,
                "f": f,
                "average_grade": average_grade,
            }

        course = Course.objects.get(code=course_code)
        data.update(
            {"course_id": course.id, "semester": str(semester), "year": year,}
        )

        return data

    def build_grade_from_data(self, grade_data):
        course_id = grade_data.get("course_id")
        semester = grade_data.get("semester")
        year = grade_data.get("year")
        try:
            grade = Grade.objects.get(
                course_id=course_id, semester=semester, year=year,
            )
            Grade.objects.filter(
                course_id=course_id, semester=semester, year=year,
            ).update(**grade_data)
            grade.refresh_from_db()
        except Grade.DoesNotExist:
            grade = Grade.objects.create(**grade_data)

        return Grade.objects.get(pk=grade.id)

    def request_grade_data(self, course_code: str, year: int, semester: Semester):
        query = self.build_query(course_code, year, semester)
        url = self.get_json_table_url()
        response = self.session.post(url, json=query)
        try:
            results = response.json()
        except JSONDecodeError:
            results = []
        return results

    def update_grade(self, course_code: str, year: int, semester: Semester):
        results = self.request_grade_data(course_code, year, semester)
        if len(results) == 0:
            return None
        grade_data = self.build_grade_data_from_results(
            results, course_code, year, semester
        )
        grade = self.build_grade_from_data(grade_data)
        return grade