#!/usr/bin/env python3

# import numpy
# import operator

class SparseArray():

    def __init__(self, seq=None):
        self.val_dict, self.length = {}, 0
        if seq:
            self.append(seq)

    def __str__(self):
        return str(self.__iter__())

    def __len__(self):
        return self.length

    def __getitem__(self, key):
        if isinstance(key, slice):
            final_slice = []
            (start, stop, step) = key.indices(self.length)
            for i in range(start, stop, step):
                final_slice.append(self.__getitem__(i))
            return final_slice[:]
        elif isinstance(key, tuple):
            pass
        else:
            key = self.test_key(key)
            if key in self.val_dict.keys():
                return self.val_dict[key]
            else:
                return 0

    def __setitem__(self, key, value):
        if isinstance(key, slice):
            (start, stop, step) = key.indices(self.length)
            for i, j in zip(range(start, stop, step), value):
                self.__setitem__(i, j)
        elif isinstance(key, tuple):
            pass
        else:
            key = self.test_key(key)
            if value:
                self.val_dict[key] = value
            elif key in self.val_dict.keys():
                del self.val_dict[key]

    def __delitem__(self, key):
        if isinstance(key, slice):
            (start, stop, step) = key.indices(self.length)
            items_to_delete = [i for i in range(start, stop, step)]
            # Make sure we delete going backward, or else subsequent
            # deletion indices will be incorrect
            if items_to_delete[0] < items_to_delete[-1]:
                direction = -1
            else:
                direction = 1
            for i in items_to_delete[::direction]:
                self.__delitem__(i)
        elif isinstance(key, tuple):
            pass
        else:
            key = self.test_key(key)
            if key in self.val_dict.keys():
                del self.val_dict[key]
            for i in range(key, self.length-1):
                if i in self.val_dict.keys():
                    del self.val_dict[i]
                self.__setitem__(i, self.__getitem__(i+1))
            self.length -= 1

    def __iter__(self):
        return [self.__getitem__(x) for x in range(self.length)]

    def __reversed__(self):
        return self.__iter__()[::-1]

    def __contains__(self, item):
        return (item in self.__iter__())

    def append(self, val):
        if isinstance(val, list):
            for i in val:
                self.append(i)
        elif isinstance(val, tuple):
            pass
        else:
            if val:
                self.val_dict[self.length] = val
            self.length += 1

    def test_key(self, key):
        if key not in range(-self.length, self.length):
            raise IndexError(f"Index {key} out of range - array is only "
                    f"{self.length} items long.")
        if key < 0:
            key += self.length
        return key

if __name__ == "__main__":
    array_to_add = [0,0,0,32,56,0,423,0,0,0,0,0,0,46,0,54,66,0]
    sa = SparseArray(array_to_add)
    print("Array sa now has {0} numbers: {1}".format(len(sa), sa))
    print("Array sa reversed is:", reversed(sa))
    sa[2] = 88
    print("Array sa now has {0} numbers: {1}".format(len(sa), sa))
    print("7th member of sa array is:", sa[6])
    print("10th member of sa array is:", sa[9])
    print("Last four members of sa are:", sa[-4:])
    sa.append(0)
    print("Array sa now has {0} numbers: {1}".format(len(sa), sa))
    sa.append(3)
    print("Array sa now has {0} numbers: {1}".format(len(sa), sa))
    sa.append([0,0,35,97,0,0,68,0,0])
    print("Array sa now has {0} numbers: {1}".format(len(sa), sa))
    del sa[4]
    print("Array sa now has {0} numbers: {1}".format(len(sa), sa))
    del sa[15:19]
    print("Array sa now has {0} numbers: {1}".format(len(sa), sa))
    print("Array sa contains 5? ", 5 in sa)
    print("Array sa contains 423? ", 423 in sa)
    print("Array sa contains 0? ", 0 in sa)

    sa2 = SparseArray()
    print("Array sa2 now has {0} numbers: {1}".format(len(sa2), sa2))
    sa2.append([0,0,35,58,0,0])
    print("Array sa2 now has {0} numbers: {1}".format(len(sa2), sa2))
    del sa2[0:]
    print("Array sa2 now has {0} numbers: {1}".format(len(sa2), sa2))
    sa2.append(5)
    print("Array sa2 now has {0} numbers: {1}".format(len(sa2), sa2))


# -*- coding: utf-8 -*-
from collections import defaultdict
from functools import partial

from django.contrib import admin
from django.contrib import messages
from django.shortcuts import redirect, render_to_response
from django.template.context import RequestContext
from django.utils.datastructures import SortedDict
from django.utils.translation import ugettext, ugettext_lazy as _

from django_tablib.views import export

from .base import BaseFormSubmissionAdmin
from .forms import FormDataExportForm
from ..models import FormData

class FormDataAdmin(BaseFormSubmissionAdmin):
    change_list_template = 'admin/aldryn_forms/formsubmission/change_list.html'
    export_form = FormDataExportForm
    readonly_fields = [
        'name',
        'data',
        'language',
        'sent_at',
        'get_recipients_for_display'
    ]

    def get_recipients(self, obj):
        return obj.get_recipients()

    def get_form_export_view(self):
        return self.form_export

    def form_export(self, request):
        form = self.export_form(request.POST or None)

        if form.is_valid():
            entries = form.get_queryset()

            if entries.exists():
                filename = form.get_filename()

                # A user can add fields to the form over time,
                # knowing this we use the latest form submission as a way
                # to get the latest form state, but this means that if a field
                # was removed then it will be ignored :(
                first_entry = entries.order_by('-sent_at')[0]

                # what follows is a bit of dark magic...
                # we call the export view in tablib with a headers dictionary, this dictionary
                # maps a key to a callable that gets passed a form submission instance and returns the value
                # for the field, we have to use a factory function in order to avoid a closure

                def clean_data(label, position):
                    def _clean_data(obj):
                        field = None
                        value = ''

                        try:
                            field = obj.get_form_data()[position]
                        except IndexError:
                            pass

                        if field and field.label == label:
                            # sanity check
                            # we need this to make sure that the field label and position remain constant
                            # otherwise we'll confuse users if a field was moved.
                            value = field.value
                        return value
                    return _clean_data

                fields = first_entry.get_form_data()

                # used to keep track of occurrences
                # in case a field with the same name appears multiple times in the form.
                occurrences = defaultdict(lambda: 1)
                headers = SortedDict()

                for position, field in enumerate(fields):
                    label = field.label

                    if label in headers:
                        occurrences[label] += 1
                        label = u'%s %s' % (label, occurrences[label])
                    headers[label] = clean_data(field.label, position)

                headers[ugettext('Language')] = 'language'
                headers[ugettext('Submitted on')] = 'sent_at'

                do_export = partial(
                    export,
                    request=request,
                    queryset=entries,
                    model=entries.model,
                    headers=headers,
                    filename=filename
                )

                try:
                    # Since django-tablib 3.1 the parameter is called file_type
                    response = do_export(file_type='xls')
                except TypeError:
                    response = do_export(format='xls')
                return response
            else:
                self.message_user(request, _("No records found"), level=messages.WARNING)
                export_url = 'admin:{}'.format(self.get_admin_url('export'))
                return redirect(export_url)

        context = RequestContext(request)
        context['errors'] = form.errors
        context.update(self.get_admin_context(form=form, title='Export'))
        return render_to_response('admin/aldryn_forms/export.html', context)

admin.site.register(FormData, FormDataAdmin)


animals = ['alligator',
 'ant',
 'bat',
 'bear',
 'bee',
 'bird',
 'bull',
 'bulldog',
 'butterfly',
 'cat',
 'chicken',
 'cow',
 'crab',
 'crocodile',
 'deer',
 'dog',
 'donkey',
 'duck',
 'eagle',
 'elephant',
 'fish',
 'fox',
 'frog',
 'giraffe',
 'gorilla',
 'hippo',
 'horse',
 'insect',
 'lion',
 'monkey',
 'moose',
 'mouse',
 'owl',
 'panda',
 'penguin',
 'pig',
 'rabbit',
 'rhino',
 'rooster',
 'shark',
 'sheep',
 'snake',
 'tiger',
 'turkey',
 'turtle',
 'wolf']


import torch.nn as nn
from torch.nn.utils.rnn import pad_packed_sequence as unpack

from pie import torch_utils
from pie import initialization

class RNNEncoder(nn.Module):
    def __init__(self, in_size, hidden_size, num_layers=1, cell='GRU'):

        self.hidden_size = hidden_size
        self.num_layers = num_layers
        self.cell = cell
        super().__init__()

        self.rnn = getattr(nn, cell)(
            in_size, hidden_size, num_layers=num_layers, bidirectional=True)

        self.init()

    def init(self):
        initialization.init_rnn(self.rnn)

    def forward(self, inp, lengths):
        hidden = torch_utils.init_hidden_for(
            inp, 2, self.num_layers, self.hidden_size, self.cell,
            add_init_jitter=True)

        inp, unsort = torch_utils.pack_sort(inp, lengths)
        inp, _ = self.rnn(inp, hidden)
        inp, _ = unpack(inp)
        inp = inp[:, unsort]

        return inp


import pandas as pd
import jieba
import multiprocessing
from multiprocessing import Pool, Manager
from flask import Flask, render_template, request, send_from_directory, make_response
import time
from word2vec import word2vec_kmeans, word2vec_huffman
from chi_square import chi_square
from tf_idf import tf_idf
import os

app = Flask(__name__)
app.config['JSON_AS_ASCII'] = False

DATA_PATH = 'data/1.xlsx'
STOPWORDS_PATH = 'data/stop_words_ch.txt'
DICT_PATH = 'data/new_dict.txt'
EMBEDDING_PATH = 'data/sgns.wiki.bigram-char'
MODEL_KMEANS_PATH = 'data/word2vec_model/word2vec_embedding'
MODEL_HUFFMAN_PATH = 'word2vec_model/word2vec_wx'
punc = "，。、【 】:“”：；（）《》‘’{}？！⑦()、%^>℃：.”“^-——=&#@￥*"
dict_data = ['ETC', 'EMS', '4S店', 'GDP', 'HPV', 'IPTV', 'P2P', 'etc', '12345APP',
             '12345app', '12345热线', 'ATM', 'atm', '12123APP', '12123app']

def generateStopwords(path):
    stopwords = [line.strip() for line in open(path, encoding='UTF-8').readlines()]
    return stopwords

# judge if chinese
def is_chinese(uchar):
    if u'\u4e00' <= uchar <= u'\u9fa5':
        return True
    else:
        return False

def jieba_multiprocessing(line):
    cate = line[0]
    content_pre = jieba.lcut(line[1])
    line_post = []
    for word in content_pre:
        if word not in stopwords and word not in punc and is_chinese(word) and len(word) > 1:
            line_post.append(word)
    return cate, line_post

def data_processing(data_path, stopwords_path, dict_path):
    data_raw = pd.read_excel(data_path, header=None)

    jieba.load_userdict(dict_path)
    """
    uniprocessing
    """
    # print('start uniprocessing jieba')
    # data = {}
    # categories = []
    # num = len(data_raw)
    # for i in range(num):
    #
    #     category = data_raw[0][i]
    #     temp = data.get(category, [])
    #     if category not in categories:
    #         categories.append(category)
    #
    #     content = jieba.lcut(data_raw[1][i])
    #     for word in content:
    #         if word not in stopwords and word not in punc and is_chinese(word) and len(word) > 1:
    #             temp.append(word)
    #             data[category] = temp
    # print('uniprocessing jieba done')

    """
    multiprocessing
    """
    print('start multiprocessing jieba')
    cpu_num = multiprocessing.cpu_count()
    pool = Pool(cpu_num - 1)
    data_post_tokenize = pool.map(jieba_multiprocessing, zip(data_raw[0], data_raw[1]))
    pool.close()
    pool.join()

    data = {}
    categories = []
    num = len(data_post_tokenize)
    for i in range(num):

        category = data_post_tokenize[i][0]
        temp = data.get(category, [])
        if category not in categories:
            categories.append(category)

        content = data_post_tokenize[i][1]
        for word in content:
            if word not in stopwords and word not in punc and is_chinese(word) and len(word) > 1:
                temp.append(word)
                data[category] = temp
    print('multiprocessing jieba done')

    corpus = list(data.values())

    # delete words that appear in all categories many times
    categories = len(corpus)
    word_frequency = [[]]
    corpus_post = [[]]

    for i in range(categories - 1):
        word_frequency.append([])
        corpus_post.append([])
        word_frequency[i] = count(corpus[i])

    word_frequency[-1] = count(corpus[-1])

    all_words = list(word_frequency[0].keys())
    corpus_post[0] = list(word_frequency[0].keys())
    for i in range(1, categories):
        all_words.extend(word_frequency[i].keys())
        corpus_post[i] = list(word_frequency[i].keys())
        # print(corpus_post[i])

    words_deleted = []
    for i in range(len(all_words)):
        check = 0
        for j in range(categories):
            if word_frequency[j].get(all_words[i], 0) > 80:
                check += 1
        if check == categories and all_words[i] not in words_deleted:
            words_deleted.append(all_words[i])

    for word in words_deleted:
        for i in range(categories):
            corpus_post[i].remove(word)

    for i in range(categories):
        # print(corpus_post[i])
        corpus_post[i] = " ".join(corpus_post[i])
        # print(corpus_post[i])
        # print('----------------')

    # print(corpus_post)
    return corpus_post

def count(word_list):
    count = {}
    for word in word_list:
        count[word] = count.get(word, 0) + 1

    # count = sorted(list(count), key=lambda x: x[1], reverse=True)
    return count

@app.route('/upload')
def index():
    return render_template('keywords.html')

@app.route('/upload_file', methods=['POST'])
def upload_file():
    if request.method == 'POST':
        file = request.files['file']
        path = 'uploaded/' + file.filename
        file.save(path)
        global UPLOAD_DATA_PATH
        UPLOAD_DATA_PATH = path
    return render_template('keywords.html', prompt='successfully uploaded')
    # return 'successfully uploaded'

@app.route('/tokenize')
def tokenize():
    print(UPLOAD_DATA_PATH)
    global corpus
    global stopwords
    print('start processing data ...')
    start_time = time.time()
    stopwords = generateStopwords(STOPWORDS_PATH)
    corpus = data_processing(UPLOAD_DATA_PATH, STOPWORDS_PATH, DICT_PATH)
    print('jieba tokenizing cost:', time.time() - start_time, 's')
    for i in corpus:
        print(i)
    return 'successfully tokenized'

@app.route('/download/<file>')
def download(file):
    current_path = os.getcwd()
    return send_from_directory(current_path, file, as_attachment=True)

@app.route('/run_tf_idf')
def run_tf_idf():
    if not os.path.exists('tf_idf_top2000.xlsx'):
        print('start tf-idf method ...')
        print(type(corpus[0]))
        start_time = time.time()
        keywords_tf_idf = tf_idf(corpus)
        print(keywords_tf_idf)
        print('total time taken:', time.time() - start_time, 's')

    res_path = 'tf_idf_top2000.xlsx'

    return res_path

@app.route('/run_word2vec')
def run_word2vec():
    if not os.path.exists('word2vec_huffman_top2000_multiprocessing.xlsx'):
        print('start huffman method ...')
        start_time = time.time()
        this_corpus = corpus
        categories = len(this_corpus)
        if type(corpus[0]) != str:
            for i in range(categories):
                corpus[i] = " ".join(corpus[i])
        for i in range(categories):
            corpus[i] = corpus[i].split()
        keywords_huffman = word2vec_huffman(this_corpus, MODEL_HUFFMAN_PATH)
        print(keywords_huffman)
        print('total time taken:', time.time() - start_time, 's')

    res_path = 'word2vec_huffman_top2000_multiprocessing.xlsx'

    return res_path

@app.route('/run_chi_square')
def run_chi_square():
    if not os.path.exists('chi_square_top2000.xlsx'):
        print('start chi_square method ...')
        start_time = time.time()
        keywords_chi_square = chi_square(DATA_PATH, DICT_PATH, corpus)
        print(keywords_chi_square)
        print('total time taken:', time.time() - start_time, 's')

    res_path = 'chi_square_top2000.xlsx'

    return res_path

@app.route('/run_intersection')
def run_intersection():
    print('start intersection ...')
    start_time = time.time()
    if not os.path.exists('tf_idf_top2000.xlsx'):
        # tf-idf
        print('start tf-idf method ...')
        start_time = time.time()
        keywords_tf_idf = tf_idf(corpus)
        print(keywords_tf_idf)
        print('total time taken:', time.time() - start_time, 's')

    if not os.path.exists('chi_square_top2000.xlsx'):
        # chi_square
        print('start chi_square method ...')
        start_time = time.time()
        keywords_chi_square = chi_square(DATA_PATH, DICT_PATH, corpus)
        print(keywords_chi_square)
        print('total time taken:', time.time() - start_time, 's')

    if not os.path.exists('word2vec_huffman_top2000_multiprocessing.xlsx'):
        # word2vec extra data processing
        categories = len(corpus)
        for i in range(categories):
            corpus[i] = corpus[i].split()

        # word2vec_huffman_softmax
        print('start huffman method ...')
        start_time = time.time()
        keywords_huffman = word2vec_huffman(corpus, MODEL_HUFFMAN_PATH)
        print(keywords_huffman)
        print('total time taken:', time.time() - start_time, 's')

    tf_idf_res = pd.read_excel('tf_idf_top2000.xlsx', sheet_name=None)
    word2vec_res = pd.read_excel('word2vec_huffman_top2000_multiprocessing.xlsx', sheet_name=None)
    chi_square_res = pd.read_excel('chi_square_top2000.xlsx', sheet_name=None)
    sheet_names = list(tf_idf_res.keys())
    sheet_num = len(sheet_names)
    writer = pd.ExcelWriter('intersection.xlsx')
    for i in range(sheet_num):
        new_sheet = []
        this_tf_idf = tf_idf_res[sheet_names[i]]
        this_word2vec = word2vec_res[sheet_names[i]]
        this_chi_square = chi_square_res[sheet_names[i]]
        for word in this_word2vec.values.tolist():
            word = word[0]
            if word not in new_sheet:
                new_sheet.append(word)
        for word in this_chi_square.values.tolist():
            word = word[0]
            if word not in new_sheet:
                new_sheet.append(word)
        for word in this_tf_idf.values.tolist():
            word = word[0]
            if word not in new_sheet:
                new_sheet.append(word)
        intersection = pd.DataFrame({'word': new_sheet})
        intersection.to_excel(writer, sheet_name=sheet_names[i], index=None)
        writer.save()
        writer.close()

    print('total time taken:', time.time() - start_time, 's')

    res_path = 'intersection.xlsx'

    return res_path

def main():
    global stopwords
    print('start processing data ...')
    start_time = time.time()
    stopwords = generateStopwords(STOPWORDS_PATH)
    corpus = data_processing(DATA_PATH, STOPWORDS_PATH, DICT_PATH)
    print('jieba tokenizing cost:', time.time() - start_time, 's')

    # tf-idf
    # print('start tf-idf method ...')
    # start_time = time.time()
    # keywords_tf_idf = tf_idf(corpus)
    # print(keywords_tf_idf)
    # print('total time taken:', time.time() - start_time, 's')

    # extra data processing for word2vec
    # categories = len(corpus)
    # for i in range(categories):
    #     corpus[i] = corpus[i].split()
    # print(corpus)

    # word2vec_kmeans
    # print('start kmeans method ...')
    # start_time = time.time()
    # keywords_kmeans = word2vec_kmeans(corpus, MODEL_KMEANS_PATH)
    # print(keywords_kmeans)
    # print('total time taken:', time.time() - start_time, 's')
    # print(corpus)

    # word2vec_huffman_softmax
    # print('start huffman method ...')
    # start_time = time.time()
    # keywords_huffman = word2vec_huffman(corpus, MODEL_HUFFMAN_PATH)
    # print(keywords_huffman)
    # print('total time taken:', time.time() - start_time, 's')

    # chi_square
    # print('start chi_square method ...')
    # start_time = time.time()
    # keywords_chi_square = chi_square(DATA_PATH, DICT_PATH, corpus)
    # print(keywords_chi_square)
    # print('total time taken:', time.time() - start_time, 's')

if __name__ == '__main__':
    # main()
    app.run(host='127.0.0.1', port=5000, debug=False, processes=True)


import webapp2
from google.appengine.ext import ndb
import db_models
import json

class Company(webapp2.RequestHandler):
	def post(self):
		'''
		Creates a Company entity
		name - Required
		symbol - Required
		'''
		if 'application/json' not in self.request.accept:
			self.response.status = 406
			self.response.status_message = "Not Acceptable, API only supports application/json MIME type."
			return
		new_company = db_models.Company()
		cname = self.request.get('cname', default_value=None)
		symbol = self.request.get('symbol', default_value=None)
		if cname:
			new_company.cname = cname
		else:
			self.response.status = 400
			self.response.status_message = "Invalid Request, Company name is Required."
		if symbol:
			new_company.symbol = symbol
		else:
			self.response.status = 400
			self.response.status_message = "Invalid Request, Company Symbol is Required."
		key = new_company.put() # save in database
		out = new_company.to_dict() # return the thing we just made
		self.response.write(json.dumps(out))
		return
	def get(self, **kwargs): #keyword arguments, in this case 'id'
		if 'application/json' not in self.request.accept:
			self.response.status = 406
			self.response.status_message = "Not Acceptable, API only supports application/json MIME type."
			return
		# looking for id in keyword arguments
		if 'id' in kwargs: # if it's there we make a key for a Country by passing in a type of company and id
			out = ndb.Key(db_models.Company, int(kwargs['id'])).get().to_dict()     # from key we get the Country and turn it into a dictionary (python datatype)
			self.response.write(json.dumps(out)) # dump that to a json string and write it back as a response
		else: # if no id passed in keyword argumetns then we return all the key ids
			q = db_models.Company.query()
			keys = q.fetch(keys_only=True)
			results = {'keys': [x.id() for x in keys]}
			self.response.write(json.dumps(results))

# can search by a company name or symbol
class CompanySearch(webapp2.RequestHandler):
	def get(self):
		'''
		Search for Companies
		POST Body Variables:
		cname - String. Company name
		symbol - String. Company Symbol
		'''
		if 'application/json' not in self.request.accept:
			self.response.status = 406
			self.response.status_message = "Not Acceptable, API only supports application/json MIME type."
			return
		q = db_models.Company.query()
		# applying some filters, passing in those keys, getting information
		if self.request.get('cname',None):
			q = q.filter(db_models.Company.cname == self.request.get('cname'))
		if self.request.get('symbol', None):
			q = q.filter(db_models.Company.symbol == self.request.get('symbol'))
		keys = q.fetch(keys_only=True)
		results = {'keys' : [x.id() for x in keys]}
		self.response.write(json.dumps(results))

#delete company by id
class DeleteCompany(webapp2.RequestHandler):
	def delete(self, **kwargs):
		if 'application/json' not in self.request.accept:
			self.response.status = 406
			self.response.status_message = "Not Acceptable, API only supports application/json MIME type."
			return
		if 'id' in kwargs:
			companyID = int(kwargs['id'])
			company = db_models.Company().get_by_id(int(companyID))

			nations = db_models.Nation.query()
			# nation = nation.filter(db_models.Nation.companies == ndb.Key(db_models.Company, companyID))
			for nation in nations:
				self.response.write(" FOR LOOP ")
				for id in nation.companies:
					self.response.write(" ANOTHER FOR LOOP ")
					if company.key == id:
						self.response.write(" FOUND COMPANY ")
						nation.companies.remove(id)
						nation.put()
					self.response.write(company.key)
					self.response.write(id)
				self.response.write(json.dumps(nation.to_dict()))

			company.key.delete()
			self.response.write("company deleted")


import requests
import json

def uniqueSensor(sensorType):
	f = open('platformID.txt', 'r+')
	platformID = f.read()
	print(platformID)
	f.close()
	f = open('sensors.txt', 'r+')
	if(f.read != ""):
		exists = False
		#NEED TO IMPLEMENT MULTIPLE SENSORS
		#for line in f:
		#	lineArr = line.split()
		#	exists = (lineArr[0] == sensorType)
		if(not exists):
			f.close()
			f = open('sensors.txt', 'a')
			package = {'platformID':platformID,'sensorType':sensorType}
			r = requests.get('http://sense-backend-vmcool09.c9.io/uniqueSensor', params=package)
			print(r.content)
			f.write(sensorType + ' = ' + r.content)


# getting b' ' strings in csv file, can't figure out why

import os
import sys
import csv
import os.path
import time
import datetime
from datetime import datetime

def main():
    temp = sys.stdout

    path_list = [os.path.normpath("S:")]

    write_mode = ["w+"]

    rfd = str(os.getcwd() + "/Reports/Program_Files/")
    reportdir = str(os.getcwd() + "/Reports/")

    def my_info(info):
        sys.stdout.close()
        sys.stdout = temp
        print(str(info))

    def file_dump_print(path_list):

        def write_path():
            print(os.path.join(root, file).encode("ascii", "ignore"))

        sys.stdout = open(rfd + "file dump.txt", w)
        for root, dirs, files in os.walk(a):
            for file in files:
                if file.endswith(".pdf"):
                    write_path()
                if file.endswith(".pptx"):
                    write_path()
                if file.endswith(".doc"):
                    write_path()
                if file.endswith(".docx"):
                    write_path()
                if file.endswith(".xlsx"):
                    write_path()

    def file_name_print(path_list):

        def write_name():
            print(str(os.path.splitext(file)[0].encode("ascii", "ignore")))

        sys.stdout = open(rfd + "file names.txt", w)
        for root, dirs, files in os.walk(a):
            for file in files:
                if file.endswith(".pdf"):
                    write_name()
                if file.endswith(".pptx"):
                    write_name()
                if file.endswith(".doc"):
                    write_name()
                if file.endswith(".docx"):
                    write_name()
                if file.endswith(".xlsx"):
                    write_name()

    def file_type_print(path_list):

        def write_type():
            print(os.path.splitext(file)[1])

        sys.stdout = open(rfd + "file type.txt", w)
        for root, dirs, files in os.walk(a):
            for file in files:
                if file.endswith(".pdf"):
                    write_type()
                if file.endswith(".pptx"):
                    write_type()
                if file.endswith(".doc"):
                    write_type()
                if file.endswith(".docx"):
                    write_type()
                if file.endswith(".xlsx"):
                    write_type()

    def file_rdcf_print(path_list):

        def write_rdcf():
            if "RDCF" in file:
                print("Yes")
            else:
                print("No")

        sys.stdout = open(rfd + "rdcf.txt", w)
        for root, dirs, files in os.walk(a):
            for file in files:
                if file.endswith(".pdf"):
                    write_rdcf()
                if file.endswith(".pptx"):
                    write_rdcf()
                if file.endswith(".doc"):
                    write_rdcf()
                if file.endswith(".docx"):
                    write_rdcf()
                if file.endswith(".xlsx"):
                    write_rdcf()

    def file_folder_print(path_list):

        def write_folder():
            print(os.path.join(root).encode("utf-8"))

        sys.stdout = open(rfd + "folders.txt", w)
        for root, dirs, files in os.walk(a):
            for file in files:
                if file.endswith(".pdf"):
                    write_folder()
                if file.endswith(".pptx"):
                    write_folder()
                if file.endswith(".doc"):
                    write_folder()
                if file.endswith(".docx"):
                    write_folder()
                if file.endswith(".xlsx"):
                    write_folder()

    def file_policy(path_list):

        def write_policy():
            if "policy" in file:
                print("Yes")
            else:
                print("No")

        sys.stdout = open(rfd + "policy.txt", w)
        for root, dirs, files, in os.walk(a):
            for file in files:
                if file.endswith(".pdf"):
                    write_policy()
                if file.endswith(".pptx"):
                    write_policy()
                if file.endswith(".doc"):
                    write_policy()
                if file.endswith(".docx"):
                    write_policy()
                if file.endswith(".xlsx"):
                    write_policy()

    def file_date_created(path_list):

        def write_datecreated():
            filetimemod = datetime.fromtimestamp(
                os.path.getctime(os.path.join(root, file))
            )
            print(str(filetimemod)[:4])

        sys.stdout = open(rfd + "date created.txt", w)
        for root, dirs, files, in os.walk(a):
            for file in files:
                file_path = os.path.join(root, file)
                file_path.replace("\\\\", "/")  # tries to resolve "Error", doesn't work
                if os.path.exists(file_path):
                    if file.endswith(".pdf"):
                        write_datecreated()
                    if file.endswith(".pptx"):
                        write_datecreated()
                    if file.endswith(".doc"):
                        write_datecreated()
                    if file.endswith(".docx"):
                        write_datecreated()
                    if file.endswith(".xlsx"):
                        write_datecreated()
                else:
                    print("Error")

    def file_date_modified(path_list):

        def write_datemodified():
            if file.endswith(".pdf"):
                datemodified = datetime.fromtimestamp(
                    os.path.getmtime(os.path.join(root, file))
                )
                print(str(datemodified)[:4])

        sys.stdout = open(rfd + "date modified.txt", w)
        for root, dirs, files, in os.walk(a):
            for file in files:
                file_path = os.path.join(root, file)
                file_path.replace("\\\\", "/")
                if os.path.exists(file_path):
                    if file.endswith(".pdf"):
                        write_datemodified()
                    if file.endswith(".pptx"):
                        write_datemodified()
                    if file.endswith(".doc"):
                        write_datemodified()
                    if file.endswith(".docx"):
                        write_datemodified()
                    if file.endswith(".xlsx"):
                        write_datemodified()
                else:
                    print("Error")

    def run_report():
        file_dump_print(path_list)
        file_name_print(path_list)
        file_type_print(path_list)
        file_rdcf_print(path_list)
        file_folder_print(path_list)
        file_date_created(path_list)
        file_date_modified(path_list)
        file_policy(path_list)

    print("Running OWS ALL Report",
          "n/",
          os.getcwd()
          )

    for a, w in zip(path_list, write_mode):
        run_report()

    # import files as list
    file_dump = open(rfd + "file dump.txt")
    listfiledump = file_dump.readlines()
    file_names = open(rfd + "file names.txt")
    listfilenames = file_names.readlines()
    file_type = open(rfd + "file type.txt")
    listfiletype = file_type.readlines()
    file_rdcf = open(rfd + "rdcf.txt")
    listrdcf = file_rdcf.readlines()
    file_folders = open(rfd + "folders.txt")
    listfolders = file_folders.readlines()
    file_date_created = open(rfd + "date created.txt")
    listdatecreated = file_date_created.readlines()
    file_date_modified = open(rfd + "date modified.txt")
    listdatemodified = file_date_modified.readlines()
    file_policy = open(rfd + "policy.txt")
    listpolicy = file_policy.readlines()

    textFileList = [rfd + "file dump.txt",
                    rfd + "file names.txt",
                    rfd + "file type.txt",
                    rfd + "rdcf.txt",
                    rfd + "folders.txt",
                    rfd + "date created.txt",
                    rfd + "date modified.txt",
                    rfd + "policy.txt"
                    ]

    print(listfilenames,
          listfiletype,
          listrdcf,
          listdatecreated,
          listdatemodified,
          listfolders,
          listfiledump,
          listpolicy
          )

    rows = zip(listfilenames,
               listfiletype,
               listrdcf,
               listdatecreated,
               listdatemodified,
               listfolders,
               listfiledump,
               listpolicy
               )

    headers = ["File",
               "Extension",
               "RDCF?",
               "Date Created",
               "Last Modified",
               "Folder",
               "Path/ Link",
               "Policy?"
               ]

    reporttimestamp = str(time.ctime(int(time.time()))).replace(":", "_")
    reportname = (reportdir + "OWS_All_Report_" + reporttimestamp + ".csv")

    with open(reportname, "w+", newline="") as f:
        writer = csv.writer(f)
        for row in rows:
            writer.writerow(row)
    with open(reportname, "r", newline="") as readFile:
        reader = csv.reader(readFile)
        lines = list(reader)
        lines[0] = headers
    with open(reportname, "w", newline="") as writeFile:
        writer = csv.writer(writeFile)
        writer.writerows(lines)

    if os.path.exists(reportname):
        os.startfile(reportname)
        sys.exit()

if __name__ == "__main__":
    main()


#!/usr/bin/env python3

from typing import Any, Dict, List, Tuple, Type, cast

from torch.nn import Module

from captum.attr._utils.attribution import Attribution

def gen_test_name(
    prefix: str, test_name: str, algorithm: Type[Attribution], noise_tunnel: bool
) -> str:
    # Generates test name for dynamically generated tests
    return (
        prefix
        + "_"
        + test_name
        + "_"
        + algorithm.__name__
        + ("NoiseTunnel" if noise_tunnel else "")
    )

def parse_test_config(
    test_config: Dict,
) -> Tuple[List[Type[Attribution]], Module, Dict[str, Any], Module, bool, bool]:
    algorithms = cast(List[Type[Attribution]], test_config["algorithms"])
    model = test_config["model"]
    args = cast(Dict[str, Any], test_config["attribute_args"])
    layer = test_config["layer"] if "layer" in test_config else None
    noise_tunnel = (
        test_config["noise_tunnel"] if "noise_tunnel" in test_config else False
    )
    baseline_distr = (
        test_config["baseline_distr"] if "baseline_distr" in test_config else False
    )
    return algorithms, model, args, layer, noise_tunnel, baseline_distr


import json
from datetime import datetime

import spread_core.bam.const as bam_const
import spread_core.mqtt as mqtt
from spread_core.bam import engineries, subgineries
from spread_core.bam.dali import *
from spread_core.errors import project_errors
from spread_core.errors.project_errors import ClassifierError
from spread_core.mqtt import spread as spread
from spread_core.mqtt.variables import VariableJocket, VariableTRS3, VariableReader
from spread_core.tools import settings
from spread_core.tools.service_launcher import Launcher, logging

PROJECT_ID = settings.config[settings.PROJECT_ID]

class Frontier(Launcher):
    _dumped = False

    def __init__(self):
        self._manager = self
        self.subgineries = {}
        self.engineries = {}
        self.server_id = 'Здесь_могла_быть_ваша_реклама!!'
        super(Frontier, self).__init__()

    def start(self):
        try:
            self.subscribe(mqtt.TopicProject(PROJECT_ID, bam_const.SERVERS + '.json'))
        except BaseException as ex:
            logging.exception(ex)

    def on_message(self, mosq, obj, msg):
        try:
            topic = mqtt.mqtt.of(msg.topic)
        except project_errors.TopicError as ex:
            logging.warning(ex)
        else:
            try:
                if isinstance(topic, mqtt.TopicProject):
                    self.on_project(topic, json.loads(msg.payload.decode()))
                elif isinstance(topic, (mqtt.TopicStateTros3, mqtt.TopicCommandTros3)):
                    self.on_tros3(topic, msg.payload)
                elif isinstance(topic, (mqtt.TopicCommand, mqtt.TopicState)):
                    self.on_jocket(topic, msg.payload)
                else:
                    logging.debug(f'[NO MOVE] {topic}')

            except BaseException as ex:
                logging.exception(ex)

    def on_project(self, topic, data):
        self.unsubscribe(topic)

        if bam_const.SERVERS in data:
            self.server_id = data[bam_const.SERVERS][0]['id']
            self.subscribe(mqtt.TopicProject(PROJECT_ID, bam_const.ENGINERIES + '.json'))

        elif bam_const.ENGINERIES in data:
            cnt = 0
            for e_data in data[bam_const.ENGINERIES]:
                try:
                    self.engineries[e_data['id']] = engineries.of(PROJECT_ID, e_data, {})
                except project_errors.ProjectError as ex:
                    continue

            self.subscribe(mqtt.TopicProject(PROJECT_ID, bam_const.SUBGINERIES + '.json'))

        if bam_const.SUBGINERIES in data:
            for e_data in data[bam_const.SUBGINERIES]:
                try:
                    self.subgineries[e_data['id']] = subgineries.of(e_data)
                except project_errors.ProjectError as ex:
                    continue

            self.subscribe(mqtt.TopicCommandTros3(PROJECT_ID))
            self.subscribe(mqtt.TopicStateTros3(PROJECT_ID, '#'))
            self.subscribe(mqtt.TopicCommand(PROJECT_ID))
            self.subscribe(mqtt.TopicState(PROJECT_ID, '#'))
            self.subscribe(spread.topic.Set(spread.address.BroadcastAddress(PROJECT_ID)))
            self.subscribe(spread.topic.Renew(spread.address.BroadcastAddress(PROJECT_ID)))

    def on_exit(self, sig, frame):
        super(Frontier, self).on_exit(sig, frame)

    def on_jocket(self, _topic, data):
        _var = VariableJocket(json.loads(data.decode()))
        _address = _topic.entity_addr
        if isinstance(_address, mqtt.EngineryAddress):
            e_id = int(_address.entity_id)
            if e_id in self.engineries:
                e_data = self.engineries[e_id]
                address = spread.address.EngineryAddress(_topic.p_id, e_data.__class__.__name__, e_id, _address.funit_id)
            elif e_id in self.subgineries:
                e_data = self.subgineries[e_id]
                address = spread.address.SubgineryAddress(_topic.p_id, e_data.location_id, e_data.__class__.__name__, _address.funit_id)
            else:
                logging.debug(f'Unknown enginery/subgnery ({_address})')
                return
        elif isinstance(_address, mqtt.ProviderAddress):
            address = spread.address.ProviderAddress(PROJECT_ID, _address.manager_type, _address.manager_id,
                                                     _address.provider_type, _address.provider_id, _address.funit_type)
        elif isinstance(_address, mqtt.ManagerAddress):
            address = spread.address.ManagerAddress(PROJECT_ID, _address.manager_type, _address.manager_id, _address.funit_type)
        else:
            logging.debug(f'Unsupported address ({_address.__class__.__name__})')
            return

        if isinstance(_topic, mqtt.TopicState):
            topic = spread.topic.State(address)
        elif isinstance(_topic, mqtt.TopicCommand):
            topic = spread.topic.Event(address)
        else:
            logging.debug(f'Unsupported topic ({_topic.__class__.__name__})')
            return

        var = spread.variable.Variable(_var.value, timestamp=datetime.fromisoformat(str(_var.timeStamp)))
        self.publish(topic, var, retain=isinstance(_topic, mqtt.TopicState))

    def on_spread(self, _topic: (spread.topic.Set, spread.topic.Renew), data):
        _var = spread.variable.Variable(json.loads(data.decode()))
        _address = _topic.entity_address
        if isinstance(_topic, spread.topic.Set):
            if isinstance(_topic.entity_address, (spread.address.EngineryAddress, spread.address.SubgineryAddress)):
                cl = mqtt.classifier['Lighting'][_address.type][_address.funit_type]['id']
                value = True
                if _address.funit_type == F_ON:
                    if _var.value:
                        funit_id = engineries.onId
                    else:
                        funit_id = engineries.offId
                elif _address.funit_type == F_BrightnessLevel:
                    funit_id = engineries.powerLevelId
                    value = _var.value
                elif _address.funit_type == F_GROUP_LEVEL_RAW:
                    if _var.value == 0:
                        funit_id = engineries.groupOffId
                    elif _var.value == 254:
                        funit_id = engineries.groupOnId
                    else:
                        funit_id = engineries.groupSetLevelId
                        e_data = self.engineries[_address.id]
                        if isinstance(e_data, engineries.DimmingLight):
                            value = e_data.raw2prs(_var.value)
                        else:
                            logging.debug(f'Unsupported funit "{_address.funit_type} for {e_data.__class__.__name__}"')
                            return
                elif _address.funit_type == F_PresenceSensorsOn:
                    if _var.value:
                        funit_id = subgineries.presenceSensorsOnId
                    else:
                        funit_id = subgineries.presenceSensorsOffId
                elif _address.funit_type == F_LightSensorsOn:
                    if _var.value:
                        funit_id = subgineries.lightSensorsOnId
                    else:
                        funit_id = subgineries.lightSensorsOffId
                else:
                    logging.debug(f'Unsupported funit "{_address.funit_type}"')
                    return

                var = VariableTRS3(_address.id, cl, value, _var.invalid)
                topic = mqtt.TopicCommandTros3(PROJECT_ID, mqtt.EngineryAddress(_address.id, funit_id))
            else:
                try:
                    address = spread_address_to_mqtt(self.server_id, _address)
                    funit = get_funit(_address)
                except ClassifierError as ex:
                    logging.debug(ex)
                    return
                except BaseException:
                    logging.debug(f'Unsupported address "{_address.__class__.__name__}"')
                    return
                else:
                    var = VariableJocket.create_data(_address.id, funit['id'], 'set', _var.value, invalid=_var.invalid)
                    topic = mqtt.TopicCommand(PROJECT_ID, 'Frontier_SID', address)
        elif isinstance(_topic, spread.topic.Renew):
            try:
                topic = mqtt.TopicCommand(spread_address_to_mqtt(self.server_id, _address))
                funit = get_funit(_address)
            except ClassifierError as ex:
                logging.debug(ex)
                return
            except BaseException:
                logging.debug(f'Unsupported address "{_address.__class__.__name__} of {_topic.__class__.__name__}"')
                return
            else:
                var = VariableJocket.create_data(_address.id, funit['id'], 'get', _var.value)
        else:
            logging.debug(f'Unsupported topic "{_topic.__class__.__name__}"')
            return

        self.publish(topic, var, retain=False)

    def on_tros3(self, _topic: mqtt.TopicData, data):
        _var = VariableTRS3(VariableReader(data))
        e_id = _var.id
        timestamp = None

        if _var.timeStamp:
            timestamp = datetime.fromisoformat(str(_var.timeStamp))

        if e_id in self.engineries:
            e_data = self.engineries[e_id]
            funit_name = e_data._cmds[_var.cl]

            if isinstance(_topic, mqtt.TopicStateTros3):
                value = _var.value

                if funit_name == engineries.isOnId:
                    funit_type = F_ON
                elif funit_name == engineries.levelId:
                    funit_type = F_BrightnessLevel
                elif funit_name == engineries.powerLevelId:
                    funit_type = F_PowerLevel
                else:
                    logging.debug(f'Unsupported funit "{funit_name}"')
                    return

                if _var.invalid:
                    value = None

                topic = spread.topic.State(
                    spread.address.EngineryAddress(_topic.p_id, e_data.__class__.__name__, e_id, funit_type)
                )
                retain = True
            elif isinstance(_topic, mqtt.TopicCommandTros3):
                if funit_name == engineries.onId:
                    funit_type = F_ON
                    value = True
                elif funit_name == engineries.offId:
                    funit_type = F_ON
                    value = False
                elif funit_name == engineries.setLevelId:
                    funit_type = F_BrightnessLevel
                    value = _var.value
                elif funit_name == engineries.groupOnId:
                    funit_type = F_GROUP_LEVEL_RAW
                    value = 254
                elif funit_name == engineries.groupOffId:
                    funit_type = F_GROUP_LEVEL_RAW
                    value = 0
                elif funit_name == engineries.groupSetLevelId:
                    funit_type = F_GROUP_LEVEL_RAW
                    value = _var.value
                else:
                    logging.debug(f'Unsupported funit "{funit_name}"')
                    return

                topic = spread.topic.Event(
                    spread.address.EngineryAddress(_topic.p_id, e_data.__class__.__name__, e_id, funit_type)
                )
                retain = False
            else:
                return

        elif e_id in self.subgineries:
            e_data = self.subgineries[e_id]
            funit_name = e_data._cmds[_var.cl]

            if isinstance(_topic, mqtt.TopicStateTros3):
                value = _var.value

                if funit_name == subgineries.isOnId:
                    funit_type = F_SwitchOn
                elif funit_name == subgineries.isOffId:
                    funit_type = F_SwitchOff
                elif funit_name == subgineries.isMatchScene1Id:
                    funit_type = F_Scene1On
                elif funit_name == subgineries.isMatchScene2Id:
                    funit_type = F_Scene2On
                elif funit_name == subgineries.powerLevelId:
                    funit_type = F_PowerLevel
                elif funit_name == subgineries.isLightSensorsOnId:
                    funit_type = F_LightSensorsOn
                    value = True
                elif funit_name == subgineries.isLightSensorsOffId:
                    funit_type = F_LightSensorsOn
                    value = False
                elif funit_name == subgineries.isPresenceSensorsOnId:
                    funit_type = F_PresenceSensorsOn
                    value = True
                elif funit_name == subgineries.isPresenceSensorsOffId:
                    funit_type = F_PresenceSensorsOn
                    value = False
                else:
                    logging.debug(f'Unsupported funit "{funit_name}"')
                    return

                if _var.invalid:
                    value = None

                topic = spread.topic.State(
                    spread.address.SubgineryAddress(_topic.p_id, e_data.location_id, e_data.__class__.__name__, funit_type)
                )
                retain = True
            elif isinstance(_topic, mqtt.TopicCommandTros3):
                if funit_name == subgineries.onId:
                    funit_type = F_ON
                    value = True
                elif funit_name == subgineries.offId:
                    funit_type = F_ON
                    value = False
                # elif funit_name == subgineries.loadScene1Id:
                # elif funit_name == subgineries.loadScene2Id:
                elif funit_name == subgineries.presenceSensorsOnId:
                    funit_type = F_PresenceSensorsOn
                    value = True
                elif funit_name == subgineries.presenceSensorsOffId:
                    funit_type = F_PresenceSensorsOn
                    value = False
                elif funit_name == subgineries.lightSensorsOnId:
                    funit_type = F_LightSensorsOn
                    value = True
                elif funit_name == subgineries.lightSensorsOffId:
                    funit_type = F_LightSensorsOn
                    value = False
                else:
                    logging.debug(f'Unsupported funit "{funit_name}"')
                    return

                topic = spread.topic.Event(
                    spread.address.SubgineryAddress(_topic.p_id, e_data.location_id, e_data.__class__.__name__, funit_type)
                )
                retain = False
            else:
                logging.debug(f'Unsupported topic "{_topic}"')
                return
        else:
            logging.debug(f'Unknown entity({e_id})')
            return

        var = spread.variable.Variable(value, timestamp=timestamp)

        self.publish(topic=topic, data=var, retain=retain)

if __name__ == '__main__':
    Frontier()

def get_funit(address: spread.address.ProviderAddress):
    if address.manager_type in mqtt.classifier:
        funit = mqtt.classifier[address.manager_type]
        if address.type in funit[address.type]:
            funit = funit[address.type][address.type]
            if address.funit_type in funit:
                return funit[address.funit_type]

    raise ClassifierError('Объект {} отсутствует в classifier[{}]'.format(address.funit_type, address.manager_type))

def spread_address_to_mqtt(server_id: (str, int), _address: spread.address.EntityAddress):
    if isinstance(_address, spread.address.ProviderAddress):
        address = mqtt.ProviderAddress('AppServer', server_id,
                                       _address.manager_type, _address.manager_id,
                                       _address.type, _address.id,
                                       _address.funit_type)
    elif isinstance(_address, spread.address.ManagerAddress):
        address = mqtt.ProviderAddress('AppServer', server_id, _address.type,
                                       _address.id, _address.funit_type)
    else:
        raise

    return address


from collections import deque

import cv2
import numpy as np
import pandas as pd

class DistanceRatio(object):

    """
    A stateful object to store ratio test results and provenance.

    Attributes
    ----------

    nvalid : int
             The number of valid entries in the mask

    mask : series
           Pandas boolean series indexed by the match id

    matches : dataframe
              The matches dataframe from an edge.  This dataframe
              must have 'source_idx' and 'distance' columns.

    single : bool
             If True, then single entries in the distance ratio
             mask are assumed to have passed the ratio test.  Else
             False.

    """

    def __init__(self, matches):

        self._action_stack = deque(maxlen=10)
        self._current_action_stack = 0
        self._observers = set()
        self.matches = matches
        self.mask = None

    @property
    def nvalid(self):
        return self.mask.sum()

    def compute(self, ratio, mask=None, mask_name=None, single=False):
        """
        Compute and return a mask for a matches dataframe
        using Lowe's ratio test.  If keypoints have a single
        Lowe (2004) [Lowe2004]_

        Parameters
        ----------
        ratio : float
                the ratio between the first and second-best match distances
                for each keypoint to use as a bound for marking the first keypoint
                as "good". Default: 0.8

        mask : series
               A pandas boolean series to initially mask the matches array

        mask_name : list or str
                    An arbitrary mask name for provenance tracking

        single : bool
                 If True, points with only a single entry are included (True)
                 in the result mask, else False.
        """
        def func(group):
            res = [False] * len(group)
            if len(res) == 1:
                return [single]
            if group.iloc[0] < group.iloc[1] * ratio:
                res[0] = True
            return res

        self.single = single

        if mask is not None:
            self.mask = mask.copy()
            new_mask = self.matches[mask].groupby('source_idx')['distance'].transform(func).astype('bool')
            self.mask[mask==True] = new_mask
        else:
            new_mask = self.matches.groupby('source_idx')['distance'].transform(func).astype('bool')
            self.mask = new_mask.copy()

        state_package = {'ratio': ratio,
                         'mask': self.mask.copy(),
                         'clean_keys': mask_name,
                         'single': single
                         }
        self._action_stack.append(state_package)
        self._current_action_stack = len(self._action_stack) - 1

    def subscribe(self, func):
        """
        Subscribe some observer to the edge

        Parameters
        ----------
        func : object
               The callable that is to be executed on update
        """
        self._observers.add(func)

    def _notify_subscribers(self, *args, **kwargs):
        """
        The 'update' call to notify all subscribers of
        a change.
        """
        for update_func in self._observers:
            update_func(self, *args, **kwargs)

    def rollforward(self, n=1):
        """
        Roll forwards in the object history, e.g. do

        Parameters
        ----------
        n : int
            the number of steps to roll forwards
        """
        idx = self._current_action_stack + n
        if idx > len(self._action_stack) - 1:
            idx = len(self._action_stack) - 1
        self._current_action_stack = idx
        state = self._action_stack[idx]
        setattr(self, 'mask', state['mask'])
        setattr(self, 'ratio', state['ratio'])
        setattr(self, 'clean_keys', state['clean_keys'])
        setattr(self, 'single', state['single'])
        # Reset attributes (could also cache)
        self._notify_subscribers(self)

    def rollback(self, n=1):
        """
        Roll backward in the object histroy, e.g. undo

        Parameters
        ----------
        n : int
            the number of steps to roll backwards
        """
        idx = self._current_action_stack - n
        if idx < 0:
            idx = 0
        self._current_action_stack = idx
        state = self._action_stack[idx]
        setattr(self, 'mask', state['mask'])
        setattr(self, 'ratio', state['ratio'])
        setattr(self, 'clean_keys', state['clean_keys'])
        setattr(self, 'single', state['single'])
        # Reset attributes (could also cache)
        self._notify_subscribers(self)

def self_neighbors(matches):
    """
    Returns a pandas data series intended to be used as a mask. Each row
    is True if it is not matched to a point in the same image (good) and
    False if it is (bad.)

    Parameters
    ----------
    matches : dataframe
              the matches dataframe stored along the edge of the graph
              containing matched points with columns containing:
              matched image name, query index, train index, and
              descriptor distance
    Returns
    -------
    : dataseries
      Intended to mask the matches dataframe. True means the row is not matched to a point in the same image
      and false the row is.
    """
    return matches.source_image != matches.destination_image

def mirroring_test(matches):
    """
    Compute and return a mask for the matches dataframe on each edge of the graph which
    will keep only entries in which there is both a source -> destination match and a destination ->
    source match.

    Parameters
    ----------
    matches : dataframe
              the matches dataframe stored along the edge of the graph
              containing matched points with columns containing:
              matched image name, query index, train index, and
              descriptor distance

    Returns
    -------
    duplicates : dataseries
                 Intended to mask the matches dataframe. Rows are True if the associated keypoint passes
                 the mirroring test and false otherwise. That is, if 1->2, 2->1, both rows will be True,
                 otherwise, they will be false. Keypoints with only one match will be False. Removes
                 duplicate rows.
    """
    duplicates = matches.duplicated(keep='first').astype(bool)
    return duplicates

def compute_fundamental_matrix(kp1, kp2, method='ransac', reproj_threshold=5.0, confidence=0.99):
    """
    Given two arrays of keypoints compute the fundamental matrix

    Parameters
    ----------
    kp1 : ndarray
          (n, 2) of coordinates from the source image

    kp2 : ndarray
          (n, 2) of coordinates from the destination image

    outlier_algorithm : {'ransac', 'lmeds', 'normal'}
                        The openCV algorithm to use for outlier detection

    reproj_threshold : float
                       The maximum distances in pixels a reprojected points
                       can be from the epipolar line to be considered an inlier

    confidence : float
                 [0, 1] that the estimated matrix is correct

    Returns
    -------
    transformation_matrix : ndarray
                            The 3x3 transformation matrix

    mask : ndarray
           Boolean array of the outliers

    Notes
    -----
    While the method is user definable, if the number of input points
    is < 7, normal outlier detection is automatically used, if 7 > n > 15,
    least medians is used, and if 7 > 15, ransac can be used.
    """

    if method == 'ransac':
        method_ = cv2.FM_RANSAC
    elif method == 'lmeds':
        method_ = cv2.FM_LMEDS
    elif method == 'normal':
        method_ = cv2.FM_7POINT
    else:
        raise ValueError("Unknown outlier detection method.  Choices are: 'ransac', 'lmeds', or 'normal'.")

    transformation_matrix, mask = cv2.findFundamentalMat(kp1,
                                                     kp2,
                                                     method_,
                                                     reproj_threshold,
                                                     confidence)
    try:
        mask = mask.astype(bool)
    except: pass  # pragma: no cover

    return transformation_matrix, mask

def compute_homography(kp1, kp2, method='ransac', **kwargs):
    """
    Given two arrays of keypoints compute the homography

    Parameters
    ----------
    kp1 : ndarray
          (n, 2) of coordinates from the source image

    kp2 : ndarray
          (n, 2) of coordinates from the destination image

    method : {'ransac', 'lmeds', 'normal'}
             The openCV algorithm to use for outlier detection

    ransacReprojThreshold : float
                            The maximum distances in pixels a reprojected points
                            can be from the epipolar line to be considered an inlier

    Returns
    -------
    transformation_matrix : ndarray
                            The 3x3 perspective transformation matrix

    mask : ndarray
           Boolean array of the outliers

    Notes
    -----
    While the method is user definable, if the number of input points
    is < 7, normal outlier detection is automatically used, if 7 > n > 15,
    least medians is used, and if 7 > 15, ransac can be used.
    """

    if method == 'ransac':
        method_ = cv2.RANSAC
    elif method == 'lmeds':
        method_ = cv2.LMEDS
    elif method == 'normal':
        method_ = 0  # Normal method
    else:
        raise ValueError("Unknown outlier detection method.  Choices are: 'ransac', 'lmeds', or 'normal'.")

    transformation_matrix, mask = cv2.findHomography(kp1,
                                                     kp2,
                                                     method_,
                                                     **kwargs)
    if mask is not None:
        mask = mask.astype(bool)
    return transformation_matrix, mask

# TODO: CITATION and better design?
def adaptive_non_max_suppression(keypoints, n, robust):
    """
    Select the top n keypoints, using Adaptive Non-Maximal Suppression (see: Brown (2005) [Brown2005]_)
    to rank the keypoints in order of largest minimum suppression
    radius. A mask with only the positions of the top n keypoints set to 1 (and all else set to 0) is returned.

    Parameters
    ----------
    keypoints : list
               List of KeyPoint objects from a node of the graph or equivalently, for 1 image.

    n : int
        The number of top-ranked keypoints to return.

    Returns
    -------
    keypoint_mask : list
                    A list containing a 1 in the positions of the top n selected keypoints and 0 in the positions
                    of all the other keypoints.
    """
    minimum_suppression_radius = {}
    for i, kp1 in keypoints.iterrows():
        x1 = kp1['x']
        y1 = kp1['y']
        temp = []
        for j, kp2 in keypoints.iterrows(): #includes kp1 for now
            if kp1['response'] < robust*kp2['response']:
                x2 = kp2['x']
                y2 = kp2['y']
                temp.append(np.sqrt((x2-x1)**2 + (y2-y1)**2))
        if(len(temp) > 0):
            minimum_suppression_radius[i] = np.min(np.array(temp))
        else:
            minimum_suppression_radius[i] = np.nan
    df = pd.DataFrame(list(minimum_suppression_radius.items()), columns=['keypoint', 'radius'])
    top_n = df.sort_values(by='radius', ascending=False).head(n)
    temp_df = df.mask(df.radius < top_n.radius.min(), other=np.nan)
    temp_df = temp_df.where(np.isnan(temp_df.keypoint), other=1)
    temp_df = temp_df.mask(np.isnan(temp_df.keypoint), other=0)
    return np.array(temp_df.radius, dtype=np.bool)


import data
import queries as q

def orderExists(orderId):
    return q.checkRecordExistByConditions("Orders", "order_id = '%s'", orderId)

def itemExists(itemId):
    return q.checkRecordExistByConditions("Items", "item_id = '%s'", itemId)

def allocationExists(alloId):
    return q.checkRecordExistByConditions("Allocations", "allo_id = '%s'", alloId)

def createOrder(groupId, orderName, numOfItems):
    check = q.insertRecordTo(
        "Orders", "(group_id, order_name, item_unres_num)",
        (groupId, orderName, numOfItems), "(%s, %s, %s)",
    )

    if check:
        result_list = q.selectInfoByConditions(
            "Orders", "order_id",
            "order_name = '%s' AND group_id = '%s'", (orderName, groupId),
        )
        if len(result_list) > 0:
            return result_list[-1]['order_id']  # get the newly inserted
    return -1  # failed

def deleteOrderById(orderId):
    return q.deleteRecordByCondition("Orders", "order_id = '%s'", str(orderId))

def createReceipt(orderId, receiptPath, receiptIdx=1):
    if not (orderExists(orderId)):
        return (-1, -1)

    if not q.insertRecordTo(
        "OrderReceipts", "(order_id, receipt_idx, "
        "receipt_path)", (orderId, receiptIdx, receiptPath), "(%s, %s, %s)",
    ):
        return (-1, -1)

    return (orderId, receiptIdx)

def deleteReceipt(orderId, receiptIdx):
    return q.deleteRecordByCondition(
        "OrderReceipts",
        " order_id = '%s' AND receipt_idx = '%s'", (orderId, receiptIdx),
    )

def createItem(itemName, leftAmount, orderId):
    q.insertRecordTo(
        "Items", "(item_name, left_amount, order_id)",
        (itemName, leftAmount, orderId), "(%s, %s, %s)",
    )
    result_list = q.selectInfoByConditions(
        "Items", "item_id",
        "order_id = '%s' AND item_name = '%s'", (orderId, itemName),
    )
    if len(result_list) > 0:
        return result_list[0]['item_id']
    else:
        return -1

def deleteItemById(itemId):
    return q.deleteRecordByCondition("Items", "item_id = '%s'", itemId)

def modifyItemName(itemId, itemName):
    if not itemExists(itemId):
        return False
    return q.updateRecordByConditions(
        "Items", "item_name = '%s'",
        "item_id = %s", (itemName, str(itemId)),
    )

def modifyItemAmount(itemId, itemAmount):
    if not itemExists(itemId):
        return False
    if itemAmount > data.MAX_AMOUNT or itemAmount < 0:
        return False
    return q.updateRecordByConditions(
        "Items", "left_amount = '%s'",
        "item_id = %s", (itemAmount, str(itemId)),
    )

def deductItemAmount(itemId, allocated):  # diff >= 0
    # Assume the item exists
    prevAmount = q.selectInfoByConditions(
        "Items", "left_amount",
        "item_id = '%s'", str(itemId),
    )[0]['left_amount']
    return modifyItemAmount(itemId, prevAmount - allocated)

def createAllocation(userId, itemId, alloAmount):
    if not itemExists(itemId):
        return -1

    leftAmount = q.selectInfoByConditions(
        "Items", "left_amount",
        "item_id = '%s'", itemId,
    )[0]['left_amount']
    if alloAmount > leftAmount:
        return -1

    if not deductItemAmount(itemId, alloAmount):  # Modify left_amount
        return -1

    if not q.insertRecordTo(
        "Allocations", "(item_id, user_id, allo_amount)",
        (str(itemId), str(userId), str(alloAmount)), "(%s, %s, %s)",
    ):
        return -1

    return q.selectInfoByConditions(
        "Allocations", "allo_id",
        "item_id = '%s' AND user_id = '%s'", (itemId, userId),
    )[-1]['allo_id']

def deleteAllocation(alloId):
    if not allocationExists(alloId):
        return False

    result = q.selectAllByConditions(
        "Allocations", "allo_id = '%s'", alloId,
    )[0]
    itemId = result['item_id']
    alloAmount = result['allo_amount']
    curAmount = q.selectInfoByConditions(
        "Items", "left_amount",
        "item_id = '%s'", itemId,
    )[0]['left_amount']

    if not modifyItemAmount(itemId, curAmount + alloAmount):
        return False
    return q.deleteRecordByCondition("Allocations", "allo_id = '%s'", alloId)

def modifyAllocatedAmount(alloId, alloAmount):
    if not allocationExists(alloId):
        return False

    result = q.selectAllByConditions(
        "Allocations", "allo_id = '%s'", alloId,
    )[0]
    itemId = result['item_id']
    curAllo = result['allo_amount']
    curAmount = q.selectInfoByConditions(
        "Items", "left_amount",
        "item_id = '%s'", itemId,
    )[0]['left_amount']

    recoverAmount = curAmount + curAllo

    if alloAmount > recoverAmount:
        return False

    if not q.updateRecordByConditions(
        "Allocations", "allo_amount = '%s'",
        "allo_id = '%s'", (alloAmount, alloId),
    ):
        return False

    return q.updateRecordByConditions(
        "Items", "left_amount = '%s'",
        "item_id = '%s'", (recoverAmount - alloAmount, itemId),
    )


"""
Check platform status after reboot. Three types of reboot are covered in this script:
* Cold reboot
* Fast reboot
* Warm reboot

This script is to cover the test case 'Reload configuration' in the SONiC platform test plan:
https://github.com/Azure/SONiC/blob/master/doc/pmon/sonic_platform_test_plan.md
"""
import logging
import re
import os
import time
import sys

from datetime import datetime

import pytest

from platform_fixtures import conn_graph_facts
from psu_controller import psu_controller
from common.utilities import wait_until
from check_critical_services import check_critical_services
from check_transceiver_status import check_transceiver_basic
from check_daemon_status import check_pmon_daemon_status
from check_all_interface_info import check_interface_information

pytestmark = [pytest.mark.disable_loganalyzer]

REBOOT_TYPE_WARM = "warm"
REBOOT_TYPE_COLD = "cold"
REBOOT_TYPE_FAST = "fast"
REBOOT_TYPE_POWEROFF = "power off"
REBOOT_TYPE_WATCHDOG = "watchdog"

reboot_ctrl_dict = {
    REBOOT_TYPE_POWEROFF: {
        "timeout": 300,
        "cause": "Power Loss",
        "test_reboot_cause_only": True
    },
    REBOOT_TYPE_COLD: {
        "command": "reboot",
        "timeout": 300,
        "cause": "reboot",
        "test_reboot_cause_only": False
    },
    REBOOT_TYPE_FAST: {
        "command": "fast-reboot",
        "timeout": 180,
        "cause": "fast-reboot",
        "test_reboot_cause_only": False
    },
    REBOOT_TYPE_WARM: {
        "command": "warm-reboot",
        "timeout": 180,
        "cause": "warm-reboot",
        "test_reboot_cause_only": False
    },
    REBOOT_TYPE_WATCHDOG: {
        "command": "python -c \"import sonic_platform.platform as P; P.Platform().get_chassis().get_watchdog().arm(5); exit()\"",
        "timeout": 300,
        "cause": "Watchdog",
        "test_reboot_cause_only": True
    }
}

def check_reboot_cause(dut, reboot_cause_expected):
    """
    @summary: Check the reboot cause on DUT.
    @param dut: The AnsibleHost object of DUT.
    @param reboot_cause_expected: The expected reboot cause.
    """
    logging.info("Check the reboot cause")
    output = dut.shell("show reboot-cause")
    reboot_cause_got = output["stdout"]
    logging.debug("show reboot-cause returns {}".format(reboot_cause_got))
    m = re.search(reboot_cause_expected, reboot_cause_got)
    assert m is not None, "got reboot-cause %s after rebooted by %s" % (reboot_cause_got, reboot_cause_expected)

def reboot_and_check(localhost, dut, interfaces, reboot_type=REBOOT_TYPE_COLD, reboot_helper=None, reboot_kwargs=None):
    """
    Perform the specified type of reboot and check platform status.
    @param localhost: The Localhost object.
    @param dut: The AnsibleHost object of DUT.
    @param interfaces: DUT's interfaces defined by minigraph
    @param reboot_type: The reboot type, pre-defined const that has name convention of REBOOT_TYPE_XXX.
    @param reboot_helper: The helper function used only by power off reboot
    @param reboot_kwargs: The argument used by reboot_helper
    """
    logging.info("Run %s reboot on DUT" % reboot_type)

    assert reboot_type in reboot_ctrl_dict.keys(), "Unknown reboot type %s" % reboot_type

    reboot_timeout = reboot_ctrl_dict[reboot_type]["timeout"]
    reboot_cause = reboot_ctrl_dict[reboot_type]["cause"]

    dut_datetime = datetime.strptime(dut.command('date -u +"%Y-%m-%d %H:%M:%S"')["stdout"], "%Y-%m-%d %H:%M:%S")

    if reboot_type == REBOOT_TYPE_POWEROFF:
        assert reboot_helper is not None, "A reboot function must be provided for power off reboot"

        reboot_helper(reboot_kwargs)

        localhost.wait_for(host=dut.hostname, port=22, state="stopped", delay=10, timeout=120)
    else:
        reboot_cmd = reboot_ctrl_dict[reboot_type]["command"]
        reboot_task, reboot_res = dut.command(reboot_cmd, module_ignore_errors=True, module_async=True)

        logging.info("Wait for DUT to go down")
        res = localhost.wait_for(host=dut.hostname, port=22, state="stopped", timeout=180, module_ignore_errors=True)
        if "failed" in res:
            try:
                logging.error("Wait for switch down failed, try to kill any possible stuck reboot task")
                pid = dut.command("pgrep -f '%s'" % reboot_cmd)["stdout"]
                dut.command("kill -9 %s" % pid)
                reboot_task.terminate()
                logging.error("Result of command '%s': " + str(reboot_res.get(timeout=0)))
            except Exception as e:
                logging.error("Exception raised while cleanup reboot task and get result: " + repr(e))

    logging.info("Wait for DUT to come back")
    localhost.wait_for(host=dut.hostname, port=22, state="started", delay=10, timeout=reboot_timeout)

    logging.info("Check the uptime to verify whether reboot was performed")
    dut_uptime = datetime.strptime(dut.command("uptime -s")["stdout"], "%Y-%m-%d %H:%M:%S")
    assert float(dut_uptime.strftime("%s")) - float(dut_datetime.strftime("%s")) > 10, "Device did not reboot"

    logging.info("Wait until all critical services are fully started")
    check_critical_services(dut)

    logging.info("Check reboot cause")
    check_reboot_cause(dut, reboot_cause)

    if reboot_ctrl_dict[reboot_type]["test_reboot_cause_only"]:
        logging.info("Further checking skipped for %s test which intends to verify reboot-cause only".format(reboot_type))
        return

    logging.info("Wait some time for all the transceivers to be detected")
    assert wait_until(300, 20, check_interface_information, dut, interfaces), \
        "Not all transceivers are detected or interfaces are up in 300 seconds"

    logging.info("Check transceiver status")
    check_transceiver_basic(dut, interfaces)

    logging.info("Check pmon daemon status")
    assert check_pmon_daemon_status(dut), "Not all pmon daemons running."

    if dut.facts["asic_type"] in ["mellanox"]:

        current_file_dir = os.path.dirname(os.path.realpath(__file__))
        sub_folder_dir = os.path.join(current_file_dir, "mellanox")
        if sub_folder_dir not in sys.path:
            sys.path.append(sub_folder_dir)
        from check_hw_mgmt_service import check_hw_management_service
        from check_sysfs import check_sysfs

        logging.info("Check the hw-management service")
        check_hw_management_service(dut)

        logging.info("Check sysfs")
        check_sysfs(dut)

def test_cold_reboot(testbed_devices, conn_graph_facts):
    """
    @summary: This test case is to perform cold reboot and check platform status
    """
    ans_host = testbed_devices["dut"]
    localhost = testbed_devices["localhost"]

    reboot_and_check(localhost, ans_host, conn_graph_facts["device_conn"], reboot_type=REBOOT_TYPE_COLD)

def test_fast_reboot(testbed_devices, conn_graph_facts):
    """
    @summary: This test case is to perform cold reboot and check platform status
    """
    ans_host = testbed_devices["dut"]
    localhost = testbed_devices["localhost"]

    reboot_and_check(localhost, ans_host, conn_graph_facts["device_conn"], reboot_type=REBOOT_TYPE_FAST)

def test_warm_reboot(testbed_devices, conn_graph_facts):
    """
    @summary: This test case is to perform cold reboot and check platform status
    """
    ans_host = testbed_devices["dut"]
    localhost = testbed_devices["localhost"]
    asic_type = ans_host.facts["asic_type"]

    if asic_type in ["mellanox"]:
        issu_capability = ans_host.command("show platform mlnx issu")["stdout"]
        if "disabled" in issu_capability:
            pytest.skip("ISSU is not supported on this DUT, skip this test case")

    reboot_and_check(localhost, ans_host, conn_graph_facts["device_conn"], reboot_type=REBOOT_TYPE_WARM)

@pytest.fixture(params=[15, 5])
def power_off_delay(request):
    """
    @summary: used to parametrized test cases on power_off_delay
    @param request: pytest request object
    @return: power_off_delay
    """
    return request.param

def _power_off_reboot_helper(kwargs):
    """
    @summary: used to parametrized test cases on power_off_delay
    @param kwargs: the delay time between turning off and on the PSU
    """
    psu_ctrl = kwargs["psu_ctrl"]
    all_psu = kwargs["all_psu"]
    power_on_seq = kwargs["power_on_seq"]
    delay_time = kwargs["delay_time"]

    for psu in all_psu:
        logging.debug("turning off {}".format(psu))
        psu_ctrl.turn_off_psu(psu["psu_id"])
    time.sleep(delay_time)
    logging.info("Power on {}".format(power_on_seq))
    for psu in power_on_seq:
        logging.debug("turning on {}".format(psu))
        psu_ctrl.turn_on_psu(psu["psu_id"])

def test_power_off_reboot(testbed_devices, conn_graph_facts, psu_controller, power_off_delay):
    """
    @summary: This test case is to perform reboot via powercycle and check platform status
    @param testbed_devices: Fixture initialize devices in testbed
    @param conn_graph_facts: Fixture parse and return lab connection graph
    @param psu_controller: The python object of psu controller
    @param power_off_delay: Pytest fixture. The delay between turning off and on the PSU
    """
    ans_host = testbed_devices["dut"]
    localhost = testbed_devices["localhost"]

    psu_ctrl = psu_controller(ans_host.hostname, ans_host.facts["asic_type"])
    if psu_ctrl is None:
        pytest.skip("No PSU controller for %s, skip rest of the testing in this case" % ans_host.hostname)

    all_psu = psu_ctrl.get_psu_status()

    # Purpose of this list is to control sequence of turning on PSUs in power off testing.
    # If there are 2 PSUs, then 3 scenarios would be covered:
    # 1. Turn off all PSUs, turn on PSU1, then check.
    # 2. Turn off all PSUs, turn on PSU2, then check.
    # 3. Turn off all PSUs, turn on one of the PSU, then turn on the other PSU, then check.
    power_on_seq_list = []
    if all_psu:
        power_on_seq_list = [[item] for item in all_psu]
        power_on_seq_list.append(all_psu)

    logging.info("Got all power on sequences {}".format(power_on_seq_list))

    poweroff_reboot_kwargs = {"dut": ans_host}

    for power_on_seq in power_on_seq_list:
        poweroff_reboot_kwargs["psu_ctrl"] = psu_ctrl
        poweroff_reboot_kwargs["all_psu"] = all_psu
        poweroff_reboot_kwargs["power_on_seq"] = power_on_seq
        poweroff_reboot_kwargs["delay_time"] = power_off_delay
        reboot_and_check(localhost, ans_host, conn_graph_facts["device_conn"], REBOOT_TYPE_POWEROFF,
                         _power_off_reboot_helper, poweroff_reboot_kwargs)

def test_watchdog_reboot(testbed_devices, conn_graph_facts):
    """
    @summary: This test case is to perform reboot via watchdog and check platform status
    """
    ans_host = testbed_devices["dut"]
    localhost = testbed_devices["localhost"]

    test_watchdog_supported = "python -c \"import sonic_platform.platform as P; P.Platform().get_chassis().get_watchdog(); exit()\""

    watchdog_supported = ans_host.command(test_watchdog_supported)["stderr"]
    if "" != watchdog_supported:
        pytest.skip("Watchdog is not supported on this DUT, skip this test case")

    reboot_and_check(localhost, ans_host, conn_graph_facts["device_conn"], REBOOT_TYPE_WATCHDOG)


from flask import Flask, send_from_directory, render_template
from flask_restful import Resource, Api
from flask_cors import CORS
from datetime import datetime

# Register all the folder structures inside src and their path
import sys
import os
project_root = os.path.dirname(os.path.realpath(os.path.join(__file__, '.')))

# Initialize app and enable cors to it
template_dir = os.path.join(project_root, 'public')
app = Flask(__name__, static_folder="public", template_folder=template_dir)
CORS(app)
api = Api(app)

# Routes and their mapping
@app.route('/')
def serve_home_page():
    return render_template('index.html')

@app.route('/firealert', methods = ['GET'])
def alert_for_fire():
    print("FIRE ALERT!!! --", datetime.now())
    return render_template('firealert.html')

@app.route('/piggyback', methods = ['GET'])
def alert_for_piggybacking():
    print("PIGGYBACK ALERT!!! --", datetime.now())
    return render_template('piggyback.html')

@app.route('/access/<name>', methods = ['GET'])
def access_verify(name):
    # print(name)
    if (name == 'suchi' or name == 'lizi' or name == 'chetan'):
        print("ACCESS GRANTED FOR", name, "AT", datetime.now())
        return render_template('accessgranted.html', name = name)
    else:
        print("ACCESS DENIED FOR", name, "AT", datetime.now())
        return render_template('accessdenied.html', name = name)

if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True, port=3001)
    # print("Hello")


from dps_metric_api.models import User, Activity
from dps_metric_api.extensions import db
from dps_metric_api.main import app

def teardown_metric_test_entry():
    with app.app_context():
        ckan_user_id = '123-456-123-abc'

        user = User.query.filter_by(ckan_user_id=ckan_user_id)
        activity = Activity.query.filter_by(ckan_user_id=ckan_user_id)

        if user and activity:
            user.delete()
            activity.delete()
            db.session.commit()
            db.session.close()


"""The text module

This module supports various text utility functions as:

    * lineiter - iterate on text lines
    * linestrip - removes empty lines at the begin of a text
    * indent - removes empty lines at the ends of a text and indents it

"""
import re
import os
import collections

import six

def _startendswith(txt, values, method, casesensitive=True):
    values = [values,] if isinstance(values, six.string_types) else values
    if casesensitive:
        itxt, ivalues = txt, values
    else:
        itxt = txt.upper()
        ivalues = [ v.upper() for v in values]

    for i, v in enumerate(ivalues or []):
        if getattr(itxt, method)(v):
            return values[i]

def endswith(txt, values, casesensitive=True):
    """return the value matching the ending of txt

    This function returns a value if any of values match ends of txt.

    Example:

        >>> endswith('hello.txt', [ '.txt', '.o'])
        '.txt'

    Args:
        txt (str): the text to match
        values (str or list of str): the candindate endings

    Returns:
        txt or None: the matching text
"""
    return _startendswith(txt, values, 'endswith', casesensitive=casesensitive)

def startswith(txt, values, casesensitive=True):
    """return the value matching the ending of txt

    This function returns a value if any of values match ends of txt.

    Example:

        >>> endswith('hello.txt', [ '.txt', '.o'])
        '.txt'

    Args:
        txt (str): the text to match
        values (str or list of str): the candindate endings

    Returns:
        txt or None: the matching text
   """

    return _startendswith(txt, values, 'startswith', casesensitive=casesensitive)

def findlongestCommon(lines):
   scope, common = False, ''
   for line in lines:
       if line and not scope:
           scope = True
           common = line

       if not scope:
           continue

       if not line:
           continue

       if not common:
           return

       match = [ 1 if l==r else 0 for l, r in zip(common, line) ]
       if all(match):
           continue
       if not any(match):
           return ''

       first0 = match.index(0)
       if first0 == 0:
           return ''

       common = common[:first0]
   return common

def indent(txt, prefix=' '*3, dedent=False):
    '''indent text

   Args:
       txt (str): a string to be indented
       prefix (str): the indentation string
       dedent (bool): dedent lines before indenting them

   Examples:

       >>> print(indent("""
        ...
        ...   Wow
        ...
        ...   This is a
        ... very complex text!
        ...
        ... """, pre='.'))
        .  Wow
        .
        .  This is a
        .very complex text!

'''

    if not txt:
        return ''

    # skip the empty lines at begin, until the first empty line at the end
    lines = [l.strip() for l in txt.split('\n')]
    i0, i1 = 0, len(lines)
    for i in range(len(lines)):
        if lines[i]:
            i0 = i
            break
    for i in reversed(range(len(lines))):
        if lines[i]:
            i1 = i+1
            break
    # all lines with text
    lines = txt.split('\n')[i0:i1]

    # if we dedent...
    if dedent:
        common = findlongestCommon(lines)
        lines = [ l[len(common):] for l in lines ]

    return '\n'.join((prefix + l) for l in lines).strip()

def docparse(txt, sep=':', container=collections.OrderedDict):
    """parses a simple key value text into a dictionary

    Args:
        txt (str): the triple quoted string to strip
        sep (str): key value separator
        container (class): dict-like class to store the data

    Examples:

        >>> kvals = docparse('''
        ...   Key: Value
        ...   Key1: Value 1
        ...   Document: a long value
        ...     split across lines
        ...      with indented text
        ...       spanning multiple lines
        ...   Document1: a long value
        ...     split across lines
        ...      another
        ... ''', container=dict)
        >>> expected = {
        ...   'key': 'Value',
        ...   'key1': 'Value 1',
        ...   'document': 'a long value\\nsplit across lines\\n with indented text\\n  spanning multiple lines',
        ...   'document1': 'a long value\\nsplit across lines\\n another'}
        >>> kvals == expected
        True
    """
    expr = re.compile(r'^\s*(?P<key>\w+)\s*'+sep)

    thiskey, result = None, container()
    for line in txt.split('\n'):
        match = expr.search(line)
        if match:
            thiskey = match.group('key').lower()
            #if not thiskey in result: result[thiskey] = []
            result[thiskey] = []
            result[thiskey].append(line.partition(sep)[2])
            continue
        if thiskey:
            if not thiskey in result: result[thiskey] = []
            result[thiskey].append(line)
    for key in result:
        value = result[key]
        if len(result[key]) > 1:
            #import pdb; pdb.set_trace()
            line0, lines = result[key][0], result[key][1:]
            common = findlongestCommon(lines)
            value = [ line0.strip(), ]
            for l in lines:
                value.append(l[len(common):])
            value = '\n'.join(value).rstrip()
        else:
            value = result[key][0].strip()
        result[key] = value
    return result

def docsplit(txt, prefix='', join=False, dedent=True, sep=os.linesep):
    """splits txt into a description part and an epilog part

    Args:
        txt (str): a string to be indented
        sep (str): the char to use as separator between the parts

    """
    txt = txt or ''
    if not txt or not sep in txt:
        return txt, ''

    summary, _, doc = txt.lstrip().partition(sep)
    result = summary, indent(doc, prefix, dedent=dedent)
    return sep.join(result) if (join is True) else (join.join(result) if join else result)

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


from django.contrib import messages
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse
from django.views import View

from app.forms.RequestForms import CreateRequestForm
from app.forms.PaymentAccountsForms import PaymentAccountsForm, RemovePaymentAccountForm
from app.mixins import LoginAndOTPRequiredMixin
from app.models import MyUser, UserRequest
from app.views import CommonHelpers
from app.views.known_accounts.KnownAccountHelpers import get_account_from_number, check_same_user_account
from app.views.payment_accounts.PaymentAccountHelpers import get_payment_accounts, check_duplicate
import logging

logger = logging.getLogger(__name__)

class EnterPaymentAccountsView(LoginAndOTPRequiredMixin, View):
    def get(self, request):
        user = request.user

        target_user = MyUser.objects.filter(id=user.id, user_type=MyUser.MERCHANT, is_active=True).exclude(username=MyUser.ANON).first()

        if not target_user:
            return render(request, 'error.html', {
                'err': 'You cannot add user accounts',
            })

        form = PaymentAccountsForm()

        return render(request, 'form_template.html', {
            'title': 'User Accounts',
            'form': form,
        })

    def post(self, request):
        user = request.user

        target_user = MyUser.objects.filter(id=user.id, user_type=MyUser.MERCHANT, is_active=True).exclude(username=MyUser.ANON).first()

        if not target_user:
            return render(request, "error.html", {
                'err': "You cannot add client accounts"
            })

        form = PaymentAccountsForm(request.POST)

        if form.is_valid():
            acc_number = form.cleaned_data['account_number']
            account = get_account_from_number(acc_number)

            if check_same_user_account(target_user.id, acc_number):
                return render(request, 'error.html', {
                    'err': 'Please don\'t enter your own accounts.',
                })

            if check_duplicate(target_user.id, acc_number):
                return render(request, 'error.html', {
                    'err': 'Account exists in your list',
                })

            form = CreateRequestForm(data={
                'request_type': UserRequest.CREATE,
                'model_type': UserRequest.ACCOUNT,
            })

            if form.is_valid():

                user_request = form.save(commit=False)
                user_request.from_user = target_user
                user_request.to_user = account.user
                user_request.account_obj = account

                if CommonHelpers.is_request_duplicate(user_request):
                    messages.warning(request, 'Request Already Sent')

                    return HttpResponseRedirect(reverse('app:HomeView'))

                user_request.save()

                messages.success(request, 'Request Sent To %s' % user_request.to_user)
                logger.info("Request for new adding client account %s sent by %s", str(account.user.username), str(target_user.username))

                return HttpResponseRedirect(reverse('app:HomeView'))
            else:

                return render(request, "error.html", {
                    'err': "Request could not be sent"
                })

        return render(request, 'form_template.html', {
            'title': 'User Accounts',
            'form': form,
        })

class ViewPaymentccounts(LoginAndOTPRequiredMixin, View):
    def get(self, request):
        user = request.user

        target_user = MyUser.objects.filter(id=user.id, user_type= MyUser.MERCHANT, is_active=True).exclude(username=MyUser.ANON).first()

        if not target_user:
            return render(request, 'error.html', {
                'err': 'You cannot add user accounts',
            })

        links = get_payment_accounts(target_user.id)

        return render(request, 'display_list.html', {
            'title': 'Payment Accounts',
            'links': links,
        })

class RemovePaymentAccounts(LoginAndOTPRequiredMixin, View):

    def get(self, request):

        user = request.user

        if user.is_merchant() or user.is_individual_user():

            form = RemovePaymentAccountForm(user)

            return render(request, 'form_template.html', {
                'title': 'Remove Merchant User Account Permission',
                'form': form,
            })

        return render(request, 'error.html', {
            'err': 'You do not have permissions to view this.',
        })

    def post(self, request):

        user = request.user

        if user.is_merchant() or user.is_individual_user():

            form = RemovePaymentAccountForm(user, request.POST)

            if form.is_valid():

                merchant_account = form.cleaned_data['merchant_account']
                merchant_account.delete()

                messages.success(request, 'Merchant permissions removed')
                logger.info("User account permissions of %s removed by %s", merchant_account.merchant_user.__str__(), str(user.username))

                return HttpResponseRedirect(reverse('app:HomeView'))

        return render(request, 'error.html', {
            'err': 'You do not have permissions to view this.',
        })