# coding: utf-8

# **Chapter 9 – Up and running with TensorFlow**

# _This notebook contains all the sample code and solutions to the exercises in chapter 9._

# # Setup

# First, let's make sure this notebook works well in both python 2 and 3, import a few common modules, ensure MatplotLib plots figures inline and prepare a function to save the figures:

# In[1]:

# To support both python 2 and python 3
from __future__ import division, print_function, unicode_literals

# Common imports
import numpy as np
import os

# to make this notebook's output stable across runs
def reset_graph(seed=42):
    tf.reset_default_graph()
    tf.set_random_seed(seed)
    np.random.seed(seed)

# To plot pretty figures
import matplotlib
import matplotlib.pyplot as plt
plt.rcParams['axes.labelsize'] = 14
plt.rcParams['xtick.labelsize'] = 12
plt.rcParams['ytick.labelsize'] = 12

# Where to save the figures
PROJECT_ROOT_DIR = "."
CHAPTER_ID = "tensorflow"

def save_fig(fig_id, tight_layout=True):
    path = os.path.join(PROJECT_ROOT_DIR, "images", CHAPTER_ID, fig_id + ".png")
    print("Saving figure", fig_id)
    if tight_layout:
        plt.tight_layout()
    plt.savefig(path, format='png', dpi=300)

# # Creating and running a graph

# In[2]:

import tensorflow as tf

x = tf.Variable(3, name="x")
y = tf.Variable(4, name="y")
f = x*x*y + y + 2

f

sess = tf.Session()
sess.run(x.initializer)
sess.run(y.initializer)
result = sess.run(f)
print(result)

sess.close()

with tf.Session() as sess:
    x.initializer.run()
    y.initializer.run()
    result = f.eval()

result

init = tf.global_variables_initializer()

with tf.Session() as sess:
    init.run()
    result = f.eval()

result

init = tf.global_variables_initializer()

sess = tf.InteractiveSession()
init.run()
result = f.eval()
print(result)

sess.close()

result

# # Managing graphs

x1 = tf.Variable(1)
x1.graph is tf.get_default_graph()
graph = tf.Graph()
with graph.as_default():
    x2 = tf.Variable(2)

x2.graph is graph

# In[16]:

x2.graph is tf.get_default_graph()

# In[17]:

w = tf.constant(3)
x = w + 2
y = x + 5
z = x * 3

with tf.Session() as sess:
    print(y.eval())  # 10
    print(z.eval())  # 15

# In[18]:

with tf.Session() as sess:
    y_val, z_val = sess.run([y, z])
    print(y_val)  # 10
    print(z_val)  # 15

# # Linear Regression

# ## Using the Normal Equation

# In[19]:

import tensorflow as tf
import numpy as np
from sklearn.datasets import fetch_california_housing

housing = fetch_california_housing()
m, n = housing.data.shape
housing_data_plus_bias = np.c_[np.ones((m, 1)), housing.data]

X = tf.constant(housing_data_plus_bias, dtype=tf.float32, name="X")
y = tf.constant(housing.target.reshape(-1, 1), dtype=tf.float32, name="y")
XT = tf.transpose(X)
theta = tf.matmul(tf.matmul(tf.matrix_inverse(tf.matmul(XT, X)), XT), y)

with tf.Session() as sess:
    theta_value = theta.eval()

theta_value

# Compare with pure NumPy

# In[21]:

X = housing_data_plus_bias
y = housing.target.reshape(-1, 1)
theta_numpy = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(y)

print(theta_numpy)

# Compare with Scikit-Learn

# In[22]:

from sklearn.linear_model import LinearRegression
lin_reg = LinearRegression()
lin_reg.fit(housing.data, housing.target.reshape(-1, 1))

print(np.r_[lin_reg.intercept_.reshape(-1, 1), lin_reg.coef_.T])

# ## Using Batch Gradient Descent

# Gradient Descent requires scaling the feature vectors first. We could do this using TF, but let's just use Scikit-Learn for now.

# In[23]:

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaled_housing_data = scaler.fit_transform(housing.data)
scaled_housing_data_plus_bias = np.c_[np.ones((m, 1)), scaled_housing_data]

print(scaled_housing_data_plus_bias.mean(axis=0))
print(scaled_housing_data_plus_bias.mean(axis=1))
print(scaled_housing_data_plus_bias.mean())
print(scaled_housing_data_plus_bias.shape)

# ### Manually computing the gradients
n_epochs = 1000
learning_rate = 0.01

X = tf.constant(scaled_housing_data_plus_bias, dtype=tf.float32, name="X")
y = tf.constant(housing.target.reshape(-1, 1), dtype=tf.float32, name="y")
theta = tf.Variable(tf.random_uniform([n + 1, 1], -1.0, 1.0, seed=42), name="theta")
y_pred = tf.matmul(X, theta, name="predictions")
error = y_pred - y
mse = tf.reduce_mean(tf.square(error), name="mse")
gradients = 2/m * tf.matmul(tf.transpose(X), error)
training_op = tf.assign(theta, theta - learning_rate * gradients)

init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)

    for epoch in range(n_epochs):
        if epoch % 100 == 0:
            print("Epoch", epoch, "MSE =", mse.eval())
        sess.run(training_op)

    best_theta = theta.eval()

best_theta

# ### Using autodiff

# Same as above except for the `gradients = ...` line:

n_epochs = 1000
learning_rate = 0.01

X = tf.constant(scaled_housing_data_plus_bias, dtype=tf.float32, name="X")
y = tf.constant(housing.target.reshape(-1, 1), dtype=tf.float32, name="y")
theta = tf.Variable(tf.random_uniform([n + 1, 1], -1.0, 1.0, seed=42), name="theta")
y_pred = tf.matmul(X, theta, name="predictions")
error = y_pred - y
mse = tf.reduce_mean(tf.square(error), name="mse")

gradients = tf.gradients(mse, [theta])[0]

training_op = tf.assign(theta, theta - learning_rate * gradients)

init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)

    for epoch in range(n_epochs):
        if epoch % 100 == 0:
            print("Epoch", epoch, "MSE =", mse.eval())
        sess.run(training_op)

    best_theta = theta.eval()

print("Best theta:")
print(best_theta)

# How could you find the partial derivatives of the following function with regards to `a` and `b`?

def my_func(a, b):
    z = 0
    for i in range(100):
        z = a * np.cos(z + i) + z * np.sin(b - i)
    return z

my_func(0.2, 0.3)

a = tf.Variable(0.2, name="a")
b = tf.Variable(0.3, name="b")
z = tf.constant(0.0, name="z0")
for i in range(100):
    z = a * tf.cos(z + i) + z * tf.sin(b - i)

grads = tf.gradients(z, [a, b])
init = tf.global_variables_initializer()

# Let's compute the function at $a=0.2$ and $b=0.3$, and the partial derivatives at that point with regards to $a$ and with regards to $b$:

# In[33]:

with tf.Session() as sess:
    init.run()
    print(z.eval())
    print(sess.run(grads))

# ### Using a `GradientDescentOptimizer`

n_epochs = 1000
learning_rate = 0.01

X = tf.constant(scaled_housing_data_plus_bias, dtype=tf.float32, name="X")
y = tf.constant(housing.target.reshape(-1, 1), dtype=tf.float32, name="y")
theta = tf.Variable(tf.random_uniform([n + 1, 1], -1.0, 1.0, seed=42), name="theta")
y_pred = tf.matmul(X, theta, name="predictions")
error = y_pred - y
mse = tf.reduce_mean(tf.square(error), name="mse")

optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
training_op = optimizer.minimize(mse)
init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)

    for epoch in range(n_epochs):
        if epoch % 100 == 0:
            print("Epoch", epoch, "MSE =", mse.eval())
        sess.run(training_op)

    best_theta = theta.eval()

print("Best theta:")
print(best_theta)

# ### Using a momentum optimizer
n_epochs = 1000
learning_rate = 0.01

X = tf.constant(scaled_housing_data_plus_bias, dtype=tf.float32, name="X")
y = tf.constant(housing.target.reshape(-1, 1), dtype=tf.float32, name="y")
theta = tf.Variable(tf.random_uniform([n + 1, 1], -1.0, 1.0, seed=42), name="theta")
y_pred = tf.matmul(X, theta, name="predictions")
error = y_pred - y
mse = tf.reduce_mean(tf.square(error), name="mse")

optimizer = tf.train.MomentumOptimizer(learning_rate=learning_rate, momentum=0.9)
training_op = optimizer.minimize(mse)
init = tf.global_variables_initializer()
with tf.Session() as sess:
    sess.run(init)

    for epoch in range(n_epochs):
        sess.run(training_op)

    best_theta = theta.eval()

print("Best theta:")
print(best_theta)

# # Feeding data to the training algorithm
# ## Placeholder nodes
A = tf.placeholder(tf.float32, shape=(None, 3))
B = A + 5
with tf.Session() as sess:
    B_val_1 = B.eval(feed_dict={A: [[1, 2, 3]]})
    B_val_2 = B.eval(feed_dict={A: [[4, 5, 6], [7, 8, 9]]})

print(B_val_1)
print(B_val_2)

# ## Mini-batch Gradient Descent
n_epochs = 1000
learning_rate = 0.01

X = tf.placeholder(tf.float32, shape=(None, n + 1), name="X")
y = tf.placeholder(tf.float32, shape=(None, 1), name="y")

theta = tf.Variable(tf.random_uniform([n + 1, 1], -1.0, 1.0, seed=42), name="theta")
y_pred = tf.matmul(X, theta, name="predictions")
error = y_pred - y
mse = tf.reduce_mean(tf.square(error), name="mse")
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
training_op = optimizer.minimize(mse)

init = tf.global_variables_initializer()

n_epochs = 10
batch_size = 100
n_batches = int(np.ceil(m / batch_size))

def fetch_batch(epoch, batch_index, batch_size):
    np.random.seed(epoch * n_batches + batch_index)  # not shown in the book
    indices = np.random.randint(m, size=batch_size)  # not shown
    X_batch = scaled_housing_data_plus_bias[indices] # not shown
    y_batch = housing.target.reshape(-1, 1)[indices] # not shown
    return X_batch, y_batch

with tf.Session() as sess:
    sess.run(init)

    for epoch in range(n_epochs):
        for batch_index in range(n_batches):
            X_batch, y_batch = fetch_batch(epoch, batch_index, batch_size)
            sess.run(training_op, feed_dict={X: X_batch, y: y_batch})

    best_theta = theta.eval()

best_theta

# # Saving and restoring a model
n_epochs = 1000                                                                       # not shown in the book
learning_rate = 0.01                                                                  # not shown

X = tf.constant(scaled_housing_data_plus_bias, dtype=tf.float32, name="X")            # not shown
y = tf.constant(housing.target.reshape(-1, 1), dtype=tf.float32, name="y")            # not shown
theta = tf.Variable(tf.random_uniform([n + 1, 1], -1.0, 1.0, seed=42), name="theta")
y_pred = tf.matmul(X, theta, name="predictions")                                      # not shown
error = y_pred - y                                                                    # not shown
mse = tf.reduce_mean(tf.square(error), name="mse")                                    # not shown
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)            # not shown
training_op = optimizer.minimize(mse)                                                 # not shown

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

with tf.Session() as sess:
    sess.run(init)

    for epoch in range(n_epochs):
        if epoch % 100 == 0:
            print("Epoch", epoch, "MSE =", mse.eval())  # not shown
            save_path = saver.save(sess, "c:/my_model.ckpt")
        sess.run(training_op)

    best_theta = theta.eval()
    save_path = saver.save(sess, "c:/my_model_final.ckpt")

best_theta

with tf.Session() as sess:
    saver.restore(sess, "c:/my_model_final.ckpt")
    best_theta_restored = theta.eval() # not shown in the book

np.allclose(best_theta, best_theta_restored)

# If you want to have a saver that loads and restores `theta` with a different name, such as `"weights"`:
saver = tf.train.Saver({"weights": theta})

# By default the saver also saves the graph structure itself in a second file with the extension `.meta`.
# You can use the function `tf.train.import_meta_graph()` to restore the graph structure.
# This function loads the graph into the default graph and returns a `Saver`
# that can then be used to restore the graph state (i.e., the variable values):

saver = tf.train.import_meta_graph("c:/my_model_final.ckpt.meta")  # this loads the graph structure
theta = tf.get_default_graph().get_tensor_by_name("theta:0") # not shown in the book

with tf.Session() as sess:
    saver.restore(sess, "c:/my_model_final.ckpt")  # this restores the graph's state
    best_theta_restored = theta.eval() # not shown in the book

np.allclose(best_theta, best_theta_restored)

# This means that you can import a pretrained model without having to have the corresponding Python code to build the graph. This is very handy when you keep tweaking and saving your model: you can load a previously saved model without having to search for the version of the code that built it.

# # Visualizing the graph
# ## inside Jupyter

# To visualize the graph within Jupyter, we will use a TensorBoard server available online at https://tensorboard.appspot.com/ (so this will not work if you do not have Internet access).  As far as I can tell, this code was originally written by Alex Mordvintsev in his [DeepDream tutorial](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/tutorials/deepdream/deepdream.ipynb). Alternatively, you could use a tool like [tfgraphviz](https://github.com/akimach/tfgraphviz).
from tensorflow_graph_in_jupyter import show_graph
show_graph(tf.get_default_graph())

# ## Using TensorBoard

from datetime import datetime

now = datetime.utcnow().strftime("%Y%m%d%H%M%S")
root_logdir = "tf_logs"
logdir = "{}/run-{}/".format(root_logdir, now)

n_epochs = 1000
learning_rate = 0.01

X = tf.placeholder(tf.float32, shape=(None, n + 1), name="X")
y = tf.placeholder(tf.float32, shape=(None, 1), name="y")
theta = tf.Variable(tf.random_uniform([n + 1, 1], -1.0, 1.0, seed=42), name="theta")
y_pred = tf.matmul(X, theta, name="predictions")
error = y_pred - y
mse = tf.reduce_mean(tf.square(error), name="mse")
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
training_op = optimizer.minimize(mse)

init = tf.global_variables_initializer()

mse_summary = tf.summary.scalar('MSE', mse)
file_writer = tf.summary.FileWriter(logdir, tf.get_default_graph())

n_epochs = 10
batch_size = 100
n_batches = int(np.ceil(m / batch_size))

with tf.Session() as sess:                                                        # not shown in the book
    sess.run(init)                                                                # not shown

    for epoch in range(n_epochs):                                                 # not shown
        for batch_index in range(n_batches):
            X_batch, y_batch = fetch_batch(epoch, batch_index, batch_size)
            if batch_index % 10 == 0:
                summary_str = mse_summary.eval(feed_dict={X: X_batch, y: y_batch})
                step = epoch * n_batches + batch_index
                file_writer.add_summary(summary_str, step)
            sess.run(training_op, feed_dict={X: X_batch, y: y_batch})

    best_theta = theta.eval()                                                     # not shown

file_writer.close()

best_theta

# # Name scopes

# In[66]:

now = datetime.utcnow().strftime("%Y%m%d%H%M%S")
root_logdir = "tf_logs"
logdir = "{}/run-{}/".format(root_logdir, now)

n_epochs = 1000
learning_rate = 0.01

X = tf.placeholder(tf.float32, shape=(None, n + 1), name="X")
y = tf.placeholder(tf.float32, shape=(None, 1), name="y")
theta = tf.Variable(tf.random_uniform([n + 1, 1], -1.0, 1.0, seed=42), name="theta")
y_pred = tf.matmul(X, theta, name="predictions")

with tf.name_scope("loss") as scope:
    error = y_pred - y
    mse = tf.reduce_mean(tf.square(error), name="mse")

optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
training_op = optimizer.minimize(mse)

init = tf.global_variables_initializer()

mse_summary = tf.summary.scalar('MSE', mse)
file_writer = tf.summary.FileWriter(logdir, tf.get_default_graph())

n_epochs = 10
batch_size = 100
n_batches = int(np.ceil(m / batch_size))

with tf.Session() as sess:
    sess.run(init)

    for epoch in range(n_epochs):
        for batch_index in range(n_batches):
            X_batch, y_batch = fetch_batch(epoch, batch_index, batch_size)
            if batch_index % 10 == 0:
                summary_str = mse_summary.eval(feed_dict={X: X_batch, y: y_batch})
                step = epoch * n_batches + batch_index
                file_writer.add_summary(summary_str, step)
            sess.run(training_op, feed_dict={X: X_batch, y: y_batch})

    best_theta = theta.eval()

file_writer.flush()
file_writer.close()
print("Best theta:")
print(best_theta)

print(error.op.name)

print(mse.op.name)

a1 = tf.Variable(0, name="a")      # name == "a"
a2 = tf.Variable(0, name="a")      # name == "a_1"

with tf.name_scope("param"):       # name == "param"
    a3 = tf.Variable(0, name="a")  # name == "param/a"

with tf.name_scope("param"):       # name == "param_1"
    a4 = tf.Variable(0, name="a")  # name == "param_1/a"

for node in (a1, a2, a3, a4):
    print(node.op.name)

# # Modularity

# An ugly flat code:

n_features = 3
X = tf.placeholder(tf.float32, shape=(None, n_features), name="X")

w1 = tf.Variable(tf.random_normal((n_features, 1)), name="weights1")
w2 = tf.Variable(tf.random_normal((n_features, 1)), name="weights2")
b1 = tf.Variable(0.0, name="bias1")
b2 = tf.Variable(0.0, name="bias2")

z1 = tf.add(tf.matmul(X, w1), b1, name="z1")
z2 = tf.add(tf.matmul(X, w2), b2, name="z2")

relu1 = tf.maximum(z1, 0., name="relu1")
relu2 = tf.maximum(z1, 0., name="relu2")  # Oops, cut&paste error! Did you spot it?

output = tf.add(relu1, relu2, name="output")

# Much better, using a function to build the ReLUs:
def relu(X):
    w_shape = (int(X.get_shape()[1]), 1)
    w = tf.Variable(tf.random_normal(w_shape), name="weights")
    b = tf.Variable(0.0, name="bias")
    z = tf.add(tf.matmul(X, w), b, name="z")
    return tf.maximum(z, 0., name="relu")

n_features = 3
X = tf.placeholder(tf.float32, shape=(None, n_features), name="X")
relus = [relu(X) for i in range(5)]
output = tf.add_n(relus, name="output")

file_writer = tf.summary.FileWriter("logs/relu1", tf.get_default_graph())

# Even better using name scopes:

# In[76]:

reset_graph()

def relu(X):
    with tf.name_scope("relu"):
        w_shape = (int(X.get_shape()[1]), 1)                          # not shown in the book
        w = tf.Variable(tf.random_normal(w_shape), name="weights")    # not shown
        b = tf.Variable(0.0, name="bias")                             # not shown
        z = tf.add(tf.matmul(X, w), b, name="z")                      # not shown
        return tf.maximum(z, 0., name="max")                          # not shown

# In[77]:

n_features = 3
X = tf.placeholder(tf.float32, shape=(None, n_features), name="X")
relus = [relu(X) for i in range(5)]
output = tf.add_n(relus, name="output")

file_writer = tf.summary.FileWriter("logs/relu2", tf.get_default_graph())
file_writer.close()

# ## Sharing Variables

# Sharing a `threshold` variable the classic way, by defining it outside of the `relu()` function then passing it as a parameter:

# In[78]:

reset_graph()

def relu(X, threshold):
    with tf.name_scope("relu"):
        w_shape = (int(X.get_shape()[1]), 1)                        # not shown in the book
        w = tf.Variable(tf.random_normal(w_shape), name="weights")  # not shown
        b = tf.Variable(0.0, name="bias")                           # not shown
        z = tf.add(tf.matmul(X, w), b, name="z")                    # not shown
        return tf.maximum(z, threshold, name="max")

threshold = tf.Variable(0.0, name="threshold")
X = tf.placeholder(tf.float32, shape=(None, n_features), name="X")
relus = [relu(X, threshold) for i in range(5)]
output = tf.add_n(relus, name="output")

# In[79]:

reset_graph()

def relu(X):
    with tf.name_scope("relu"):
        if not hasattr(relu, "threshold"):
            relu.threshold = tf.Variable(0.0, name="threshold")
        w_shape = int(X.get_shape()[1]), 1                          # not shown in the book
        w = tf.Variable(tf.random_normal(w_shape), name="weights")  # not shown
        b = tf.Variable(0.0, name="bias")                           # not shown
        z = tf.add(tf.matmul(X, w), b, name="z")                    # not shown
        return tf.maximum(z, relu.threshold, name="max")

# In[80]:

X = tf.placeholder(tf.float32, shape=(None, n_features), name="X")
relus = [relu(X) for i in range(5)]
output = tf.add_n(relus, name="output")

# In[81]:

reset_graph()

with tf.variable_scope("relu"):
    threshold = tf.get_variable("threshold", shape=(),
                                initializer=tf.constant_initializer(0.0))

# In[82]:

with tf.variable_scope("relu", reuse=True):
    threshold = tf.get_variable("threshold")

# In[83]:

with tf.variable_scope("relu") as scope:
    scope.reuse_variables()
    threshold = tf.get_variable("threshold")

# In[84]:

reset_graph()

def relu(X):
    with tf.variable_scope("relu", reuse=True):
        threshold = tf.get_variable("threshold")
        w_shape = int(X.get_shape()[1]), 1                          # not shown
        w = tf.Variable(tf.random_normal(w_shape), name="weights")  # not shown
        b = tf.Variable(0.0, name="bias")                           # not shown
        z = tf.add(tf.matmul(X, w), b, name="z")                    # not shown
        return tf.maximum(z, threshold, name="max")

X = tf.placeholder(tf.float32, shape=(None, n_features), name="X")
with tf.variable_scope("relu"):
    threshold = tf.get_variable("threshold", shape=(),
                                initializer=tf.constant_initializer(0.0))
relus = [relu(X) for relu_index in range(5)]
output = tf.add_n(relus, name="output")

# In[85]:

file_writer = tf.summary.FileWriter("logs/relu6", tf.get_default_graph())
file_writer.close()

# In[86]:

reset_graph()

def relu(X):
    with tf.variable_scope("relu"):
        threshold = tf.get_variable("threshold", shape=(), initializer=tf.constant_initializer(0.0))
        w_shape = (int(X.get_shape()[1]), 1)
        w = tf.Variable(tf.random_normal(w_shape), name="weights")
        b = tf.Variable(0.0, name="bias")
        z = tf.add(tf.matmul(X, w), b, name="z")
        return tf.maximum(z, threshold, name="max")

X = tf.placeholder(tf.float32, shape=(None, n_features), name="X")
with tf.variable_scope("", default_name="") as scope:
    first_relu = relu(X)     # create the shared variable
    scope.reuse_variables()  # then reuse it
    relus = [first_relu] + [relu(X) for i in range(4)]
output = tf.add_n(relus, name="output")

file_writer = tf.summary.FileWriter("logs/relu8", tf.get_default_graph())
file_writer.close()

# In[87]:

reset_graph()

def relu(X):
    threshold = tf.get_variable("threshold", shape=(),
                                initializer=tf.constant_initializer(0.0))
    w_shape = (int(X.get_shape()[1]), 1)                        # not shown in the book
    w = tf.Variable(tf.random_normal(w_shape), name="weights")  # not shown
    b = tf.Variable(0.0, name="bias")                           # not shown
    z = tf.add(tf.matmul(X, w), b, name="z")                    # not shown
    return tf.maximum(z, threshold, name="max")

X = tf.placeholder(tf.float32, shape=(None, n_features), name="X")
relus = []
for relu_index in range(5):
    with tf.variable_scope("relu", reuse=(relu_index >= 1)) as scope:
        relus.append(relu(X))
output = tf.add_n(relus, name="output")

# In[88]:

file_writer = tf.summary.FileWriter("logs/relu9", tf.get_default_graph())
file_writer.close()

# # Extra material

# In[89]:

reset_graph()

with tf.variable_scope("my_scope"):
    x0 = tf.get_variable("x", shape=(), initializer=tf.constant_initializer(0.))
    x1 = tf.Variable(0., name="x")
    x2 = tf.Variable(0., name="x")

with tf.variable_scope("my_scope", reuse=True):
    x3 = tf.get_variable("x")
    x4 = tf.Variable(0., name="x")

with tf.variable_scope("", default_name="", reuse=True):
    x5 = tf.get_variable("my_scope/x")

print("x0:", x0.op.name)
print("x1:", x1.op.name)
print("x2:", x2.op.name)
print("x3:", x3.op.name)
print("x4:", x4.op.name)
print("x5:", x5.op.name)
print(x0 is x3 and x3 is x5)

# The first `variable_scope()` block first creates the shared variable `x0`, named `my_scope/x`. For all operations other than shared variables (including non-shared variables), the variable scope acts like a regular name scope, which is why the two variables `x1` and `x2` have a name with a prefix `my_scope/`. Note however that TensorFlow makes their names unique by adding an index: `my_scope/x_1` and `my_scope/x_2`.
#
# The second `variable_scope()` block reuses the shared variables in scope `my_scope`, which is why `x0 is x3`. Once again, for all operations other than shared variables it acts as a named scope, and since it's a separate block from the first one, the name of the scope is made unique by TensorFlow (`my_scope_1`) and thus the variable `x4` is named `my_scope_1/x`.
#
# The third block shows another way to get a handle on the shared variable `my_scope/x` by creating a `variable_scope()` at the root scope (whose name is an empty string), then calling `get_variable()` with the full name of the shared variable (i.e. `"my_scope/x"`).

# ## Strings

# In[90]:

reset_graph()

text = np.array("Do you want some café?".split())
text_tensor = tf.constant(text)

with tf.Session() as sess:
    print(text_tensor.eval())

# ## Autodiff

# Note: the autodiff content was moved to the [extra_autodiff.ipynb](extra_autodiff.ipynb) notebook.

# # Exercise solutions

# ## 1. to 11.

# See appendix A.

# ## 12. Logistic Regression with Mini-Batch Gradient Descent using TensorFlow

# First, let's create the moons dataset using Scikit-Learn's `make_moons()` function:

# In[91]:

from sklearn.datasets import make_moons

m = 1000
X_moons, y_moons = make_moons(m, noise=0.1, random_state=42)

# Let's take a peek at the dataset:

# In[92]:

plt.plot(X_moons[y_moons == 1, 0], X_moons[y_moons == 1, 1], 'go', label="Positive")
plt.plot(X_moons[y_moons == 0, 0], X_moons[y_moons == 0, 1], 'r^', label="Negative")
plt.legend()
plt.show()

# We must not forget to add an extra bias feature ($x_0 = 1$) to every instance. For this, we just need to add a column full of 1s on the left of the input matrix $\mathbf{X}$:

# In[93]:

X_moons_with_bias = np.c_[np.ones((m, 1)), X_moons]

# Let's check:

# In[94]:

X_moons_with_bias[:5]

# Looks good. Now let's reshape `y_train` to make it a column vector (i.e. a 2D array with a single column):

# In[95]:

y_moons_column_vector = y_moons.reshape(-1, 1)

# Now let's split the data into a training set and a test set:

# In[96]:

test_ratio = 0.2
test_size = int(m * test_ratio)
X_train = X_moons_with_bias[:-test_size]
X_test = X_moons_with_bias[-test_size:]
y_train = y_moons_column_vector[:-test_size]
y_test = y_moons_column_vector[-test_size:]

# Ok, now let's create a small function to generate training batches. In this implementation we will just pick random instances from the training set for each batch. This means that a single batch may contain the same instance multiple times, and also a single epoch may not cover all the training instances (in fact it will generally cover only about two thirds of the instances). However, in practice this is not an issue and it simplifies the code:

# In[97]:

def random_batch(X_train, y_train, batch_size):
    rnd_indices = np.random.randint(0, len(X_train), batch_size)
    X_batch = X_train[rnd_indices]
    y_batch = y_train[rnd_indices]
    return X_batch, y_batch

# Let's look at a small batch:

# In[98]:

X_batch, y_batch = random_batch(X_train, y_train, 5)
X_batch

# In[99]:

y_batch

# Great! Now that the data is ready to be fed to the model, we need to build that model. Let's start with a simple implementation, then we will add all the bells and whistles.

# First let's reset the default graph.

# In[100]:

reset_graph()

# The _moons_ dataset has two input features, since each instance is a point on a plane (i.e., 2-Dimensional):

# In[101]:

n_inputs = 2

# Now let's build the Logistic Regression model. As we saw in chapter 4, this model first computes a weighted sum of the inputs (just like the Linear Regression model), and then it applies the sigmoid function to the result, which gives us the estimated probability for the positive class:
#
# $\hat{p} = h_\boldsymbol{\theta}(\mathbf{x}) = \sigma(\boldsymbol{\theta}^T \mathbf{x})$
#

# Recall that $\boldsymbol{\theta}$ is the parameter vector, containing the bias term $\theta_0$ and the weights $\theta_1, \theta_2, \dots, \theta_n$. The input vector $\mathbf{x}$ contains a constant term $x_0 = 1$, as well as all the input features $x_1, x_2, \dots, x_n$.
#
# Since we want to be able to make predictions for multiple instances at a time, we will use an input matrix $\mathbf{X}$ rather than a single input vector. The $i^{th}$ row will contain the transpose of the $i^{th}$ input vector $(\mathbf{x}^{(i)})^T$. It is then possible to estimate the probability that each instance belongs to the positive class using the following equation:
#
# $ \hat{\mathbf{p}} = \sigma(\mathbf{X} \boldsymbol{\theta})$
#
# That's all we need to build the model:

# In[102]:

X = tf.placeholder(tf.float32, shape=(None, n_inputs + 1), name="X")
y = tf.placeholder(tf.float32, shape=(None, 1), name="y")
theta = tf.Variable(tf.random_uniform([n_inputs + 1, 1], -1.0, 1.0, seed=42), name="theta")
logits = tf.matmul(X, theta, name="logits")
y_proba = 1 / (1 + tf.exp(-logits))

# In fact, TensorFlow has a nice function `tf.sigmoid()` that we can use to simplify the last line of the previous code:

# In[103]:

y_proba = tf.sigmoid(logits)

# As we saw in chapter 4, the log loss is a good cost function to use for Logistic Regression:
#
# $J(\boldsymbol{\theta}) = -\dfrac{1}{m} \sum\limits_{i=1}^{m}{\left[ y^{(i)} \log\left(\hat{p}^{(i)}\right) + (1 - y^{(i)}) \log\left(1 - \hat{p}^{(i)}\right)\right]}$
#
# One option is to implement it ourselves:

# In[104]:

epsilon = 1e-7  # to avoid an overflow when computing the log
loss = -tf.reduce_mean(y * tf.log(y_proba + epsilon) + (1 - y) * tf.log(1 - y_proba + epsilon))

# But we might as well use TensorFlow's `tf.losses.log_loss()` function:

# In[105]:

loss = tf.losses.log_loss(y, y_proba)  # uses epsilon = 1e-7 by default

# The rest is pretty standard: let's create the optimizer and tell it to minimize the cost function:

# In[106]:

learning_rate = 0.01
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
training_op = optimizer.minimize(loss)

# All we need now (in this minimal version) is the variable initializer:

# In[107]:

init = tf.global_variables_initializer()

# And we are ready to train the model and use it for predictions!

# There's really nothing special about this code, it's virtually the same as the one we used earlier for Linear Regression:

# In[108]:

n_epochs = 1000
batch_size = 50
n_batches = int(np.ceil(m / batch_size))

with tf.Session() as sess:
    sess.run(init)

    for epoch in range(n_epochs):
        for batch_index in range(n_batches):
            X_batch, y_batch = random_batch(X_train, y_train, batch_size)
            sess.run(training_op, feed_dict={X: X_batch, y: y_batch})
        loss_val = loss.eval({X: X_test, y: y_test})
        if epoch % 100 == 0:
            print("Epoch:", epoch, "\tLoss:", loss_val)

    y_proba_val = y_proba.eval(feed_dict={X: X_test, y: y_test})

# Note: we don't use the epoch number when generating batches, so we could just have a single `for` loop rather than 2 nested `for` loops, but it's convenient to think of training time in terms of number of epochs (i.e., roughly the number of times the algorithm went through the training set).

# For each instance in the test set, `y_proba_val` contains the estimated probability that it belongs to the positive class, according to the model. For example, here are the first 5 estimated probabilities:

# In[109]:

y_proba_val[:5]

# To classify each instance, we can go for maximum likelihood: classify as positive any instance whose estimated probability is greater or equal to 0.5:

# In[110]:

y_pred = (y_proba_val >= 0.5)
y_pred[:5]

# Depending on the use case, you may want to choose a different threshold than 0.5: make it higher if you want high precision (but lower recall), and make it lower if you want high recall (but lower precision). See chapter 3 for more details.

# Let's compute the model's precision and recall:

# In[111]:

from sklearn.metrics import precision_score, recall_score

precision_score(y_test, y_pred)

# In[112]:

recall_score(y_test, y_pred)

# Let's plot these predictions to see what they look like:

# In[113]:

y_pred_idx = y_pred.reshape(-1) # a 1D array rather than a column vector
plt.plot(X_test[y_pred_idx, 1], X_test[y_pred_idx, 2], 'go', label="Positive")
plt.plot(X_test[~y_pred_idx, 1], X_test[~y_pred_idx, 2], 'r^', label="Negative")
plt.legend()
plt.show()

# Well, that looks pretty bad, doesn't it? But let's not forget that the Logistic Regression model has a linear decision boundary, so this is actually close to the best we can do with this model (unless we add more features, as we will show in a second).

# Now let's start over, but this time we will add all the bells and whistles, as listed in the exercise:
# * Define the graph within a `logistic_regression()` function that can be reused easily.
# * Save checkpoints using a `Saver` at regular intervals during training, and save the final model at the end of training.
# * Restore the last checkpoint upon startup if training was interrupted.
# * Define the graph using nice scopes so the graph looks good in TensorBoard.
# * Add summaries to visualize the learning curves in TensorBoard.
# * Try tweaking some hyperparameters such as the learning rate or the mini-batch size and look at the shape of the learning curve.

# Before we start, we will add 4 more features to the inputs: ${x_1}^2$, ${x_2}^2$, ${x_1}^3$ and ${x_2}^3$. This was not part of the exercise, but it will demonstrate how adding features can improve the model. We will do this manually, but you could also add them using `sklearn.preprocessing.PolynomialFeatures`.

# In[114]:

X_train_enhanced = np.c_[X_train,
                         np.square(X_train[:, 1]),
                         np.square(X_train[:, 2]),
                         X_train[:, 1] ** 3,
                         X_train[:, 2] ** 3]
X_test_enhanced = np.c_[X_test,
                        np.square(X_test[:, 1]),
                        np.square(X_test[:, 2]),
                        X_test[:, 1] ** 3,
                        X_test[:, 2] ** 3]

# This is what the "enhanced" training set looks like:

# In[115]:

X_train_enhanced[:5]

# Ok, next let's reset the default graph:

# In[116]:

reset_graph()

# Now let's define the `logistic_regression()` function to create the graph. We will leave out the definition of the inputs `X` and the targets `y`. We could include them here, but leaving them out will make it easier to use this function in a wide range of use cases (e.g. perhaps we will want to add some preprocessing steps for the inputs before we feed them to the Logistic Regression model).

# In[117]:

def logistic_regression(X, y, initializer=None, seed=42, learning_rate=0.01):
    n_inputs_including_bias = int(X.get_shape()[1])
    with tf.name_scope("logistic_regression"):
        with tf.name_scope("model"):
            if initializer is None:
                initializer = tf.random_uniform([n_inputs_including_bias, 1], -1.0, 1.0, seed=seed)
            theta = tf.Variable(initializer, name="theta")
            logits = tf.matmul(X, theta, name="logits")
            y_proba = tf.sigmoid(logits)
        with tf.name_scope("train"):
            loss = tf.losses.log_loss(y, y_proba, scope="loss")
            optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
            training_op = optimizer.minimize(loss)
            loss_summary = tf.summary.scalar('log_loss', loss)
        with tf.name_scope("init"):
            init = tf.global_variables_initializer()
        with tf.name_scope("save"):
            saver = tf.train.Saver()
    return y_proba, loss, training_op, loss_summary, init, saver

# Let's create a little function to get the name of the log directory to save the summaries for Tensorboard:

# In[118]:

from datetime import datetime

def log_dir(prefix=""):
    now = datetime.utcnow().strftime("%Y%m%d%H%M%S")
    root_logdir = "tf_logs"
    if prefix:
        prefix += "-"
    name = prefix + "run-" + now
    return "{}/{}/".format(root_logdir, name)

# Next, let's create the graph, using the `logistic_regression()` function. We will also create the `FileWriter` to save the summaries to the log directory for Tensorboard:

# In[119]:

n_inputs = 2 + 4
logdir = log_dir("logreg")

X = tf.placeholder(tf.float32, shape=(None, n_inputs + 1), name="X")
y = tf.placeholder(tf.float32, shape=(None, 1), name="y")

y_proba, loss, training_op, loss_summary, init, saver = logistic_regression(X, y)

file_writer = tf.summary.FileWriter(logdir, tf.get_default_graph())

# At last we can train the model! We will start by checking whether a previous training session was interrupted, and if so we will load the checkpoint and continue training from the epoch number we saved. In this example we just save the epoch number to a separate file, but in chapter 11 we will see how to store the training step directly as part of the model, using a non-trainable variable called `global_step` that we pass to the optimizer's `minimize()` method.
#
# You can try interrupting training to verify that it does indeed restore the last checkpoint when you start it again.

# In[120]:

n_epochs = 10001
batch_size = 50
n_batches = int(np.ceil(m / batch_size))

checkpoint_path = "/tmp/my_logreg_model.ckpt"
checkpoint_epoch_path = checkpoint_path + ".epoch"
final_model_path = "./my_logreg_model"

with tf.Session() as sess:
    if os.path.isfile(checkpoint_epoch_path):
        # if the checkpoint file exists, restore the model and load the epoch number
        with open(checkpoint_epoch_path, "rb") as f:
            start_epoch = int(f.read())
        print("Training was interrupted. Continuing at epoch", start_epoch)
        saver.restore(sess, checkpoint_path)
    else:
        start_epoch = 0
        sess.run(init)

    for epoch in range(start_epoch, n_epochs):
        for batch_index in range(n_batches):
            X_batch, y_batch = random_batch(X_train_enhanced, y_train, batch_size)
            sess.run(training_op, feed_dict={X: X_batch, y: y_batch})
        loss_val, summary_str = sess.run([loss, loss_summary], feed_dict={X: X_test_enhanced, y: y_test})
        file_writer.add_summary(summary_str, epoch)
        if epoch % 500 == 0:
            print("Epoch:", epoch, "\tLoss:", loss_val)
            saver.save(sess, checkpoint_path)
            with open(checkpoint_epoch_path, "wb") as f:
                f.write(b"%d" % (epoch + 1))

    saver.save(sess, final_model_path)
    y_proba_val = y_proba.eval(feed_dict={X: X_test_enhanced, y: y_test})
    os.remove(checkpoint_epoch_path)

# Once again, we can make predictions by just classifying as positive all the instances whose estimated probability is greater or equal to 0.5:

# In[121]:

y_pred = (y_proba_val >= 0.5)

# In[122]:

precision_score(y_test, y_pred)

# In[123]:

recall_score(y_test, y_pred)

# In[124]:

y_pred_idx = y_pred.reshape(-1) # a 1D array rather than a column vector
plt.plot(X_test[y_pred_idx, 1], X_test[y_pred_idx, 2], 'go', label="Positive")
plt.plot(X_test[~y_pred_idx, 1], X_test[~y_pred_idx, 2], 'r^', label="Negative")
plt.legend()
plt.show()

# Now that's much, much better! Apparently the new features really helped a lot.

# Try starting the tensorboard server, find the latest run and look at the learning curve (i.e., how the loss evaluated on the test set evolves as a function of the epoch number):
#
# ```
# $ tensorboard --logdir=tf_logs
# ```

# Now you can play around with the hyperparameters (e.g. the `batch_size` or the `learning_rate`) and run training again and again, comparing the learning curves. You can even automate this process by implementing grid search or randomized search. Below is a simple implementation of a randomized search on both the batch size and the learning rate. For the sake of simplicity, the checkpoint mechanism was removed.

# In[125]:

from scipy.stats import reciprocal

n_search_iterations = 10

for search_iteration in range(n_search_iterations):
    batch_size = np.random.randint(1, 100)
    learning_rate = reciprocal(0.0001, 0.1).rvs(random_state=search_iteration)

    n_inputs = 2 + 4
    logdir = log_dir("logreg")

    print("Iteration", search_iteration)
    print("  logdir:", logdir)
    print("  batch size:", batch_size)
    print("  learning_rate:", learning_rate)
    print("  training: ", end="")

    reset_graph()

    X = tf.placeholder(tf.float32, shape=(None, n_inputs + 1), name="X")
    y = tf.placeholder(tf.float32, shape=(None, 1), name="y")

    y_proba, loss, training_op, loss_summary, init, saver = logistic_regression(
        X, y, learning_rate=learning_rate)

    file_writer = tf.summary.FileWriter(logdir, tf.get_default_graph())

    n_epochs = 10001
    n_batches = int(np.ceil(m / batch_size))

    final_model_path = "./my_logreg_model_%d" % search_iteration

    with tf.Session() as sess:
        sess.run(init)

        for epoch in range(n_epochs):
            for batch_index in range(n_batches):
                X_batch, y_batch = random_batch(X_train_enhanced, y_train, batch_size)
                sess.run(training_op, feed_dict={X: X_batch, y: y_batch})
            loss_val, summary_str = sess.run([loss, loss_summary], feed_dict={X: X_test_enhanced, y: y_test})
            file_writer.add_summary(summary_str, epoch)
            if epoch % 500 == 0:
                print(".", end="")

        saver.save(sess, final_model_path)

        print()
        y_proba_val = y_proba.eval(feed_dict={X: X_test_enhanced, y: y_test})
        y_pred = (y_proba_val >= 0.5)

        print("  precision:", precision_score(y_test, y_pred))
        print("  recall:", recall_score(y_test, y_pred))

# The `reciprocal()` function from SciPy's `stats` module returns a random distribution that is commonly used when you have no idea of the optimal scale of a hyperparameter. See the exercise solutions for chapter 2 for more details.


from configparser import ConfigParser
from pathlib import Path

import click

ROOT = Path(__file__).parent

@click.group()
def config():
    pass

@config.command()
@click.option('-t', '--token', prompt=True, hide_input=True, help='An explicit api token')
@click.option('-c', '--config', default='~/.flagrc', help='flagrc to save token to')
def login(token, config):
    flagrc = Path(config)
    click.echo("Writing token to {}".format(flagrc))
    flagrc = flagrc.expanduser()

    c = ConfigParser()
    c.read(str(flagrc))

    if not c.has_section('iscore'):
        c.add_section('iscore')

    c['iscore']['api_token'] = token
    with flagrc.open('w') as fp:
        c.write(fp)


import json
from MyMQTT import *
import random

import time
class My_heart_publisher():
    def __init__(self, clientID, topic, broker, port):
        self.topic=topic
        self.client=MyMQTT(clientID, broker, port)
        self.__message={
            "bn":"MQ5_sensor",
            "e":[{"n":"glass_infraction","u":"Bool","t":None,"v":"status"}]}
    def start(self):
        self.client.start()

    def stop(self):
        self.client.stop()

    def publish(self):
        message=self.__message
        status = random.randint(0,1)
        if status == 0:
            message["e"][0]["v"]=False
        else:
            message["e"][0]["v"]=True
        message["e"][0]["t"]=time.time()
        #message = "{\"bn\":\"MQ-5\",\"e\":[{\"n\":\"Blood Alcohol Level\",\"u\":\"/\",\"v\":\"10\"}]}"
        self.client.myPublish(self.topic,message)
        print("Published")

if __name__=="__main__":
    conf=json.load(open("settings.json"))
    broker=conf["broker"]
    port=conf["port"]
    topic="smart2safe/raspberry/window_monitor"
    hrp=My_heart_publisher("HearthRate",topic,broker,port)
    hrp.start()
    t_end=time.time()+60*2
    while True:
        hrp.publish()
        time.sleep(5)
    hrp.stop()


import logging
from abc import ABCMeta, abstractmethod

from eth_abi import decode_abi
from eth_abi.exceptions import InsufficientDataBytes
from hexbytes import HexBytes
from polyswarmartifact import ArtifactType

from polyswarmclient.utils import int_to_bool_list, guid_as_string, sha3

logger = logging.getLogger(__name__)

UNKNOWN_PARAMETER = 'XXX'

class DecodedTransaction:
    """This is a decoded representation of the transaction object returned by polyswarmd."""

    def __init__(self, to, value, data, abi, signature, parameters):
        self.to = to
        self.value = value
        self.data = data
        self.abi = abi
        self.signature = signature
        self.parameters = parameters

    @classmethod
    def from_transaction(cls, transaction, abi):
        """Parse a transaction from data returned from polyswarmd.

        Args:
            transaction (dict): Transaction to be simplified
            abi (str, list[str]): ABI of the expected function call
        Returns:
            DecodedTransaction: If valid, returns a SimplifiedTransaction
        Raises:
            ValueError: If invalid transaction is provided
        """
        transaction_data = transaction.get('data')
        if transaction_data is None:
            raise ValueError('No data field in this transaction')

        transaction_to = transaction.get('to')
        if transaction_to is None:
            raise ValueError('No recipient field in this transaction')

        value = transaction.get('value')
        if value is None:
            raise ValueError('No value field in this transaction')

        to = transaction_to.lower()

        byte_data = bytes(HexBytes(transaction_data))
        sig = byte_data[:4]
        data = bytes(HexBytes(byte_data[4:]))

        method, args = abi
        expected_sig = sha3('{}({})'.format(method, ','.join(args)))[:4]
        if sig != expected_sig:
            raise ValueError(
                'Method signature did not match expected, got {} expected {} ({})'.format(sig, expected_sig, method))

        try:
            parameters = decode_abi(args, data)
        except InsufficientDataBytes:
            raise ValueError(
                'Transaction data did not match expected ABI (expected {}({}))'.format(method, ','.join(args)))

        return cls(to, value, data, abi, sig, parameters)

    def __repr__(self):
        method, args = self.abi

        # Display readable guids
        parameters = [guid_as_string(p) if t == 'uint128' else p for p, t in zip(self.parameters, args)]
        return '{}({})'.format(method, ', '.join(['{}:{}'.format(v, t) for v, t in zip(parameters, args)]))

class AbstractTransactionVerifier(metaclass=ABCMeta):
    """Verifier is used to verify the details of a single transaction."""
    ABI = ('', [])

    def __init__(self, parameters):
        self.parameters = parameters

    @abstractmethod
    def verify(self, transaction):
        """Called when a list of transactions were returned from polyswarmd.
        This function will verify the transactions, and determines if the transactions are expected.

        Args:
            transaction: Transaction representation returned from polyswarmd
        Returns:
            True if valid and expected
        """
        raise NotImplementedError('Verify is not implemented')

    def __repr__(self):
        method, args = self.ABI
        return '{}({})'.format(method, ', '.join(['{}:{}'.format(v, t) for v, t in zip(self.parameters, args)]))

class NctApproveVerifier(AbstractTransactionVerifier):
    ABI = ('approve', ['address', 'uint256'])

    def __init__(self, amount):
        super().__init__((UNKNOWN_PARAMETER, amount))
        self.amount = amount

    def verify(self, transaction):
        try:
            decoded = DecodedTransaction.from_transaction(transaction, self.ABI)
        except ValueError as e:
            logger.error('Transaction verification failed: %s', str(e))
            return False

        logger.debug('Expected: %s, Actual: %s', self, decoded)
        account, amount = decoded.parameters

        return decoded.value == 0 and amount == self.amount

class NctTransferVerifier(AbstractTransactionVerifier):
    ABI = ('transfer', ['address', 'uint256'])

    def __init__(self, amount):
        super().__init__((UNKNOWN_PARAMETER, amount))
        self.amount = amount

    def verify(self, transaction):
        try:
            decoded = DecodedTransaction.from_transaction(transaction, self.ABI)
        except ValueError as e:
            logger.error('Transaction verification failed: %s', str(e))
            return False

        logger.debug('Expected: %s, Actual: %s', self, decoded)
        account, amount = decoded.parameters

        return decoded.value == 0 and amount == self.amount

class PostBountyVerifier(AbstractTransactionVerifier):
    ABI = ('postBounty', ['uint128', 'uint256', 'uint256', 'string', 'uint256', 'uint256', 'uint256[8]', 'string'])

    def __init__(self, artifact_type, amount, artifact_uri, num_artifacts, duration, bloom, metadata):
        super().__init__((UNKNOWN_PARAMETER, amount, artifact_uri, num_artifacts, duration, bloom, metadata))

        self.artifact_type = ArtifactType.from_string(artifact_type)
        self.amount = amount
        self.artifact_uri = artifact_uri
        self.num_artifacts = num_artifacts
        self.duration = duration
        self.bloom = bloom
        self.metadata = metadata

    def verify(self, transaction):
        try:
            decoded = DecodedTransaction.from_transaction(transaction, self.ABI)
        except ValueError as e:
            logger.error('Transaction verification failed: %s', str(e))
            return False

        logger.debug('Expected: %s, Actual: %s', self, decoded)
        guid, artifact_type, amount, artifact_uri, num_artifacts, duration, bloom, metadata = decoded.parameters

        bloom_value = 0
        for b in bloom:
            bloom_value = bloom_value << 256 | int(b)

        artifact_type = ArtifactType(int(artifact_type))
        artifact_uri = artifact_uri.decode('utf-8')

        return decoded.value == 0 and \
            artifact_type == self.artifact_type and \
            artifact_uri == self.artifact_uri and \
            num_artifacts == self.num_artifacts and \
            duration == self.duration and \
            bloom_value == self.bloom and \
            amount == self.amount and \
            metadata.decode('utf-8') == self.metadata

class PostAssertionVerifier(AbstractTransactionVerifier):
    ABI = ('postAssertion', ['uint128', 'uint256', 'uint256', 'uint256'])

    def __init__(self, bounty_guid, bid, mask, commitment):
        super().__init__((bounty_guid, bid, mask, commitment))

        self.bounty_guid = bounty_guid
        self.bid = bid
        self.mask = mask
        self.commitment = commitment

    def verify(self, transaction):
        try:
            decoded = DecodedTransaction.from_transaction(transaction, self.ABI)
        except ValueError as e:
            logger.error('Transaction verification failed: %s', str(e))
            return False

        logger.debug('Expected: %s, Actual: %s', self, decoded)
        bounty_guid, bid, mask, commitment = decoded.parameters

        return decoded.value == 0 and \
            guid_as_string(bounty_guid) == self.bounty_guid and \
            bid == self.bid and \
            commitment == self.commitment and \
            int_to_bool_list(mask, len(self.mask)) == self.mask

class RevealAssertionVerifier(AbstractTransactionVerifier):
    ABI = ('revealAssertion', ['uint128', 'uint256', 'uint256', 'uint256', 'string'])

    def __init__(self, bounty_guid, index, nonce, verdicts, metadata):
        super().__init__((bounty_guid, index, nonce, verdicts, metadata))

        self.bounty_guid = bounty_guid
        self.index = index
        self.nonce = nonce
        self.verdicts = verdicts
        self.metadata = metadata

    def verify(self, transaction):
        try:
            decoded = DecodedTransaction.from_transaction(transaction, self.ABI)
        except ValueError as e:
            logger.error('Transaction verification failed: %s', str(e))
            return False

        logger.debug('Expected: %s, Actual: %s', self, decoded)
        bounty_guid, index, nonce, verdicts, metadata = decoded.parameters

        metadata = metadata.decode('utf-8')

        # If there is a 1 anywhere beyond the length of items we expect, fail it
        if verdicts >> len(self.verdicts) > 0:
            return False

        return decoded.value == 0 and \
            guid_as_string(bounty_guid) == self.bounty_guid and \
            index == self.index and \
            nonce == self.nonce and \
            int_to_bool_list(verdicts, len(self.verdicts)) == self.verdicts and \
            metadata == self.metadata

class PostVoteVerifier(AbstractTransactionVerifier):
    ABI = ('voteOnBounty', ['uint128', 'uint256', 'bool'])

    def __init__(self, bounty_guid, votes, valid_bloom):
        super().__init__((bounty_guid, votes, valid_bloom))

        self.bounty_guid = bounty_guid
        self.votes = votes
        self.valid_bloom = valid_bloom

    def verify(self, transaction):
        try:
            decoded = DecodedTransaction.from_transaction(transaction, self.ABI)
        except ValueError as e:
            logger.error('Transaction verification failed: %s', str(e))
            return False

        logger.debug('Expected: %s, Actual: %s', self, decoded)
        bounty_guid, votes, valid_bloom = decoded.parameters

        return decoded.value == 0 and \
            guid_as_string(bounty_guid) == self.bounty_guid and \
            int_to_bool_list(votes, len(self.votes)) == self.votes and \
            valid_bloom == self.valid_bloom

class SettleBountyVerifier(AbstractTransactionVerifier):
    ABI = ('settleBounty', ['uint128'])

    def __init__(self, bounty_guid):
        super().__init__((bounty_guid,))
        self.bounty_guid = bounty_guid

    def verify(self, transaction):
        try:
            decoded = DecodedTransaction.from_transaction(transaction, self.ABI)
        except ValueError as e:
            logger.error('Transaction verification failed: %s', str(e))
            return False

        logger.debug('Expected: %s, Actual: %s', self, decoded)
        bounty_guid, = decoded.parameters

        return decoded.value == 0 and \
            guid_as_string(bounty_guid) == self.bounty_guid

class StakingDepositVerifier(AbstractTransactionVerifier):
    ABI = ('deposit', ['uint256'])

    def __init__(self, amount):
        super().__init__((amount,))
        self.amount = amount

    def verify(self, transaction):
        try:
            decoded = DecodedTransaction.from_transaction(transaction, self.ABI)
        except ValueError as e:
            logger.error('Transaction verification failed: %s', str(e))
            return False

        logger.debug('Expected: %s, Actual: %s', self, decoded)
        amount, = decoded.parameters

        return decoded.value == 0 and \
            amount == self.amount

class StakingWithdrawVerifier(AbstractTransactionVerifier):
    ABI = ('withdraw', ['uint256'])

    def __init__(self, amount):
        super().__init__((amount,))
        self.amount = amount

    def verify(self, transaction):
        try:
            decoded = DecodedTransaction.from_transaction(transaction, self.ABI)
        except ValueError as e:
            logger.error('Transaction verification failed: %s', str(e))
            return False

        logger.debug('Expected: %s, Actual: %s', self, decoded)
        amount, = decoded.parameters

        return decoded.value == 0 and \
            amount == self.amount


from __future__ import unicode_literals

import datetime
import os
import subprocess

def get_version(version=None):
    """Returns a PEP 440-compliant version number from VERSION."""
    version = get_complete_version(version)

    # Now build the two parts of the version number:
    # main = X.Y[.Z]
    # sub = .devN - for pre-alpha releases
    #     | {a|b|rc}N - for alpha, beta, and rc releases

    main = get_main_version(version)

    sub = ''
    if version[3] == 'alpha' and version[4] == 0:
        git_changeset = get_git_changeset()
        if git_changeset:
            sub = '.dev%s' % git_changeset

    elif version[3] != 'final':
        mapping = {'alpha': 'a', 'beta': 'b', 'rc': 'rc'}
        sub = mapping[version[3]] + str(version[4])

    return str(main + sub)

def get_main_version(version=None):
    """Returns main version (X.Y[.Z]) from VERSION."""
    version = get_complete_version(version)
    parts = 2 if version[2] == 0 else 3
    return str('.'.join(str(x) for x in version[:parts]))

def get_complete_version(version=None):
    """Returns a tuple of the django version. If version argument is non-empty,
    then checks for correctness of the tuple provided.
    """
    if version is None:
        from core.buildinfo import __version__ as version
    else:
        assert len(version) == 5
        assert version[3] in ('alpha', 'beta', 'rc', 'final')

    return version

def get_docs_version(version=None):
    """ since this is usually designed to get a docs repo, the names
    are tied to corresponding Wrapper repo expected to house these releases"""
    version = get_complete_version(version)
    if version[3] == 'final':
        repo = 'master'
    elif version[3] == 'rc':
        repo = 'development'
    else:
        repo = 'experimental'
    return str(repo)

def get_git_changeset(formatter=True):
    """
    **We really can't use this at the present time because builds_script.py
    is run PRIOR to comitting.  This means our identifier would actually
    be for the LAST build, not the present one.**

    Returns a string representation of numeric identifier of the latest
    git changeset.

    The result is the UTC timestamp of the changeset in YYYYMMDDHHMMSS format.
    This value isn't guaranteed to be unique, but collisions are very unlikely,
    so it's sufficient for generating the development version numbers.

    A more compact, less readable, EPOCH time can be returned by specifying
    `formatter=False`
    """
    repo_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    git_log = subprocess.Popen(
        'git log --pretty=format:%ct --quiet -1 HEAD',
        stdout=subprocess.PIPE, stderr=subprocess.PIPE,
        shell=True, cwd=repo_dir, universal_newlines=True,
    )
    timestamp = git_log.communicate()[0]
    if formatter:
        try:
            timestamp = datetime.datetime.utcfromtimestamp(int(timestamp))
        except ValueError:
            return None
        return timestamp.strftime('%Y%m%d%H%M%S')
    else:
        return timestamp

if __name__ == "__main__":
    print(get_version(), "get_version()")
    print(get_main_version(), "get_main_version()")
    print(get_complete_version(), "get_complete_version()")
    print(get_docs_version(), "get_docs_version()")
    print(get_git_changeset(formatter=False), "get_git_changeset()")


from __future__ import print_function, division

from datetime import datetime
import pprint
import os
import cPickle
import sys

import time
import random

import numpy as np
import torch
import torch.nn as nn
import torch.nn.init

import argparse
import subprocess
import utils
from models import Seq2Seq, Searcher
from trainer import bleu_test, translate_
from datastream import DataStream, DataStreamRandom
from trainer import Trainer

def prepare_corpus(names, paths, buckets, max_size=0, use_all=False, vocabs=None, method='both', replace_unk=False, use_morph=False):
    corpus = utils.corpus.Corpus(max_size=max_size)
    # add columns
    for name, path in zip(names, paths):
        morph = use_morph and name == 'src'
        corpus.add_entry(name, path, morph=morph)
    # construct a dictionary
    dictionary = utils.vocab.Dictionary(corpus) if method == 'both' and replace_unk else None
    # indexify sentences
    if vocabs is not None:
        for k in vocabs:
            corpus.indexify(k, vocabs[k])
    # count lengths
    for entry_name in corpus.entry_dict.keys():
        if entry_name in ['src', 'tgt']:
            corpus.add_length_column(entry_name)
    # bucketify
    corpus = utils.corpus.BucketedCorpus(corpus, buckets, use_all=use_all, method=method)
    corpus.dictionary = dictionary # HACK
    return corpus

def train(args):
    if args.use_morph:
        train_src_data_path = '%s/train.seg.%s' %(args.data_dir, args.src)
    else:
        train_src_data_path = '%s/train.%s' %(args.data_dir, args.src)
    train_tgt_data_path = '%s/train.%s' %(args.data_dir, args.tgt)
    names = ['src', 'tgt']
    paths = [train_src_data_path, train_tgt_data_path]
    if args.replace_unk:
        names.append('almt')
        paths.append('%s/train.align' %(args.data_dir))
    train_corpus = prepare_corpus(names,
                                  paths,
                                  buckets,
                                  max_size=args.max_size,
                                  vocabs=vocabs,
                                  replace_unk=args.replace_unk,
                                  use_morph=args.use_morph)

    dictionary = train_corpus.dictionary
    if args.use_morph:
        dev_src_data_path = '%s/dev.seg.%s' %(args.data_dir, args.src)
    else:
        dev_src_data_path = '%s/dev.%s' %(args.data_dir, args.src)
    dev_tgt_data_path = '%s/dev.%s' %(args.data_dir, args.tgt)
    if args.DEBUG: # use smaller dev set for debugging
        if not os.path.isfile(dev_src_data_path + '.debug'):
            subprocess.call('head -n 100 %s > %s' %(dev_src_data_path, dev_src_data_path + '.debug'), shell=True)
            subprocess.call('head -n 100 %s > %s' %(dev_tgt_data_path, dev_tgt_data_path + '.debug'), shell=True)
        dev_src_data_path += '.debug'
        dev_tgt_data_path += '.debug'

    dev_corpus = prepare_corpus(['src', 'tgt'],
                                [dev_src_data_path, dev_tgt_data_path],
                                buckets,
                                max_size=args.max_size,
                                use_all=True, # use all data for dev, which means do NOT discard very long sentences
                                vocabs=vocabs,
                                method='src',
                                use_morph=args.use_morph)

    train_set = DataStreamRandom(train_corpus, vocabs=vocabs, **vars(args)) # random batching
    dev_set = DataStream(dev_corpus, vocabs=vocabs, **vars(args)) # no random batching, iterated by length
    trainer = Trainer(model, **vars(args))

    datastate_path = '%s/datastate.pkl' %args.train_dir
    if os.path.isfile(datastate_path):
       trainer.tracker.load(datastate_path)

    trainer.train(train_set, dev_set, tgt_vocab, dictionary=dictionary)

def test(args):
    train_src_data_path = '%s/train.%s' %(args.data_dir, args.src)
    train_tgt_data_path = '%s/train.%s' %(args.data_dir, args.tgt)
    names = ['src', 'tgt']
    paths = [train_src_data_path, train_tgt_data_path]
    if args.replace_unk:
        names.append('almt')
        paths.append('%s/train.align' %(args.data_dir))
    if args.use_morph:
        names.append('morph')
        paths.append('%s/seg.%s' %(args.data_dir, args.src))
    train_corpus = prepare_corpus(names,
                                  paths,
                                  buckets,
                                  max_size=args.max_size,
                                  vocabs=vocabs,
                                  replace_unk=args.replace_unk)

    dictionary = train_corpus.dictionary

    test_src_data_path = '%s/test.%s' %(args.data_dir, args.src)
    #test_tgt_data_path = '%s/test.%s' %(args.data_dir, args.tgt)
    if args.test_path is not None:
        test_src_data_path = '%s.%s' %(args.test_path, args.src)
        #test_tgt_data_path = '%s.%s' %(args.test_path, args.tgt)
    else:
        test_src_data_path = '%s/test.%s' %(args.data_dir, args.src)
        #test_tgt_data_path = '%s/test.%s' %(args.data_dir, args.tgt)

    test_corpus = prepare_corpus(['src'], [test_src_data_path], buckets, vocabs={'src': vocabs['src']}, use_all=True, method='src')
    test_set = DataStream(test_corpus, vocabs=vocabs, **vars(args))

    model.eval()
    translations = dict()
    alignments = dict()
    start = time.time()
    for b, batch in enumerate(test_set, 1):
        print('\rbatch %d: %.4fs' %(b, time.time() - start), end='')
        sys.stdout.flush()

        preds, alignments, _ = model.search(batch)
        translate_(translations, preds, batch, vocabs['tgt'], src_tokens=batch.src_tokens, dictionary=dictionary, alignments=alignments)
    print()
    bleu_test(translations, test_set, args.bleu_path, gold_path=None) # NOTE no bleu evaluation for test

def init_params(model):
    for p in model.state_dict().itervalues():
        nn.init.uniform(p, a=-0.08, b=0.08)
    for name, p in model.named_parameters():
        if 'bias_ih' in name or 'bias_hh' in name:
            size = p.size(0)
            ind = torch.arange(size // 4, size // 2).long()
            p.data[ind] = 1.0

def load_params(load_path, model):
    saved_dict = torch.load(load_path, map_location=lambda storage, loc: storage)
    state_dict = model.state_dict()
    # NOTE only update params existent in model
    for k in saved_dict:
        if k in state_dict:
            state_dict[k] = saved_dict[k]
    model.load_state_dict(state_dict)
    print('Loaded parameters from %s' %load_path)

def parse_args():
    parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument('mode', type=str, help='mode')
    parser.add_argument('data_dir', type=str, help='Data directory')
    parser.add_argument('-DEBUG', action='store_true', help='Debug mode')
    parser.add_argument('--seed', default=1234, type=int, help='Random seed')
    parser.add_argument('-random', '-r', action='store_true', help='use random random seed')
    parser.add_argument('-cuda', '-c', action='store_true', help='Use cuda')
    parser.add_argument('--beam_width', '-bw', default=1, type=int, help='Beam width', metavar='')
    parser.add_argument('-replace_unk', '-ru', action='store_true', help='Replace unknown tokens')
    # arguments for training
    train_group = parser.add_argument_group('Train')
    train_group.add_argument('--num_epochs', '-ne', default=50, type=int, help='Number of epochs', metavar='')
    train_group.add_argument('--batch_size', '-bs', default=64, type=int, help='Batch size', metavar='')
    train_group.add_argument('--max_length', '-ml', default=100, type=int, help='Maximum sequence length', metavar='')
    train_group.add_argument('--max_size', '-ms', default=0, type=int, help='Maximum training data size', metavar='')
    train_group.add_argument('--check_frequency', '-cf', default=100, type=int, help='How ofter to check progress', metavar='')
    train_group.add_argument('--validate_frequency', '-vf', default=0, type=int, help='How ofter to validate', metavar='')
    train_group.add_argument('--msg', '-M', type=str, help='Message', metavar='')
    train_group.add_argument('--lr_init', default=0.0005, type=float, help='Initial learning rate', metavar='')
    train_group.add_argument('--dropout', '-do', default=0.5, type=float, help='dropout rate', metavar='')
    train_group.add_argument('--src', '-s', default='de', type=str, help='Source language', metavar='')
    train_group.add_argument('--tgt', '-t', default='en', type=str, help='Target language', metavar='')
    train_group.add_argument('--model_path', '-mp', type=str, help='Path to trained model', metavar='')
    # arguments for testing
    test_group = parser.add_argument_group('Test')
    test_group.add_argument('--test_path', '-tp', help='test path', metavar='')
    # arguments for model
    model_group = parser.add_argument_group('Model')
    model_group.add_argument('--cell_dim', '-cd', default=256, type=int, help='Cell dimensionality', metavar='')
    model_group.add_argument('--num_layers', '-nl', default=1, type=int, help='Number of layers', metavar='')
    model_group.add_argument('--src_vocab_size', '-svs', default=30000, type=int, help='Vocabulary size for source language', metavar='')
    model_group.add_argument('--tgt_vocab_size', '-tvs', default=15000, type=int, help='Vocabulary size for target language', metavar='')
    model_group.add_argument('-use_morph', '-um', action='store_true', help='Use morpheme embeddings')

    args = parser.parse_args()

    if args.cuda:
        os.environ['USE_CUDA'] = '1'

    if args.DEBUG:
        args.batch_size = 32
        args.max_size = 10000
        args.cell_dim = 100
        args.src_vocab_size = 500
        args.tgt_vocab_size = 500

    assert args.mode in ['train', 'test'], args.mode

    # set up training directory and temporary files
    now = datetime.now()
    date = now.strftime("%m-%d")
    timestamp = now.strftime("%H:%M:%S")
    if not args.msg:
        args.train_dir = 'train/%s/%s' %(date, timestamp)
    else:
        args.train_dir = 'train/%s/%s-%s' %(date, args.msg, timestamp)
    if not os.path.isdir(args.train_dir):
        os.makedirs(args.train_dir)
    args.bleu_path = '%s/bleu' %args.train_dir

    return args

if __name__ == '__main__':
    args = parse_args()

    buckets = utils.corpus.Buckets(args.max_length, 5)
    sys.stderr = utils.logger.Logger(args.train_dir + '/log')

    src_vocab_path = '%s/vocab.%s' %(args.data_dir, args.src)
    tgt_vocab_path = '%s/vocab.%s' %(args.data_dir, args.tgt)
    src_vocab = utils.vocab.Vocab(src_vocab_path, 0, threshold=2)
    tgt_vocab = utils.vocab.Vocab(tgt_vocab_path, args.tgt_vocab_size, threshold=2, replace_unk=args.replace_unk)
    vocabs = {'src': src_vocab, 'tgt': tgt_vocab}
    if args.use_morph:
        morph_vocab_path = '%s/vocab.seg.%s' %(args.data_dir, args.src)
        utils.vocab.prepare_vocab('%s/train.seg.%s' %(args.data_dir, args.src), morph_vocab_path, 0, morph=True)
        morph_vocab = utils.vocab.Vocab(morph_vocab_path, 0, threshold=2)
        vocabs['morph'] = morph_vocab
        args.morph_vocab_size = len(morph_vocab)

    # change vocab size after thresholdding
    args.src_vocab_size = len(src_vocab)
    args.tgt_vocab_size = len(tgt_vocab)

    if args.mode == 'train':
        model_mod = Seq2Seq
    elif args.mode == 'test':
        model_mod = Searcher
    else:
        raise
    model = model_mod(**vars(args))
    init_params(model)

    # load trained model
    if args.mode == 'test':
        load_params(args.model_path + '/params.best', model)

    if args.cuda:
        print('Getting things set up on gpu...', end='')
        sys.stdout.flush()
        model.cuda()
        print('Done')
    print(pprint.pformat(model), file=sys.stderr)
    print(pprint.pformat(vars(args)), file=sys.stderr)

    if not args.random:
        random.seed(args.seed)
        np.random.seed(args.seed)
        torch.manual_seed(args.seed)
    torch.set_printoptions(precision=4, threshold=50)
    if args.mode == 'train':
        train(args)
    elif args.mode == 'test':
        test(args)


bl_info = {
  "name": "Filter Tracks",
  "author": "Sebastian Koenig, Andreas Schuster",
  "version": (1, 0),
  "blender": (2, 7, 2),
  "location": "Clip Editor > Filter Tracks",
  "description": "Filter out spikes in tracker curves",
  "warning": "",
  "wiki_url": "",
  "tracker_url": "",
  "category": "Movie Tracking"
  }

import bpy
from bpy.props import *
from mathutils import Vector

def log(*args):
  print("".join(map(str, args)))

def get_marker_coordinates_in_pixels(context, track, frame_number):
    width, height = context.space_data.clip.size
    marker = track.markers.find_frame(frame_number)
    return Vector((marker.co[0] * width, marker.co[1] * height))

def marker_velocity(context, track, frame):
    marker_a = get_marker_coordinates_in_pixels(context, track, frame)
    marker_b = get_marker_coordinates_in_pixels(context, track, frame - 1)
    return marker_a - marker_b

def filter_values(threshold, context):
    scene = context.scene
    frame_start = scene.frame_start
    frame_end = scene.frame_end
    clip = context.space_data.clip
    length = clip.frame_duration
    width, height = clip.size
    log("Clip size:", Vector((width, height)))
    log("Clean from frame", frame_start, "to", frame_end, ";", length, "frames")

    bpy.ops.clip.clean_tracks(frames=10, action='DELETE_TRACK')

    tracks_to_clean = []

    for frame in range(frame_start, frame_end):
        log('Frame: ', frame)
        # TODO(sebastian_k): What about frame_start = 0?

        # Find tracks with markers in both this frame and the previous one.
        relevant_tracks = [track for track in clip.tracking.tracks
                           if track.markers.find_frame(frame) and
                              track.markers.find_frame(frame - 1)]

        if not relevant_tracks:
            # log('Skipping frame; no tracks with markers in this and the previous frame')
            continue

        # Get average velocity and deselect track.
        average_velocity = Vector().to_2d()
        for track in relevant_tracks:
            track.select = False
            average_velocity += marker_velocity(context, track, frame)
        average_velocity = average_velocity / float(len(relevant_tracks))

        # log('Average velocity', average_velocity.magnitude)

        # Then find all markers that behave differently than the average.
        for track in relevant_tracks:
            track_velocity = marker_velocity(context, track, frame)
            distance = (average_velocity - track_velocity).magnitude

            # TODO: find a way to exclude foreground markers. something like:
            # if markers are part of the tracks_to_clean list but move very similarly,
            # they are no spikes, but fast moving foreground markers and should be excluded.

            if distance > threshold and not track in tracks_to_clean:
                log('To clean:' , track.name,
                    ', average velocity:', average_velocity.magnitude,
                    'distance:', distance)
                tracks_to_clean.append(track)

    for track in tracks_to_clean:
        track.select = True
    return len(tracks_to_clean)

class CLIP_OT_filter_tracks(bpy.types.Operator):
    bl_idname="clip.filter_tracks"
    bl_label="Filter Tracks"

    @classmethod
    def poll(cls, context):
        sc = context.space_data
        return (sc.type == 'CLIP_EDITOR') and sc.clip

    def execute(self, context):
        num_tracks = filter_values(context.scene.track_threshold, context)
        self.report({"INFO"}, "Identified %d faulty tracks" % num_tracks)
        return {'FINISHED'}

class CLIP_PT_filter_tracks(bpy.types.Panel):
    bl_idname = "clip.filter_track_panel"
    bl_label = "Filter Tracks"
    bl_space_type = "CLIP_EDITOR"
    bl_region_type = "TOOLS"
    bl_category = "Track"

    def draw(self, context):
        layout = self.layout
        scene = context.scene

        layout.operator("clip.filter_tracks")
        layout.prop(scene, "track_threshold")

def register():
    bpy.utils.register_class(CLIP_OT_filter_tracks)
    bpy.utils.register_class(CLIP_PT_filter_tracks)
    bpy.types.Scene.track_threshold = bpy.props.FloatProperty \
      (
        name = "Track Threshold",
        description = "Filter Threshold",
        default = 5.0
      )

def unregister():
    bpy.utils.unregister_class(CLIP_OT_filter_tracks)
    bpy.utils.unregister_class(CLIP_PT_filter_tracks)

if __name__ == "__main__":
    register()


import os
import subprocess

# Get the list of all files tracked by git
git_files = subprocess.check_output(['git', 'ls-files']).decode().splitlines()

# Initialize the tree
tree = {}

# Populate the tree
for file_path in git_files:
    parts = file_path.split('/')
    node = tree
    for part in parts:
        node = node.setdefault(part, {})

# Function to print the tree
def print_tree(tree, prefix=""):
    keys = sorted(tree.keys())
    for key in keys:
        print(f"{prefix}- {key}")
        print_tree(tree[key], prefix + "   ")

# Print the tree
print_tree(tree)