import json

from django.http import JsonResponse

#from manpower.utils.constants import ERROR_DICT

__author__ = 'senthamilarasu'

from rest_framework.response import Response
from rest_framework import status

from street.code_msg import *

# Rest Response for Success
def success_response(code=3000, message='', data={}, status=status.HTTP_200_OK):
    if message == '':
        message = codes_msg[code]

    meta = {
        'status':'success',
        'message': message,
        'code': status
    }
    return Response({'meta':meta, 'data':data}, status=status)

# Rest Response for Fail
def fail_response(error_code, message='', data={}, status=status.HTTP_400_BAD_REQUEST):
    if message == '':
        message = codes_msg[error_code]

    meta = {
        'status':'fail',
        'message': message,
        'code': error_code
    }
    return Response({'meta':meta, 'data':data}, status=status)

def generate_failed_json(error_code, message, status=200, data={}):
    """
    Generates a failure response json message

    :param message:     The message to return as reason for failure
                        :type <type, 'str'>
    :param error_code:  The magical internal error code used by magical to identify and track common
                        known and uncommon unknown errors and or exceptions
                        :type <type, 'str'>
    :param status :     The status code that holds the http status code
    :return:            The collection object that holds the formatted key value collections
                        :type <type, 'dict'>
    """
    failed_json_data = load_failed_json_payload(data, error_code, message)
    failed_json_object = dict()

    failed_json_object['status'] = "fail"
    failed_json_object['message']=message
    failed_json_object['code']=error_code
    #failed_json_object['data']=dict()
    #failed_json_object['data'] = failed_json_data
    return JsonResponse({"meta":failed_json_object})

    #return JsonResponse({"meta":success_json,"data":data},status=status,  safe=False)

def generate_success_message(message,data, status=200):
    """
    Generates successful operation ,json message from the valid json resolvable :param `data`

    This :param `data` is what ends up as the value of the data key of all successful json responses
    this in line with the json schema chosen to represent all magical json responses
    :see http:\\www.jsonapi.com/schema for more information.

    :param data:            The data to be appended as the value of the json response key of the same
                            name i.e. `data`
                            :type <type, 'object'> limited to [str, int, list, None]
    :param code:
    :param message:
    :param status:
    :return success_json:   The fully parsed json response dict, might require additional wrapping by flask
                            json generating header function
                            :type <type, 'collections.OrderedDict'>
    """

    success_json = dict()

    success_json['status'] ='success'
    success_json['message']=message
    success_json['code']=200
    #success_json['data'] = data

    return JsonResponse({"meta":success_json,"data":data},status=status,  safe=False)

def load_failed_json_payload(data={}, error_code="", message=""):
    """
    Generates a failure response json dictionary

    :param message:     The message to return as reason for failure
                        :type <type, 'str'>
    :param error_code:  The magical internal error code used by magical to identify and track common
                        known and uncommon unknown errors and or exceptions
                        :type <type, 'str'>
    :return:            The collection object that holds the formatted key value collections
                        :type <type, 'dict'>
    """
    failed_json_info = dict()
    #failed_json_info['info'] = data
    failed_json_info['code'] = error_code
    failed_json_info['message'] = message
    return failed_json_info

def load_success_json_payload(data ="", code="", message=""):
    """
    Generates a failure response json dictionary

    :param message:     The message to return as reason for failure
                        :type <type, 'str'>
    :param code:  The magical internal code used by magical to identify and track common
                        known and uncommon unknown errors and or exceptions
                        :type <type, 'str'>
    :return:            The collection object that holds the formatted key value collections
                        :type <type, 'dict'>
    """
    success_json_info = dict()
    success_json_info['info'] = data
    success_json_info['code'] = code
    success_json_info['message'] = message
    return success_json_info


import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.metrics import r2_score

df = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/housing/housing.data', header=None, sep='\s+')
df.columns = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV']

X = df[['LSTAT']].values
y = df['MEDV'].values

regr = LinearRegression()

#create polynomial features
quadratic = PolynomialFeatures(degree=2)
cubic = PolynomialFeatures(degree=3)
X_quad = quadratic.fit_transform(X)
X_cubic = cubic.fit_transform(X)

#linear fit
X_fit = np.arange(X.min(), X.max(), 1)[:, np.newaxis]
regr = regr.fit(X, y)
y_lin_fit = regr.predict(X_fit)
linear_r2 = r2_score(y, regr.predict(X))

#quadratic fit
regr = regr.fit(X_quad, y)
y_quad_fit = regr.predict(quadratic.fit_transform(X_fit))
quadratic_r2 = r2_score(y, regr.predict(X_quad))

#cubic fit
regr = regr.fit(X_cubic, y)
y_cubic_fit = regr.predict(cubic.fit_transform(X_fit))
cubic_r2 = r2_score(y, regr.predict(X_cubic))

#plot results
plt.scatter(X, y, label='training points', color='lightgray')
plt.plot(X_fit, y_lin_fit, label=f'linear (d=1), $Rˆ2={linear_r2:.2f}', color='blue', lw=2, linestyle=':')
plt.plot(X_fit, y_quad_fit, label=f'linear (d=2), $Rˆ2={quadratic_r2:.2f}', color='red', lw=2, linestyle='-')
plt.plot(X_fit, y_cubic_fit, label=f'linear (d=3), $Rˆ2={cubic_r2:.2f}', color='green', lw=2, linestyle='--')
plt.xlabel('% lower status of the population [LSTAT]')
plt.ylabel('Price in $1000\'s [MEDV]')
plt.legend(loc='upper right')
plt.show()


from glados.api.shared.dynamic_downloads import jobs
from glados.es.es_properties_configuration import configuration_manager
from glados.api.shared.dynamic_downloads.models import DownloadJobManager
from glados.api.shared.dynamic_downloads.models import DownloadJob
from glados.usage_statistics import glados_server_statistics
import json
import os
from datetime import timezone
import logging
from django.conf import settings

logger = logging.getLogger('django')

def queue_download_job(index_name, raw_query, desired_format, context_id, columns_group='download'):

    columns_to_download = configuration_manager.get_config_for_group(index_name, columns_group)['properties']['default']
    raw_columns_to_download = json.dumps(columns_to_download)
    id_property = configuration_manager.get_id_property_for_index(index_name)

    try:
        download_job = jobs.queue_new_job(
            index_name=index_name,
            raw_columns_to_download=raw_columns_to_download,
            raw_query=raw_query,
            parsed_desired_format=desired_format.upper(),
            context_id=context_id,
            id_property=id_property
        )
    except DownloadJobManager.DownloadJobAlreadyExistsError:
        download_job_manager = DownloadJobManager()
        job_id = download_job_manager.get_download_id(index_name, raw_query, desired_format, context_id)
        download_job = DownloadJob.objects.get(job_id=job_id)

        if download_job.status == DownloadJob.ERROR:
            # if it was in error state, requeue it
            jobs.requeue_job(job_id, 'Job was in error state, queuing again.')

        elif download_job.status == DownloadJob.FINISHED:
            # verify that the job exists and save statistics
            try:
                file_size = os.path.getsize(download_job.file_path)
                glados_server_statistics.record_download(
                    download_id=job_id,
                    time_taken=0,
                    is_new=False,
                    file_size=file_size,
                    es_index=index_name,
                    es_query=raw_query,
                    desired_format=desired_format,
                    total_items=download_job.total_items
                )

            except FileNotFoundError:
                # if for some reason the file is not found. requeue que job
                jobs.requeue_job(job_id, 'File not found, queuing again.')

        elif download_job.status == DownloadJob.DELETING:
            # someone is deleting the job, I just need to wait until it is deleted and then re queue it
            logger.info('job is being deleted! We need to wait until the process finishes')
            if settings.SPAWN_JOBS:
                jobs.wait_until_job_is_deleted_and_requeue.delay(job_id)
            else:
                jobs.wait_until_job_is_deleted_and_requeue(job_id)

    return download_job.job_id

def get_download_status(download_id):

    download_job = DownloadJob.objects.get(job_id=download_id)
    status = download_job.status

    response = {
        'percentage': download_job.progress,
        'status': status
    }

    if status == DownloadJob.FINISHED:
        if download_job.expires is not None:
            expiration_time_str = download_job.expires.replace(tzinfo=timezone.utc).isoformat()
            response['expires'] = expiration_time_str

    return response


import csv
from datetime import datetime
import re
import os

def clear():
    """Function to clear screen as the program runs."""
    if os.name == 'nt':
        os.system('cls')
    else:
        os.system('clear')

def read_file():
    """
    Function to read the csv file and return data as a dictionary, dates being
    the keys and tasks, time, notes are the values.
    {'2017-10-14': [ {'name': 'Task', 'time': '10', 'notes': ''} ]}
    """
    with open("logs.csv", 'r') as csvfile:
        reader = csv.reader(csvfile)
        result = list(reader)
        dictionary = {}
        for i in result[1:]:
            date, task, mins, notes = i[0], i[1], i[2], i[3]
            details = {'Name': task, 'Time': mins, 'Notes': notes}
            if date in dictionary.keys():
                dictionary[date].append(details)
            else:
                dictionary.update({date: [details]})
        return dictionary

def show_options(data):
    """
    Function to display date options after the user input. it's formatted to
    be used after the search logic in each search function.
    """
    indexed = {}
    for i, v in enumerate(data):
        indexed.update({i + 1: v})
    return indexed

def show_options_direct(data):
    """
    Function to display date options after the user input. it's formatted to
    be used after the search logic in each search function.
    """
    indexed = {}
    for i, v in enumerate(data):
        print(i + 1, v)
        indexed.update({i + 1: v})
    return indexed

def show_results(dictionary, selection):
    """
    Function to display results based on the selected date.
    If a date (the key of the dictionary) has more than one entry,
    this function will make sure to provide these options.
    Otherwise, only one result will be shown.
    """
    for key, value in dictionary.items():
        if selection == key:
            for i in value:
                print(key)
                for keys, values in i.items():
                    print(keys, values)
                print('\t')

def show_details(filtered_dictionary):
    """
    After the search results are shown and final selection is made,
    this function organizes the data to be included in the final
    results/details. It's formatted to be used by each search function.
    """
    while True:
        try:
            display_dictionary = show_options(filtered_dictionary.keys())
            index = list(range(1, len(display_dictionary)+1))
            for i in index:
                selection = display_dictionary[i]
                show_results(filtered_dictionary, selection)
        except ValueError:
            print('Sorry, your entry is not valid.\n')
        else:
            break

def read_dates():
    """
    Function to read dates in the csv file and return entries based on the
    date selected by the user. Data is stored as a dictionary, dates being
    the keys.
    """
    dictionary = read_file()
    while True:
        display_dictionary = show_options_direct(dictionary.keys())
        index = int(input("Please select a date to list the details by "
                          "entering its number on the left side:\n"))
        if 0 < index <= len(display_dictionary):
            selection = display_dictionary[index]
            show_results(dictionary, selection)
        else:
            raise ValueError
        show_details(dictionary)
        prompt = (input('\nPress any letter to go back to the main menu or '
                        'R to return to selection screen.\n')).upper()
        if prompt == 'R':
            continue
        else:
            break

def read_time():
    """
    Function to run the search logic to find entries by time. The search
    logic filters the data and stores it in a variable called
    'filtered_dictionary', to be passed to the function 'show_details' to list
    the details.
    """
    while True:
        dictionary = read_file()
        match = []
        try:
            user_input = int(input("Enter the total amount of minutes spent "
                                   "to list associated tasks:\n"))
            search = str(user_input)
            if user_input > 0:
                for key, value in dictionary.items():
                    for v in value:
                        if v['Time'] == search:
                            match.append(key)
                if len(match) == 0:
                    print("Sorry, we couldn't find any entry.\n")
                else:
                    filtered_dictionary = dict(
                        (k, dictionary[k]) for k in match if k in dictionary)
                    for v in filtered_dictionary.values():
                        for i in v:
                            if i['Time'] != search:
                                v.remove(i)
                    show_details(filtered_dictionary)
            else:
                raise ValueError
        except ValueError:
            print('Sorry, your entry is not valid.\n')
        else:
            break

def read_string():
    """
    Function to run the search logic to find entries by exact match.
    The search logic filters the data and stores it in a variable called
    'filtered_dictionary', then passed to the function 'show_details' to list
    the details.
    """
    dictionary = read_file()
    results = {}
    search = str(input("Enter a keyword to search for a specific task or "
                       "note:\n")).lower()
    for key, value in dictionary.items():
        for v in value:
            if search in (v['Name']).lower():
                if key in results:
                    results[key].append(v)
                else:
                    results.update({key: [v]})
            if search in (v["Notes"]).lower():
                if key in results:
                    results[key].append(v)
                else:
                    results.update({key: [v]})
    if len(results) == 0:
        print("Sorry, no entry found.\n")
    show_details(results)

def read_pattern():
    """
    Function to run the search logic to find entries by pattern.
    The search logic filters the data and stores it in a variable called
    'filtered_dictionary', then passed to the function 'show_details' to list
    the details.
    """
    while True:
        dictionary = read_file()
        filtered = []
        try:
            search = str(input("Please enter a pattern (e.g. \w).\n"))
            for key, value in dictionary.items():
                for v in value:
                    match_name = re.findall(search, v['Name'])
                    match_notes = re.findall(search, v['Notes'])
                    if match_name or match_notes:
                        filtered.append(key)
            if len(filtered) == 0:
                print("Sorry, no entry found.\n")
                break
            filtered_dictionary = dict(
                (k, dictionary[k]) for k in filtered if k in dictionary)
            for v in filtered_dictionary.values():
                for i in v:
                    match_name = re.findall(search, i['Name'])
                    match_notes = re.findall(search, i['Notes'])
                    if not match_name or not match_notes:
                        v.remove(i)
            show_details(filtered_dictionary)
        except ValueError:
            print('Sorry, your entry is not valid.\n')
        else:
            break

def write_file():
    """Function to enter a new log to the csv file and make sure the user
    input is in the required format."""
    with open("logs.csv", 'a', newline='') as csvfile:
        writer = csv.writer(csvfile)
        while True:
            try:
                date_input = (datetime.strptime(input(
                    'Enter a date (MM/DD/YYYY).\n'), '%m/%d/%Y')).date()
                task_input = str(input('Enter the name of the task.\n'))
                time_input = int(input('Enter minutes spent:\n'))
                if time_input > 0 and len(task_input) > 0:
                    notes_input = str(input('Enter any additional notes:\n'))
                    writer.writerow(
                        [date_input, task_input, time_input, notes_input])
                    print('Entry recorded.\n')
            except ValueError:
                print("Sorry, not a valid entry.\n")
            else:
                break


import os
from glob import glob
from sklearn.metrics import confusion_matrix
from sklearn.metrics import classification_report
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from keras.utils.np_utils import to_categorical # convert to one-hot-encoding
import keras
import functools
from keras.preprocessing.image import ImageDataGenerator
from keras import layers
from  keras.layers import Conv2D,Concatenate,UpSampling2D, AveragePooling2D,GlobalAveragePooling2D
from keras import Model
from keras.applications.vgg16 import VGG16, preprocess_input

from keras.optimizers import Adam
from keras.callbacks import ReduceLROnPlateau, EarlyStopping,ModelCheckpoint

import tensorflow
import matplotlib.pyplot as plt
from keras.callbacks import TensorBoard

tensorboard = TensorBoard(log_dir='./logs', histogram_freq=0,
                          write_graph=True, write_images=False)

X_train = np.load("D:/AI in medicine/final_project_mobilenet/256_192_train.npy")
y_train = np.load("D:/AI in medicine/final_project_mobilenet/train_labels.npy")
X_val = np.load("D:/AI in medicine/final_project_mobilenet/256_192_val.npy")

y_val = np.load("D:/AI in medicine/final_project_mobilenet/val_labels.npy")
print(type(X_train))
print(X_train.shape, X_val.shape)
print(y_train.shape, y_val.shape)

y_train = to_categorical(y_train)
y_val = to_categorical(y_val)
print(y_train.shape, y_val.shape)
pre_trained_model = VGG16(input_shape=(192, 256, 3), include_top=False, weights="imagenet")
for layer in pre_trained_model.layers:
    print(layer.name)
    layer.trainable = False

print(len(pre_trained_model.layers))

last_layer = pre_trained_model.get_layer('block5_pool')
print('last layer output shape:', last_layer.output_shape)
last_output = last_layer.output

# Flatten the output layer to 1 dimension
x = layers.GlobalMaxPooling2D()(last_output)
# Add a fully connected layer with 512 hidden units and ReLU activation

x = layers.Dense(512, activation='relu')(x)
# Add a dropout rate of 0.5
x = layers.Dropout(0.5)(x)

# Add a final sigmoid layer for classification
x = layers.Dense(7, activation='softmax')(x)
print("x",x.shape)
# Configure and compile the model

top3_acc = functools.partial(keras.metrics.top_k_categorical_accuracy, k=3)

top3_acc.__name__ = 'top3_acc'

model = Model(pre_trained_model.input, x)
optimizer = Adam(lr=0.0001, beta_1=0.9, beta_2=0.999, epsilon=None, decay=0.0, amsgrad=True)
model.compile(loss='categorical_crossentropy',
              optimizer=optimizer,
              metrics=['accuracy','top_k_categorical_accuracy',top3_acc])

model.summary()

train_datagen = ImageDataGenerator(rotation_range=60, width_shift_range=0.2, height_shift_range=0.2,
                                   shear_range=0.2, zoom_range=0.2, fill_mode='nearest')

train_datagen.fit(X_train)

val_datagen = ImageDataGenerator()
val_datagen.fit(X_val)

batch_size = 32
epochs = 1
history = model.fit_generator(train_datagen.flow(X_train,y_train, batch_size=batch_size),
                              epochs = epochs, validation_data = val_datagen.flow(X_val, y_val),
                              verbose = 1, steps_per_epoch=(X_train.shape[0] // batch_size),
                              validation_steps=(X_val.shape[0] // batch_size))

model.summary()
'''for layer in model.layers:
    layer.trainable = True
'''
for layer in model.layers[0:1]:
    layer.trainable = True

for layer in model.layers[1:3]:
    layer.trainable = Conv2D(64, (3, 3), dilation_rate=(1,1),activation="relu",padding="same")
for layer in model.layers[3:4]:
    layer.trainable = True
for layer in model.layers[4:6]:
    layer.trainable = Conv2D(128, (3, 3), dilation_rate=(2,2),activation="relu")
for layer in model.layers[6:7]:
    layer.trainable = True
for layer in model.layers[7:10]:
    layer.trainable = Conv2D(256, (3, 3), dilation_rate=(4,4),activation="relu")
for layer in model.layers[10:11]:
    layer.trainable = True
for layer in model.layers[11:14]:
    layer.trainable = Conv2D(512, (3, 3), dilation_rate=(8,8),activation="relu")
for layer in model.layers[14:15]:
    layer.trainable = True
for layer in model.layers[15:18]:
    layer.trainable = Conv2D(512, (3, 3), dilation_rate=(16,16),activation="relu")
for layer in model.layers[18:]:
    layer.trainable = True

optimizer = Adam(lr=0.0001, beta_1=0.9, beta_2=0.999, epsilon=None, decay=0.0, amsgrad=False)
model.compile(loss='categorical_crossentropy',
              optimizer=optimizer,
              metrics=['acc','top_k_categorical_accuracy',top3_acc])
model.summary()
model.count_params()
save_best = ModelCheckpoint(filepath='D:/AI in medicine/final_project_mobilenet/vgg16/checkpoint-{val_acc:.4f}.h5',monitor='val_acc',mode='auto',save_best_only=True)
learning_rate_reduction = ReduceLROnPlateau(monitor='val_loss', patience=7, verbose=1, factor=np.sqrt(0.1),
                                            min_lr=0.5e-6, cooldown=0,mode='auto')
callbacks=[learning_rate_reduction,tensorboard,save_best]

batch_size = 32
epochs = 200
history = model.fit_generator(train_datagen.flow(X_train,y_train, batch_size=batch_size),
                              epochs = epochs, validation_data = val_datagen.flow(X_val, y_val),
                              verbose = 1, steps_per_epoch=(X_train.shape[0] // batch_size),
                              validation_steps=(X_val.shape[0] // batch_size), callbacks=callbacks)

loss_val, acc_val,top5,top3 = model.evaluate(X_val, y_val, verbose=1)
print("Validation: accuracy = %f  ;  loss_v = %f" % (acc_val, loss_val))
print('top5 validate accuracy: ',top5)
print('top3 validate accuracy: ',top3)

X_test = np.load("D:/AI in medicine/final_project_mobilenet/256_192_test.npy")
y_test = np.load("D:/AI in medicine/final_project_mobilenet/test_labels.npy")
print("1st y_test",y_test)
target_names = ['Actinic keratoses', 'Basal cell carcinoma', 'Benign_keratosis-like_lesions', 'Dermatofibroma', 'Melanocytic Nevi', 'Vascular_lesions', 'Melanoma']
print("1st y_test",y_test, y_test.shape)
y_pred = model.predict(X_test)
print("4th y_pred",y_pred,y_pred.shape)
y_classes = y_pred.argmax(axis=-1)
print("5th y_pred",y_classes,y_classes.shape)
print(classification_report(y_test, y_classes, target_names=target_names))
y_test = to_categorical(y_test)
print("2nd y_test",y_test)

loss_test, acc_test,top5,top3 = model.evaluate(X_test, y_test, verbose=1)
print("Test: accuracy = %f  ;  loss = %f" % (acc_test, loss_test))
print("top5 test accuracy: ",top5)
print("top3 test accuracy: ",top3)

pre=model.predict(X_test,verbose=1)
print("pre",pre)
n_values=7
c = np.eye(n_values, dtype=int)[np.argmax(pre, axis=1)]
print('one-hot-encoding',c)
cm = confusion_matrix(y_test.argmax(axis=1), c.argmax(axis=1))
print("confusion matrix",cm)
cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
print('new_cm',cm)
print('acc',cm.diagonal())
model.save("VGG16.h5")
# Retrieve a list of accuracy results on training and test data
# sets for each training epoch
acc = history.history['acc']
val_acc = history.history['val_acc']

# Retrieve a list of list results on training and test data
# sets for each training epoch
loss = history.history['loss']
val_loss = history.history['val_loss']

# Get number of epochs
epochs = range(len(acc))

# Plot training and validation accuracy per epoch
plt.plot(epochs, acc, label = "training")
plt.plot(epochs, val_acc, label = "validation")
plt.legend(loc="upper left")
plt.title('Training and validation accuracy')
plt.show()
plt.figure()

# Plot training and validation loss per epoch
plt.plot(epochs, loss, label = "training")
plt.plot(epochs, val_loss, label = "validation")
plt.legend(loc="upper right")
plt.title('Training and validation loss')
plt.show()


import re
import pymorphy2
from bs4 import BeautifulSoup as bs

morph = pymorphy2.MorphAnalyzer()

def get_sample():
    with open('sample.xml', 'r', encoding='utf8') as inf:
        return bs(inf.read(), 'html.parser')

def lemmatize_texts(text):
    global morph
    texts = []
    for sentence in text:
        s = []
        word_list = re.sub('[».,«:;"%—!?)(]|\W-\W', '', sentence.strip().lower()).split()
        for word in word_list:
            p = morph.parse(word)[0]
            try:
                s.append(p.normal_form + '_' + p.tag.POS)
            except TypeError:
                s.append(word)
        texts.append(' '.join(s))
    return texts

def splitter(doc):
    return doc.split()


import csv, sys, os
import pandas as pd

project_dir = "/Users/colton_proctor/Desktop/seniorProject/mySite"

sys.path.append(project_dir)

os.environ['DJANGO_SETTINGS_MODULE']='mySite'

import django
django.setup()

from main.models import Property

data = pd.read_csv('/Users/colton_proctor/Desktop/seniorProject/mySite/db.csv') #,delimiter="|")
#data = csv.reader(open('/Users/cohen/my-python-project/venv/ofac/ofac_project/ofac_sdn/sdn2.csv'), dialect='excel-tab')
for index, row in data.iterrows():
        property = Property()
        property.state = row[0]
        property.recorded = row[1]
        property.date = row[2]
        property.grantor = row[3]
        property.address = row[4]
        property.city = row[5]
        property.grantee = row[6]
        property.price = row[7]
        property.propType = row[8]
        property.built = row[9]
        property.acreage = row[10]
        property.impsq = row[11]
        property.units = row[12]
        property.landsq = row[13]
        property.sfimp = row[14]
        property.unitimp = row[15]
        property.sfland = row[16]
        property.garage = row[17]
        property.caprate = row[18]
        property.noi = row[19]
        property.exp = row[20]
        property.egi = row[21]
        property.occup = row[22]
        property.corner = row[23]
        property.regshape = row[24]
        property.utilities = row[25]
        property.location = row[26]
        property.quality = row[27]
        property.condition = row[28]
        property.description = row[29]
        property.comments = row[30]
        property.save()


import random
import string
import serial
import time

'''SET UP'''
#PORTS
#port = '/dev/tty.usbserial-A1014XTT' #NANO
#port = '/dev/tty.usbserial-AM01VG4I'
#port = '/dev/cu.usbmodem1421'

port = '/dev/tty.usbserial-AL00U150' #USB
#port = '/dev/tty.hapticJacket3-DevB'#BT
#port = '/dev/tty.BlueSmirf1-RNI-SPP' #BT BlueSmirf

#BAUD
baud = 57600

#Serial
ser = serial.Serial(port, baud)

if ser.isOpen():
    ser.close()

print("Connecting to jacket at port %s (baud: %d)" %(port,baud))
ser.open()
print("Serial established")

print('FROM CONNECTION:')
print(ser.inWaiting())
print(ser.read(ser.inWaiting()))

#print(b)

'''FUNCTIONS'''

# def frombits(bits):
#     chars = []
#     for b in range(len(bits) / 8):
#         byte = bits[b*8:(b+1)*8]
#         chars.append(chr(int(''.join([str(bit) for bit in byte]), 2)))
#     return ''.join(chars)
# s = frombits(b)

'''Packets'''
packets = []
for i in xrange(48):
    packets += ['#%d %d$' %(i, 100)]
    # packets += ['#%d %d$' %(i, 500)]
    # packets += ['#%d %d$' %(i, 1000)]

freq = 1

'''LOOP'''
while(True):
	for packet in packets:
		ser.write(packet)
		print(ser.read())
		time.sleep(1.0/freq)

	# ser.close()


# from selenium import webdriver
# import time
#
# browser = webdriver.Chrome()
# browser.implicitly_wait(5)
# browser.get("http://suninjuly.github.io/wait1.html")
#
#
# button = browser.find_element_by_id("verify")
# button.click()
# message = browser.find_element_by_id("verify_message")
#
# assert "successful" in message.text

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium import webdriver

import math

def calc(x):
    return str(math.log(abs(12*math.sin(int(x)))))

link = "http://suninjuly.github.io/explicit_wait2.html"
browser = webdriver.Chrome()
browser.get(link)

button = WebDriverWait(browser, 12).until(
        EC.text_to_be_present_in_element((By.ID, "price"), "$100")
    )
button = browser.find_element_by_class_name("btn-primary")
button.click()

x_element = browser.find_element_by_id("input_value")
x = x_element.text
y = calc(x)

input1 = browser.find_element_by_id("answer")
input1.send_keys(y)

btn = browser.find_element_by_id("solve")
btn.click()

browser.quit()


import time
import sys
import logging
from threading import Event, Thread, Lock
from queue import Queue, PriorityQueue, Empty
from urllib.parse import urlsplit
from traceback import format_exception
from collections import defaultdict
from copy import deepcopy
from datetime import datetime
from uuid import uuid4
from typing import cast, MutableMapping, Union

from bson import json_util as json

from .util import Pause

# from .loop import MultiCurlLoop
from .network_service import NetworkService
from .stat import Stat
from .request import Request, CallbackRequest, BaseRequest
from .error import get_error_tag, collect_error_context, DataNotValid, IowebConfigError
from .error_logger import ErrorLogger
from .proxylist import ProxyList

class Crawler(object):
    _taskgen_sleep_time = 0.01
    dataop_threshold_default = {
        "number": 500,
        "size": None,
        #'time': None,
    }
    dataop_threshold: MutableMapping[
        str, MutableMapping[str, Union[int, float, None]]
    ] = {}
    network_service_class = NetworkService

    def task_generator(self):
        if False:  # pylint: disable=using-constant-test
            yield None

    def __init__(
        self,
        network_threads=3,
        result_workers=4,
        num_task_generators=1,
        retry_limit=3,
        extra_data=None,
        stop_on_handler_error=False,
        debug=False,
        stat_logging=True,
        stat_logging_format="text",
        master_taskq=None,
    ):
        self.uuid = uuid4().hex
        logging.debug("Session ID: %s", self.uuid)
        if extra_data is None:
            self.extra_data = {}
        else:
            self.extra_data = deepcopy(extra_data)
        self.taskq = PriorityQueue()
        self.taskq_size_limit = max(100, network_threads * 2)
        self.resultq = Queue()
        self.shutdown_event = Event()
        self.fatal_error_happened = Event()
        self.retry_limit = retry_limit
        self.stat = Stat(
            speed_keys="crawler:request-processed",
            logging_enabled=stat_logging,
            logging_format=stat_logging_format,
        )
        self.fatalq = Queue()
        self.network = self.network_service_class(
            self.taskq,
            self.resultq,
            fatalq=self.fatalq,
            threads=network_threads,
            shutdown_event=self.shutdown_event,
            setup_request_hook=self.setup_request_hook,
            setup_request_proxy_hook=self.setup_request_proxy_hook,
            prepare_response_hook=self.prepare_response_hook,
            stat=self.stat,
        )
        self.result_workers = result_workers
        self.run_started = None

        self.dataopq = {}
        self.dataop_lock = defaultdict(Lock)
        self.dataop_counters = defaultdict(
            lambda: {
                "number": 0,
                "size": 0,
            }
        )
        self.error_logger = ErrorLogger()
        self.stop_on_handler_error = stop_on_handler_error
        self.proxylist = None
        self.debug = debug
        self.num_task_generators = num_task_generators
        self.master_taskq_cfg = master_taskq

        self.init_hook()

    @classmethod
    def update_arg_parser(cls, parser):
        for key, config in cls.extra_cli_args().items():
            parser.add_argument("--extra-%s" % key, **config)

    @classmethod
    def extra_cli_args(cls):
        return {}

    def load_proxylist(self, list_type, list_location, **kwargs):
        self.proxylist = ProxyList.create_from_source(
            list_type, list_location, **kwargs
        )

    def is_dataopq_dump_time(self, name):
        to_dump = False
        try:
            number_th = self.dataop_threshold[name]["number"]
        except KeyError:
            number_th = self.dataop_threshold_default["number"]
        if number_th:
            if self.dataop_counters[name]["number"] >= number_th:
                to_dump = True
        if not to_dump:
            try:
                size_th = self.dataop_threshold[name]["size"]
            except KeyError:
                size_th = self.dataop_threshold_default["size"]
            if size_th:
                if self.dataop_counters[name]["size"] >= size_th:
                    to_dump = True
        return to_dump

    def enq_dataop(self, name, op, size=None, force_dump=False):
        if op:
            self.enq_dataop_hook(name, op)
        self.dataop_lock[name].acquire()
        released = False
        try:
            self.dataopq.setdefault(name, [])
            if op:
                self.dataopq[name].append(op)
                self.dataop_counters[name]["number"] += 1
                if size:
                    self.dataop_counters[name]["size"] += size

            if force_dump or self.is_dataopq_dump_time(name):
                # logging.debug('Dumping data ops')
                self.stat.inc("dataop-dump-%s" % name)
                ops = self.dataopq[name]
                if ops:
                    self.dataopq[name] = []
                    self.dataop_counters[name]["number"] = 0
                    self.dataop_counters[name]["size"] = 0
                    # release as soon as possible
                    self.dataop_lock[name].release()
                    released = True
                    func = getattr(self, "dataop_handler_%s" % name)
                    func(ops)
                else:
                    self.dataop_lock[name].release()
                    released = True
        finally:
            if not released:
                self.dataop_lock[name].release()

    def enq_dataop_hook(self, name, op):
        pass

    def init_hook(self):
        pass

    def prepare_response_hook(self, transport, req, res, urllib3_response):
        pass

    def setup_request_proxy_hook(self, unused_transport, req):
        if self.proxylist:
            proxy = self.proxylist.random_server()
            req.setup(
                proxy=proxy.address(),
                proxy_auth=proxy.auth(),
                proxy_type=proxy.proxy_type,
            )
            # If requst is configured to not close connection (default)
            # and proxylist requires to close connection
            # then update request config
            if not req["close_connection"] and self.proxylist.close_connection:
                req.setup(close_connection=True)

    def setup_request_hook(self, transport, req):
        pass

    def submit_task(self, req):
        self.submit_task_hook(req)
        self.taskq.put((req.priority, req))

    def submit_task_hook(self, req):
        pass

    def task_generator_master(self):
        cfg = self.master_taskq_cfg
        if not cfg:
            raise IowebConfigError("Master task queue is not configured")
        backend_id = cfg.pop("backend", None)
        if backend_id not in ("redis",):
            raise IowebConfigError("Invalid master task queue backend: %s" % backend_id)
        # Redis specific things
        # TODO: move into backend class
        taskq_id = cfg.pop("taskq_id", None)
        if not taskq_id:
            raise IowebConfigError("Invalid queue ID: %s" % taskq_id)
        from redis import Redis  # pylint: disable=import-outside-toplevel

        rdb = Redis(decode_responses=True, **cfg)
        none_task_time = time.time()
        while True:
            task = rdb.lpop(taskq_id)
            if task is None:
                if time.time() - none_task_time > 5:
                    none_task_time = time.time()
                    self._flush_dataops()
                time.sleep(0.01)
            else:
                task = json.loads(task)
                if "$op" in task:
                    if task["$op"] == "shutdown":
                        return
                    else:
                        raise IowebConfigError(
                            "Got invalid $op from master taskq queue: %s" % task["$op"]
                        )
                else:
                    req = Request.from_data(task)
                    yield req

    def thread_task_generator(self):
        try:
            try:
                if self.master_taskq_cfg:
                    tgen_iter = self.task_generator_master()
                else:
                    tgen_iter = iter(self.task_generator())
            except TypeError:
                return
            else:
                for item in tgen_iter:
                    while item:
                        if self.shutdown_event.is_set():
                            return
                        if self.taskq.qsize() >= self.taskq_size_limit:
                            time.sleep(self._taskgen_sleep_time)
                        else:
                            self.submit_task(item)
                            item = None
        except (Exception, KeyboardInterrupt):  # pylint: disable=broad-except
            self.fatalq.put((sys.exc_info(), None))

    def is_result_ok(self, req, res):
        if res.error:
            return False
        elif isinstance(req, CallbackRequest):
            return True
        elif (
            0 < res.status < 400
            or res.status == 404
            or (
                req.config["extra_valid_status"]
                and res.status in req.config["extra_valid_status"]
            )
        ):
            return True
        else:
            return False

    def thread_result_processor(self, pause):
        error_ctx = None
        try:
            while not self.shutdown_event.is_set():
                if pause.pause_event.is_set():
                    pause.process_pause()
                try:
                    result = self.resultq.get(True, 0.1)
                except Empty:
                    pass
                else:
                    self.stat.inc("crawler:request-processed")
                    try:
                        if result["request"]["raw"] or self.is_result_ok(
                            result["request"],
                            result["response"],
                        ):
                            self.process_ok_result(result)
                        else:
                            self.process_fail_result(result)
                    except Exception:
                        error_ctx = collect_error_context(result["request"])
                        raise
        except (KeyboardInterrupt, Exception):  # pylint: disable=broad-except
            self.fatalq.put((sys.exc_info(), error_ctx))

    def thread_fatalq_processor(self):
        try:
            while not self.shutdown_event.is_set():
                try:
                    exc_info, ctx = self.fatalq.get(True, 0.1)
                except Empty:
                    pass
                else:
                    self.shutdown_event.set()
                    self.fatal_error_happened.set()
                    logging.error("Fatal exception")
                    if ctx:
                        logging.error("Exception context:")
                        for key, val in sorted(ctx.items(), key=lambda x: x[0]):
                            logging.error(" * %s: %s", key, val)
                    else:
                        logging.error("Exception context: N/A")
                    logging.error("".join(format_exception(*exc_info)))
                    if not isinstance(exc_info[1], KeyboardInterrupt):
                        self.log_error(exc_info, ctx)
        except Exception:
            self.shutdown_event.set()
            raise

    def log_error(self, exc_info, ctx=None):
        ctx = ctx or {}
        ctx.update(
            {
                "crawler_id": self.__class__.__name__,
                "date": datetime.utcnow().isoformat(),
            }
        )
        self.error_logger.log_error(exc_info, ctx)

    def thread_manager(self, task_gens, pauses):
        try:
            for th in task_gens:
                th.join()

            def system_is_busy():
                return (
                    self.taskq.qsize()
                    or self.resultq.qsize()
                    or len(self.network.active_handlers)
                )

            while not self.shutdown_event.is_set():
                while system_is_busy():
                    if self.shutdown_event.is_set():
                        return
                    time.sleep(0.1)

                for pause in pauses:
                    pause.pause_event.set()
                ok = True
                for pause in pauses:
                    if not pause.is_paused.wait(0.1):
                        ok = False
                        break
                if not ok:
                    for pause in pauses:
                        pause.pause_event.clear()
                        pause.resume_event.set()
                else:
                    if not system_is_busy():
                        for pause in pauses:
                            pause.pause_event.clear()
                            pause.resume_event.set()
                        self.shutdown_event.set()
                        return
                    else:
                        for pause in pauses:
                            pause.pause_event.clear()
                            pause.resume_event.set()
        except (KeyboardInterrupt, Exception):  # pylint: disable=broad-except
            self.fatalq.put((sys.exc_info(), None))

    def process_ok_result(self, result):
        self.stat.inc("crawler:request-ok")
        name = result["request"].config["name"]
        handler = getattr(self, "handler_%s" % name)
        try:
            handler_result = handler(
                result["request"],
                result["response"],
            )
            try:
                iter(handler_result)
            except TypeError:
                pass
            else:
                for item in handler_result:
                    if isinstance(item, BaseRequest):
                        self.submit_task(item)
                    else:
                        raise Exception("Handler yielded non request task: %s" % item)
        except Exception as ex:  # pylint: disable=broad-except
            self.stat.inc("result-handler-error:%s" % get_error_tag(ex))
            if isinstance(ex, DataNotValid):
                self.process_fail_result(result)
            else:
                if self.stop_on_handler_error:
                    raise
                else:
                    logging.exception("Error in result handler")
                    ctx = collect_error_context(result["request"])
                    self.log_error(sys.exc_info(), ctx)

    def process_fail_result(self, result):
        self.stat.inc("crawler:request-fail")
        req = result["request"]

        if result["response"].error:
            self.stat.inc("network-error:%s" % get_error_tag(result["response"].error))
        if result["response"].status:
            self.stat.inc("http:status-%s" % result["response"].status)

        if req.retry_count + 1 < self.retry_limit:
            self.stat.inc("crawler:request-retry")
            req.retry_count += 1
            req.priority = req.priority - 1
            self.submit_task(req)
        else:
            self.stat.inc("crawler:request-rejected")
            name = result["request"].config["name"]
            handler = getattr(self, "rejected_handler_%s" % name, None)
            if handler is None:
                handler = self.default_rejected_handler
            try:
                handler(result["request"], result["response"])
            except Exception as ex:  # pylint: disable=broad-except
                self.stat.inc("rejected-handler-error:%s" % get_error_tag(ex))
                if self.stop_on_handler_error:
                    raise
                else:
                    logging.exception("Error in rejected result handler")
                    ctx = collect_error_context(req)
                    self.log_error(sys.exc_info(), ctx)

    def default_rejected_handler(self, req, res):
        pass

    def run_hook(self):
        pass

    def thread_debug(self):
        try:
            while not self.shutdown_event.is_set():
                stat = []
                now = time.time()
                for hdl in self.network.active_handlers:
                    stat.append((hdl, self.network.registry[hdl]["start"]))
                with open("var/crawler.debug", "w", encoding="utf-8") as out:
                    for hdl, start in list(
                        sorted(stat, key=lambda x: (x[1] or now), reverse=True)
                    ):
                        req = cast(Request, self.network.registry[hdl]["request"])
                        out.write(
                            "%.2f - [#%s] - %s\n"
                            % (
                                (now - start) if start else 0,
                                req.retry_count if req else "NA",
                                urlsplit(req["url"]).netloc if req else "NA",
                            )
                        )
                    out.write(
                        "Active handlers: %d\n" % len(self.network.active_handlers)
                    )
                    out.write("Idle handlers: %d\n" % len(self.network.idle_handlers))
                    out.write("Taskq size: %d\n" % self.taskq.qsize())
                    out.write("Resultq size: %d\n" % self.resultq.qsize())

                total = 0
                count = 0
                for hdl, start in stat:
                    if start:
                        total += now - start
                        count += 1
                logging.debug(
                    "Median handler time: %.2f", (total / count) if count else 0
                )

                self.shutdown_event.wait(3)
        except (KeyboardInterrupt, Exception):  # pylint: disable=broad-except
            self.fatalq.put((sys.exc_info(), None))

    def thread_network(self):
        try:
            self.network.run()
        except (KeyboardInterrupt, Exception):  # pylint: disable=broad-except
            self.fatalq.put((sys.exc_info(), None))

    def _flush_dataops(self):
        for name in list(self.dataopq.keys()):
            self.enq_dataop(name, None, force_dump=True)

    def shutdown(self):
        self._flush_dataops()
        self.shutdown_hook()
        if self.stat.th_export:
            self.stat.th_export_dump_stat()

    def shutdown_hook(self):
        pass

    def run(self):
        try:
            self.run_hook()
            self.run_started = time.time()

            th_fatalq_proc = Thread(target=self.thread_fatalq_processor)
            th_fatalq_proc.start()

            task_gens = []
            if self.master_taskq_cfg and self.num_task_generators > 1:
                raise IowebConfigError(
                    "num_task_generators must be 1 in" " master task queue mode"
                )
            for _ in range(self.num_task_generators):
                th = Thread(target=self.thread_task_generator)
                th.start()
                task_gens.append(th)

            th_debug = Thread(target=self.thread_debug)
            if self.debug:
                th_debug.start()

            pauses = [x["pause"] for x in self.network.registry.values()]
            result_workers = []
            for _ in range(self.result_workers):
                pause = Pause()
                th = Thread(
                    target=self.thread_result_processor,
                    args=[pause],
                )
                pauses.append(pause)
                th.start()
                result_workers.append(th)

            th_manager = Thread(
                target=self.thread_manager,
                args=[task_gens, pauses],
            )
            th_manager.start()

            th_network = Thread(
                target=self.thread_network,
            )
            th_network.start()

            th_manager.join()
            th_fatalq_proc.join()
            for th in task_gens:
                th.join()
            if self.debug:
                th_debug.join()
            for th in result_workers:
                th.join()

        except (Exception, KeyboardInterrupt):
            self.fatal_error_happened.set()
            raise
        finally:
            self.shutdown_event.set()
            self.shutdown()


from PyQt5 import QtGui, QtCore, QtWidgets
from appGUI.GUIElements import FCTable, FCEntry, FCButton, FCFileSaveDialog

import sys
import webbrowser

from copy import deepcopy
from datetime import datetime
import gettext
import appTranslation as fcTranslate
import builtins

fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__:
    _ = gettext.gettext

class BookmarkManager(QtWidgets.QWidget):

    # mark_rows = QtCore.pyqtSignal()

    def __init__(self, app, storage, parent=None):
        super(BookmarkManager, self).__init__(parent)

        self.app = app

        assert isinstance(storage, dict), "Storage argument is not a dictionary"

        self.bm_dict = deepcopy(storage)

        # Icon and title
        # self.setWindowIcon(parent.app_icon)
        # self.setWindowTitle(_("Bookmark Manager"))
        # self.resize(600, 400)

        # title = QtWidgets.QLabel(
        #     "FlatCAM
"
        # )
        # title.setOpenExternalLinks(True)

        # layouts
        layout = QtWidgets.QVBoxLayout()
        self.setLayout(layout)

        table_hlay = QtWidgets.QHBoxLayout()
        layout.addLayout(table_hlay)

        self.table_widget = FCTable(drag_drop=True, protected_rows=[0, 1])
        self.table_widget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
        table_hlay.addWidget(self.table_widget)

        self.table_widget.setColumnCount(3)
        self.table_widget.setColumnWidth(0, 20)
        self.table_widget.setHorizontalHeaderLabels(
            [
                '#',
                _('Title'),
                _('Web Link')
            ]
        )
        self.table_widget.horizontalHeaderItem(0).setToolTip(
            _("Index.\n"
              "The rows in gray color will populate the Bookmarks menu.\n"
              "The number of gray colored rows is set in Preferences."))
        self.table_widget.horizontalHeaderItem(1).setToolTip(
            _("Description of the link that is set as an menu action.\n"
              "Try to keep it short because it is installed as a menu item."))
        self.table_widget.horizontalHeaderItem(2).setToolTip(
            _("Web Link. E.g: https://your_website.org "))

        # pal = QtGui.QPalette()
        # pal.setColor(QtGui.QPalette.Background, Qt.white)

        # New Bookmark
        new_vlay = QtWidgets.QVBoxLayout()
        layout.addLayout(new_vlay)

        new_title_lbl = QtWidgets.QLabel('%s' % _("New Bookmark"))
        new_vlay.addWidget(new_title_lbl)

        form0 = QtWidgets.QFormLayout()
        new_vlay.addLayout(form0)

        title_lbl = QtWidgets.QLabel('%s:' % _("Title"))
        self.title_entry = FCEntry()
        form0.addRow(title_lbl, self.title_entry)

        link_lbl = QtWidgets.QLabel('%s:' % _("Web Link"))
        self.link_entry = FCEntry()
        self.link_entry.set_value('http://')
        form0.addRow(link_lbl, self.link_entry)

        # Buttons Layout
        button_hlay = QtWidgets.QHBoxLayout()
        layout.addLayout(button_hlay)

        add_entry_btn = FCButton(_("Add Entry"))
        remove_entry_btn = FCButton(_("Remove Entry"))
        export_list_btn = FCButton(_("Export List"))
        import_list_btn = FCButton(_("Import List"))
        # closebtn = QtWidgets.QPushButton(_("Close"))

        # button_hlay.addStretch()
        button_hlay.addWidget(add_entry_btn)
        button_hlay.addWidget(remove_entry_btn)

        button_hlay.addWidget(export_list_btn)
        button_hlay.addWidget(import_list_btn)
        # button_hlay.addWidget(closebtn)
        # ##############################################################################
        # ######################## SIGNALS #############################################
        # ##############################################################################

        add_entry_btn.clicked.connect(self.on_add_entry)
        remove_entry_btn.clicked.connect(self.on_remove_entry)
        export_list_btn.clicked.connect(self.on_export_bookmarks)
        import_list_btn.clicked.connect(self.on_import_bookmarks)
        self.title_entry.returnPressed.connect(self.on_add_entry)
        self.link_entry.returnPressed.connect(self.on_add_entry)
        # closebtn.clicked.connect(self.accept)

        self.ui_connect()
        self.build_bm_ui()

    def ui_connect(self):
        self.table_widget.drag_drop_sig.connect(self.mark_table_rows_for_actions)

    def ui_disconnect(self):
        try:
            self.table_widget.drag_drop_sig.connect(self.mark_table_rows_for_actions)
        except (TypeError, AttributeError):
            pass

    def build_bm_ui(self):

        self.table_widget.setRowCount(len(self.bm_dict))

        nr_crt = 0
        sorted_bookmarks = sorted(list(self.bm_dict.items()), key=lambda x: int(x[0]))
        for entry, bookmark in sorted_bookmarks:
            row = nr_crt
            nr_crt += 1

            title = bookmark[0]
            weblink = bookmark[1]

            id_item = QtWidgets.QTableWidgetItem('%d' % int(nr_crt))
            # id.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
            self.table_widget.setItem(row, 0, id_item)  # Tool name/id

            title_item = QtWidgets.QTableWidgetItem(title)
            self.table_widget.setItem(row, 1, title_item)

            weblink_txt = QtWidgets.QTextBrowser()
            weblink_txt.setOpenExternalLinks(True)
            weblink_txt.setFrameStyle(QtWidgets.QFrame.NoFrame)
            weblink_txt.document().setDefaultStyleSheet("a{ text-decoration: none; }")

            weblink_txt.setHtml('%s' % (weblink, weblink))

            self.table_widget.setCellWidget(row, 2, weblink_txt)

            vertical_header = self.table_widget.verticalHeader()
            vertical_header.hide()

            horizontal_header = self.table_widget.horizontalHeader()
            horizontal_header.setMinimumSectionSize(10)
            horizontal_header.setDefaultSectionSize(70)
            horizontal_header.setSectionResizeMode(0, QtWidgets.QHeaderView.Fixed)
            horizontal_header.resizeSection(0, 20)
            horizontal_header.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents)
            horizontal_header.setSectionResizeMode(2, QtWidgets.QHeaderView.Stretch)

        self.mark_table_rows_for_actions()

        self.app.defaults["global_bookmarks"].clear()
        for key, val in self.bm_dict.items():
            self.app.defaults["global_bookmarks"][key] = deepcopy(val)

    def on_add_entry(self, **kwargs):
        """
        Add a entry in the Bookmark Table and in the menu actions
        :return: None
        """
        if 'title' in kwargs:
            title = kwargs['title']
        else:
            title = self.title_entry.get_value()
        if title == '':
            self.app.inform.emit('[ERROR_NOTCL] %s' % _("Title entry is empty."))
            return 'fail'

        if 'link' in kwargs:
            link = kwargs['link']
        else:
            link = self.link_entry.get_value()

        if link == 'http://':
            self.app.inform.emit('[ERROR_NOTCL] %s' % _("Web link entry is empty."))
            return 'fail'

        # if 'http' not in link or 'https' not in link:
        #     link = 'http://' + link

        for bookmark in self.bm_dict.values():
            if title == bookmark[0] or link == bookmark[1]:
                self.app.inform.emit('[ERROR_NOTCL] %s' % _("Either the Title or the Weblink already in the table."))
                return 'fail'

        # for some reason if the last char in the weblink is a slash it does not make the link clickable
        # so I remove it
        if link[-1] == '/':
            link = link[:-1]
        # add the new entry to storage
        new_entry = len(self.bm_dict) + 1
        self.bm_dict[str(new_entry)] = [title, link]

        # add the link to the menu but only if it is within the set limit
        bm_limit = int(self.app.defaults["global_bookmarks_limit"])
        if len(self.bm_dict) < bm_limit:
            act = QtWidgets.QAction(parent=self.app.ui.menuhelp_bookmarks)
            act.setText(title)
            act.setIcon(QtGui.QIcon(self.app.resource_location + '/link16.png'))
            act.triggered.connect(lambda: webbrowser.open(link))
            self.app.ui.menuhelp_bookmarks.insertAction(self.app.ui.menuhelp_bookmarks_manager, act)

        self.app.inform.emit('[success] %s' % _("Bookmark added."))

        # add the new entry to the bookmark manager table
        self.build_bm_ui()

    def on_remove_entry(self):
        """
        Remove an Entry in the Bookmark table and from the menu actions
        :return:
        """
        index_list = []
        for model_index in self.table_widget.selectionModel().selectedRows():
            index = QtCore.QPersistentModelIndex(model_index)
            index_list.append(index)
            title_to_remove = self.table_widget.item(model_index.row(), 1).text()

            if title_to_remove == 'FlatCAM' or title_to_remove == _('Backup Site'):
                self.app.inform.emit('[WARNING_NOTCL] %s.' % _("This bookmark can not be removed"))
                self.build_bm_ui()
                return
            else:
                for k, bookmark in list(self.bm_dict.items()):
                    if title_to_remove == bookmark[0]:
                        # remove from the storage
                        self.bm_dict.pop(k, None)

                        for act in self.app.ui.menuhelp_bookmarks.actions():
                            if act.text() == title_to_remove:
                                # disconnect the signal
                                try:
                                    act.triggered.disconnect()
                                except TypeError:
                                    pass
                                # remove the action from the menu
                                self.app.ui.menuhelp_bookmarks.removeAction(act)

        # house keeping: it pays to have keys increased by one
        new_key = 0
        new_dict = {}
        for k, v in self.bm_dict.items():
            # we start with key 1 so we can use the len(self.bm_dict)
            # when adding bookmarks (keys in bm_dict)
            new_key += 1
            new_dict[str(new_key)] = v

        self.bm_dict = deepcopy(new_dict)
        new_dict.clear()

        self.app.inform.emit('[success] %s' % _("Bookmark removed."))

        # for index in index_list:
        #     self.table_widget.model().removeRow(index.row())
        self.build_bm_ui()

    def on_export_bookmarks(self):
        self.app.defaults.report_usage("on_export_bookmarks")
        self.app.log.debug("on_export_bookmarks()")

        date = str(datetime.today()).rpartition('.')[0]
        date = ''.join(c for c in date if c not in ':-')
        date = date.replace(' ', '_')

        filter__ = "Text File (*.TXT);;All Files (*.*)"
        filename, _f = FCFileSaveDialog.get_saved_filename(
            caption=_("Export Bookmarks"),
            directory='{l_save}/{n}_{date}'.format(l_save=str(self.app.get_last_save_folder()),
                                                   n=_("Bookmarks"),
                                                   date=date),
            ext_filter=filter__)

        filename = str(filename)

        if filename == "":
            self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled."))
            return
        else:
            try:
                f = open(filename, 'w')
                f.close()
            except PermissionError:
                self.app.inform.emit('[WARNING] %s' %
                                     _("Permission denied, saving not possible.\n"
                                       "Most likely another app is holding the file open and not accessible."))
                return
            except IOError:
                self.app.log.debug('Creating a new bookmarks file ...')
                f = open(filename, 'w')
                f.close()
            except Exception:
                e = sys.exc_info()[0]
                self.app.log.error("Could not load the file.")
                self.app.log.error(str(e))
                self.app.inform.emit('[ERROR_NOTCL] %s' % _("Could not load the file."))
                return

            # Save Bookmarks to a file
            try:
                with open(filename, "w") as f:
                    for title, link in self.bm_dict.items():
                        line2write = str(title) + ':' + str(link) + '\n'
                        f.write(line2write)
            except Exception:
                self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed to write bookmarks to file."))
                return
        self.app.inform.emit('[success] %s: %s' % (_("Exported bookmarks to"), filename))

    def on_import_bookmarks(self):
        self.app.log.debug("on_import_bookmarks()")

        filter_ = "Text File (*.txt);;All Files (*.*)"
        filename, _f = QtWidgets.QFileDialog.getOpenFileName(caption=_("Import Bookmarks"), filter=filter_)

        filename = str(filename)

        if filename == "":
            self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled."))
        else:
            try:
                with open(filename) as f:
                    bookmarks = f.readlines()
            except IOError:
                self.app.log.error("Could not load bookmarks file.")
                self.app.inform.emit('[ERROR_NOTCL] %s' % _("Could not load the file."))
                return

            for line in bookmarks:
                proc_line = line.replace(' ', '').partition(':')
                self.on_add_entry(title=proc_line[0], link=proc_line[2])

            self.app.inform.emit('[success] %s: %s' % (_("Imported Bookmarks from"), filename))

    def mark_table_rows_for_actions(self):
        for row in range(self.table_widget.rowCount()):
            item_to_paint = self.table_widget.item(row, 0)
            if row < self.app.defaults["global_bookmarks_limit"]:
                item_to_paint.setBackground(QtGui.QColor('gray'))
                # item_to_paint.setForeground(QtGui.QColor('black'))
            else:
                item_to_paint.setBackground(QtGui.QColor('white'))
                # item_to_paint.setForeground(QtGui.QColor('black'))

    def rebuild_actions(self):
        # rebuild the storage to reflect the order of the lines
        self.bm_dict.clear()
        for row in range(self.table_widget.rowCount()):
            title = self.table_widget.item(row, 1).text()
            wlink = self.table_widget.cellWidget(row, 2).toPlainText()

            entry = int(row) + 1
            self.bm_dict.update(
                {
                    str(entry): [title, wlink]
                }
            )

        self.app.install_bookmarks(book_dict=self.bm_dict)

    # def accept(self):
    #     self.rebuild_actions()
    #     super().accept()

    def closeEvent(self, QCloseEvent):
        self.rebuild_actions()
        self.ui_disconnect()
        super().closeEvent(QCloseEvent)


# 先寫網路模型
import torch
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear

# 寫完網絡的時候建議檢查網絡中的參數是否正確，因為網絡中key錯參數並不會特別報錯
from torch.utils.tensorboard import SummaryWriter

class Tudui(nn.Module):
    def __init__(self):
        super(Tudui, self).__init__()
        # 如何計算 padding, stride 可參考官方文件中的公式

        ''' 不用 nn.Sequential 的作法，比較囉唆
        self.conv1 = Conv2d(3, 32, 5, padding=2)
        ## Max-pooling kernel size 為 2
        self.maxpool1 = MaxPool2d(2)
        self.conv2 = Conv2d(32, 32, 5, padding=2)
        self.maxpool2 = MaxPool2d(2)
        self.conv3 = Conv2d(32, 64, 5, padding=2)
        self.maxpool3 = MaxPool2d(2)
        self.flatten = Flatten()
        self.linear1 = Linear(1024, 64)
        self.linear2 = Linear(64, 10)
        '''

        self.model1 = nn.Sequential(
            Conv2d(3, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 64, 5, padding=2),
            MaxPool2d(2),
            Flatten(),
            Linear(1024, 64),
            Linear(64, 10)
        )
    ''' 不用 Sequential 的 forward，真的很囉唆
    def forward(self, x):
        x = self.conv1(x)
        x = self.maxpool1(x)
        x = self.conv2(x)
        x = self.maxpool2(x)
        x = self.conv3(x)
        x = self.maxpool3(x)
        x = self.flatten(x)
        x = self.linear1(x)
        x = self.linear2(x)
        return x
    '''

    def forward(self,x):
        x = self.model1(x)
        return x

# 驗證網絡正確性
tudui = Tudui()
print(tudui)

input = torch.ones((64, 3, 32, 32))
output = tudui(input)
print(output.shape)

# 使用 tensorboard 做 visualization
writer = SummaryWriter("../logs_seq")
writer.add_graph(tudui, input)
writer.close()


from django.contrib import admin

from django_ymap.admin import YmapAdmin
from team.models import SEO
from .models import EventLocation, Event

class SEO(admin.StackedInline):
    model = SEO
    extra = 0
    fields = (
        'seo_description',
        'key_words',
    )
    show_change_link = True

class EventAdmin(admin.ModelAdmin):
    model = Event
    inlines = (SEO,)
    prepopulated_fields = {'slug': ('title',)}
    fieldsets = (
        ('Основное', {'fields': (
            'title', 'sub_title', 'slug', 'start', 'end', 'tags', 'type', 'featured_image', 'profile_image',
            'location')}),
        ('Описание', {'fields': ('allow_comments', 'description')}),
        ('Дополнительная информация', {'fields': ('internet_available', 'take_computer', 'site', 'value')}),
    )

    class Media:
        js = ['js/FB_CKEditor.js',
              'js/ckeditor.js']

    def save_model(self, request, obj, form, change):
        obj.author = request.user
        obj.save()

admin.site.register(Event, EventAdmin)

class RecordAdmin(YmapAdmin, admin.ModelAdmin):
    pass

admin.site.register(EventLocation, RecordAdmin)


"""
Copyright (c) Nikita Moriakov and Jonas Teuwen

This source code is licensed under the MIT license found in the
LICENSE file in the root directory of this source tree.
"""
import pathlib
import SimpleITK as sitk
import numpy as np

_SITK_INTERPOLATOR_DICT = {
    'nearest': sitk.sitkNearestNeighbor,
    'linear': sitk.sitkLinear,
    'gaussian': sitk.sitkGaussian,
    'label_gaussian': sitk.sitkLabelGaussian,
    'bspline': sitk.sitkBSpline,
    'hamming_sinc': sitk.sitkHammingWindowedSinc,
    'cosine_windowed_sinc': sitk.sitkCosineWindowedSinc,
    'welch_windowed_sinc': sitk.sitkWelchWindowedSinc,
    'lanczos_windowed_sinc': sitk.sitkLanczosWindowedSinc
}

def read_image_as_sitk_image(filename):
    """
    Read file as a SimpleITK image trying to parse the error.

    Parameters
    ----------
    filename : pathlib.Path or str

    Returns
    -------
    SimpleITK image.
    """
    try:
        sitk_image = sitk.ReadImage(str(filename))
    except RuntimeError as error:
        if 'itk::ERROR' in str(error):
            error = str(error).split('itk::ERROR')[-1]

        raise RuntimeError(error)

    return sitk_image

def read_image(filename, dtype=None, no_metadata=False, force_2d=False, **kwargs):
    """Read medical image

    Parameters
    ----------
    filename : Path, str
        Path to image, can be any SimpleITK supported filename
    dtype : dtype
        The requested dtype the output should be cast.
    no_metadata : bool
        Do not output metadata
    force_2d : bool
        If this is set to true, first slice in first axis will be taken, if the size[0] == 1.

    Returns
    -------
    Image as ndarray and dictionary with metadata.
    """
    filename = pathlib.Path(filename)
    if not filename.exists():
        raise FileNotFoundError(f'{filename} does not exist.')

    new_spacing = kwargs.get('spacing', False)
    if new_spacing and np.all(np.asarray(new_spacing) <= 0):
        new_spacing = False

    metadata = {}
    sitk_image = read_image_as_sitk_image(filename)

    # TODO: A more elaborate check for dicom can be needed, not necessarly all dicom files have .dcm as extension.
    if filename.suffix.lower() == '.dcm' and kwargs.get('dicom_keys', None):
        dicom_data = {}
        metadata_keys = sitk_image.GetMetaDataKeys()
        for v in kwargs['dicom_keys']:
            dicom_data[v] = None if v not in metadata_keys else sitk_image.GetMetaData(v).strip()
        metadata['dicom_tags'] = dicom_data

    orig_shape = sitk.GetArrayFromImage(sitk_image).shape
    if new_spacing:
        sitk_image, orig_spacing = resample_sitk_image(
            sitk_image,
            spacing=new_spacing,
            interpolator=kwargs.get('interpolator', None),
            fill_value=0
        )
        metadata.update(
            {'orig_spacing': tuple(orig_spacing), 'orig_shape': orig_shape})

    image = sitk.GetArrayFromImage(sitk_image)

    metadata.update({
        'filename': filename.resolve(),
        'depth': sitk_image.GetDepth(),
        'spacing': sitk_image.GetSpacing(),
        'origin': sitk_image.GetOrigin(),
        'direction': sitk_image.GetDirection()
    })

    if force_2d:
        if not image.shape[0] == 1:
            raise ValueError(f'Forcing to 2D while the first dimension is not 1.')
        image = image[0]

    if dtype:
        image = image.astype(dtype)

    if no_metadata:
        return image

    return image, metadata

def resample_sitk_image(sitk_image, spacing=None, interpolator=None,
                        fill_value=0):
    """Resamples an ITK image to a new grid. If no spacing is given,
    the resampling is done isotropically to the smallest value in the current
    spacing. This is usually the in-plane resolution. If not given, the
    interpolation is derived from the input data type. Binary input
    (e.g., masks) are resampled with nearest neighbors, otherwise linear
    interpolation is chosen.

    Parameters
    ----------
    sitk_image : SimpleITK image or str
      Either a SimpleITK image or a path to a SimpleITK readable file.
    spacing : tuple
      Tuple of integers
    interpolator : str
      Either `nearest`, `linear` or None.
    fill_value : int

    Returns
    -------
    SimpleITK image.
    """
    if isinstance(sitk_image, (str, pathlib.Path)):
        sitk_image = read_image_as_sitk_image(sitk_image)
    num_dim = sitk_image.GetDimension()
    if not interpolator:
        interpolator = 'linear'
        pixelid = sitk_image.GetPixelIDValue()

        if pixelid not in [1, 2, 4]:
            raise NotImplementedError(
                'Set `interpolator` manually, '
                'can only infer for 8-bit unsigned or 16, 32-bit signed integers')
        if pixelid == 1: #  8-bit unsigned int
            interpolator = 'nearest'

    orig_pixelid = sitk_image.GetPixelIDValue()
    orig_origin = sitk_image.GetOrigin()
    orig_direction = sitk_image.GetDirection()
    orig_spacing = np.array(sitk_image.GetSpacing())
    orig_size = np.array(sitk_image.GetSize(), dtype=np.int)

    if not spacing:
        min_spacing = orig_spacing.min()
        new_spacing = [min_spacing]*num_dim
    else:
        new_spacing = [float(s) if s else orig_spacing[idx] for idx, s in enumerate(spacing)]

    assert interpolator in _SITK_INTERPOLATOR_DICT.keys(),\
        '`interpolator` should be one of {}'.format(_SITK_INTERPOLATOR_DICT.keys())

    sitk_interpolator = _SITK_INTERPOLATOR_DICT[interpolator]

    new_size = orig_size*(orig_spacing/new_spacing)
    new_size = np.ceil(new_size).astype(np.int)  # Image dimensions are in integers
    # SimpleITK expects lists
    new_size = [int(s) if spacing[idx] else int(orig_size[idx]) for idx, s in enumerate(new_size)]

    resample_filter = sitk.ResampleImageFilter()
    resampled_sitk_image = resample_filter.Execute(
        sitk_image,
        new_size,
        sitk.Transform(),
        sitk_interpolator,
        orig_origin,
        new_spacing,
        orig_direction,
        fill_value,
        orig_pixelid
    )

    return resampled_sitk_image, orig_spacing


import random

from fractions import Fraction

class MatrixSizeError(Exception):
    """
    Matrix has wrong size.
    """
    pass

class MatrixValueError(Exception):
    """
    Matrix values are wrong.
    """
    pass

class Matrix:

    """

    Reminders:

    Test for any ways to break the code. Fix them.
    Add any other useful functions.

    Finish code.

    """

    def __init__(self, l, element_type='Fraction'):
        len_list = []
        for i in l:
            len_list.append(len(i))
        if len(set(len_list)) > 1:
            raise MatrixSizeError('All rows must be the same length.')

        self.l = l
        if element_type not in ('Fraction', 'Float'):
            raise ValueError(
                "Invalid element type. Valid types: 'Fraction', 'Float'"
                )
        self._element_type = element_type
        self.element_type = element_type
        if element_type == 'Fraction':
            for row in range(len(self.l)):
                for element in range(len(self.l[0])):
                    if type(self.l[row][element]) != Fraction:
                        self.l[row][element] = Matrix._get_fraction(
                            self.l[row][element]
                            )
        self.size = (len(l), len(l[0]))
        self.rows = len(l)
        self.cols = len(l[0])

    @property
    def element_type(self):
        return self._element_type
    @element_type.setter
    def element_type(self, value):
        if self._element_type == 'Float' and value == 'Fraction':
            for row in range(len(self.l)):
                for element in range(len(self.l[0])):
                    if type(self.l[row][element]) != Fraction:
                        self.l[row][element] = Matrix._get_fraction(
                            self.l[row][element]
                            )
        elif self._element_type == 'Fraction' and value == 'Float':
            for row in range(len(self.l)):
                for element in range(len(self.l[0])):
                    if not float(self.l[row][element]).is_integer():
                        self.l[row][element] = float(self.l[row][element])

        self._element_type = value
    @element_type.deleter
    def element_type(self):
        del self._element_type

    def __add__(self, other):
        """A + B"""
        if type(other) != Matrix:
            raise TypeError(
                "Cannot add matrices to anything other than a matrix."
                )
        if self.size != other.size:
            raise MatrixSizeError(
                'Cannot add matrices with different sizes.'
                )

        """
        return Matrix(
            [
                [
                    sum(pair) for pair in zip(self[i], other[i])
                    ] for i in range(self.rows)
                ], element_type = self.element_type
            )
        """

        res = Matrix(other.l)
        for row in range(self.rows):
            for col in range(self.cols):
                res[row, col] += self[row, col]
        return res

    def __sub__(self, other):
        """A - B"""
        if type(other) != Matrix:
            raise TypeError(
                "Cannot subtract matrices to anything other than a matrix."
                )
        if self.size != other.size:
            raise MatrixSizeError(
                'Cannot add matrices with different sizes.'
                )

        return Matrix(
            [
                [
                    pair[0]-pair[1] for pair in zip(self[i], other[i])
                    ] for i in range(self.rows)
                ]
            )

    def __mul__(self, other):
        """
        A * B (dot multiplication)
        Uses first matrix's element type.
        """
        if type(other) != Matrix:
            return Matrix([[other*val for val in row] for row in self],
                          element_type=self.element_type)
        else:
            if self.cols != other.rows:
                raise MatrixSizeError(
                    'Number of columns in first matrix must be '+\
                    'equal to number of rows in second matrix.'
                    )

            end_size = (self.rows, other.cols)
            res = Matrix([[0]*other.cols for i in range(self.rows)],
                         element_type=self.element_type)

            for row in range(self.rows):
                for col in range(other.cols):
                    res[row, col] = sum(
                        [pair[0] * pair[1] for pair in zip(
                            self[row], [
                                other[i, col] for i in range(other.rows)
                                ])]
                        )

            return res

    def std_mult(self, other):
        """
        A * B (standard multiplication)
        Multiplies each term by the corresponding term in the other matrix.
        Uses first matrix's element type.
        """
        if type(other) != Matrix:
            raise TypeError("Second argument must be of type 'Matrix'")
        if self.size != other.size:
            raise MatrixSizeError('Both matrices must be the same size.')

        return Matrix([[
            self[row, col]*other[row, col] for col in range(self.cols)
            ] for row in range(self.rows)])

    def __getitem__(self, i):
        """A[i] or A[i, j]"""
        if type(i) == tuple:
            return self.l[i[0]][i[1]]
        else:
            return self.l[i]

    def __setitem__(self, i, val):
        if type(i) != tuple:
            raise TypeError('Item assignment must in the form A[i, j]')
        else:
            self.l[i[0]][i[1]] = val

    def __repr__(self):
        """Makes matrices pretty."""

        raw_list = []
        # List of pretty versions of each element in the matrix
        for row in range(len(self.l)):
            for item in self.l[row]:
                raw_list.append(str(item))

        # Longest total length
        longest_total = max([len(item) for item in raw_list])
        # If any element is negative
        has_sign = any([item[0] == '-' for item in raw_list])
        if has_sign:
            has_sign = 1
        else:
            has_sign = 0

        # List of lengths of elements. Only gives length before the
        # decimal point or before the '/' symbol (length of numerator)
        int_len_list = []
        if self.element_type == 'Float':
            for row in range(self.rows):
                for item in self.l[row]:
                    num = 0
                    while num != len(str(item)) and str(item)[num] != '.':
                        num += 1
                    int_len_list.append(num)
        elif self.element_type == 'Fraction':
            for row in range(self.rows):
                for item in self.l[row]:
                    int_len_list.append(len(str(item.numerator)))
        # Longest length before '.' or '/' depending on element_type
        longest_int = max(int_len_list)

        # Adds one to longest_total if longest length isn't negative and
        # there is a negative in the matrix.
        for i in raw_list:
            if len(str(i)) == longest_total:
                if str(i)[0] != '-' and has_sign:
                    longest_total += 1
                    break

        # Makes things pretty; combines everything.
        res = '['
        for i in range(0, len(raw_list), self.cols):
            res += '['
            for gap in range(self.cols):
                #             Add spaces before
                res += ' '*(longest_int-int_len_list[i+gap])+\
                       raw_list[i+gap]+' '*(longest_total-( # Insert element
                           # Add spaces after so that all lengths are equal
                           longest_int-int_len_list[i+gap]+\
                           len(raw_list[i+gap])
                           ))
                if gap != self.cols-1:
                    res += ', '
                elif i != len(raw_list)-self.cols:
                    res += '], \n '
                else:
                    res += ']'
        res += ']'
        return res

    def _row_mult(self, n, row):
        """Multiplies a row by a scalar. Returns row."""
        if self.element_type == 'Float':
            # Fixes rounding mistakes
            res = [round(n*i, 15) for i in row]
        else:
            res = [n*i for i in row]
        for i in range(len(res)):
            if float(int(res[i])) == res[i]:
                res[i] = int(res[i])
        return res

    def _row_add(self, row_from, row_to):
        """Adds one row to another. Returns resulting row."""
        # The round() around the sum() below is to fix rounding mistakes
        res = [round(sum(pair), 15) for pair in zip(row_from, row_to)]
        for i in range(len(res)):
            if float(int(res[i])) == res[i]:
                res[i] = int(res[i])
        return res

    def _get_fraction(decimal):
        """
        Expresses a decimal as a ratio.
        If denominator too big, uses fractions module
        to determine answer.
        """
        count = 0
        while True:
            count += 1
            res = round(1.0*decimal*count,14)
            if res.is_integer():
                return Fraction(int(res), count)
            if count > 10000:
                return Fraction(
                    *decimal.as_integer_ratio()
                    ).limit_denominator()

    def add_row(self, row_from, row_to):
        """Adds one row to another. In-place; Changes its own lists."""
        self.l[row_to] = __row_add(self.l[row_from], self.l[row_to])

    def mult_row(self, n, row):
        """Multiplies a row by a scalar. In-place; Changes its own lists."""
        self.l[row] = self._row_mult(n, self.l[row])

    def mult_row_add(self, n, row_from, row_to):
        """
        Multiplies a row by a scalar, then adds it to another row.
        In-place; Changes its own lists.
        """
        self.l[row_to] = self._row_add(
            self._row_mult(n, self.l[row_from]),
            self.l[row_to]
            )

    def swap_rows(self, row_1, row_2):
        """Swaps two rows. In-place; Changes its own lists."""
        self.l[row_1], self.l[row_2] = self.l[row_2], self.l[row_1]

    def inverse(self):
        """
        Calculates the multiplicative inverse of a matrix.
        Uses Gauss-Jordan elimination.
        """

        if self.rows != self.cols:
            raise MatrixSizeError('Only square matrices are invertible.')

        if self.det() == 0:
            raise MatrixValueError('Singular matrix. (Determinant = 0)')

        I = self.I(self.rows, self.element_type)
        M = Matrix(
            [self[i]+I[i] for i in range(len(self.l))],
            self.element_type
            )

        for place in range(self.rows):
            cur = M[place, place]
            # If the current element is not one, make it one by
            # dividing the row by the inverse of the value
            if cur != 1:
                val = 1/cur
                M.mult_row(val, place)

            other_list = list(range(self.rows))
            other_list.remove(place)
            for other in other_list:
                val = -M[other, place]
                M.mult_row_add(val, place, other)

            if self.element_type == 'Fraction':
                for row in range(M.rows):
                    for item in range(M.cols):
                        M.l[row][item] = Matrix._get_fraction(
                            M[row, item].numerator / M[row, item].denominator)
        res_M_l = []
        for i in range(M.rows):
            row = M.l[i]
            res_M_l.append(row[-M.cols//2:])
        return Matrix(res_M_l, self.element_type)

    def minorMatrix(self):
        """Returns the matrix of minors of a certain matrix."""
        if self.rows != self.cols:
            raise MatrixSizeError(
                'Can only calculate the matrix of minors of square matrices.'
                )

        minors = Matrix([[0]*self.cols for i in range(self.rows)],
                           element_type=self.element_type)

        for row in range(self.rows): # Loop through rows
            for col in range(self.cols): # Loop through cols
                det_matrix = Matrix([
                    [0]*(self.cols-1) for i in range(self.rows-1)],
                                    element_type=self.element_type)
                rows_list = list(range(self.rows))
                rows_list.remove(row) # Remove current row
                cols_list = list(range(self.cols))
                cols_list.remove(col) # Remove current col

                i = 0
                for row_2 in rows_list:
                    j = 0
                    for col_2 in cols_list:
                        # Append determinant of remaining matrix
                        det_matrix[i, j] = self[row_2, col_2]
                        j += 1
                    i += 1
                minors[row, col] = det_matrix.det() # Determinant of matrix
        return minors

    def cofactorMatrix(self):
        """Returns the matrix of cofactors of a certain matrix."""
        if self.rows != self.cols:
            raise MatrixSizeError(
                'Can only calculate the matrix of cofactors of square matrices.'
                )

        minors = self.minorMatrix()
        return Matrix([[
            minors[row, col] * (-1)**(row+col) for col in range(self.cols)]
                       for row in range(self.rows)],
                      element_type=self.element_type)

    def adj(self):
        """
        Returns the adjugate of a certain matrix.
        Essentially, it reflects the matrix across the downwards-diagonal:
        the diagonal from the top-left corner to the bottom-right corner.
        """

        return Matrix([[self[col, row] for col in range(self.cols)]
                       for row in range(self.rows)],
                      element_type=self.element_type)

    def inverse2(self):
        """
        Calculates the multiplicative inverse of a matrix.
        Uses the matrix of cofactors and adjugates.
        """

        if self.rows != self.cols:
            raise MatrixSizeError('Only square matrices are invertible.')

        if self.det() == 0:
            raise MatrixValueError('Singular matrix. (Determinant = 0)')

        # Matrix of cofactors (with change of sign)
        cofactors = self.cofactorMatrix()

        # Adjugate matrix
        adjugate = cofactors.adj()

        # Multiply by 1/determinant
        if self.element_type == 'Fraction':
            det_inv = Fraction(1, self.det())
        elif self.element_type == 'Float':
            det_inv = 1/self.det()

        return adjugate*det_inv

    def det(self):
        """Calculates the determinant of the matrix."""
        if self.rows != self.cols:
            raise MatrixSizeError('Only square matrices have determinants.')

        if self.size[0] == self.size[1] == 2:
            return self[0, 0]*self[1, 1] - self[0, 1]*self[1, 0]
        else:
            res = 0
            # range(self.cols) is equal to the length of each row.
            for item in range(self.cols):
                rest = []
                i = 0
                for item_row in list(range(1, self.rows)):
                    rest.append([])
                    cur_cols = list(range(self.cols))
                    cur_cols.remove(item)
                    for item_col in cur_cols:
                        rest[i].append(self[item_row, item_col])
                    i += 1
                res += self[0, item] * Matrix(rest).det() * (-1)**(item)
            if float(res).is_integer:
                return int(res)
            else:
                if self.element_type == 'Fraction':
                    return res
                elif self.element_type == 'Float':
                    return float(res)

    def I(self, size, element_type='Fraction'):
        """Returns identity matrix."""
        l = []
        for row in range(size):
            l.append([])
            for col in range(size):
                if row == col:
                    l[row].append(1)
                else:
                    l[row].append(0)
        return Matrix(l, element_type)

    def filled(rows, cols, n, element_type='Fraction'):
        """Returns filled matrix, each element being n."""
        return Matrix([[n]*cols for i in range(rows)], element_type=element_type)

    def random(rows, cols, numrange, element_type='Fraction',
               is_int=True, dec_places=5):
        """
        Returns a random matrix.
        numrange can be defined as the tuple (min, max).
        numrange includes min and may include max;
        depends on is_int and rounding.
        """

        if not is_int:
            if numrange[0] == numrange[1]:
                raise ValueError("Values in 'numrange' cannot be equal.")
            if numrange[0] == None or numrange[1] == None:
                raise ValueError(
                    "None of the values in 'numrange' can be 'None'."
                    )
            if numrange[0] > numrange[1]:
                raise ValueError(
                    "First value in 'numrange' "+\
                    "has to be less than the second."
                    )

            if element_type == 'Fraction':
                res = Matrix.filled(rows, cols, 0, element_type='Fraction')
            elif element_type == 'Float':
                res = Matrix.filled(rows, cols, 0, element_type='Float')

            for row in range(rows):
                for col in range(cols):
                    if element_type == 'Fraction':
                        res[row, col] = Matrix._get_fraction(
                            round(random.uniform(*numrange), dec_places)
                            )
                    elif element_type == 'Float':
                        res[row, col] = round(
                            random.uniform(*numrange), dec_places
                            )
            return res
        else:
            if numrange[0] == numrange[1]:
                raise ValueError("Values in 'numrange' cannot be equal.")
            if numrange[0] == None or numrange[1] == None:
                raise ValueError(
                    "None of the values in 'numrange' can be 'None'."
                    )
            if numrange[0] > numrange[1]:
                raise ValueError(
                    "First value in 'numrange' "+\
                    "has to be less than the second."
                    )
            if (not float(numrange[0]).is_integer) or\
               (not float(numrange[1]).is_integer):
                raise ValueError(
                    "If is_int is True, values in numrange cannot be floats."
                    )
            res = Matrix.filled(rows, cols, 0, element_type=element_type)
            for row in range(rows):
                for col in range(cols):
                    res[row, col] = random.randint(*numrange)
            return res