# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================

"""A very simple MNIST classifier.
See extensive documentation at
https://www.tensorflow.org/get_started/mnist/beginners
"""

#5 layer perceptron

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

import argparse
import sys

from tensorflow.examples.tutorials.mnist import input_data

import argparse
import sys
import scipy.io
import numpy as np
import tensorflow as tf
import pickle
import random
import os
import math
import csv
import itertools

NLAYERS = 5
NCLASS = 10
NDATA = 784
NUNITS = [NDATA, 90, 80, 50, 30, NCLASS]
EPOCH = 100
MBATCH = 100
DATASET = 'MNIST'
FLAGS = None

def sigmoid(y):
    # Sigmoid function
    return 1 / (1 + tf.exp(-y))

def ReLU(y):
    # ReLU
    return tf.maximum(0.0, y)

def weight_variable(shape):
    # Define initial weight by normal distribution
    initial = tf.truncated_normal(shape, stddev=0.1)
    return tf.Variable(initial)

def bias_variable(shape):
    # Define initial weight by normal distribution
    initial = tf.constant(0.1, shape=shape)
    return tf.Variable(initial)

ACTIVATION_FUNC = {'ReLU':ReLU,'sigmoid':sigmoid}
USE_FUNC = 'ReLU'

def main(self):
  # Import data
  file_in = '../datasets/MNIST_data/'
  mnist = input_data.read_data_sets(file_in, one_hot=True)
  W_b_in = '../datasets/W_b_init'
  with open(W_b_in, mode='rb') as f:
      W_b_init = pickle.load(f)
      W1_init = W_b_init['W1_init']
      W2_init = W_b_init['W2_init']
      W3_init = W_b_init['W3_init']
      W4_init = W_b_init['W4_init']
      W5_init = W_b_init['W5_init']
      b1_init = W_b_init['b1_init']
      b2_init = W_b_init['b2_init']
      b3_init = W_b_init['b3_init']
      b4_init = W_b_init['b4_init']
      b5_init = W_b_init['b5_init']

  print('%s loaded' % file_in)
  print('%s loaded' % W_b_in)

  # Create the model
  x = tf.placeholder(tf.float32, [None, NDATA])

  with tf.variable_scope('fc1') as scope:
      W_1 = tf.Variable(np.resize(W1_init, (NUNITS[0], NUNITS[1])))
      b_1 = tf.Variable(np.resize(b1_init, (NUNITS[1])))
      h_1 = ACTIVATION_FUNC[USE_FUNC](tf.matmul(x, W_1) + b_1)

  with tf.variable_scope('fc2') as scope:
      W_2 = tf.Variable(np.resize(W2_init, (NUNITS[1], NUNITS[2])))
      b_2 = tf.Variable(np.resize(b2_init, (NUNITS[2])))
      h_2 = ACTIVATION_FUNC[USE_FUNC](tf.matmul(h_1, W_2) + b_2)

  with tf.variable_scope('fc3') as scope:
      W_3 = tf.Variable(np.resize(W3_init, (NUNITS[2], NUNITS[3])))
      b_3 = tf.Variable(np.resize(b3_init, (NUNITS[3])))
      h_3 = ACTIVATION_FUNC[USE_FUNC](tf.matmul(h_2, W_3) + b_3)

  with tf.variable_scope('fc4') as scope:
      W_4 = tf.Variable(np.resize(W4_init, (NUNITS[3], NUNITS[4])))
      b_4 = tf.Variable(np.resize(b4_init, (NUNITS[4])))
      h_4 = ACTIVATION_FUNC[USE_FUNC](tf.matmul(h_3, W_4) + b_4)

  with tf.variable_scope('fc5') as scope:
      W_5 = tf.Variable(np.resize(W5_init, (NUNITS[4], NUNITS[5])))
      b_5 = tf.Variable(np.resize(b5_init, (NUNITS[5])))
      y = tf.matmul(h_4, W_5) + b_5

  # Define loss and optimizer
  y_ = tf.placeholder(tf.float32, [None, 10])

  tf.add_to_collection('vars', W_1)
  tf.add_to_collection('vars', b_1)
  tf.add_to_collection('vars', W_2)
  tf.add_to_collection('vars', b_2)

  model = {'x': x, 'y': y, 'y_': y_}

  # Model
  x, y, y_ = model['x'], model['y'], model['y_']

  # Load Data
  train_data = mnist.train.images
  train_label = mnist.train.labels
  test_data = mnist.test.images
  test_label = mnist.test.labels
  validation_data = mnist.validation.images
  validation_label = mnist.validation.labels

  # Define lists
  list_epoch = ['epoch']
  list_iter = ['iter']
  list_train_loss = ['train_loss']
  list_validation_loss = ['validation_loss']
  list_train_accuracy = ['train_accuracy']
  list_validation_accuracy = ['validation_accuracy']
  list_gradients_norm = ['gradients_norm']

  # The raw formulation of cross-entropy,
  #
  #   tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(tf.nn.softmax(y)),
  #                                 reduction_indices=[1]))
  #
  # can be numerically unstable.
  #
  # So here we use tf.nn.softmax_cross_entropy_with_logits on the raw
  # outputs of 'y', and then average across the batch.
  loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y))
  params = tf.trainable_variables()
  gradients = tf.gradients(loss, params)
  train_step = tf.train.GradientDescentOptimizer(0.5).apply_gradients(zip(gradients, params))

  #Test trained model
  correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
  accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

  # Setting
  saver = tf.train.Saver(max_to_keep=0)
  sess = tf.InteractiveSession()
  sess.run(tf.global_variables_initializer())

  # Train
  iter = int(55000 / MBATCH * EPOCH)
  for i in range(iter):
    batch_xs, batch_ys = mnist.train.next_batch(MBATCH, shuffle=False)
    _, gradient = sess.run([train_step, gradients], feed_dict={x: batch_xs, y_: batch_ys})

    # Display progress
    sys.stdout.write("\r%.3f%%" % (i / iter * 100))
    sys.stdout.flush()

    # Testing
    if (i + 1) % (55000 / MBATCH) == 0:
        list_epoch.append(int((i + 1) / (55000 / MBATCH)))
        list_iter.append(i + 1)
        list_train_loss.append(sess.run(loss, feed_dict={x: train_data, y_: train_label}))
        list_train_accuracy.append(sess.run(accuracy, feed_dict={x: train_data, y_: train_label}))
        list_validation_loss.append(sess.run(loss, feed_dict={x: validation_data, y_: validation_label}))
        list_validation_accuracy.append(sess.run(accuracy, feed_dict={x: validation_data, y_: validation_label}))
        list_gradients_norm.append(
            np.linalg.norm(list(itertools.chain.from_iterable(na.flatten().tolist() for na in gradient))))

        #Display accuracy
        print(list_train_accuracy[-1])

        if (i + 1) / (55000 / MBATCH) % 10 == 0:
            # Save a model
            saver.save(sess,
                       '../models/' + DATASET + '/' + USE_FUNC + '/'+ str(NLAYERS) + 'layers_' + str(int((i + 1) / (55000 / MBATCH))) + '.ckpt')
            #print('Saved a models.')

  print()

  # Make CSV
  with open('../models/%s/%s/%slayers_%s.csv' % (DATASET, USE_FUNC, NLAYERS, USE_FUNC), 'w') as f:
      list_score = [list_epoch, list_iter, list_train_loss, list_train_accuracy, list_validation_loss,
                    list_validation_accuracy, list_gradients_norm]
      writer = csv.writer(f, lineterminator='\n')
      writer.writerows(list_score)
      print('%s.csv written' % USE_FUNC)

  print(sess.run(accuracy, feed_dict={x: mnist.test.images,
                                      y_: mnist.test.labels}))

  # Accuracy
  std_output = 'Train Loss: %s, \t Train Accuracy: %s, \t Test Accuracy: %s'
  print(std_output % (list_train_loss[-1], list_train_accuracy[-1], list_validation_accuracy[-1]))

 #Restore Model
  for i in range(iter):
      if (i + 1) / (55000 / MBATCH) % 10 == 0:
          saver.restore(sess,
                        '../models/' + DATASET + '/' + USE_FUNC + '/' + str(NLAYERS) + 'layers_' + str(int((i + 1) / (55000 / MBATCH))) + '.ckpt')

          #print('Restored a model')

  test_accuracy = sess.run(accuracy, feed_dict={x: test_data, y_: test_label})
  print('Test Accuracy(restore): %s' % test_accuracy)

  sess.close()

if __name__ == '__main__':
  parser = argparse.ArgumentParser()
  parser.add_argument('--data_dir', type=str, default='/tmp/tensorflow/mnist/input_data',
                      help='Directory for storing input data')
  FLAGS, unparsed = parser.parse_known_args()
  tf.app.run(main=main, argv=[sys.argv[0]] + unparsed)


import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as sp

centre, stdn, datapts = map(int, input("Enter Centre, Standard Deviation & No. of DataPoints for the Normal Distribution\n").split())

data = np.random.normal(centre, stdn, datapts)

fig = plt.figure(figsize=(6,6))
axes = fig.add_axes([0.05,0.55, 0.9, 0.4])

details = "DataSet (Normal distribution)\nCentre "+str(centre)+"\nStandard Deviation "+str(stdn)+"\nSize "+str(datapts)+"\n1st Moment (Mean) "+str(np.mean(data))+"\n2nd Moment (Variance) "+str(np.var(data))+"\n3rd Moment (Skewness) "+str(sp.skew(data))+"\n4th Moment (Kurtosis) "+str(sp.kurtosis(data))

fig.text(0.15,0.25, details)
axes.hist(data, 100)
plt.show()


"""
This module is going to be used as an Interface bewtween the Arduino and
the top layer application which is in charge of manage the LED strip.
The serial module is used to make the serial connection and the sleep
from the time module to enhace it.
"""
import serial
from time import sleep
import experiment.utils.logger as my_logger

logger = my_logger.get_logger('arudinocomm')

class ArduinoInstruction:
    """
    This class abstracts the communication between the application and
    the Arduino. The communication is done via the serial port where
    the Arduino is connected, also the baud rate has to be set.
    By default there is a timeout, to finish the communication if there
    is any problem and wait time that allows to wait until the
    connection is ready.
    """
    TIMEOUT = 5
    START_WAIT_TIME = 2
    MESSAGE_WAIT_TIME = 0.0625

    def __init__(self, port, baud):
        """
        This is where the port and baud rate are set.
        ----------
        port : string
            The serial port where the Arduino is connected.
        baud : int
            The baud rate used to transmit information.
        Returns
        -------
        new ArduinoInstruction Object
        """
        self.port = port
        self.baud = baud

    def start_connection(self):
        """Starts the serial connection with the Arduino."""
        try:
            self.arduino = serial.Serial(
                self.port, self.baud, timeout=self.TIMEOUT
            )
            sleep(self.START_WAIT_TIME)  # This is important
            logger.info(
                "Connection started: %s, rate: %d" % (self.port, self.baud)
            )
        except Exception as e:
            logger.error(e)

    def send_instrunction(self, instruction):
        """ This sends the instruction to the Arduino. """
        logger.debug(instruction)
        self.arduino.write(instruction.encode())
        sleep(self.MESSAGE_WAIT_TIME)
        response = ''
        while self.arduino.in_waiting:
            response += self.arduino.readline().decode()
        return response

    def close_connection(self):
        """ This closes the serial connection."""
        self.arduino.close()

if __name__ == "__main__":
    # Test to check if it works.
    inst = ArduinoInstruction('COM4', 57600)
    inst.start_connection()
    for i in range(0, 3):
        res = inst.send_instrunction("""
        {
            "block":""" + '"' + str(i) + """,2,0,0,255",
            "brightness": 25,
            "led": []
        }
        """)
        logger.info("From Arduino: %s" % (res))
    inst.close_connection()


import matplotlib.pyplot as plt
import numpy as np
import random
import pandas as pd
import itertools

def scaleData(data, scaleAmp=True, scaleMean=True, scaleVar=True):
    data = np.array(data).T
    for i in range(len(data)):
        if scaleAmp:
            data[i] = (data[i]-np.min(data[i]))/(np.max(data[i]-np.min(data[i])))
        if scaleMean:
            data[i] = data[i] - np.mean(data[i])
        if scaleVar:
            data[i] = data[i] / np.sqrt(np.var(data[i]))
    data = data.T
    return data

def scalogram(data = 0 , title = 'default'):
    bottom = 0

    vmin = min(map(lambda x: min(abs(x)), data))
    vmax = max(map(lambda x: max(abs(x)), data))

    plt.gca().set_autoscale_on(False)
    plt.title(title)

    for row in range(0, len(data)):
        scale = 2.0 ** (row - len(data))

        plt.imshow(
            np.array([(data[row])]),
            interpolation='nearest',
            vmin=vmin,
            vmax=vmax,
            extent=[0, 1, bottom, bottom + scale])
#            extent=[time[0], time[-1], bottom, bottom + scale])

        bottom += scale

def shuffleData(x, y):
    if len(x)==len(y):
        x_out = np.zeros(np.shape(x))
        y_out = np.zeros(np.shape(y))
        index = np.linspace(0, len(x) - 1, len(x))
        random.shuffle(index)

        for i in range(len(index)):
            x_out[i] = x[int(index[i])]
            y_out[i] = y[int(index[i])]
    else:
        print("Data not shuffled (x!=y).")
    return x_out, y_out

def powerSetOfArray(set):
    x = [i for i in itertools.chain.from_iterable(itertools.combinations(set, r) for r in range(len(set) + 1))]
    out =[]
    for i in range(len(x)):
        out.append(np.array(x[i]))
    return out

def writeDataToCsvFile(data, fileName="test.dat", path=""):
    data = {'time': np.linspace(0,241,242), 'val': data}
    output_df = pd.DataFrame(data=data)
    output_df.to_csv(path+fileName, sep=' ', index=False, header=False)

def writeMatrixToCsvFile(data, fileName="test.dat", path="", matrix=True):
    import csv
    data = np.array(data)
    outputFile = open(path + fileName, "w")
    with open(file=path + fileName, mode="w"):
        writer = csv.writer(outputFile, delimiter=' ')
        if matrix:
            for i in range(np.size(data[::, 0])):
                for j in range(np.size(data[0, ::])):
                    dataString = str(i), str(j), str(np.round(data[i, j], 5))
                    writer.writerow(dataString)
                writer.writerow('')
        else:
            for i in range(np.size(data[::, 0])):
                dataString = str(np.round(data[i, 0], 5)), str(np.round(data[i, 1], 5))
                writer.writerow(dataString)


#!python

from math import pi
import numpy as np
from scipy.integrate import odeint
from joblib import Parallel, delayed
import multiprocessing
import matplotlib.pyplot as plt
from scipy.optimize import fmin

def Epi(k, ux):
    return np.sqrt(k**2 + 2*ux)

def Esig(k, x, ux, uxx):
    return np.sqrt(k**2 + 2*ux + 4*x*uxx)

def Eq(k, g, x):
    return np.sqrt(k**2 + g**2*x)

def flow_eq(u, k, N, g, mu, T, x, dx):

    uxForw = (-3.0/2.0*u[0] + 2.0*u[1] - 1.0/2.0*u[2])/dx
    uxBack = (3.0/2.0*u[N-1] - 2.0*u[N-2] + 1.0/2.0*u[N-3])/dx
    uxCent = (-1.0/2.0*u[0:-2] + 1.0/2.0*u[2:])/dx
    ux = np.append(np.append(uxForw, uxCent), uxBack)
    uxxForw = (2.0*u[0] - 5.0*u[1] + 4.0*u[2] - 1.0*u[3])/dx**2
    uxxBack = (2.0*u[N-1] - 5.0*u[N-2] + 4.0*u[N-3] - 1.0*u[N-4])/dx**2
    uxxCent = (u[0:-2] - 2*u[1:-1] + u[2:])/dx**2
    uxx = np.append(np.append(uxxForw, uxxCent), uxxBack)

    # Compute du/dk.
    dudk = k**4/(12*pi**2)*(3.0/Epi(k, ux)*(1.0/np.tanh(Epi(k, ux)/(2*T)))
                            + 1.0/(Esig(k, x, ux, uxx))
                            * (1.0/np.tanh(Esig(k, x, ux, uxx)/(2*T)))
                            - 12.0/Eq(k, g, x)*(np.tanh((Eq(k, g, x) - mu)
                                                        / (2*T))
                            + np.tanh((Eq(k, g, x) + mu)/(2*T))))
    # print(k)
    return dudk

def solution(u0, k, N, g, mu, T, x, dx):
    sol = odeint(flow_eq, u0, k, args=(N, g, mu, T, x, dx, ), mxstep=200000,
                 rtol=1e-13, atol=1e-13, full_output=False)
    print((mu, T))
    return sol

def interpFunc(t, a, b, c):
    return a*t**2 + b*t + c

def interpolate(s, expl_sym_br, dx):
    # Quadratische Interpolation vielleicht zu ungenau...
    x1 = np.argmin([s[-1, :] - expl_sym_br])
    x2 = x1 + 1
    x3 = x1 - 1
    y1 = s[-1, x1] - expl_sym_br[x1]
    y2 = s[-1, x2] - expl_sym_br[x2]
    y3 = s[-1, x3] - expl_sym_br[x3]
    a = (x1*(y3 - y2) + x2*(y1 - y3) + x3*(y2 - y1))/((x1 - x2)*(x1 - x3) *
                                                      (x2 - x3))
    b = (y2 - y1)/(x2 - x1) - a*(x1 + x2)
    c = y1 - a*x1**2 - b*x1
    minimum = np.sqrt(fmin(interpFunc, x1, args=(a, b, c), xtol=0.001,
                           ftol=1e+6)[0]*dx)
    return minimum, b, 2*a

if __name__ == "__main__":
    lam = 2.0
    m_lam = 794.
    g = 3.2
    k_cutoff = 1000
    k_IR = 100
    N_k = 100
    L = 140.0**2
    N = 50
    x = np.linspace(0, L, N)
    dx = x[1] - x[0]
    k = np.linspace(k_cutoff, k_IR, N_k)
    u0 = 1.0/2.0*m_lam**2*x + lam/4.0*x**2
    T_max = 250
    N_T = 20
    mu_max = 400
    N_mu = 20
    T_min = 5
    mu_min = 0
    T_array = np.linspace(T_min, T_max, N_T)
    mu_array = np.linspace(mu_min, mu_max, N_mu)
    h = 1750000
    expl_sym_br = h*np.sqrt(x)
    sol = [[None for _ in range(len(mu_array))] for _ in
           range(len(T_array))]
    min_values = np.zeros([len(mu_array), len(T_array)])
    m_sig = np.zeros([len(mu_array), len(T_array)])
    m_pi = np.zeros([len(mu_array), len(T_array)])

    num_cores = multiprocessing.cpu_count()

    for t in range(len(T_array)):
        sol[t] = Parallel(n_jobs=num_cores)(delayed(solution)
                                            (u0, k, N, g, mu_array[m],
                                             T_array[t], x, dx)
                                            for m in range(len(mu_array)))
    for t in range(len(T_array)):
        for m in range(len(mu_array)):
            s = sol[t][m]
            argmin = np.argmin([s[-1, :] - expl_sym_br])
            if argmin != 0 and argmin != N - 1:
                min_values[t, m] = interpolate(s, expl_sym_br, dx)[0]
                m_pi[t, m] = np.sqrt(h/min_values[t, m])
                m_sig[t, m] = np.sqrt(4*min_values[t, m]**2 *
                                      interpolate(s, expl_sym_br, dx)[2]/dx**2
                                      + m_pi[t, m]**2)
            else:
                min_values[t, m] = np.sqrt(np.argmin([s[-1, :]
                                                      - expl_sym_br])*dx)
            # print(min_values)

    print("chiral condensate: "+str(min_values[0, 0]))
    print("vacuum pion mass: "+str(m_pi[0, 0]))
    print("vacuum sigma mass: "+str(m_sig[0, 0]))
    param_list = np.array([lam, m_lam, g, k_cutoff, k_IR, N_k, L, N, dx, T_max,
                           N_T, mu_max, N_mu])
    dat_name = 'TripoltPhaseDiagramN_T'+str(N_T)+'N_mu'+str(N_mu)
    params_name = dat_name+'params'
    fig_name = 'TripoltPhaseDiagramN_T'+str(N_T)+'N_mu'+str(N_mu)+'.png'
    np.save(dat_name, sol)
    np.save(params_name, param_list)
    mu_ax, T_ax = np.meshgrid(mu_array, T_array)
    fig = plt.figure()
    CS = plt.contourf(mu_ax, T_ax, min_values, 15)
    plt.title('Phase Diagram')
    plt.savefig(fig_name)
    plt.show()


# -*- coding: utf-8 -*-
# @Time    : 2018/2/22 9:34
# @Author  : DGG
# @Site    :
# @File    : test.py
# @Software: PyCharm

import requests
import json
import random

class Tongke(object):
    #生成手机号码
    def create_phone(self):
        # 第二位数字
        second = [3, 4, 5, 7, 8][random.randint(0, 4)]

        # 第三位数字
        third = {
            3: random.randint(0, 9),
            4: [5, 7, 9][random.randint(0, 2)],
            5: [i for i in range(10) if i != 4][random.randint(0, 8)],
            7: [i for i in range(10) if i not in [4, 9]][random.randint(0, 7)],
            8: random.randint(0, 9),
        }[second]

        # 最后八位数字
        suffix = random.randint(9999999, 100000000)

        # 拼接手机号
        return "1{}{}{}".format(second, third, suffix)

    #获取短信验证码
    def get_code(self,phone):
        url = 'http://www.tongke.cn/user/sendsmscode'
        res = requests.post(url, data={"telephone": phone})
        if res.status_code != 200:
            print('获取短信验证码请求失败')
            return None
        data = res.json()
        if data['code'] == 1:
            return data['data']
        return None

    #检测手机号码是否已注册
    def check_phone(self,phone):
        url = 'http://www.tongke.cn/user/check-user-is-exist?user_tel='
        res = requests.get(url + phone)
        data = res.json()
        if data['code'] == 100011 :
            return True
        return False

    #发送订单请求
    def send_order(self):
        order_url = "http://www.tongke.cn/serverPay/createOrder"
        phone = self.create_phone()
        #如果手机号码已经注册，则开始请求
        if not self.check_phone(phone):
            print(phone+"未注册")
            return

        code = self.get_code(phone)
        data = {
            "goodId": "481c35ed113d443a9b31706f0b5b7402",
            "skuId": 6957,
            "userSymbolPath": 101,
            "regionId": 510104,
            "number": 1,
            "totalAmount": 888,
            "telephone": phone,
            "smscode": code,
            "message":"备注"
        }
        rest_ss = requests.session()
        res = rest_ss.post(order_url,data=data)
        res_data = res.json()
        if res_data['code'] == 1:
            print('订单提交成功，开始查询数据....')
            real_url = 'http://www.tongke.cn/user/mine/pay-order/default/1'
            real_res = rest_ss.get(real_url)
            real_data = real_res.json()
            if real_data['code'] ==1 and real_data['data']['totalRows']>1 :
            #if real_data['code'] ==1 :
                with open('data.json','a+',encoding="utf-8") as f:
                    line = phone
                    for item in real_data['data']['list']:
                        line += ','+item['serverSku']
                    f.write(line+'\n')
                    print("写入%s" % line)

    #开始执行
    def run(self):
        while True:
            self.send_order()

if __name__ == '__main__':
    tongke = Tongke()
    tongke.run()


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

from django.db import migrations, models

class Migration(migrations.Migration):

    dependencies = [
        ('customer', '0001_initial'),
        ('table', '0001_initial'),
    ]

    operations = [
        migrations.CreateModel(
            name='Booking',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('date_of_booking', models.DateField(auto_now=True)),
                ('customer', models.ForeignKey(to='customer.Customer')),
                ('table', models.ForeignKey(to='table.Table')),
            ],
        ),
    ]


#coding=utf-8

from definition import *
import matplotlib.pyplot as plt
from planar_utils import plot_decision_boundary, load_planar_dataset

#加载数据
X, Y = load_planar_dataset()

shape_X = X.shape
shape_Y = Y.shape
m = shape_X[1]  # training set size
print ('The shape of X is: ' + str(shape_X))
print ('The shape of Y is: ' + str(shape_Y))
print ('I have m = %d training examples!' % (m))

# Build a model with a n_h-dimensional hidden layer
parameters = nn_model(X, Y, n_h = 4, num_iterations = 10000, print_cost=True)

# Plot the decision boundary
plot_decision_boundary(lambda x: predict(parameters, x.T), X, Y)
plt.title("Decision Boundary for hidden layer size " + str(4))
plt.show()

#预测准确率
predictions = predict(parameters, X)
print ('Accuracy: %d' % float((np.dot(Y,predictions.T) + np.dot(1-Y,1-predictions.T))/float(Y.size)*100) + '%')

#改变隐藏层单元数量进行训练预测查看
plt.figure(figsize=(16, 32))
hidden_layer_sizes = [1, 2, 3, 4, 5, 10, 20,50]
for i, n_h in enumerate(hidden_layer_sizes):
    # plt.subplot(5, 2, i+1)
    plt.title('Hidden Layer of size %d' % n_h)
    plt.show()
    parameters = nn_model(X, Y, n_h, num_iterations = 5000)
    plot_decision_boundary(lambda x: predict(parameters, x.T), X, Y)
    predictions = predict(parameters, X)
    accuracy = float((np.dot(Y,predictions.T) + np.dot(1-Y,1-predictions.T))/float(Y.size)*100)
    print ("Accuracy for {} hidden units: {} %".format(n_h, accuracy))


from multiprocessing import Process
import subprocess
import socket
import os
import time

Django_Server_Web_Port = 8000
Java_Sock_Port = 8001
Django_Sock_Port = 8005

JAVA_CMD = ['java','-cp','/home/jelix/example-zookeeper.jar','cn.itcast.zk.TestZKClient']
DJANGO_CMD = ['/home/jelix/HelloWorld/manage.py','runserver','0.0.0.0:8000']

def run_django_server(name):
    django_proc = subprocess.call(DJANGO_CMD,stdout=open('./test_3.out','w'),stderr=open('./test_4.out','w'))

# 子进程要执行的代码
def run_java_sock_proc(name):
	print('Run child process %s (%s)...' % (name, os.getpid()))
	server = socket.socket()#声明socket类型，并且生成socket连接对象
	server.bind(('localhost',Java_Sock_Port))#把服务器绑定到localhost的6969端口上
	server.listen(5)#开始监听
	print("等待连接中……")
	django_proc_flag = False
	django_proc = Process(target=run_django_server, args=('test_django',))
	while True:
		conn,addr = server.accept()#接收连接
		print("***连接成功***")
		data = bytes.decode(conn.recv(4096)).split() #接收客户发来的数据

		me_flag = data[-1]==data[-2]
		if me_flag and (not django_proc_flag):
			django_proc.start()
			print("Django Server Started")
			django_proc_flag = True

		if (not me_flag) and django_proc_flag:
			django_proc.terminate()
			print("Django Server Stopped")
			django_proc_flag = False

		print("接收到的命令为：",data[-1]==data[-2])
	server.close()

def run_java(name):
    java_proc = subprocess.call(JAVA_CMD,stdout=open('./test_1.out','w'),stderr=open('./test_2.out','w'))

def run_django_sock(name):
	print('Run child process %s (%s)...' % (name, os.getpid()))
	server = socket.socket()#声明socket类型，并且生成socket连接对象
	server.bind(('localhost',Django_Sock_Port))#把服务器绑定到localhost的6969端口上
	server.listen(5)#开始监听
	print("等待连接中……")
	while True:
		conn,addr = server.accept()#接收连接
		print("***连接成功***")
		data = conn.recv(4096) #接收客户发来的数据
		print("接收到的命令为：",data)

	server.close()

if __name__=='__main__':
    print('Parent process %s.' % os.getpid())
    # s = Process(target=run_django_sock, args=('test_django_sock',))
    # s.start()
    # time.sleep(1)
    # p = Process(target=run_java_sock_proc, args=('test_java_sock',))
    # print('Child process will start.')
    # p.start()
    # time.sleep(1)
    # r = Process(target=run_java, args=('test_java',))
    # r.start()
    # s.join()
    # r.join()
    # p.join()
    # print('Child process end.')
    s = Process(target=run_django_sock, args=('test_django_sock',))
    s.start()
    s.join()


from cmd import Cmd
from file_to_data import FileToData
import os.path
from os import path
import webbrowser
# import matplotlib.pyplot as plt
# import matplotlib.image as mpimg
# import numpy as np
from DiagramCreator import MyCreator
from PickleMaker import MyPickle
from SQLDatabase import MyDatabase
import os
import cmd
import subprocess
import shlex
import sys
import os.path
import shelve_create

class MyCli(Cmd):
    """Command line interpreter for generating UML class diagram"""

    # Harry's work
    def __init__(self, my_name=">"):
        Cmd.__init__(self, my_name)
        self.my_name = my_name
        self.prompt = ">>" + my_name + ">> "
        self.file_to_data = FileToData()

    # Matt's work
    def do_exit(self):  # delete
        # exit the application.
        print('Exiting Program...')
        return True

    # Matt's work
    def help_exit(self):
        print('Exit the application.')

    # Matt's work
    def do_diagram(self, inp):
        image_name = input('Image name/type:')
        MyCreator(image_name, inp).create_diagram()

    # Matt's work
    def help_diagram(self):
        print('Create a class diagram. Enter file location of py/dot file, then enter name/type of image.')

    # Matt's work
    def do_deletediagram(self, inp):
        MyCreator(inp, 'pass').delete_diagram()

    # Matt's work
    def help_deletediagram(self):
        print('Deletes a diagram')

    # Matt's work
    def do_pickle(self, inp):
        MyPickle(inp, input('name of pickle file: ')).make_pickle()

    # Matt's work
    def help_pickle(self):
        print('pickle [filename], enter file to pickle then the name of the pickle file')

    # Matt's work
    def do_unpickle(self, inp):
        MyPickle('a', inp).make_pickle()

    # Matt's work
    def help_unpickle(self):
        print('unpickle [picklefilename], enter the name of a text file that has been pickled')

    # Matt's work
    def do_deletepickle(self, inp):
        MyPickle('pass', inp).delete_pickle()

    # Matt's work
    def help_deletepickle(self):
        print('Deletes a pickle file')

    # Matt's work
    def do_createtable(self, inp):
        MyDatabase().create_table(inp)

    # Matt's work
    def help_createtable(self):
        print('createtable [TABLE_NAME], creates a table with: file_number INTEGER PRIMARY KEY, file_name VARCHAR(30),'
              'file_content VARCHAR(999) ')

    # Matt's work
    def do_addtotable(self, inp):
        f_number = input('File number: ')
        try:
            val = int(f_number)
            MyDatabase().add_data(inp, val, input('File name: '), input('File content: '))
        except ValueError:
            print('Please input a integer!')

    # Matt's work
    def help_addtotable(self):
        print('addtotable [TABLE_NAME], adds data to specified table')

    # Matt's work
    def do_showtable(self, inp):
        MyDatabase().show_data(inp)

    # Matt's work
    def help_showtable(self):
        print('showtable [TABLE_NAME], shows data held within specified table')

    # Matt's work
    def do_deletetable(self, inp):
        MyDatabase().delete_table(inp)

    # Matt's work
    def help_deletetable(self):
        print('deletetable [TABLE_NAME], deletes specified table')

    # Matt's work
    def do_closedb(self):
        MyDatabase().close_database()

    # Matt's work
    def help_closedb(self):
        print('Closes current open database')

    # Matt's work
    def do_deletedb(self):
        MyDatabase().close_database()

    # Matt's work
    def help_deletedb(self):
        print('Deletes current database')

    # Matt's work
    def default(self, inp):
        print(inp + ' is an incorrect command. Type ? to list commands.')

	    #John's work
    def help_help(self):
        message = 'Commands help.'
        print(message)

    #John's work
    def do_help(self, args):
        """Get help on commands"""
        cmd.Cmd.do_help(self, args)

    #John's work
    def do_create(self, source_file):
        """Generate dot file."""
        try:
            if os.path.exists(source_file):
                args = shlex.split('-o dot -p result source_file.py')
                subprocess.call(['pyreverse'] + args)
                print('Dot File is ready please check folder.')
            else:
                message = "Process has failed."
                raise NameError(message)

        except NameError as e:
            print(e)

    def help_create(self):
        message = 'Make source py file into dot file. Example: create source_file.py'
        print(message)

    def do_check_dot(self, classes_result):
        """Checks if dot file exists"""
        try:
            if os.path.exists(classes_result):
                print(classes_result + ' is ready to be converted')
            else:
                message = "the dot file does not exist"
                raise NameError(message)

        except NameError as e:
            print(e)

    def help_check_dot(self):
        message = 'Checks if dot file exists. Example: check_dot classes_result.dot'
        print(message)

    def do_dot(self, classes_result):
        """Turn dot file into png file."""
        try:
            if os.path.exists(classes_result):
                args = shlex.split(' -Tpng -O classes_result.dot')
                subprocess.call(['dot'] + args)
                print('the conversion is done')

            else:
                message = "the dot file failed to be converted to png.."
                print(message)

        except Exception as err:
            print("Failed, the error is: ", err)

    def help_dot(self):
        message = 'Turn dot file into png file. Example: dot classes_result.dot'
        print(message)

    def do_make_shelve(self, inp):
        """Create shelf!"""
        shelve_create.Shelf(inp, input('name of file to shelf: ')).make_shelf()

    def help_make_shelve(self):
        message = 'make_shelve then press enter, then enter the name of the file shelved [example: cli.py]'
        print(message)

    def do_existing_shelve(self, inp):
        """Access data!"""
        shelve_create.Shelf(inp, input('name of shelf file to access: ')).existing_shelf()

    def help_existing_shelve(self):
        message = 'existing_shelve then press enter, then enter the name of the shelved file to access'
        print(message)

    def run_pyreverse(self):
        """run pyreverse"""
        from pylint.pyreverse.main import Run
        Run(sys.argv[1:])

    # Harry's work
    def do_pyr_class_diagram(self, file_names):
        """Generate and display a class diagram in png format from given [png_file_name_suffix py_file_name.py]"""
        self.file_names = file_names
        python_file_name = file_names[(file_names.find(" ") + 1):]
        png_file_name = 'classes_' + file_names[0:(file_names.find(" "))] + '.png'
        try:
            if path.exists(python_file_name):
                pyreverse_command = 'pyreverse -ASmn -o png -p ' + file_names
                subprocess.call(pyreverse_command)
                print(file_names + ' are done')

                if path.exists(png_file_name):
                    # show png image
                    img = mpimg.imread(png_file_name)
                    fig = plt.imshow(img)
                    fig.axes.get_xaxis().set_visible(False)
                    fig.axes.get_yaxis().set_visible(False)
                    plt.show()
                else:
                    print("The image of class diagram cannot be generate.")
                    print("Please check with your system administrators.")
            else:
                print("Your given python file does not exist in the current directory "
                      "or your input arguments were wrong. The input arguments "
                      "should be [png_file_name_suffix py_file_name.py]. "
                      "Please try again!")
        except Exception as err:
            print("Please try again! The exception is: ", err)

    # Harry's work
    def help_pyr_class_diagram(self):
        print("\n".join(['Generate and display a class diagram in png format from a given python file',
                         'Syntax: pyr_class_diagram [output png file name suffix] '
                         '[input source code file name.py])']))

    # Harry's work
    def do_read_source_file(self, file_name):
        """This function extract data from the given python file to be an ast node.
        The file name should be [py_file_name.py]. The node will display as an indication of extraction"""
        try:
            if path.exists(file_name):
                self.file_to_data.read_file(file_name)
                print("The ast nodes below has been read from the given python file, " + file_name + ":")
                self.file_to_data.show_ast_nodes()
            else:
                print("Your given python file does not exist in the current directory ")
                print("or your input arguments were wrong. The input arguments ")
                print("should be [py_file_name.py]. ")
                print("Please try again!")
        except Exception as err:
            print("Please try again! The exception is: ", err)

    # Harry's work
    def help_read_source_file(self):
        print("\n".join(['Extract data from the given python file to be an ast node',
                         'Syntax: read_source_file [input source code file name.py]']))

    # Harry's work
    def do_validate_class_contents(self, file_name):
        """Validate, list and display class names, function names and the total numbers of them
        in the given python file. Class and function names are displayed in command line.
        Total numbers of classes and functions are displayed in a bar graph.
        Syntax: validate_class_contents [input source code file name.py]"""

        # sample: validate_class_contents test.py
        num_of_classes = 0
        num_of_functions = 0
        try:
            if path.exists(file_name):
                self.file_to_data.read_file(file_name)
                num_of_classes = len(self.file_to_data.tree.body)
                print("---There are " + str(num_of_classes) + " classes.-------------------")
                print("-----The classes are: -------------------")
                for my_class in self.file_to_data.tree.body:
                    print("-------" + my_class.name + " class")
                for my_class in self.file_to_data.tree.body:
                    print("---------The " + my_class.name + " class has " + str(len(my_class.body)) + " functions")
                    num_of_functions += len(my_class.body)
                    print("-----------The functions in " + my_class.name + " class are ")
                    for my_function in my_class.body:
                        print("---------------" + my_function.name + " function")
                print("total number of classes is " + str(num_of_classes))
                print("total number of functions is " + str(num_of_functions))
                # for my_function in my_class.body:
                #     if my_function.name == "__init__":
                #         print("---------The " + my_class.name + " class has " + str(
                #             len(my_function.body)) + " attributes")
                #         print("-----------The attributes in " + my_class.name + " class are ")
                #         for my_attribute in my_function.body:
                #             print("---------------" + my_attribute.targets[0].attr + " attribute")

                # types_x = ["class", "function"]
                # num_y = [num_of_classes, num_of_functions]
                # plt.plot(types_x, num_y, '-b', label="A simple line")
                # plt.legend(loc='upper left')
                # plt.title("Total Numbers of classes and functions")
                # plt.xlabel('Types')
                # plt.ylabel('Total Numbers')
                # plt.show()
                types_x = ["class", "function"]
                x_pos = np.arange(len(types_x))
                num_y = [num_of_classes, num_of_functions]
                plt.bar(x_pos, num_y, align='center', alpha=0.5)
                plt.xticks(x_pos, types_x)
                plt.ylabel('Total Numbers')
                plt.title('Total Numbers of classes and functions')
                plt.show()
            else:
                print("Your given python file does not exist in the current directory ")
                print("or your input arguments were wrong. The input arguments ")
                print("should be [py_file_name.py]. ")
                print("Please try again!")
        except Exception as err:
            print("Please try again! The exception is: ", err)

    # Harry's work
    def help_validate_class_contents(self):
        print("\n".join(['Validate, list and display class names, function names and the total numbers of them'
                         ' in the given python file.',
                         'Class and function names are displayed in command line.',
                         'Total numbers of classes and functions are displayed in a bar graph.',
                         'Syntax: validate_class_contents [input source code file name.py].']))

    # Harry's work
    def do_dot_2_png(self, input_dot_file_name):
        """Generate and display png file from the given dot file.
        Syntax: dot_2_png [input dot file name.dot]"""
        try:
            if path.exists(input_dot_file_name):
                dot_command = 'dot -Tpng ' + input_dot_file_name + ' -o ' + input_dot_file_name + '.png'
                subprocess.call(dot_command)
                print(input_dot_file_name + '.png ' + ' are done')
                png_file_name = input_dot_file_name+".png"
                if path.exists(png_file_name):
                    # show png image
                    img = mpimg.imread(png_file_name)
                    fig = plt.imshow(img)
                    fig.axes.get_xaxis().set_visible(False)
                    fig.axes.get_yaxis().set_visible(False)
                    plt.show()
                else:
                    print("The image of class diagram cannot be generate.")
                    print("Please check with your system administrators.")
            else:
                print("Your given dot file does not exist in the current directory ")
                print("or your input arguments were wrong. The input arguments ")
                print("should be [dot_file_name.dot]. ")
                print("Please try again!")
        except Exception as err:
            print("Please try again! The exception is: ", err)

    # Harry's work
    def help_dot_2_png(self):
        """Help for dot_2_png command to generate and display png file from the given dot file.
                Syntax: dot_2_png [input dot file name.dot]"""
        print("\n".join(['Generate and display png file from the given dot file.',
                         'Syntax: dot_2_png [input dot file name.dot].']))

    # Harry's work
    def do_quit(self, line):
        """Exit this command line interpreter"""
        print("Quitting......")
        return True

    # Harry's work
    def help_quit(self):
        print("\n".join(['Quit from this CLI', ':return: True']))

# below is for manual testing only
if __name__ == '__main__':
    my_cli = MyCli()
    my_cli.cmdloop()


from django import template
from django.utils import timezone
from postapp.models import Post

register = template.Library()

@register.simple_tag
def get_tags():
    tag_tuple = Post.objects.filter(
        deleted__isnull=True, date_post__lte=timezone.now()).values_list(
        'tags__name', 'tags__slug')
    tag_dct = dict()
    for tag in tag_tuple:
        if tag[1] and '0' not in tag[1]:
            tag_dct.setdefault(tag[1], {'name': tag[0], 'count': 0})
            tag_dct[tag[1]]['count'] += 1
    return tag_dct

@register.simple_tag
def get_calendar():
    post_qs = Post.objects.filter(deleted__isnull=True, date_post__lte=timezone.now()).order_by('-date_post')

    date_dct = dict()
    # date_format = "%d-%B-%Y"
    date_format = "%B %Y"
    date_format_slug = "%Y-%m"
    for post in post_qs:
        date_post = post.date_post.strftime(date_format)
        date_post_slug = post.date_post.strftime(date_format_slug)
        date_dct.setdefault(date_post_slug, {'name': date_post, 'count': 0})
        date_dct[date_post_slug]['count'] += 1
    return date_dct


from bs4 import BeautifulSoup
import requests
import time
import re

# Declaring variables

# Crawl limit = 1000
links_crawl_limit = 1000

# Maxiumum depth limit to crawl
maximum_depth_limit = 5

# Frontier (Queue)
frontier_queue = []

# List of Visited links
links_visit = []

# Main page
page_wiki = "https://en.wikipedia.org"

#Seed link of the assignment
#karen_seed_wiki_link = 'https://en.wikipedia.org/wiki/Karen_Sparck_Jones'
#keyword = 'retrieval'

def main():
    web_crawler(karen_seed_wiki_link)
    link2_file_name = 'Link_Task_2.txt'
    output_file = open(link2_file_name, 'w')
    ind = 1

    # Output file will be created
    for i in links_visit:
        row_var = str(ind) + " " + str(i) + "\n"
        output_file.write(row_var)
        ind += 1
    output_file.close()

# Define a function called web_crawler that will store URL's and will choose the URL should be crawled in future
def web_crawler(seed):
    frontier_queue.append((seed, 1))
    while len(links_visit) != links_crawl_limit and len(frontier_queue) != 0:
        curr = frontier_queue.pop()
        url_info = curr[0]
        if url_info in links_visit:
            continue
        links_visit.append(url_info)
        web_crawler_page(curr)

    while len(frontier_queue) != 0:
        curr = frontier_queue.pop()
        links_visit.append(curr[0])

# Define a function called Web Crawler Page that crawls page of a particular URL and gets the URL's
def web_crawler_page(curr):
    if curr[1] == maximum_depth_limit or len(links_visit) == links_crawl_limit:
        return
    link_info = ""
    url_info = curr[0]

    # Declaring Sleep time politeness policy
    time.sleep(1)
    depth = curr[1]
    doc = requests.get(url_info)
    content_text = BeautifulSoup(doc.text, 'html.parser').find('div', {'id': 'mw-content-text'})

    # Need to maintain and restore the order of links that is obtained
    temp_frontier = []

    if len(content_text.find('ol', class_='references') or ()) > 1:
        content_text.find('ol', class_='references').decompose()

    for link_new in content_text.find_all('a', {'href': re.compile("^/wiki")}):
        if ':' not in link_new.get('href') and len(frontier_queue) + len(links_visit) != links_crawl_limit:
            try:
                link_info = str(link_new.text)
            except UnicodeEncodeError as e:
                pass
            if (keyword.lower() in str(link_new.get('href')).lower()) or (keyword.lower() in link_info.lower()):
                #print(link_new)
                link_new = page_wiki + link_new.get('href')
                link_new = link_new.split('#')
                link_new = link_new[0]
                if not ((link_new in temp_frontier) or (link_new in links_visit)):
                    #print(depth)
                    temp_frontier.append((link_new, depth + 1))

    # Back to original link restoration
    while len(temp_frontier) != 0:
        #print(temp_frontier)
        frontier_queue.append(temp_frontier.pop())

if __name__ == "__main__":
    karen_seed_wiki_link = input("Enter the seed link: ")
    keyword = input("\nPlease enter keyword retrieval: ")
    main()


#!/usr/bin/env python
# -*-coding:utf-8 -*-
# created by 'zjh' on 18-1-26

from shapely.geometry import mapping, Polygon
import fiona

def geojson2shp(geojson, shpdst, id):
    '''

    :param geojson: the geojson format of a polygon
    :param shpdst: the path of the shapefile
    :param id: the id property
    :return: no return, just save the shapefile into the shpdst
    '''
    # an example Shapely geometry
    coordinates = geojson['coordinates']
    poly = Polygon(coordinates[0])

    # Define a polygon feature geometry with one attribute
    schema = {
        'geometry': 'Polygon',
        'properties': {'id': 'int'},
    }

    # Write a new Shapefile
    with fiona.open(shpdst, 'w', 'ESRI Shapefile', schema) as c:
        ## If there are multiple geometries, put the "for" loop here
        c.write({
            'geometry': mapping(poly),
            'properties': {'id': id},
        })


from lxml import html
import requests, time, zhihu_oauth

start_time = time.time()  # 初始时间戳

# ========================登录========================
from zhihu_oauth import ZhihuClient

save_file_path = '/Users/alicewish/我的坚果云/找出任意用户粉丝中的轮子粉.txt'

client = ZhihuClient()
client.load_token('/Users/alicewish/我的坚果云/token.pkl')

# ========================我========================
me = client.me()
pid = "wang-sheng-70-88"

people = client.people(pid)
# ==================查询我的粉丝==================
followers_line = []
i = 0
n = 11
for follower in people.followers:
    entry_start_time = time.time()
    i = i + 1
    if i > n:
        # 查询可用信息
        gender = follower.gender
        id = follower.id
        name = follower.name
        sina_weibo_name = follower.sina_weibo_name
        sina_weibo_url = follower.sina_weibo_url
        uid = follower.uid
        # 整理
        follower_info = [name, str(id), str(uid), str(gender), str(sina_weibo_name), str(sina_weibo_url)]
        info_line = '\t'.join(follower_info)
        print(info_line)
        # ==================查询是否关注了轮子vczh==================
        followings = follower.followings
        status = False
        for following in followings:
            # 查询可用信息
            id = following.id
            name = following.name
            uid = following.uid
            print(name)
            if name == "vczh":
                status = True
        if status:
            print("找到一个!")
            followers_line.append(info_line)
            f = open(save_file_path, 'a')
            append_line = str(i) + info_line + "\r\n"
            try:
                f.write(append_line)
            finally:
                f.close()
    # ================每项时间计时================
    entry_run_time = time.time() - entry_start_time
    entry_print = "耗时:{:.4f}秒".format(entry_run_time)
    print(entry_print)
# 合并数据
text = '\r\n'.join(followers_line)
print(text)
# ================写入剪贴板================
import pyperclip

pyperclip.copy(text)
spam = pyperclip.paste()

# ================运行时间计时================
run_time = time.time() - start_time
if run_time < 60:  # 两位小数的秒
    print("耗时:{:.2f}秒".format(run_time))
elif run_time < 3600:  # 分秒取整
    print("耗时:{:.0f}分{:.0f}秒".format(run_time // 60, run_time % 60))
else:  # 时分秒取整
    print("耗时:{:.0f}时{:.0f}分{:.0f}秒".format(run_time // 3600, run_time % 3600 // 60, run_time % 60))

知乎-找出任意用户粉丝中的轮子粉.py

知乎-找出任意用户粉丝中的轮子粉.py


import bpy
import bvp
import os
from bpy.types import Panel
import numpy as np

"""
THIS WAS COOPTED FOR ANOTHER PROJECT, AND GOT LEFT HERE. DELETE ME.

This is the graphical interface add-on to Blender for the B.lender V.ision P.roject (bvp) python module.

It's possible to use bvp without actually opening Blender, but if you want to, this GUI is designed to
make it easier to:
- modify scene elements (objects, backgrounds, actions, skies, and shadows) in your bvp database
- create, edit, modify, and save scenes
- label certian properties of new scene elements
"""

"""
NOTES
=====

TO DO:
- Start/stop database buttons from top DBtools pane
- Mechanism to add new databases from DBtools pane (with setup of folders??)
- Break this ridiculous file up into multiple files. This is approaching 1,000 lines long.

Check out http://www/wiki/Useful_Blender_Links for misc. tips on objects, material libraries, etc -
need to compile those into a list of useful Blenderization on a public web page

Shit, there's a selected_objects value in bpy.context - who knew?
"""

bl_info = {
    "name": "BVP tools panel",
    "description": "B.lender V.ision P.roject toolbox panel",
    "author": "Mark Lescroart",
    "version": (0, 1),
    "blender": (2, 72, 0),
    #"location": "File > Import-Export",
    #"warning": "", # used for warning icon and text in addons panel
    #"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"
    #      "Scripts/My_Script",
    "category": "3D View"
    }

### --- Misc parameters --- ###
bb_types = ['MESH','LATTICE','ARMATURE'] # Types allowable for computing bounding box of object groups. Add more?
dbport = bvp.Settings['db']['port']
dbpath = bvp.Settings['Paths']['LibDir'] # only necessary for creating client instances...
dbname = bvp.Settings['db']['name']
to_save = {}
db_results = []
last_import = ""
wn_results = []

## -- Base properties for property groups -- ##
class WordNet_Label(bpy.types.PropertyGroup):
    name = bpy.props.StringProperty(name="label", default = "")
    frame = bpy.props.IntProperty(default=1)
    id = bpy.props.IntProperty() # necessary?

class WordNet_Label_List(bpy.types.UIList):
## -- Display UI list -- ##
    """List class to set up display of WordNet label list"""
    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
        split = layout.split(0.2)
        split.label(str(item.frame)) # item.name
        split.prop(item, "name", text="", emboss=False, translate=False) #, icon='BORDER_RECT'

### --- BVP element properties --- ###
class ObjectProps(bpy.types.PropertyGroup):
    """Properties for bvpObjects"""
    fp = bpy.data.filepath
    if fp=="":
        pth = ""
    else:
        pth = os.path.split(bpy.data.filepath)[1][:-6]
    name = bpy.props.StringProperty(name='name',default="")
    parent_file = bpy.props.StringProperty(name='parent_file',default=pth)
    real_world_size = bpy.props.FloatProperty(name="real_world_size",min=.001,max=300.,default=1.)
    semantic_cat = bpy.props.StringProperty(name='semantic_cat',default='thing')
    basic_cat = bpy.props.StringProperty(name='basic_cat',default='thing')
    wordnet_label = bpy.props.StringProperty(name='wordnet_label',default='entity.n.01')
    is_realistic = bpy.props.BoolProperty(name='is_realistic',default=False)
    is_cycles = bpy.props.BoolProperty(name='is_cycles',default=False)
    # Define computed properties (nverts, nfaces, manifold, etc) here, too?
    del fp
    del pth

class ActionProps(bpy.types.PropertyGroup):
    """Properties for bvpActions"""
    # Set act_name default to bpy.context.object.animation_data.action.name? Will that dynamically update?
    # Or: new wisdom: these necessarily depend on the current action & file, so just read those properties
    # rather than creating duplicate properties just to have everything in the same place.
    #act_name = bpy.props.StringProperty(name='act_name',default="")
    #parent_file = bpy.props.StringProperty(name='parent_file',default="")
    #semantic_cat = bpy.props.StringProperty(name='semantic_cat',default='')
    wordnet_label = bpy.props.CollectionProperty(type=WordNet_Label)
    fps = bpy.props.FloatProperty(name='fps',default=30.,min=15.,max=100.) # 100 is optimistic...
    nframes = bpy.props.IntProperty(name='fps',default=30,min=2,max=1000) # 1000 is also optimistic...
    is_cyclic = bpy.props.BoolProperty()
    is_broken = bpy.props.BoolProperty()
    bg_interaction = bpy.props.BoolProperty()
    obj_interaction = bpy.props.BoolProperty()
    is_translating = bpy.props.BoolProperty()
    is_armature = bpy.props.BoolProperty(default=True)
    is_interactive = bpy.props.BoolProperty()
    is_animal = bpy.props.BoolProperty()
    # Define computed properties (compute from constraints?) (number of bones?)

class BGProps(bpy.types.PropertyGroup):
    """Properties for bvpSkies"""
    parent_file = bpy.props.StringProperty(name='parent_file',default="")
    semantic_cat = bpy.props.StringProperty(name='semantic_cat',default='sky')
    wordnet_label = bpy.props.StringProperty(name='wordnet_label',default='sky.n.01')

class SkyProps(bpy.types.PropertyGroup):
    """Properties for bvpSkies"""
    parent_file = bpy.props.StringProperty(name='parent_file',default="")
    semantic_cat = bpy.props.StringProperty(name='semantic_cat',default='sky')
    wordnet_label = bpy.props.StringProperty(name='wordnet_label',default='sky.n.01')

class RenderOptions(bpy.types.PropertyGroup):
    """Properties for bvpSkies"""
    do_image = bpy.props.BoolProperty(default=True)
    do_zdepth = bpy.props.BoolProperty(default=False)
    do_masks = bpy.props.BoolProperty(default=False)
    do_normals = bpy.props.BoolProperty(default=False)

'''
# UI list option for displaying databases (more flexible, more space)
class DBprop(bpy.types.PropertyGroup):
    """Grouped database properties"""
    id = bpy.props.IntProperty()
    port = bpy.props.IntProperty(name='port',default=bvp.Settings['db']['port'])
    path = bpy.props.StringProperty(name='path',default=bvp.Settings['Paths']['LibDir'])
'''

## -- For dynamic EnumProperties -- ##
def enum_groups(self,context):
    ob = context.object
    if len(ob.users_group)==0:
        return [("","No Group",""),]
    else:
        return [(g.name,g.name,"") for g in ob.users_group]

def enum_db_results(self,context):
    """Enumerate all objects (group names) returned from a database query"""
    global db_results
    out = [("","","")]+[(o['name'],o['name'],','.join(o['semantic_cat'])) for o in db_results]
    return out

def enum_wn_results(self,context):
    """Enumerate all WordNet synsets (WordNet labels) returned from the most recent lemma query"""
    global wn_results
    out = [("","","")]+[(o['synset'],o['synset']+': '+o['definition'],o['hypernyms']) for o in wn_results]
    return out

def enum_dbs(self,context):
    """Enumerate all active databases for pymongo server (if running)"""
    try:
        # TO DO: Add ShapeNet / ModelNet to this list?
        dbi = bvp.bvpDB(port=dbport)
        dbnm = [(d,d,'') for d in dbi.dbi.connection.database_names() if not d in ['local','admin']]
    except:
        dbnm = [('(none)','(none)','')]
    return dbnm

def enum_scene_objects(self,context):
    scn = context.scene
    if len(scn.objects)==0:
        return [("","No objects",""),]
    else:
        return [(o.name,o.name,"") for o in scn.objects]

## -- General property declarations -- ##
def declare_properties():
    '''Declarations of extra object properties

    These properties contain (most of) the meta-data stored about
    each scene element in the BVP database.

    This doesn't need to be a function, necessarily. Done this way just to
    keep all the bvp-specific property definitions together.

    TO DO: Un-register them upon close (?)

    DEPRECATED. All objects in DB will need to be updated to put these
    properties onto GROUPS rather than objects.
    '''
    ### --- DEPRECATED --- ###

    # ## -- For both object and background elements -- ##
    # # Real world size
    # bpy.types.Object.RealWorldSize = bpy.props.FloatProperty(name="RealWorldSize",min=.001,max=300.,default=1.)
    # # Imprecise list of semantic labels for an object; for convenience
    # # (a string, w/ comma-separated descriptors/categories for the object in question)
    # bpy.types.Object.SemanticCat = bpy.props.StringProperty(name='SemanticCat',default='thing')
    # # Precise definitional label for object
    # bpy.types.Object.wordnet_label = bpy.props.StringProperty(name='wordnet_label',default='entity.n.01')
    # # Reasonably realistic-looking, not cartoony or otherwise bad.
    # bpy.types.Object.realistic = bpy.props.BoolProperty(name='realistic',default=False)
    # # Is configured with cycles materials, ready to render with cycles render engine
    # bpy.types.Object.is_cycles = bpy.props.BoolProperty(name='is_cycles',default=False)
    # # Parent file
    # bpy.types.Object.parent_file = bpy.props.StringProperty(name='parent_file',default="")

    ## -- Specifically for background elements -- ##
    # Semantic Category of allowable objects (within scene)
    bpy.types.Object.ObjectSemanticCat = bpy.props.StringProperty(name='ObjectSemanticCat',default='thing')
    # Semantic Category of allowable skies (for scene)
    bpy.types.Object.SkySemanticCat = bpy.props.StringProperty(name='SkySemanticCat',default='all') # DomeTex, FlatTex, BlenderSky, Night, Day, etc...
    # Focal length of camera (for background)
    bpy.types.Object.Lens = bpy.props.FloatProperty(name='Lens',min=25.,max=50.,default=50.) # DomeTex, FlatTex, BlenderSky, Night, Day, etc...

    ### --- /DEPRECATED --- ###

    ## -- By class -- ##
    bpy.types.Object.groups = bpy.props.EnumProperty(name='groups',description='Groups using this object',items=enum_groups)

    bpy.types.Group.bvpObject = bpy.props.PointerProperty(type=ObjectProps)
    bpy.types.Group.is_object = bpy.props.BoolProperty(name='is_object',default=True)

    bpy.types.Group.bvpBG = bpy.props.PointerProperty(type=BGProps)
    #bpy.types.Group.is_bg = bpy.props.BoolProperty(name='is_bg',default=False)

    bpy.types.Action.bvpAction = bpy.props.PointerProperty(type=ActionProps)

    bpy.types.Scene.bvpRenderOptions = bpy.props.PointerProperty(type=RenderOptions)
    ## -- For database management -- ##
    bpy.types.WindowManager.active_db = bpy.props.EnumProperty(items=enum_dbs,name='active_db')
    bpy.types.WindowManager.active_group = bpy.props.StringProperty(name='active_group',default="")
    #bpy.types.WindowManager.active_action = bpy.props.StringProperty(name='active_action',default="")
    bpy.types.WindowManager.query_results = bpy.props.EnumProperty(items=enum_db_results,name='Search results')
    bpy.types.WindowManager.scene_objects = bpy.props.EnumProperty(items=enum_scene_objects,name='Scene objects')
    bpy.types.WindowManager.wn_results = bpy.props.EnumProperty(items=enum_wn_results,name='WordNet search results')
    bpy.types.WindowManager.wn_label_index = bpy.props.IntProperty(default=0)
    # Add .WindowManager.bvp.active_xxx?

### --- Operators --- ###
class NextScene(bpy.types.Operator):
    """Skip to the next scene"""
    bl_idname = "bvp.nextscene"
    bl_label = "Skip to next scene"
    bl_options = {'REGISTER','UNDO'}

    def execute(self,context):
        ScnList = list(bpy.data.scenes)
        ScnIdx = ScnList.index(context.scene)
        if ScnIdx<len(ScnList)-1:
            context.screen.scene = ScnList[ScnIdx+1]
        return {"FINISHED"}

class PrevScene(bpy.types.Operator):
    """Skip to the previous scene"""
    bl_idname = "bvp.prevscene"
    bl_label = "Skip to previous scene"
    bl_options = {'REGISTER','UNDO'}

    def execute(self,context):
        ScnList = list(bpy.data.scenes)
        ScnIdx = ScnList.index(context.scene)
        if ScnIdx>0:
            context.screen.scene = ScnList[ScnIdx-1]
        return {"FINISHED"}

class RescaleGroup(bpy.types.Operator):
    """Creates a group of Blender objects and standardizes the size.

    Set a group of objects to canonical position (centered, max dimension = 10)
    Position is defined relative to the BOTTOM, CENTER of the object (defined by the  bounding
    box (maximal extent of vertices, irrespective of the object's origin)

    Origins of all objects are set to (0,0,0).

    WARNING: NOT NECESSARILY RELIABLE. There is a great deal of variability in the way in which 3D
    models are stored in the myriad free 3D sites online; thus a GREAT MANY conditional statements
    would be necesary to have a reliably working function. If you want to write such a function,
    be my guest. In the meantime, use with caution.

    """
    bl_idname = "bvp.rescale_group"
    bl_label = "Set up group of objects"
    bl_options = {'REGISTER','UNDO'}
    def execute(self,context):
        scn = bpy.context.scene
        ob_list = [o for o in scn.objects if o.select and not o.type in ['CAMERA']]
        ToSet_Size = 10.0
        ToSet_Loc = (0.0,0.0,0.0)
        ToSet_Rot = 0.0
        # FIRST: Clear parent relationships
        p = [o for o in ob_list if not o.parent and not 'ChildOf' in o.constraints.keys()]
        if len(p)!=1:
            raise Exception('BVP group set-up requires exactly one parent object in the group!')
        else:
            p = p[0]
        np = [o for o in ob_list if o.parent or 'ChildOf' in o.constraints.keys()]
        if p:
            for o in np:
                bvp.utils.blender.grab_only(o)
                bpy.ops.object.parent_clear(type='CLEAR_KEEP_TRANSFORM')
                if 'ChildOf' in o.constraints.keys():
                    o.constraints.remove(o.constraints['ChildOf'])
        # SECOND: Reposition all object origins
        (MinXYZ,MaxXYZ) = self.get_group_bounding_box(ob_list)
        BotMid = [(MaxXYZ[0]+MinXYZ[0])/2,(MaxXYZ[1]+MinXYZ[1])/2,MinXYZ[2]]
        bvp.utils.blender.set_cursor(BotMid)
        SzXYZ = []
        for Dim in range(3):
            SzXYZ.append(MaxXYZ[Dim]-MinXYZ[Dim])
        ScaleF = ToSet_Size/max(SzXYZ)
        for o in ob_list:
            bvp.utils.blender.grab_only(o)
            bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
            o.scale = o.scale * ScaleF
            o.location = ToSet_Loc
        # Update scene to reflect changes
        scn.update()
        # THIRD: Re-parent everything
        for o in np:
            bvp.utils.blender.grab_only(p)
            o.select = True
            bpy.ops.object.parent_set()
        # LAST: Create group (if necessary) and name group
        if not ob_list[0].users_group:
            for o in ob_list:
                o.select=True
            bpy.ops.group.create(name=scn.name)
        # Done
        return {"FINISHED"}

    def get_group_bounding_box(self,ob_list):
        '''Returns the maximum and minimum X, Y, and Z coordinates of a set of objects

        Parameters
        ----------
        ob_list : list or tuple
            list of Blender objects for which to get bounding box

        Returns
        -------
        minxyz,maxxyz : lists
            min/max x,y,z coordinates for all objects. Think about re-structuring this to be a
            more standard format for a bounding box.
        '''
        BBx = list()
        BBy = list()
        BBz = list()
        for ob in ob_list:
            bvp.utils.blender.grab_only(ob)
            if ob.type in bb_types:
                bpy.ops.object.transform_apply(rotation=True)
            for ii in range(8):
                BBx.append(ob.bound_box[ii][0] * ob.scale[0] + ob.location[0])
                BBy.append(ob.bound_box[ii][1] * ob.scale[1] + ob.location[1])
                BBz.append(ob.bound_box[ii][2] * ob.scale[2] + ob.location[2])
        MinXYZ = [min(BBx),min(BBy),min(BBz)]
        MaxXYZ = [max(BBx),max(BBy),max(BBz)]
        # Done
        return MinXYZ,MaxXYZ

class DBSaveObject(bpy.types.Operator):
    bl_idname = "bvp.db_save_object"
    bl_label = "Save the active object to the active database"
    bl_options = {'REGISTER','UNDO'}
    def execute(self,context):
        wm = context.window_manager
        ob = context.object
        grp = bpy.data.groups[wm.active_group]
        # Parent file nonsense because we can't set bvpObject.parent_file here:
        pfile = grp.bvpObject.parent_file
        thisfile = bpy.data.filepath #if len(bpy.data.filepath)>0 else pfile
        if thisfile=="":
            raise NotImplementedError("Please save this file into %s before trying to save to database."%(os.path.join(dbpath,'Objects/')))
            # Need to check for over-writing file?
        if pfile=="":
            pfile = os.path.split(bpy.data.filepath)[1][:-6]

        # Compute parameters
        ## Poses
        rig = [o for o in grp.objects if o.type=='ARMATURE']
        nposes = None # by default
        if rig:
            if len(rig)>1:
                raise Exception('More than one rig present in group %s! Abort, abort!'%grp.name)
            rig = rig[0]
            if rig.pose_library:
                nposes = len(rig.pose_library.pose_markers)
        ## Faces
        try:
            nfaces = sum([len(oo.data.faces) for oo in grp.objects if oo.type=='MESH'])
        except:
            # New for version 2.63 w/ bmeshes:
            nfaces = sum([len(oo.data.polygons) for oo in grp.objects if oo.type=='MESH'])
        ## Vertices
        nverts = sum([len(oo.data.vertices) for oo in grp.objects if oo.type=='MESH'])
        ## Semantic categories
        semcat = [s.strip() for s in grp.bvpObject.semantic_cat.split(',')]
        semcat = [s.lower() for s in semcat if s]
        ## WordNet labels
        wordnet = [s.strip() for s in grp.bvpObject.wordnet_label.split(',')]
        wordnet = [s.lower() for s in wordnet if s]
        #is_manifold = False # worth it?
        # Create database instance
        dbi = bvp.bvpDB(port=dbport,dbname=wm.active_db)
        # Construct object struct to save
        to_save = dict(
            # Edited through UI
            name=wm.active_group, # also not great.
            parent_file=pfile, # hacky. ugly.
            wordnet_label=wordnet,
            semantic_cat=semcat,
            basic_cat=grp.bvpObject.basic_cat,
            real_world_size=grp.bvpObject.real_world_size,
            is_realistic=grp.bvpObject.is_realistic,
            is_cycles=grp.bvpObject.is_cycles,
            # Computed
            nfaces=nfaces,
            nvertices=nverts,
            nposes=nposes,
            constraints=None,
            #is_manifold=is_manifold, # worth it?
            #_id='tempX12345', # dbi.db.id? generate_id? Look up ID? Check database for extant
            )
        dbi.objects.save(to_save)
        save_path = os.path.join(dbpath,'Objects',pfile+'.blend')
        if save_path==thisfile:
            bpy.ops.wm.save_as_mainfile(filepath=save_path)
        else:
            raise NotImplementedError('Still WIP! Just work inside your database files, you lazy bastard!')
            tmpf = '/tmp/action_tempfile.blend' # Set in settings?
            bpy.ops.wm.save_as_mainfile(filepath=tmpf,copy=True)
            script = bvp.utils.basics.load_template('Save') # 'SaveGroup' instead? This script doesn't work yet. Edit <bvp>/Scripts/Template_Save.py
            script.format() # Depends on script
            bvp.blend(script,pfile)
        return {"FINISHED"}

## TO DO:
# class DBSaveBG(bpy.types.Operator):
#   pass

class DBSaveAction(bpy.types.Operator):
    bl_idname = "bvp.db_save_action"
    bl_label = "Save action to active database"
    bl_options = {'REGISTER','UNDO'}
    # Properties
    do_save = bpy.props.BoolProperty(name='overwrite',default=True)
    # Methods
    def execute(self,context):
        global to_save
        wm = context.window_manager
        # Create database instance
        dbi = bvp.bvpDB(port=dbport,dbname=wm.active_db)

        if self.do_save:
            print('Saving %s in database'%repr(to_save))
            # Save in database
            dbi.actions.save(to_save)
            # Save parent file
            save_path = os.path.join(dbpath,'Actions',to_save['parent_file'])
            print('saving %s'%save_path)
            bpy.ops.wm.save_as_mainfile(filepath=save_path)
        else:
            # NOOOOOO!
            print("Aborting - nothing saved!")
        # Cleanup
        to_save = {}
        #   # Eventually, I would like to add the ability to append the active action to another file
        #   raise NotImplementedError('Still WIP! Just work inside your database files, you lazy bastard!')
        #   tmpf = '/tmp/action_tempfile.blend' # Set in settings?
        #   bpy.ops.wm.save_as_mainfile(filepath=tmpf,copy=True)
        #   script = bvp.utils.basics.load_template('Save') # This script doesn't work yet. Edit <bvp>/Scripts/Template_Save.py
        #   script.format() # Depends on script
        #   bvp.blend(script,pfile)
        return {'FINISHED'}
    def invoke(self,context,event):
        global to_save
        wm = context.window_manager
        ob = context.object
        act = ob.animation_data.action
        ## -- Compute parameters -- ##
        ## Frames
        nframes = np.floor(act.frame_range[1])-np.ceil(act.frame_range[0])
        ## WordNet labels
        wordnet_labels = [s.name for s in act.bvpAction.wordnet_label]
        wordnet_frames = [s.frame for s in act.bvpAction.wordnet_label]
        ## Bounding box
        if isinstance(ob.data,bpy.types.Armature):
            # Get child objects, armatures have no position information
            ob_list = [ob]+list(ob.children)
        scn = context.scene
        mn,mx = [],[]
        for fr in range(int(np.floor(act.frame_range[0])),int(np.ceil(act.frame_range[1]))):
            scn.frame_set(fr)
            scn.update()
            mntmp,mxtmp = bvp.utils.blender.get_group_bounding_box(ob_list)
            mn.append(mntmp)
            mx.append(mxtmp)
        min_xyz = np.min(np.vstack(mn),axis=0).tolist()
        max_xyz = np.max(np.vstack(mx),axis=0).tolist()
        #bvp.utils.blender.make_cube('bbox',min_xyz,max_xyz) # works. This shows the bounding box, if you want.
        bvp.utils.blender.grab_only(ob)
        ## Parent file
        #pfile = act.bvpAction.parent_file
        # The above value (pfile) is ignored for now. Need to eventually implement some way to take the contents
        # of the current file (group/action/whatever) and save them (append them) to another specfied file
        # in the database. Currently NOT IMPLEMENTED.
        thisfile = os.path.split(bpy.data.filepath)[1] #if len(bpy.data.filepath)>0 else pfile
        if thisfile=="":
            # Require saving in db-appropriate location
            raise NotImplementedError("Please save this file into %s before trying to save to database."%(os.path.join(dbpath,'Actions/')))

        # Construct action struct to save
        to_save = dict(
            # Edited through UI
            act_name=act.name,
            parent_file=thisfile,
            wordnet_label=wordnet_labels,
            wordnet_frames=wordnet_frames,
            is_cyclic=act.bvpAction.is_cyclic,
            is_translating=act.bvpAction.is_translating,
            is_broken=act.bvpAction.is_broken,
            is_armature=act.bvpAction.is_armature,
            bg_interaction=act.bvpAction.bg_interaction,
            obj_interaction=act.bvpAction.obj_interaction,
            is_interactive=act.bvpAction.is_interactive,
            is_animal=act.bvpAction.is_animal,
            # Computed / assumed
            nframes=nframes,
            fps=act.bvpAction.fps,
            min_xyz=min_xyz,
            max_xyz=max_xyz,
            )
        # Create database instance
        dbi = bvp.bvpDB(port=dbport,dbname=wm.active_db)
        # Check for existence of to_save in database
        chk = dbi.actions.find_one(dict(act_name=to_save['act_name']))
        print("chk is: ")
        print(chk)
        if chk is None:
            self.do_save = True
            return self.execute(context) #{'RUNNING_MODAL'} #wm.invoke_props_dialog(self)
        else:
            self.do_save = False
            to_save['_id'] = chk['_id']
            return wm.invoke_props_dialog(self)

# Eventual class to start up mongo database server (or other server...)
# Look into SQLite!
# class DBStartup(bpy.types.Operator):
#   try:
#       dbi = bvp.bvpDB(dbname=dbname)
#       del dbi
#   except pymongo.errors.ConnectionError:
#       import warnings
#       warnings.warn('Unable to initialize pymongo server! You''re probably borked!')

class AlignToNormal(bpy.types.Operator):
    bl_idname = 'bvp.align_to_normal'
    bl_label = 'Align object to nearest normal'
    bl_options = {'REGISTER','UNDO'}

    def execute(self,context):
        wm = context.window_manager
        base = context.scene.objects[wm.scene_objects]
        to_rot = context.object
        # Get mesh for base object
        me = base.data
        # Get absolute locations (use matrix_world) for each vertex
        verts = np.array([v.co*base.matrix_world for v in me.vertices])
        obloc = np.array(to_rot.location)
        dst = np.linalg.norm(verts-obloc[None,:],axis=1)
        # Select nearest vertex
        vi = np.argmin(dst)
        print('Nearest vertex is vertex %d\n\tat %s'%(vi,repr(me.vertices[vi].co*base.matrix_world)))
        print('\tdistance is %0.3f'%np.min(dst))
        print('\t%d vertices'%len(dst))
        xyzr = bvp.utils.bvpMath.vec2eulerXYZ(me.vertices[vi].normal)
        rr = [x/180.*np.pi for x in xyzr]
        print('rotating %s'%repr(xyzr))
        to_rot.rotation_euler = rr
        return {'FINISHED'}

class DBSearchDialog(bpy.types.Operator):
    bl_idname = "bvp.db_search"
    bl_label = "Query database for:"
    bl_options = {'REGISTER','UNDO'}
    # Use wm.active_db?? But we probably can't change that here.
    active_db = bpy.props.StringProperty(name="Current database")
    bvp_type = bpy.props.EnumProperty(name='BVP type',
        items=[('action','action',""),
               ('background','background',""),
               ('object','object',""),
               ('sky','sky',""),
               ('shadow','shadow',"")],
        default='object')
    semantic_cat = bpy.props.StringProperty(name='Loose semantic label',default="")
    wordnet_label =  bpy.props.StringProperty(name='Precise WordNet label',default="")
    ename = bpy.props.StringProperty(name='Group/Action name',default="")
    # Real world size min/max?

    def execute(self, context):
        global db_results
        global last_import
        wm = context.window_manager # Not necessary??
        dbi = bvp.bvpDB(dbname=self.active_db)
        props = ['semantic_cat','wordnet_label','ename']
        query = dict((p,getattr(self,p)) for p in props if getattr(self,p))
        print(query) # unnecessary
        db_results = [r for r in dbi.objects.find(query)]
        last_import = self.bvp_type
        from pprint import pprint # unnecessary
        pprint(db_results) # unnecessary
        return {'FINISHED'}

    def invoke(self, context, event):
        wm = context.window_manager
        self.active_db = wm.active_db
        return context.window_manager.invoke_props_dialog(self)

        # etc...

class WordNetSearchDialog(bpy.types.Operator):
    bl_idname = "bvp.wn_search"
    bl_label = "Query WordNet for existence of lemma:"
    bl_options = {'REGISTER','UNDO'}
    lemma = bpy.props.StringProperty(name='Search word (lemma)',default="")
    # Real world size min/max?

    def get_wn_synsets(self,lemma):
        """Get all synsets for a word, return a list of [wordnet_label,definition, hypernym_string]
        for all synsets returned."""
        from nltk.corpus import wordnet as wn
        synsets = wn.synsets(lemma)
        out = []
        for s in synsets:
            if not '.v.' in s.name(): continue # only verbs!
            hyp = ''
            for ii,ss in enumerate(s.hypernym_paths()):
                try:
                    hyp+=(repr([hn.name() for hn in ss])+'\n')
                except:
                    hyp+='FAILED for %dth hypernym\n'%ii
            out.append(dict(synset=s.name(), definition=s.definition(),hypernyms=hyp))
        return out

    def execute(self, context):
        global wn_results
        wm = bpy.context.window_manager
        wn_results = self.get_wn_synsets(self.lemma)
        return {'FINISHED'}

    def invoke(self, context, event):
        print("Invoking WordNetSearchDialog!")
        return context.window_manager.invoke_props_dialog(self)

# to clear:
# wm.categories.clear()
class WordNetAddLabel(bpy.types.Operator):
    bl_idname = "bvp.wn_addlabel"
    bl_label = "Add current wordnet result as a label for group/action"
    bl_options = {'REGISTER','UNDO'}
    def execute(self,context):
        # Add current label at current frame
        wm = context.window_manager
        act = context.object.animation_data.action
        added = act.bvpAction.wordnet_label.add()
        added.name = wm.wn_results
        added.frame = bpy.context.scene.frame_current
        return {'FINISHED'}

class WordNetRemoveLabel(bpy.types.Operator):
    bl_idname = 'bvp.wn_removelabel'
    bl_label = "remove currently highlighted label"
    bl_options = {'REGISTER','UNDO'}
    def execute(self,context):
        wm = context.window_manager
        act = context.object.animation_data.action
        act.bvpAction.wordnet_label.remove(wm.wn_label_index)
        return {'FINISHED'}

class DBImport(bpy.types.Operator):
    bl_idname = "bvp.db_import"
    bl_label = "Import scene element from database"
    bl_options = {'REGISTER','UNDO'}
    proxy_import = False
    def execute(self,context):
        global db_results
        global last_import

        wm = bpy.context.window_manager
        to_import = [d for d in db_results if d['name']==wm.query_results][0]
        if last_import=='object':
            print('--- importing: ---')
            print(to_import)
            O = bvp.bvpObject(**to_import)
            O.Place(proxy=self.proxy_import)
        elif last_import=='action':
            raise NotImplementedError('Not yet! need to apply actions to objects!')
        return {'FINISHED'}

class DBImportProxy(DBImport,bpy.types.Operator):
    bl_idname = "bvp.db_import_proxy"
    bl_label = "Import scene element from database (proxy only)"
    bl_options = {'REGISTER','UNDO'}

    proxy_import = True

class ClipFrames(bpy.types.Operator):
    bl_idname = "bvp.clip_to_action"
    bl_label = "Clip scene frames to begin/end of action"
    bl_options = {'REGISTER','UNDO'}
    def execute(self,context):
        scn = bpy.context.scene
        act = bpy.context.object.animation_data.action
        scn.frame_start = np.floor(act.frame_range[0])
        scn.frame_end = np.ceil(act.frame_range[1])
        return {'FINISHED'}
### --- Misc. supporting classes --- ###
'''
# UI list option for displaying databases (more flexible, more space)
# Need database creation option (?)
class BVP_DB_LIST(bpy.types.UIList):
    """List class to establish database list in DB tools panel"""
    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
        split = layout.split(0.2)
        split.label(str(item.id)) # item.name
        split.prop(item, "name", text="", emboss=False, translate=False) #, icon='BORDER_RECT'
'''

### --- Panels --- ###

class View3DPanel():
    """SettingProperties for all child classes"""
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    bl_category = 'BVP'
    bl_context = "objectmode"

class RenderPanel():
    """SettingProperties for all child classes"""
    bl_space_type = 'NODE_EDITOR'
    bl_region_type = 'TOOLS'
    bl_category = 'BVP'
    #bl_context = "objectmode"

class BVP_PANEL_db_tools(View3DPanel,Panel):
    """Creates a BVP panel in the Tools window for database actions"""
    bl_label = "Database tools"
    bl_idname = "BVP_db_tools"

    def draw(self, context):
        # Get window manager / associated database list
        wm = context.window_manager
        # Head title
        layout = self.layout
        row = layout.row()
        spl = layout.split()
        col = spl.column()
        col.label('Active DB:')
        col = spl.column()
        col.prop(wm, "active_db",text='')

        row = layout.row()
        row.operator("bvp.db_search",text="Search DB")
        row = layout.row()
        row.prop(wm,'query_results')
        if len(db_results)>0:
            spl = layout.split()
            col = spl.column()
            col.operator('bvp.db_import',text='Place Full')
            col = spl.column()
            col.operator('bvp.db_import_proxy',text='Place Proxy')
            #col.label('Import Full')

class BVP_PANEL_temp(View3DPanel,Panel):
    """Creates a BVP panel in the Tools window"""
    bl_label = "Temp extra object tools"
    bl_idname = "BVP_object_extras"

    # NOTE: I don't want to use poll, because I want to still display this window
    # if there isn't an active object (for Create group / rescale button)
    def draw(self, context):
        layout = self.layout
        # Get currently-selected object
        ob = context.object
        scene = context.scene
        wm = context.window_manager
        # Object or no
        if ob is None: # better to use poll?
            row = layout.row()
            row.label('(No object selected)')
        else:
            row = layout.row()
            spl = layout.split()

            ## -- 1st column -- ##
            col = spl.column()
            col.label("Current object:")

            ## -- 2nd column -- ##
            col = spl.column()
            col.prop(ob,'name',text="")
            col.prop(wm,'scene_objects',text="")
            # Button for re-scaling object groups
            row = layout.row()
            row.operator('bvp.align_to_normal',text='align to normal')
            #XXXq#

class BVP_PANEL_object_tools(View3DPanel,Panel):
    """Creates a BVP panel in the Tools window"""
    bl_label = "Object tools"
    bl_idname = "BVP_object_tools"

    # NOTE: I don't want to use poll, because I want to still display this window
    # if there isn't an active object (for Create group / rescale button)
    def draw(self, context):
        layout = self.layout
        # Get currently-selected object
        ob = context.object
        scene = context.scene
        wm = context.window_manager
        # Object or no
        if ob is None: # better to use poll?
            row = layout.row()
            row.label('(No object selected)')
            wm.active_group = ""
        else:
            wm.active_group = ob.groups
            row = layout.row()
            if len(ob.users_group)<1: #ob.dupli_groups is None:
                row.label(text='(no BVP object group)')
                row = layout.row()
                row.operator('bvp.rescale_group',text='Create group & rescale')
            else:
                grp = bpy.data.groups[wm.active_group]
                spl = layout.split()

                ## -- 1st column -- ##
                col = spl.column()
                col.label("BVP object:")
                col.label("File:")
                col.label("Labels:")
                col.label("Basic cat:")
                col.label("WordNet:")
                col.label('Real size:')
                # Boolean properties
                col.prop(grp.bvpObject,'is_realistic',text='realistic')
                # Button for re-scaling object groups
                col.operator('bvp.rescale_group',text='Rescale')

                ## -- 2nd column -- ##
                col = spl.column()
                col.prop(ob,'groups',text="")
                col.prop(grp.bvpObject,'parent_file',text='')
                col.prop(grp.bvpObject,'semantic_cat',text='')
                col.prop(grp.bvpObject,'basic_cat',text='')
                col.prop(grp.bvpObject,'wordnet_label',text='')
                col.prop(grp.bvpObject,'real_world_size',text='')
                col.prop(grp.bvpObject,'is_cycles',text='cycles')
                # Button for re-scaling object groups
                col.operator('bvp.db_save_object',text='Save to DB')

class BVP_PANEL_action_tools(View3DPanel,Panel):
    """Creates a BVP actions panel in the Tools window"""
    bl_label = "Action tools"
    bl_idname = "BVP_action_tools"

    # Don't display this dialog if there isn't an action available.
    @classmethod
    def poll(self,context):
        if context.object:
            if context.object.animation_data:
                return True
    def draw(self, context):
        # Get currently-selected object
        ob = context.object
        wm = context.window_manager
        act = ob.animation_data.action
        #wm.active_action = act.name
        # Layout
        layout = self.layout
        spl = layout.split()
        ## -- 1st column -- ##
        col = spl.column()
        col.label("Name:")
        #col.label("File:") # dead
        #col.label("Labels:") # dead
        col.operator('bvp.wn_search',text='Search WordNet')
        col.label("WordNet labels:")

        ## -- 2nd column -- ##
        col = spl.column()
        col.prop(act,'name',text="")
        #col.prop(act.bvpAction,'parent_file',text='')
        #col.prop(act.bvpAction,'semantic_cat',text='')
        row = col.row(align=True)
        row.prop(wm,'wn_results',text="")
        #row.prop(wm,'label_frame',text="")
        row.operator('bvp.wn_addlabel',text="Add label")
        row = layout.row()
        row.template_list("WordNet_Label_List", "wordnet labels", act.bvpAction, "wordnet_label",wm,"wn_label_index")
        col = row.column(align=True)
        col.operator("bvp.wn_removelabel", icon='ZOOMOUT', text="")
        #col.operator("object.material_slot_remove", icon='ZOOMOUT', text="")

        row = layout.row()
        # Boolean properties - column 1
        spl = layout.split()
        col = spl.column()
        col.prop(act.bvpAction,'is_cyclic',text='cyclic')
        col.prop(act.bvpAction,'bg_interaction',text='needs bg')
        col.prop(act.bvpAction,'is_translating',text='translating')
        col.prop(act.bvpAction,'is_interactive',text='interactive')
        # Boolean properties - column 2
        col = spl.column()
        col.prop(act.bvpAction,'is_broken',text='broken')
        col.prop(act.bvpAction,'obj_interaction',text='needs obj.')
        col.prop(act.bvpAction,'is_armature',text='armature')
        col.prop(act.bvpAction,'is_animal',text='animal/unique')
        ## -- Break -- ##
        spl = layout.split()
        col = spl.column()
        # Column 1: Clip frames
        col.operator('bvp.clip_to_action',text='Clip frames')
        # Column 2: Save to DB when done
        col = spl.column()
        col.operator('bvp.db_save_action',text='Save to DB')
        if isinstance(ob.data,bpy.types.Armature):
            row = layout.row()
            row.label('%d bones'%len(ob.data.bones))

class BVP_PANEL_scene_tools(View3DPanel,Panel):
    """Creates a BVP panel in the Tools window for scene actions"""
    bl_label = "Scene tools"
    bl_idname = "BVP_scene_tools"

    def draw(self, context):
        layout = self.layout
        # Head title
        layout.label(text="Navigation")
        # Buttons for scene navigation
        row = layout.row(align=True)
        row.operator('bvp.prevscene',text='Prev')
        row.operator('bvp.nextscene',text='Next')
        # Select by list? (template_ID?) This will make it easier
        # to work in the full-screen 3D view window
        # Get current scene
        scene = context.scene
        # TO DO:
        row = layout.row()
        row.label('Background properties:')
        row = layout.row()
        row.label('(Work in progress)')
        # Search through scene objects to determine if any are BVP bg objects
        # Display bvpBG properties (constraints,realworldsize,wordnet_label,etc...)
        # Editing:
        # Buttons to add constraints of different types
        # Buttons to test constraints / reset scene
        # Buttons to add sky

class BVP_PANEL_render(RenderPanel,Panel):
    """Creates a BVP panel in the Tools window for scene actions"""
    bl_label = "BVP rendering tools"
    bl_idname = "BVP_render_tools"

    def draw(self, context):
        scn = context.scene
        layout = self.layout
        # Head title
        layout.label(text="BVP rendering tools")
        # Buttons for scene navigation
        row = layout.row()
        spl = layout.split()
        # Column 1
        col = spl.column()
        col.prop(scn.bvpRenderOptions,'do_image',text='image')
        col.prop(scn.bvpRenderOptions,'do_masks',text='masks')
        col = spl.column()
        col.prop(scn.bvpRenderOptions,'do_zdepth',text='z depth')
        col.prop(scn.bvpRenderOptions,'do_normals',text='normals')
        #row.operator('bvp.prevscene',text='Prev')
        #row.operator('bvp.nextscene',text='Next')
        # Select by list? (template_ID?) This will make it easier
        # to work in the full-screen 3D view window
        row = layout.row()
        row.label('BVP stuff properties:')
        row = layout.row()
        row.label('for scene: %s'%context.scene.name)
        # Search through scene objects to determine if any are BVP bg objects
        # Display bvpBG properties (constraints,realworldsize,wordnet_label,etc...)
        # Editing:
        # Buttons to add constraints of different types
        # Buttons to test constraints / reset scene
        # Buttons to add sky

def register():
    # Order of registering props/object should perhaps be examined for optimality...
    # It works this way, but it doesn't seem clean.
    for c in [WordNet_Label,ObjectProps,ActionProps, BGProps, SkyProps,RenderOptions]:
        # Do these in a separate file? Imported, registered separately?
        bpy.utils.register_class(c)
    declare_properties()
    # Lists again for panels, operators?
    bpy.utils.register_module(__name__)

    #bpy.types.WindowManager.db_list = bpy.props.CollectionProperty(type=DBprop) #name='Databases',
    #bpy.types.WindowManager.db_index = bpy.props.IntProperty()
    #wm = bpy.context.window_manager
    #wm.db_index = 0

def unregister():
    # Un-register classes(necessary?)
    #for c in [ObjectProps,ActionProps]: #ActionProps, BGProps]:
    #   # Do these in a separate file? Imported, registered separately?
    #   bpy.utils.unregister_class(c)
    bpy.utils.unregister_module(__name__)
    # Delete temp properties
    del bpy.types.WindowManager.active_db
    del bpy.types.WindowManager.active_group
    #del bpy.types.WindowManager.active_action
    del bpy.types.WindowManager.query_results
    del bpy.types.WindowManager.wn_results
    # More?

if __name__ == "__main__":
    # declare_properties() #(?)
    register()


import pandas as pd
import six
import trafaret as t

from datarobot import errors
from datarobot.models.api_object import APIObject
from datarobot.utils import encode_utf8_if_py2, get_id_from_response
from datarobot.utils.pagination import unpaginate

class ShapMatrix(APIObject):
    """
    Represents SHAP based prediction explanations and provides access to score values.

    Attributes
    ----------
    project_id : str
        id of the project the model belongs to
    shap_matrix_id : str
        id of the generated SHAP matrix
    model_id : str
        id of the model used to
    dataset_id : str
         id of the prediction dataset SHAP values were computed for

    Examples
    --------
    .. code-block:: python

        import datarobot as dr

        # request SHAP matrix calculation
        shap_matrix_job = dr.ShapMatrix.create(project_id, model_id, dataset_id)
        shap_matrix = shap_matrix_job.get_result_when_complete()

        # list available SHAP matrices
        shap_matrices = dr.ShapMatrix.list(project_id)
        shap_matrix = shap_matrices[0]

        # get SHAP matrix as dataframe
        shap_matrix_values = shap_matrix.get_as_dataframe()
    """

    _path = "projects/{}/shapMatrices/"
    _converter = t.Dict(
        {
            t.Key("id"): t.String(),
            t.Key("project_id"): t.String(),
            t.Key("model_id"): t.String(),
            t.Key("dataset_id"): t.String(),
        }
    ).allow_extra("*")

    def __init__(self, project_id, id, model_id=None, dataset_id=None):
        self.project_id = project_id
        self.model_id = model_id
        self.dataset_id = dataset_id
        self.id = id

    def __repr__(self):
        template = u"{}(id={!r}, project_id={!r}, model_id={!r}, dataset_id={!r})"
        return encode_utf8_if_py2(
            template.format(
                type(self).__name__, self.id, self.project_id, self.model_id, self.dataset_id,
            )
        )

    @classmethod
    def create(cls, project_id, model_id, dataset_id):
        """ Calculate SHAP based prediction explanations against previously uploaded dataset.

        Parameters
        ----------
        project_id : str
            id of the project the model belongs to
        model_id : str
            id of the model for which prediction explanations are requested
        dataset_id : str
            id of the prediction dataset for which prediction explanations are requested (as
            uploaded from Project.upload_dataset)

        Returns
        -------
        job : ShapMatrixJob
            The job computing the SHAP based prediction explanations

        Raises
        ------
        ClientError
            If the server responded with 4xx status. Possible reasons are project, model or dataset
            don't exist, user is not allowed or model doesn't support SHAP based prediction
            explanations
        ServerError
            If the server responded with 5xx status
        """
        data = {"model_id": model_id, "dataset_id": dataset_id}
        url = "projects/{}/shapMatrices/".format(project_id)
        response = cls._client.post(url, data=data)
        job_id = get_id_from_response(response)
        from .shap_matrix_job import ShapMatrixJob

        return ShapMatrixJob.get(
            project_id=project_id, job_id=job_id, model_id=model_id, dataset_id=dataset_id
        )

    @classmethod
    def from_location(cls, location, model_id=None, dataset_id=None):
        head, tail = location.split("/shapMatrices/", 1)
        project_id, id = head.split("/")[-1], tail.split("/")[0]
        return cls(project_id=project_id, id=id, model_id=model_id, dataset_id=dataset_id)

    @classmethod
    def list(cls, project_id):
        """
        Fetch all the computed SHAP prediction explanations for a project.

        Parameters
        ----------
        project_id : str
            id of the project

        Returns
        -------
        List of ShapMatrix
            A list of :py:class:`ShapMatrix <datarobot.models.ShapMatrix>` objects

        Raises
        ------
        datarobot.errors.ClientError
            if the server responded with 4xx status
        datarobot.errors.ServerError
            if the server responded with 5xx status
        """
        data = unpaginate(
            initial_url=cls._path.format(project_id), initial_params=None, client=cls._client
        )
        result = [cls.from_server_data(item) for item in data]
        return result

    @classmethod
    def get(cls, project_id, id):
        """
        Retrieve the specific SHAP matrix.

        Parameters
        ----------
        project_id : str
            id of the project the model belongs to
        id : str
            id of the SHAP matrix

        Returns
        -------
        :py:class:`ShapMatrix <datarobot.models.ShapMatrix>` object representing specified record
        """
        return cls(project_id=project_id, id=id)

    def get_as_dataframe(self):
        """
        Retrieve SHAP matrix values as dataframe.

        Returns
        -------
        dataframe : pandas.DataFrame
            A dataframe with SHAP scores

        Raises
        ------
        datarobot.dse.errors.ClientError
            if the server responded with 4xx status.
        datarobot.dse.errors.ServerError
            if the server responded with 5xx status.
        """
        path = self._path.format(self.project_id) + "{}/".format(self.id)
        resp = self._client.get(path, headers={"Accept": "text/csv"}, stream=True)
        if resp.status_code == 200:
            content = resp.content.decode("utf-8")
            return pd.read_csv(six.StringIO(content), index_col=0, encoding="utf-8")
        else:
            raise errors.ServerError(
                "Server returned unknown status code: {}".format(resp.status_code),
                resp.status_code,
            )