"""Collection of experimental functions (beta)"""

import os
import numpy as np
import csv as csv
import lmlib as lm
import itertools
import datetime as datetime

__all__ = ['find_max_mask',
           'load_source_csv',
           'zero_cross_ind',
           'diff0',
           'edge_detection',
           'poly_filter',
           'mpoly_fit_subspace1',
           'constrain_matrix_for_exponents'
           ]

"""
 This file hosts helper functions or classes which are provided as beta and will later be transferred to the library
 when having reached a stable state.
"""

def find_max_mask(y, msks, locs=None, range_start=None, range_end=None,  threshold=-np.inf, direction='maximum', skip_invalid=False, SHOW_DEBUG_PLOT=False):

    """
        Advanced peak finder with masked samples and search intervals.

        This peak finder finds in signal :code:`y` for every interval that sample fulfilling multiple criteria.

        Parameters
        ----------
        y : array_like, shape=(K,)
            input signal
        msks: array_like of shape=(K) of Boolean OR tuple of array_like of shape=(K) of Boolean,
            a mask or a list of masks each of length :code:`K` with :code:`True` for any valid samples.
            If multiple masks are provided, a sample is only valid, if set :code:`True` in all masks (multiple mask are merged using logic AND).
            The peak index is decided among all valid samples
        locs: array_line of shape=(P) of int,
            reference index for `P` intervals
        range_start: int
            start index of a interval relative to the reference index
        range_end: int
            end index of a interval relative to the reference index
        threshold: int
           min. value in :code:`y` for peaks
        direction: string {"forward", "backward", "maximum"}
           search direction :code:`"forward"` or :code:`"backward"` (return first value fulfilling all criteria) or :code:`"maximum"` (take maximum value of y)
        skip_invalid: bool
           :code:`True`: removes entries if no peak is found in a certain interval.
           :code:`False`: if no peak is found in a certain interval, the index is set to -1 instead.
            default: False

        Returns
        -------
        out: ndarray of shape(<=K,) of int
             index per location interval or -1 if :code:`skip_invalid == False`.
             if :code:`skip_invalid == True`, the returned vector might has less than `K` entries.

    """

    K = len(y)
#    msk_locs = np.zeros((K,), dtype=bool)
    if msks is None: # TODO: speed up, not very efficient to creat mask if not neede
        msk_merged=np.zeros((K, ), dtype=bool)
    elif type(msks) == tuple:
        msk_merged=np.ones((K, ), dtype=bool)
        for m in msks:
            msk_merged = msk_merged & m
    else:
        msk_merged = msks

    if not locs is None:
        NOF_LOCS = len(locs)
        ind = np.array([0] * NOF_LOCS)
        if range_start==None:
            msk_locs[locs] = True
        else:
            for iloc in range(len(locs)):
                loc = locs[iloc]
                # todo: do faster using convolution
                ind_start = np.minimum(np.maximum(loc+range_start, 0), K) # extract interval around current loc index
                ind_end = np.minimum(np.maximum(loc+range_end, 0), K)

                y_loc = y[ind_start:ind_end]
                k_loc = np.arange(len(y_loc))

                loc_msk = (y_loc>=threshold) & msk_merged[ind_start:ind_end]
                intLen = ind_end - ind_start

                if (len(loc_msk)) and (np.max(loc_msk)==True): # is mask not all False?
                    if direction=='forward':
                        rel_ind = np.argmax(loc_msk)
                    elif direction=='backward':
                        rel_ind = intLen - np.argmax(np.flip(loc_msk)) - 1
                    elif direction=='maximum':
                        rel_ind = k_loc[loc_msk][np.argmax(y_loc[loc_msk])]
                    else:
                        print("INVALID DIRECITON") # todo: throw error

                    ind[iloc] = rel_ind+ind_start
                else:
                    ind[iloc] = -1

                #print(y[ind_start:ind_end]>=height)
                #print(loc_msk[rel_ind])
                #print("R (loc)"+str(loc)+"rel_ind: "+str(rel_ind)+" ind[iloc]: "+ str(ind[iloc]))

                if SHOW_DEBUG_PLOT: # display debug plots
                    k = range(ind_start,ind_end)
                    _, axs = plt.subplots(5, 1, sharex='all')

                    axs[0].set(xlabel='window', label='win')
                    axs[0].plot(k, y[ind_start:ind_end],label='y')
#                    axs[0].plot(k[loc_msk], y[ind_start:ind_end][loc_msk], 'k.', label='peak')
                    axs[0].plot(ind[iloc], y[ind[iloc]], 'r.', label='peak')
                    axs[0].legend()

                    axs[1].plot(k, (y[ind_start:ind_end]>=threshold), label='y>threshold')
                    for m in msks:
                        axs[1].plot(k, m[ind_start:ind_end], label='msk')
                    axs[1].plot(k, msk_merged[ind_start:ind_end], 'r--', label='msk-merged')
                    axs[1].legend()

#                    axs[2].plot(k, (lcr0[ind_start:ind_end]) )

                    plt.show()

    if skip_invalid == True:
        return (ind[ind>=0])
    else:
        return (ind)

def load_source_csv(filename, time_format=None, K=-1, k=0, ch_select=None):
    r"""
    Loads time series from csv file with/without header section.

	File format:

    .. code-block:: text

	    # Description Line 1
	    # ...
	    # Description Line n
	    #
	    time,         signal1, signal2, ...
	    00:00:20.000, 10.34,   11.09, ...

    * Description: the file can start with an (optional) description section, prefixed with an '#'
    * Header: The data table can start with an (optional) column labels. A header line is detected, if the first data line starts with a non-nummeric character
    * Data: float values separated by either :code:`',',';','\space','\tab'`; first column commonly contains the time; either as float (seconds) or as 'hh:mm:ss.ttt'; the later will be converted to floats (in seconds).

    Parameters
    ----------
    filename : string
        csv file to be loaded
    time_format : string
        Format string to be used to decode first line:  "H:M:S" (e.g., 00:02:01.123) or None (e.g. 1.12)
    K : int
        Length of signal to be loaded or -1 to load until end of file.
        If `K` is larger than the maximal signal length, an assertion is raised.
    k : int
        Signal load start index.
        If `k` is larger than the maximal signal length, an assertion is raised.
    ch_select : int, list, None
        int: channel index to be loaded in single channel mode.
        list: List of `M` channels to be loaded in multi channel mode. Selects channel indices to be loaded from multi-channel signals. `0 <= ch_select < Number of CSV columns`.
        If set to `None`, all channels are loaded in multi channel mode and `M = Number of CSV columns`.
        First column in the CSV file is addressed as channel 0, and contains the time, if `time_format` is set accordingly.

    Returns
    -------
	out: Tuple (col_labels, data)
         with
             - col_labels: list of column labels; if csv does not provide column headers, headers are set as :code:`'col1','col2','col3', ...`  *** NOT YET IMPLEMENTED ***

             - data: (ndarray, shape=(K[, M])) – Multi-channel signal of shape=(K, M) if `ch_select` is of type `list`, single-channel signal of shape=(K, ) if `ch_select is of type `int`.
    """

    def string_to_float_array(arr):
        """ conversion of array of strings to array of floats; non-convertible values are substitutest by np.NAN """
        convertArr = []
        for s in arr.ravel():
            try:
                value = s.astype(np.float)
            except ValueError:
                value = np.NAN

            convertArr.append(value)

        return np.array(convertArr, dtype=float).reshape(arr.shape)

    if ch_select is None:
        ch_select = []
        is_multichannel = True
    elif isinstance(ch_select, int):
        ch_select = [ch_select,] # wrap int in a list
        is_multichannel = False
    elif isinstance(ch_select, list):
        is_multichannel = True
    else:
        assert True, "The attribute ch_select has an unsupported data type. Accepted types are: None -> loads all channels, list -> loads listed channels , int -> returns single channel."

#    print(os.path.abspath(filename) )

    with open(filename, newline='') as csvfile:
#        file_lines = csvfile.readlines()
        file_lines = [line.rstrip() for line in csvfile]

    header_str = ""

    READER_STATE = 0 # 0: reading comment header; 1: reading column headers; 2: reading values
    f_index = -1

    for data_line in file_lines:
        f_index += 1

        # update states

        if (f_index == 0) and len(data_line)>0 and (ord(data_line[0])>255): # Remove UTF Marking, if existing
            data_line = data_line[1:]

        if READER_STATE == 0:
            if data_line.startswith("#") is not True:
                READER_STATE = 1 # read header
            else:
                header_str += data_line + "\n"
                continue

        if READER_STATE == 1:
            if not data_line[:1].startswith(tuple('0123456789.-+')): # check header
                headers = data_line.split(',')
                READER_STATE = 2
                continue
            else:
                READER_STATE = 2 # read values
                break # read rest in a bunch

        if READER_STATE == 2:
            break

    K_file = len(file_lines)-f_index # total number of entries in file

    if k == 0:
        if K != -1:
            assert 0 <= K < K_file, "The signal length K is out of range." + \
                                    "\nExpected range: [0, {})".format(K_file) + \
                                    "\nFound K: {}".format(K)
    else:
        assert 0 <= k < K_file, "The signal start index k is out of range." + \
                                "\nExpected range: [0, {})".format(K_file) + \
                                "\nFound k: {}".format(k)
        if K != -1:
            assert 0 <= k + K < K_file, "The signal start + signal length is out of range." + \
                                        "\nExpected range: [0, {})".format(K_file) + \
                                        "\nReduce k to : {}".format(K_file - K - 1) + \
                                        "\nor reduce K to : {}".format(K_file - k - 1) + \
                                        "\nFound k+K: {}".format(k + K)

    f_index_start = f_index+k
    if K>=0:
        f_index_end = f_index_start + K
    else:
        f_index_end = K_file

    data = list(csv.reader(file_lines[f_index_start:f_index_end], delimiter=',', ))

    if len(data) > 0: # identify number of channels
        M = len(data[0])
    else:
        M = 0

    if time_format=="H:M:S":
        time_strs = [data_line[0].split(':') for data_line in data]

        y = np.concatenate(
                 (
                      np.array([[ ((float(time_str[0])*60+float(time_str[1])*60)+float(time_str[2])), ]  for time_str in time_strs]),
                      string_to_float_array(np.array(data)[:, 1:])
#                      np.array(data)[:, 1:].astype(
#                      np.float) # convert all columns to float except column 1
                 ), axis = 1)
    else: # no specific time format
        y = string_to_float_array(np.array(data))

    for ch in ch_select:
        assert 0 <= ch < M, "The channel selection is out of range." + \
                            "\nExpected range: [0, {})".format(M) + \
                            "\nFound channel in ch_select: {}".format(ch)

    if not ch_select:
        return y
    elif is_multichannel:
        return (y[:, ch_select]) # return multiple channels
    else:
        return (y[:, ch_select[0]]) # return single channel

def zero_cross_ind(y, threshold=0):
    """ Returns a list of the indeces of zero crossings

    Parameters
    ----------
        y: array_like of shape=(K,) of floats
             signal vector to detect zero-crossings
        threshold: float
             crossing threshold (default: 0).

    Returns
    -------
        out: ndarray of ints
            array with indices :code:`i` where :code:`y[i]<0` and :code:`y[i+1]>=0` (i.e., indices before the threshold).

    """
    return (np.where(np.diff(np.signbit(vals-zeros_at)))[0])

def diff0(y):
    """ Gets difference of consecutive elements in vector, starting with the first element

    This is the same as :code:`numpy.diff(y)`, but starting with the first element :code:`y[0]` as the first difference
    (leading to a vector of the same length as the input signal vector `y`.

    Implementation:

    .. code-block:: text

        return np.append(np.array(y[0]), np.diff(y))

    Parameters
    ----------
       y: array_like of shape(K,) of floats
           input signal vector

    Returns
    -------
       out: ndarray of shape(K,) of floats
            element-wise differences

    """
    return np.append(np.array(y[0]), np.diff(y))

def edge_detection(y, ab, g):
    r""" Performs edge detection applying joint line models

    Uses a two-line model to detect edges, according to
    example: :ref:`sphx_glr_generated_examples_11-lssm-costs-detection_example-ex110.0-edge-detection.py`

    Parameters
    ----------
    y: array_like of shape=(K,) of floats
       observation vector
    ab: tuple (a,b)
       - a (int, >0): left-sided window length (>0)
       - b (int, >0): right-sided window length (>0)
    g: tuple (g_a, g_b) of float
       Effective number of samples under the left-sided and right-sided window, see :class:`~lmlib.statespace.costfunc.CostSegment`.
         - g_a (float, >0): left-sided window length (>0)
         - g_b (float, >0): right-sided window length (>0)
    g_a: float
       Effective number of samples under the right-sided window, see :class:`~lmlib.statespace.costfunc.CostSegment`.

    Returns
    -------

    lcr: ndarray of shape(K,) of floats
         log-likelihood ratio for a detected edge
    y0: ndarray of shape(K,) of floats
        position estimate of edge on y-axis
    a0: ndarray of shape(K,) of floats
        line slope of left-sided model
    a1: ndarray of shape(K,) of floats
        line slope of right-sided model

    """

    # ALSSM models
    alssm_left = lm.AlssmPoly(poly_degree=1)  # A_L, c_L
    alssm_right = lm.AlssmPoly(poly_degree=1)  # A_R, c_R
    segment_left = lm.Segment(a=-ab[0], b=-1, direction=lm.FORWARD, g=g[0])
    segment_right = lm.Segment(a=0, b=ab[1], direction=lm.BACKWARD, g=g[1])
    F = [[1, 0], [0, 1]]  # mixing matrix, turning on and off models per segment (1=on, 0=off)
    ccost = lm.CompositeCost((alssm_left, alssm_right), (segment_left, segment_right), F, label="Edge-Model")

    # Linear Constraints

    # Forcing a continuous function of the two lines --> x_hat_edge
    H_edge = np.array([[1, 0, 0],  # x_1,left : offset of left line
                       [0, 1, 0],  # x_2,left : slope of left line
                       [1, 0, 0],  # x_1,right : offset of right line
                       [0, 0, 1]])  # x_2,right : slope of right line

    # Forcing additionally a common slope of the two lines --> x_hat_line
    H_line = np.array([[1, 0],  # x_1,left : offset of left line
                       [0, 1],  # x_2,left : slope of left line
                       [1, 0],  # x_1,right : offset of right line
                       [0, 1]])  # x_2,right : slope of right line

    # -- MODEL FITTING --
    # Filter
    separam = lm.SEParam(ccost)
    separam.filter(y)

    # constraint minimization
    x_hat_edge = separam.minimize_x(H_edge)
    x_hat_line = separam.minimize_x(H_line)

    # Square Error and LCR
    error_edge = separam.eval_errors(x_hat_edge)
    error_line = separam.eval_errors(x_hat_line)
    lcr = -1 / 2 * np.log(np.divide(error_edge, error_line))

    return (lcr, x_hat_edge[:,0], x_hat_edge[:,1], x_hat_edge[:,3])

def poly_filter(y, ab, g, poly_degree=0):
    r""" Performs edge detection applying joint line models

    Uses polynomial of oder 'poly_degree' to filter signal. (for poly_degree=0, the filter leads to a moving average filter)
    example: :ref:`sphx_glr_generated_examples_12-lssm-costs-filters-example-ex121.0-sc-filter.py`

    Parameters
    ----------
    y: array_like of shape=(K,) of floats
       observation vector
    ab: tuple (a,b)
       - a (int, >0): left-sided window length (>0)
       - b (int, >0): right-sided window length (>0)
    g: tuple (g_a, g_b) of float
       Effective number of samples under the left-sided and right-sided window, see :class:`~lmlib.statespace.costfunc.CostSegment`.
         - g_a (float, >0): left-sided window length (>0)
         - g_b (float, >0): right-sided window length (>0)
    g_a: float
       Effective number of samples under the right-sided window, see :class:`~lmlib.statespace.costfunc.CostSegment`.
    poly_degree: int
       degree of polynomial to fit; default: 0 (constant value, i.e., moving average)

    Returns
    -------

    y0: ndarray of shape(K,) of floats
         average estimate
    error: ndarray of shape(K,) of floats
        squared error of fit

    """

    # ALSSM models
    alssm = lm.AlssmPoly(poly_degree=poly_degree)
    segment_left = lm.Segment(a=-ab[0], b=-1, direction=lm.FORWARD, g=g[0])
    segment_right = lm.Segment(a=0, b=ab[1], direction=lm.BACKWARD, g=g[1])
    F = [[1, 1]]  # mixing matrix, turning on and off models per segment (1=on, 0=off)
    ccost = lm.CompositeCost((alssm, ), (segment_left, segment_right), F, label="filter-model")

    # -- MODEL FITTING --
    # Filter
    separam = lm.SEParam(ccost)
    separam.filter(y)

    # minimization
    x_hat = separam.minimize_x()

    # Square Error
    error = separam.eval_errors(x_hat)

    return (x_hat[:, 0], error)

def constrain_matrix_for_exponents(expos, threshold):
    """
    Creates a matrix which reduces exponents which are summed higher then the threshold

    Parameters
    ----------
    expos : tuple of array_like
        exponent vectors
    threshold : int
        Threshold

    Returns
    -------
    H : :class:`np.ndarray`
        H matrix
    """
    prod = list(itertools.product(*expos))
    mask = np.sum(prod, axis=1) > threshold
    H = np.eye(len(prod))
    return np.delete(H, np.argwhere(mask), 1)

def mpoly_fit_subspace1(betas, beta_expo, boundaries, coords, coord_expos, H=None, return_cost=False):
    """
    Fits a multivariate polynomial to polynomial subspace with corresponding coordinates

    Parameters
    ----------
    betas : array_like of shape (N, Q, ...)
        polynomial coefficients
    beta_expo : array_like of shape (Q,)
        exponent vector of beta
    boundaries : array_like of shape (2,)
        integral boundaries (lower, upper)
    coords : array_like of shape (N, M)
        coordinates of shape (M,) for each beta in betas
    coord_expos : tuple of shape (M,) of 1D- array_like
        exponent vector for each variable in coordinates
    H : None, array_like, optional
        output exponent reduction matrix ( max limit )
    return_cost : bool, optional
        returns additionally the cost for each sample

    Returns
    -------
    alphas : array_like
        coefficients of multivariate polynomial fit
    cost : array_like, optional
        Cost if flag `return_cost = True`

    """
    beta_expo = np.asarray(beta_expo)
    betas = np.asarray(betas)
    if betas.shape[1] != len(beta_expo):
        raise ValueError('beta is betas doesn\'t match with beta_expo. Wrong length.')
    N = betas.shape[0]
    if len(boundaries) != 2:
        raise ValueError('boundaries has not a length of 2')
    a = boundaries[0]
    b = boundaries[1]
    if a > b:
        raise ValueError('Condition not fulfilled: a <= b')
    coord_expos = np.asarray(coord_expos)
    if coord_expos.ndim != 2:
        raise ValueError('coord_expos has wrong number of dimensions. '
                         'Needs to be tuple(array_like)/tuple(array_like, array_like, ...)')
    coords = np.asarray(coords)
    if coords.shape != (N, len(coord_expos)):
        raise ValueError('coords  doesn\'t match with length of betas or with length of coord_expos.')

    J = max(beta_expo) + 1
    M = lm.poly_square_expo_M(beta_expo)
    L = lm.poly_int_coef_L(M @ beta_expo)
    c = np.power(b, M @ beta_expo + 1) - np.power(a, M @ beta_expo + 1)
    C = np.reshape(L.T @ c, (J, J))
    As = np.zeros((N, len(beta_expo), np.prod([len(expo) for expo in coord_expos])*len(beta_expo)))
    for n, coord in enumerate(coords):
        A = lm.kron_sequence([np.power(value, expo) for value, expo in zip(coord, coord_expos)])
        As[n] = np.kron(np.eye(J), A)

    if H is None:
        ACA = np.sum([A.T @ C @ A for A in As], axis=0)
        ACbeta = np.sum([np.einsum('an, n...->a...', A.T.dot(C), beta) for A, beta in zip(As, betas)], axis=0)
    else:
        ACA = np.sum([H.T @ A.T @ C @ A @ H for A in As], axis=0)
        ACbeta = np.sum([np.einsum('an, n...->a...', H.T @ A.T.dot(C), beta) for A, beta in zip(As, betas)], axis=0)
    alphas = np.einsum('ba, a...->b...', np.linalg.pinv(ACA), ACbeta)
    if return_cost:
        Js = np.einsum('a..., a...->...', np.einsum('b..., ba->a...', alphas, ACA), alphas) \
             - 2*np.einsum('b..., b...->...', ACbeta, alphas)\
             + np.einsum('ja..., ja... ->...', np.einsum('jb..., ba ->ja...', betas, C), betas)
        return alphas, Js
    return alphas


import pytest
import dynamic_yaml
import logging
import sys,os
sys.path.append('.')
import torch

from model.backbone import backbonebase

def get_hyper():
    CFG_PATH = './cfg/hyperparameter.yaml'
    with open(CFG_PATH, 'r') as file:
        para = dynamic_yaml.safe_load(file)
    return para

# print(get_hyper())
@pytest.mark.skip(reason="Skipping this CLASS level test")
class Testbackbonebase:
    def test_resnet18(self):
        x = torch.ones(1,3,256,256)
        model = backbonebase()
        y = 1
        assert model(x).shape == torch.Size([1,512,3,3])

logger = logging.getLogger('main.mod')
x = torch.ones(1,3,256,256)
model = backbonebase()
print(model.children)

# print(model.modules)


#!/usr/bin/env python
from __future__ import print_function

import cv2
import random
import os.path
import numpy as np
import PIL.ImageOps
import tensorflow as tf
from collections import deque
from sklearn.utils import shuffle
from PIL import Image, ImageChops
from pandas.io.parsers import read_csv

TRAIN_DATA_PATH = "training\\training.csv"
TEST_DATA_PATH  = "test\\test.csv"
IMAGE_WIDTH     = 96
IMAGE_HEIGHT    = 96
IMAGE_CHANNEL   = 1

#Network Parameters
INPUT_SHAPE   = 9216
OUTPUT_SHAPE  = 30
EPOCH         = 3000
learning_rate = 0.001
#======== Network Hyper Parameter
PADDING               = "SAME"
INPUT_SIZE_WIDTH      = 640
INPUT_SIZE_HEIGHT     = 160
LAYER_1_FILTER_SIZE   = 8 # 8x8
LAYER_1_FILTER_COUNT  = 32
LAYER_1_FRAMES_COUNT  = 2140
LAYER_1_FILTER_STRIDE = 4
LAYER_2_FILTER_SIZE   = 4 # 4x4
LAYER_2_FILTER_COUNT  = 64
LAYER_2_FRAMES_COUNT  = 32
LAYER_2_FILTER_STRIDE = 2
LAYER_3_FILTER_SIZE   = 3 # 3x3
LAYER_3_FILTER_COUNT  = 64
LAYER_3_FRAMES_COUNT  = 64
LAYER_3_FILTER_STRIDE = 1
FC_LAYER_1_SIZE = 256 # input to fully connected layer
FC_LAYER_2_SIZE = 256 # fully connected layer
OUT_LAYER_SIZE  = OUTPUT_SHAPE
# tf Graph input

#======== Network
def weight_variable(shape):
    initial = tf.truncated_normal(shape, stddev = 0.01)
    return tf.Variable(initial)

def bias_variable(shape):
    initial = tf.constant(0.01, shape = shape)
    return tf.Variable(initial)

def conv2d(x, W, stride):
    return tf.nn.conv2d(x, W, strides = [1, stride, stride, 1], padding = "SAME")

def max_pool_2x2(x):
    return tf.nn.max_pool(x, ksize = [1, 2, 2, 1], strides = [1, 2, 2, 1], padding = "SAME")

def create_network():
	x = tf.placeholder("float", [None, IMAGE_WIDTH, IMAGE_WIDTH, IMAGE_CHANNEL])
	W_conv1 = weight_variable([LAYER_1_FILTER_SIZE, LAYER_1_FILTER_SIZE, IMAGE_CHANNEL, LAYER_1_FILTER_COUNT])
	b_conv1 = bias_variable([LAYER_1_FILTER_COUNT])
	W_conv2 = weight_variable([LAYER_2_FILTER_SIZE, LAYER_2_FILTER_SIZE, LAYER_1_FILTER_COUNT, LAYER_2_FILTER_COUNT])
	b_conv2 = bias_variable([LAYER_2_FILTER_COUNT])
	W_conv3 = weight_variable([LAYER_3_FILTER_SIZE, LAYER_3_FILTER_SIZE, LAYER_2_FILTER_COUNT, LAYER_3_FILTER_COUNT])
	b_conv3 = bias_variable([LAYER_3_FILTER_COUNT])

	W_fc1 = weight_variable([FC_LAYER_1_SIZE, FC_LAYER_2_SIZE])
	b_fc1 = bias_variable([FC_LAYER_2_SIZE])

	W_fc2 = weight_variable([FC_LAYER_2_SIZE, OUT_LAYER_SIZE])
	b_fc2 = bias_variable([OUT_LAYER_SIZE])
	# hidden layers
	h_conv1 = tf.nn.relu(conv2d(x, W_conv1, 4) + b_conv1)
	h_pool1 = max_pool_2x2(h_conv1)
	h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2, 2) + b_conv2)
	h_pool2 = max_pool_2x2(h_conv2)
	h_conv3 = tf.nn.relu(conv2d(h_pool2, W_conv3, 1) + b_conv3)
	h_pool3 = max_pool_2x2(h_conv3)
	h_conv3_flat = tf.reshape(h_pool3, [-1, 256])
	h_fc1 = tf.nn.relu(tf.matmul(h_conv3_flat, W_fc1) + b_fc1)
	readout = tf.matmul(h_fc1, W_fc2) + b_fc2
	return x, readout

def trainNetwork(sess, x, readout, X, Y):
	y = tf.placeholder("float", [None, OUTPUT_SHAPE])
	cost = tf.reduce_mean(tf.square(readout - y))
	train_step = tf.train.AdamOptimizer(1e-6).minimize(cost)
	sess.run(tf.global_variables_initializer())
	for ep in range(0, EPOCH):
		_, loss = sess.run([train_step, cost], feed_dict={x: X, y:Y})
		print(ep, loss)

def testNetwork(sess,x, T, readout):
	readout_t = readout.eval(feed_dict={x : T})
	return readout_t

def visulize_a_image(image):
	#image = np.reshape(image_array, (IMAGE_HEIGHT, IMAGE_WIDTH))
	cv2.imshow("image", image)
	print(image)
	cv2.waitKey()

def construct_image(image, facepoints):
	xp, yp = facepoints[0::2] * 48 + 48, facepoints[1::2] * 48 + 48
	for pixel in range(0, len(xp)):
		cv2.circle(image,(int(xp[pixel]),int(yp[pixel])), 1, (0,0,255), -1)
	cv2.imshow("image", image)
	cv2.waitKey()

def load_data():
	train_df = read_csv(os.path.expanduser(TRAIN_DATA_PATH))  # load pandas dataframe
	test_df = read_csv(os.path.expanduser(TEST_DATA_PATH))  # load pandas dataframe
	train_df['Image'] = train_df['Image'].apply(lambda im: np.fromstring(im, sep=' '))
	test_df['Image'] = test_df['Image'].apply(lambda im: np.fromstring(im, sep=' '))
	train_df = train_df.dropna()  # drop all rows that have missing values in them
	test_df = test_df.dropna()
	X = np.vstack(train_df['Image'].values) / 255.
	X = np.reshape(X, (-1, IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_CHANNEL))
	X = X.astype(np.float32) # (2140 x 9216) (samples x pixels)
	T = np.vstack(test_df['Image'].values) / 255.
	print(T.shape)
	T = np.reshape(T, (-1, IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_CHANNEL))
	T = T.astype(np.float32)
	#visulize_a_image(X[0])
	y = train_df[train_df.columns[:-1]].values
	# to train the CNN scale y in range -1 to 1
	y = (y - 48) / 48  # scale target coordinates to [-1, 1]
	y = y.astype(np.float32)
	X, y = shuffle(X, y, random_state=42)  # shuffle train data
	return X, y, T

def main():
	sess = tf.InteractiveSession()
	X, y, T = load_data()
	x, readout = create_network()
	print(X.shape)
	print(y.shape)
	trainNetwork(sess, x, readout, X, y)
	facepoints = testNetwork(sess, x, T, readout)
	construct_image(T[0], facepoints[0])

if __name__ == "__main__":
	main()


# Author: Jordan Cain, 2015-16

import re
import sys
import time
import parse
import walker
from debugUtil import Trace
from methodHolder import Method
from classHolder import Class
from optimisations import Recursion
from optimisations import LoopToUnroll

def detect(parent, debugObj):
    global debug
    debug = debugObj
    debug.writeTrace("Detecting Optimisations, parent: " + parent.getName())
    recursions = recursionDetect(parent)
    unrollables = forLoopUnrollDetect(parent)
    return recursions, unrollables

#Function to print all of the optimisations
def output(recursions, loops):
    debug.writeTrace("Output optimisations")
    if recursions:
        print("The JVM struggles to optimise recurssion, consider iterative conversion")
        for recursion in recursions:
            recursion.toString()
        print("\n###################################\n")
    if loops:
        for loop in loops:
            loop.toString()
            unrollLoop(loop)
    if not loops:
        print ("No unrollable for loops")
    if not recursions:
        print("No recusrions")

#Function that will find any occourences of a for loop that can be unrolled
def forLoopUnrollDetect(parent):
    debug.writeTrace("Detect for loops to unroll")
    loops = walker.getForLoops(parent, debug)
    unrollableLoops = []
    #Check if loops use a constant number for the upper range
    #E.g for(int i=0; i<=5; i++)
    for loop in loops:
        if walker.checkIfCStyleLoop(loop, debug):
            condition = loop.getName()[loop.getName().find(';')+1:loop.getName().rfind(';')].lstrip()
            condLeft, condRight = splitCondition(condition)
            iterator, initTo = getConditionIterator(loop.getName())
            #If the iterator is a digit we may be able to unroll
            if initTo.isdigit():
                #If the iterator is used in the condition its more likely
                if iterator in condition:
                    if condLeft.lstrip().isdigit() or condRight.lstrip().isdigit():
                        unrollableLoops.append(LoopToUnroll(loop, iterator, initTo, condRight))
    return unrollableLoops

def unrollLoop(loop):
    loopObject = loop.getLoop() #Get the actual loop object
    if len(loopObject.getChildren()) < 4:
        print("Unrolling loop, Replace current for loop with: ")
        i = 0;
        while i < int(loop.getCondRight()) - int(loop.getInitto()):
            for statement in loopObject.getChildren():
                statement.printNode();
            i += 1
    else:
        print("Loop too long to unroll, \nconsider manually unrolling")

#Function that will find any occorunces of recursion in a method
#Params: parent is the highest level of the tree, debug will add extra output to console
def recursionDetect(parent):
    debug.writeTrace("Recursion Detect")
    #Initialise our return array which will hold recursion objects
    recursions = []
    #Get all the methods in the tree
    methods = walker.getMethods(parent, debug)
    for method in methods:
        #For each method we need to analyse the statements inside it
        statements = walker.getStatements(method, debug)
        #TODO:: Oppurtunity to implement threading here
        for statement in statements:
            debug.writeTrace("\tstatement: " + statement.getName() + " #### parent: " + statement.getParent().getName())
            if method.getName() in statement.getName():
                debug.writeTrace(statement.getName() + "\tin method: " + method.getName() + "Line: " + str(method.getLineNo()))
                statementName = statement.getName()
                methodName = method.getName()
                #Create a substring of the method call and parameters
                statementName = statementName[statementName.index(methodName):]
                #TODO:: if a param is a function call this will break
                statementName = statementName[:statementName.index(')')+1]
                #Get the params of the statement and method
                params = method.getParams()
                methodParamTypes = getMethodParamTypes(params)
                params = parse.getParams(statementName)
                statementParamTypes = getStatementParamTypes(params, method)

                #If paramater types match it's a recurisve call
                if statementParamTypes == methodParamTypes:
                    recursions.append(Recursion(statement, method))
                    debug.writeTrace("We found an actual recursion")
                    debug.writeTrace("Method:    " + method.toString() + " | line: " + str(method.getLineNo()))
                    debug.writeTrace("Statement: " + statement.getName().lstrip() + " | line: " + str(statement.getLineNo()))
                else:
                    debug.writeTrace("Not a recursive call")
                debug.writeTrace("Method param types: " + str(methodParamTypes))
                debug.writeTrace("Statement param types: " + str(statementParamTypes))
    return recursions

#Function to help for loop unroll, splits a condition at the operator index
#Param: Loop condition as a string
def splitCondition(condition):
    debug.writeTrace("Split condition: " + condition)
    if '>' in condition:
        condLeft = condition[0:condition.find('>')].lstrip()
        condRight = condition[condition.find('>')+1:].lstrip()
    elif '<' in condition:
        condLeft = condition[0:condition.find('<')].lstrip()
        condRight = condition[condition.find('<')+1:].lstrip()
    elif '=' in condition:
        condLeft = condition[0:condition.find('=')].lstrip()
        condRight = condition[condition.find('=')+1:].lstrip()
    #if we had <= or == we have to trim an extra character off
    if '=' in condRight:
        condRight = condRight.replace('=','').lstrip()
    return condLeft, condRight

#Fucntion to get the iterator variable name and the intialised value
#Param: loop decleration as string
#TODO:: Function will fail if the iterator name contains a number
def getConditionIterator(loop):
    debug.writeTrace("getConditionIterator: " + loop)
    iterator = loop[loop.find('(')+1:loop.find(';')]
    #Strip the type off, E.g int
    iterator = iterator[iterator.find(' '):].lstrip()
    return iterator[:iterator.find(' ')], re.findall(r'\d+', iterator)[0]

def getMethodParamTypes(params):
    debug.writeTrace("Method params: " + str(params))
    paramTypes = []
    for param in params:
        #SOURCE:: http://stackoverflow.com/questions/959215/removing-starting-spaces-in-python
        param = param.lstrip()
        param = param.split(' ')
        paramTypes.append(param[0])
    return paramTypes

def getStatementParamTypes(params, method):
    debug.writeTrace("Statement params: " + str(params))
    paramTypes = []
    for param in params:
        debug.writeTrace("Current param: " + param)
        #Check for literals?
        if '(' in param and ')' in param:
            debug.writeTrace("found a function call")
            #TODO::walk the tree to find the return type
        elif param.isdigit():
            paramTypes.append("int")
        elif re.match("\d+\.\d+(f)", param):
            paramTypes.append("float")
        elif '"' in param or "'" in param:
            paramTypes.append("String")
        elif param.lstrip().isalpha():
            #parameter is just a variable
            #Find the type of the variable
            paramTypes.append(findVariable(param.lstrip(), method))
        else:
            paramTypes.append(cleanParam(param.lstrip()))
        debug.writeTrace("ParamTypes: " + str(paramTypes))
    return paramTypes

def cleanParam(param):
    debug.writeTrace("Cleaning param: " + param)
    #Lets check if param is a number
    if '-' in param:
        operatorIndex = param.index('-')
    elif '+' in param:
        operatorIndex = param.index('+')
    elif '/' in param:
        operatorIndex = param.index('/')
    elif '*' in param:
        operatorIndex = param.index('*')
    else:
        return "Unable To Clean Param"

    left = param[:operatorIndex]
    right = param[operatorIndex+1:]
    param = getType(left, right)

    debug.writeTrace("left of op: " + left + " right of op: " + right)
    debug.writeTrace("Returning: " + param)
    return param

def getType(left, right):
    debug.writeTrace("Get type: left: " + left + " right: " + right)
    if left.isdigit() or right.isdigit():
        debug.writeTrace("Returning int")
        return "int"
    if re.match("\d+\.\d+(f)", left) or re.match("\d+\.\d+(f)", right):
        debug.writeTrace("Returning float")
        return "float"

def findVariable(variable, method):
    debug.writeTrace("Find Variable: " + variable)
    #Get a list of all statements in the class to check variable against
    statements = walker.getStatements(method, debug)
    for statement in statements:
        if '=' in statement.getName() and variable in statement.getName():
            debug.writeTrace("Found assignment: " + statement.getName())
            return getVariableType(statement.getName())
    return "ERROR: UNABLE TO DETERMINE VARIABLE TYPE"

#Function is a helper method for findVariable()
#Takes a line as parameter and returns the type
def getVariableType(line):
    debug.writeTrace("Get variable type: " + line)
    line = line.lstrip()
    line = line[:line.index(' ')]
    return line

#line ender


#!/usr/bin/python3
# -*- Mode: Python; indent-tabs-mode: nil; tab-width: 4; coding: utf-8 -*-

import apt
import apt_pkg
import hashlib
import mock
import os
import unittest
import shutil
import tempfile
import json

from DistUpgrade.DistUpgradeQuirks import DistUpgradeQuirks

CURDIR = os.path.dirname(os.path.abspath(__file__))

class MockController(object):
    def __init__(self):
        self._view = None

class MockConfig(object):
    pass

class MockPopenSnap():
    def __init__(self, cmd, universal_newlines=True,
                 stdout=None):
        self.command = cmd

    def communicate(self):
        if self.command[1] == "list":
            return []
        snap_name = self.command[2]
        if snap_name == 'gnome-logs':
            # Package to refresh
            return ["""
name:      test-snap
summary:   Test Snap
publisher: Canonical
license:   unset
description: Some description
commands:
  - gnome-calculator
snap-id:      1234
tracking:     stable/ubuntu-19.04
refresh-date: 2019-04-11
channels:
  stable:    3.32.1  2019-04-10 (406) 4MB -
  candidate: 3.32.2  2019-06-26 (433) 4MB -
  beta:      3.33.89 2019-08-06 (459) 4MB -
  edge:      3.33.90 2019-08-06 (460) 4MB -
installed:   3.32.1             (406) 4MB -
"""]
        elif "gnome-characters" in snap_name:
            # Package installed but not tracking the release channel
            return ["""
name:      test-snap
summary:   Test Snap
publisher: Canonical
license:   unset
description: Some description
commands:
  - gnome-characters
snap-id:      1234
refresh-date: 2019-04-11
channels:
  stable:    3.32.1  2019-04-10 (406) 4MB -
  candidate: 3.32.2  2019-06-26 (433) 4MB -
  beta:      3.33.89 2019-08-06 (459) 4MB -
  edge:      3.33.90 2019-08-06 (460) 4MB -
installed:   3.32.1             (406) 4MB -
"""]
        elif "gtk-common-themes" in snap_name:
            # Package installed but missing/invalid snap id
            return ["""
name:      test-snap
summary:   Test Snap
publisher: Canonical
license:   unset
description: Some description
commands:
  - gtk-common-themes
refresh-date: 2019-04-11
channels:
  stable:    3.32.1  2019-04-10 (406) 4MB -
  candidate: 3.32.2  2019-06-26 (433) 4MB -
  beta:      3.33.89 2019-08-06 (459) 4MB -
  edge:      3.33.90 2019-08-06 (460) 4MB -
"""]
        else:
            return ["""
name:      test-snap
summary:   Test Snap
publisher: Canonical
license:   unset
description: Some description
commands:
  - gnome-calculator
snap-id:      1234
refresh-date: 2019-04-11
channels:
  stable:    3.32.1  2019-04-10 (406) 4MB -
  candidate: 3.32.2  2019-06-26 (433) 4MB -
  beta:      3.33.89 2019-08-06 (459) 4MB -
  edge:      3.33.90 2019-08-06 (460) 4MB -
"""]

def mock_urlopen_snap(req):
    result = """{{
  "error-list": [],
  "results": [
    {{
      "effective-channel": "stable",
      "instance-key": "test",
      "name": "{name}",
      "released-at": "2019-04-10T18:54:15.717357+00:00",
      "result": "download",
      "snap": {{
        "created-at": "2019-04-09T17:09:29.941588+00:00",
        "download": {{
          "deltas": [],
          "size": {size},
          "url": "SNAPURL"
        }},
        "license": "GPL-3.0+",
        "name": "{name}",
        "prices": {{ }},
        "publisher": {{
          "display-name": "Canonical",
          "id": "canonical",
          "username": "canonical",
          "validation": "verified"
        }},
        "revision": 406,
        "snap-id": "{snap_id}",
        "summary": "GNOME Calculator",
        "title": "GNOME Calculator",
        "type": "app",
        "version": "3.32.1"
      }},
      "snap-id": "{snap_id}"
    }}
  ]
}}
"""
    test_snaps = {
        '1': ("gnome-calculator", 4218880),
        '2': ("test-snap", 2000000)
    }
    json_data = json.loads(req.data)
    snap_id = json_data['actions'][0]['snap-id']
    name = test_snaps[snap_id][0]
    size = test_snaps[snap_id][1]
    response_mock = mock.Mock()
    response_mock.read.return_value = result.format(
        name=name, snap_id=snap_id, size=size)
    return response_mock

def make_mock_pkg(name, is_installed, candidate_rec=""):
    mock_pkg = mock.Mock()
    mock_pkg.name = name
    mock_pkg.is_installed = is_installed
    mock_pkg.marked_install = False
    if candidate_rec:
        mock_pkg.candidate = mock.Mock()
        mock_pkg.candidate.record = candidate_rec
    return mock_pkg

class TestPatches(unittest.TestCase):

    orig_chdir = ''

    def setUp(self):
        # To patch, we need to be in the same directory as the patched files
        self.orig_chdir = os.getcwd()
        os.chdir(CURDIR)

    def tearDown(self):
        os.chdir(self.orig_chdir)

    def _verify_result_checksums(self):
        """ helper for test_patch to verify that we get the expected result """
        # simple case is foo
        patchdir = CURDIR + "/patchdir/"
        with open(patchdir + "foo") as f:
            self.assertFalse("Hello" in f.read())
        with open(patchdir + "foo_orig") as f:
            self.assertTrue("Hello" in f.read())
        md5 = hashlib.md5()
        with open(patchdir + "foo", "rb") as patch:
            md5.update(patch.read())
        self.assertEqual(md5.hexdigest(), "52f83ff6877e42f613bcd2444c22528c")
        # more complex example fstab
        md5 = hashlib.md5()
        with open(patchdir + "fstab", "rb") as patch:
            md5.update(patch.read())
        self.assertEqual(md5.hexdigest(), "c56d2d038afb651920c83106ec8dfd09")
        # most complex example
        md5 = hashlib.md5()
        with open(patchdir + "pycompile", "rb") as patch:
            md5.update(patch.read())
        self.assertEqual(md5.hexdigest(), "97c07a02e5951cf68cb3f86534f6f917")
        # with ".\n"
        md5 = hashlib.md5()
        with open(patchdir + "dotdot", "rb") as patch:
            md5.update(patch.read())
        self.assertEqual(md5.hexdigest(), "cddc4be46bedd91db15ddb9f7ddfa804")
        # test that incorrect md5sum after patching rejects the patch
        with open(patchdir + "fail") as f1, open(patchdir + "fail_orig") as f2:
            self.assertEqual(f1.read(),
                             f2.read())

    def test_patch(self):
        q = DistUpgradeQuirks(MockController(), MockConfig)
        # create patch environment
        patchdir = CURDIR + "/patchdir/"
        shutil.copy(patchdir + "foo_orig", patchdir + "foo")
        shutil.copy(patchdir + "fstab_orig", patchdir + "fstab")
        shutil.copy(patchdir + "pycompile_orig", patchdir + "pycompile")
        shutil.copy(patchdir + "dotdot_orig", patchdir + "dotdot")
        shutil.copy(patchdir + "fail_orig", patchdir + "fail")
        # apply patches
        q._applyPatches(patchdir=patchdir)
        self._verify_result_checksums()
        # now apply patches again and ensure we don't patch twice
        q._applyPatches(patchdir=patchdir)
        self._verify_result_checksums()

    def test_patch_lowlevel(self):
        # test lowlevel too
        from DistUpgrade.DistUpgradePatcher import patch, PatchError
        self.assertRaises(PatchError, patch, CURDIR + "/patchdir/fail",
                          CURDIR + "/patchdir/patchdir_fail."
                          "ed04abbc6ee688ee7908c9dbb4b9e0a2."
                          "deadbeefdeadbeefdeadbeff",
                          "deadbeefdeadbeefdeadbeff")

class TestQuirks(unittest.TestCase):

    orig_recommends = ''
    orig_status = ''

    def setUp(self):
        self.orig_recommends = apt_pkg.config.get("APT::Install-Recommends")
        self.orig_status = apt_pkg.config.get("Dir::state::status")

    def tearDown(self):
        apt_pkg.config.set("APT::Install-Recommends", self.orig_recommends)
        apt_pkg.config.set("Dir::state::status", self.orig_status)

    def test_enable_recommends_during_upgrade(self):
        controller = mock.Mock()

        config = mock.Mock()
        q = DistUpgradeQuirks(controller, config)
        # server mode
        apt_pkg.config.set("APT::Install-Recommends", "0")
        controller.serverMode = True
        self.assertFalse(apt_pkg.config.find_b("APT::Install-Recommends"))
        q.ensure_recommends_are_installed_on_desktops()
        self.assertFalse(apt_pkg.config.find_b("APT::Install-Recommends"))
        # desktop mode
        apt_pkg.config.set("APT::Install-Recommends", "0")
        controller.serverMode = False
        self.assertFalse(apt_pkg.config.find_b("APT::Install-Recommends"))
        q.ensure_recommends_are_installed_on_desktops()
        self.assertTrue(apt_pkg.config.find_b("APT::Install-Recommends"))

    def test_parse_from_modaliases_header(self):
        pkgrec = {
            "Package": "foo",
            "Modaliases": "modules1(pci:v00001002d00006700sv*sd*bc03sc*i*, "
                          "pci:v00001002d00006701sv*sd*bc03sc*i*), "
                          "module2(pci:v00001002d00006702sv*sd*bc03sc*i*, "
                          "pci:v00001001d00006702sv*sd*bc03sc*i*)"
        }
        controller = mock.Mock()
        config = mock.Mock()
        q = DistUpgradeQuirks(controller, config)
        self.assertEqual(q._parse_modaliases_from_pkg_header({}), [])
        self.assertEqual(q._parse_modaliases_from_pkg_header(pkgrec),
                         [("modules1",
                           ["pci:v00001002d00006700sv*sd*bc03sc*i*",
                            "pci:v00001002d00006701sv*sd*bc03sc*i*"]),
                          ("module2",
                           ["pci:v00001002d00006702sv*sd*bc03sc*i*",
                            "pci:v00001001d00006702sv*sd*bc03sc*i*"])])

    def disabled__as_fglrx_is_gone_testFglrx(self):
        mock_lspci_good = set(['1002:9990'])
        mock_lspci_bad = set(['8086:ac56'])
        config = mock.Mock()
        cache = apt.Cache()
        controller = mock.Mock()
        controller.cache = cache
        q = DistUpgradeQuirks(controller, config)
        if q.arch not in ['i386', 'amd64']:
            return self.skipTest("Not on an arch with fglrx package")
        self.assertTrue(q._supportInModaliases("fglrx", mock_lspci_good))
        self.assertFalse(q._supportInModaliases("fglrx", mock_lspci_bad))

    def test_screensaver_poke(self):
        # fake nothing is installed
        empty_status = tempfile.NamedTemporaryFile()
        apt_pkg.config.set("Dir::state::status", empty_status.name)

        # create quirks class
        controller = mock.Mock()
        config = mock.Mock()
        quirks = DistUpgradeQuirks(controller, config)
        quirks._pokeScreensaver()
        res = quirks._stopPokeScreensaver()
        res  # pyflakes

    def test_get_linux_metapackage(self):
        q = DistUpgradeQuirks(mock.Mock(), mock.Mock())
        mock_cache = set([
            make_mock_pkg(
                name="linux-image-3.19-24-generic",
                is_installed=True,
                candidate_rec={"Source": "linux"},
            ),
        ])
        pkgname = q._get_linux_metapackage(mock_cache, headers=False)
        self.assertEqual(pkgname, "linux-generic")

    def test_get_lpae_linux_metapackage(self):
        q = DistUpgradeQuirks(mock.Mock(), mock.Mock())
        mock_cache = set([
            make_mock_pkg(
                name="linux-image-4.2.0-16-generic-lpae",
                is_installed=True,
                candidate_rec={"Source": "linux"},
            ),
        ])
        pkgname = q._get_linux_metapackage(mock_cache, headers=False)
        self.assertEqual(pkgname, "linux-generic-lpae")

    def test_get_lowlatency_linux_metapackage(self):
        q = DistUpgradeQuirks(mock.Mock(), mock.Mock())
        mock_cache = set([
            make_mock_pkg(
                name="linux-image-4.2.0-16-lowlatency",
                is_installed=True,
                candidate_rec={"Source": "linux"},
            ),
        ])
        pkgname = q._get_linux_metapackage(mock_cache, headers=False)
        self.assertEqual(pkgname, "linux-lowlatency")

    def test_get_lts_linux_metapackage(self):
        q = DistUpgradeQuirks(mock.Mock(), mock.Mock())
        mock_cache = set([
            make_mock_pkg(
                name="linux-image-3.13.0-24-generic",
                is_installed=True,
                candidate_rec={"Source": "linux-lts-quantal"},
            ),
        ])
        pkgname = q._get_linux_metapackage(mock_cache, headers=False)
        self.assertEqual(pkgname, "linux-generic-lts-quantal")

    def test_ros_installed_warning(self):
        ros_packages = (
            "ros-melodic-catkin",
            "ros-noetic-rosboost-cfg",
            "ros-foxy-rosclean",
            "ros-kinetic-ros-environment",
            "ros-dashing-ros-workspace")
        for package_name in ros_packages:
            mock_controller = mock.Mock()
            mock_question = mock_controller._view.askYesNoQuestion
            mock_question.return_value = True

            q = DistUpgradeQuirks(mock_controller, mock.Mock())
            mock_cache = set([
                make_mock_pkg(
                    name=package_name,
                    is_installed=True,
                ),
            ])
            q._test_and_warn_if_ros_installed(mock_cache)
            mock_question.assert_called_once_with(mock.ANY, mock.ANY)
            self.assertFalse(len(mock_controller.abort.mock_calls))

            mock_controller.reset_mock()
            mock_question.reset_mock()
            mock_question.return_value = False

            mock_cache = set([
                make_mock_pkg(
                    name=package_name,
                    is_installed=True,
                ),
            ])
            q._test_and_warn_if_ros_installed(mock_cache)
            mock_question.assert_called_once_with(mock.ANY, mock.ANY)
            mock_controller.abort.assert_called_once_with()

    def test_ros_not_installed_no_warning(self):
        mock_controller = mock.Mock()
        mock_question = mock_controller._view.askYesNoQuestion
        mock_question.return_value = False

        q = DistUpgradeQuirks(mock_controller, mock.Mock())
        mock_cache = set([
            make_mock_pkg(
                name="ros-melodic-catkin",
                is_installed=False,
            ),
            make_mock_pkg(
                name="ros-noetic-rosboost-cfg",
                is_installed=False,
            ),
            make_mock_pkg(
                name="ros-foxy-rosclean",
                is_installed=False,
            ),
            make_mock_pkg(
                name="ros-kinetic-ros-environment",
                is_installed=False,
            ),
            make_mock_pkg(
                name="ros-dashing-ros-workspace",
                is_installed=False,
            ),
        ])
        q._test_and_warn_if_ros_installed(mock_cache)
        self.assertFalse(len(mock_question.mock_calls))
        self.assertFalse(len(mock_controller.abort.mock_calls))

    @mock.patch('os.path.exists')
    def test_aufs_fail(self, mock_exists):
        mock_exists.return_value = True
        mock_controller = mock.Mock()

        q = DistUpgradeQuirks(mock_controller, mock.Mock())

        q._test_and_fail_on_aufs()
        self.assertTrue(len(mock_controller.abort.mock_calls))

    def test_replace_fkms_overlay_no_config(self):
        with tempfile.TemporaryDirectory() as boot_dir:
            mock_controller = mock.Mock()

            q = DistUpgradeQuirks(mock_controller, mock.Mock())

            q._replace_fkms_overlay(boot_dir)
            self.assertFalse(os.path.exists(os.path.join(
                boot_dir, 'config.txt.distUpgrade')))

    def test_replace_fkms_overlay_no_changes(self):
        with tempfile.TemporaryDirectory() as boot_dir:
            demo_config = """\
# This is a demo boot config
[pi4]
max_framebuffers=2
[all]
arm_64bit=1
kernel=vmlinuz
initramfs initrd.img followkernel"""
            with open(os.path.join(boot_dir, 'config.txt'), 'w') as f:
                f.write(demo_config)

            mock_controller = mock.Mock()

            q = DistUpgradeQuirks(mock_controller, mock.Mock())

            q._replace_fkms_overlay(boot_dir)
            self.assertFalse(os.path.exists(os.path.join(
                boot_dir, 'config.txt.distUpgrade')))
            with open(os.path.join(boot_dir, 'config.txt')) as f:
                self.assertTrue(f.read() == demo_config)

    def test_replace_fkms_overlay_with_changes(self):
        with tempfile.TemporaryDirectory() as boot_dir:
            demo_config = """\
# This is a demo boot config
[pi4]
max_framebuffers=2
[all]
arm_64bit=1
kernel=vmlinuz
initramfs initrd.img followkernel
dtoverlay=vc4-fkms-v3d,cma-256
start_x=1
gpu_mem=256
"""
            expected_config = """\
# This is a demo boot config
[pi4]
max_framebuffers=2
[all]
arm_64bit=1
kernel=vmlinuz
initramfs initrd.img followkernel
# changed by do-release-upgrade (LP: #1923673)
#dtoverlay=vc4-fkms-v3d,cma-256
dtoverlay=vc4-kms-v3d,cma-256
# disabled by do-release-upgrade (LP: #1923673)
#start_x=1
# disabled by do-release-upgrade (LP: #1923673)
#gpu_mem=256
"""
            with open(os.path.join(boot_dir, 'config.txt'), 'w') as f:
                f.write(demo_config)

            mock_controller = mock.Mock()

            q = DistUpgradeQuirks(mock_controller, mock.Mock())

            q._replace_fkms_overlay(boot_dir)
            self.assertTrue(os.path.exists(os.path.join(
                boot_dir, 'config.txt.distUpgrade')))
            with open(os.path.join(boot_dir, 'config.txt')) as f:
                self.assertTrue(f.read() == expected_config)

    def test_remove_uboot_no_config(self):
        with tempfile.TemporaryDirectory() as boot_dir:
            mock_controller = mock.Mock()
            q = DistUpgradeQuirks(mock_controller, mock.Mock())
            q._remove_uboot_on_rpi(boot_dir)

            self.assertFalse(os.path.exists(os.path.join(
                boot_dir, 'config.txt.distUpgrade')))

    def test_remove_uboot_no_changes(self):
        with tempfile.TemporaryDirectory() as boot_dir:
            native_config = """\
# This is a demo boot config with a comment at the start that should not
# be removed

[pi4]
max_framebuffers=2

[all]
arm_64bit=1
kernel=vmlinuz
initramfs initrd.img followkernel

# This is a user-added include that should not be merged
include custom.txt
"""
            custom_config = """\
# This is the custom included configuration file

hdmi_group=1
hdmi_mode=4
"""
            with open(os.path.join(boot_dir, 'config.txt'), 'w') as f:
                f.write(native_config)
            with open(os.path.join(boot_dir, 'custom.txt'), 'w') as f:
                f.write(custom_config)

            mock_controller = mock.Mock()
            q = DistUpgradeQuirks(mock_controller, mock.Mock())
            q._remove_uboot_on_rpi(boot_dir)

            self.assertFalse(os.path.exists(os.path.join(
                boot_dir, 'config.txt.distUpgrade')))
            self.assertFalse(os.path.exists(os.path.join(
                boot_dir, 'custom.txt.distUpgrade')))
            with open(os.path.join(boot_dir, 'config.txt')) as f:
                self.assertTrue(f.read() == native_config)
            with open(os.path.join(boot_dir, 'custom.txt')) as f:
                self.assertTrue(f.read() == custom_config)

    def test_remove_uboot_with_changes(self):
        with tempfile.TemporaryDirectory() as boot_dir:
            config_txt = """\
# This is a warning that you should not edit this file. The upgrade should
# remove this comment

[pi4]
# This is a comment that should be included
kernel=uboot_rpi_4.bin
max_framebuffers=2

[pi2]
kernel=uboot_rpi_2.bin

[pi3]
kernel=uboot_rpi_3.bin

[all]
arm_64bit=1
device_tree_address=0x3000000
include syscfg.txt
include usercfg.txt
dtoverlay=vc4-fkms-v3d,cma-256
include custom.txt
"""
            usercfg_txt = """\
# Another chunk of warning text that should be skipped
"""
            syscfg_txt = """\
# Yet more warnings to exclude
dtparam=audio=on
dtparam=spi=on
enable_uart=1
"""
            custom_txt = """\
# This is a user-added file that should be left alone by the upgrade
[gpio4=1]
kernel=custom
"""
            expected_config_txt = """\

[pi4]
# This is a comment that should be included
# commented by do-release-upgrade (LP: #1936401)
#kernel=uboot_rpi_4.bin
max_framebuffers=2

[pi2]
# commented by do-release-upgrade (LP: #1936401)
#kernel=uboot_rpi_2.bin

[pi3]
# commented by do-release-upgrade (LP: #1936401)
#kernel=uboot_rpi_3.bin

[all]
# added by do-release-upgrade (LP: #1936401)
kernel=vmlinuz
initramfs initrd.img followkernel
arm_64bit=1
# commented by do-release-upgrade (LP: #1936401)
#device_tree_address=0x3000000
# merged from syscfg.txt by do-release-upgrade (LP: #1936401)
dtparam=audio=on
dtparam=spi=on
enable_uart=1
# merged from usercfg.txt by do-release-upgrade (LP: #1936401)
dtoverlay=vc4-fkms-v3d,cma-256
include custom.txt
"""
            with open(os.path.join(boot_dir, 'config.txt'), 'w') as f:
                f.write(config_txt)
            with open(os.path.join(boot_dir, 'syscfg.txt'), 'w') as f:
                f.write(syscfg_txt)
            with open(os.path.join(boot_dir, 'usercfg.txt'), 'w') as f:
                f.write(usercfg_txt)
            with open(os.path.join(boot_dir, 'custom.txt'), 'w') as f:
                f.write(custom_txt)

            mock_controller = mock.Mock()
            q = DistUpgradeQuirks(mock_controller, mock.Mock())
            q._remove_uboot_on_rpi(boot_dir)

            self.assertTrue(os.path.exists(os.path.join(
                boot_dir, 'config.txt.distUpgrade')))
            self.assertTrue(os.path.exists(os.path.join(
                boot_dir, 'syscfg.txt.distUpgrade')))
            self.assertTrue(os.path.exists(os.path.join(
                boot_dir, 'usercfg.txt.distUpgrade')))
            self.assertTrue(os.path.exists(os.path.join(
                boot_dir, 'config.txt')))
            self.assertTrue(os.path.exists(os.path.join(
                boot_dir, 'custom.txt')))
            self.assertFalse(os.path.exists(os.path.join(
                boot_dir, 'syscfg.txt')))
            self.assertFalse(os.path.exists(os.path.join(
                boot_dir, 'usercfg.txt')))
            self.assertFalse(os.path.exists(os.path.join(
                boot_dir, 'custom.txt.distUpgrade')))
            with open(os.path.join(boot_dir, 'config.txt')) as f:
                self.assertTrue(f.read() == expected_config_txt)
            with open(os.path.join(boot_dir, 'custom.txt')) as f:
                self.assertTrue(f.read() == custom_txt)

    def test_remove_uboot_no_all_section(self):
        with tempfile.TemporaryDirectory() as boot_dir:
            config_txt = """\
arm_64bit=1
device_tree_address=0x3000000

[pi4]
# This is a comment that should be included
kernel=uboot_rpi_4.bin
max_framebuffers=2

[pi3]
kernel=uboot_rpi_3.bin
"""
            expected_config_txt = """\
arm_64bit=1
# commented by do-release-upgrade (LP: #1936401)
#device_tree_address=0x3000000

[pi4]
# This is a comment that should be included
# commented by do-release-upgrade (LP: #1936401)
#kernel=uboot_rpi_4.bin
max_framebuffers=2

[pi3]
# commented by do-release-upgrade (LP: #1936401)
#kernel=uboot_rpi_3.bin
# added by do-release-upgrade (LP: #1936401)
[all]
kernel=vmlinuz
initramfs initrd.img followkernel
"""
            with open(os.path.join(boot_dir, 'config.txt'), 'w') as f:
                f.write(config_txt)

            mock_controller = mock.Mock()
            q = DistUpgradeQuirks(mock_controller, mock.Mock())
            q._remove_uboot_on_rpi(boot_dir)

            self.assertTrue(os.path.exists(os.path.join(
                boot_dir, 'config.txt.distUpgrade')))
            with open(os.path.join(boot_dir, 'config.txt')) as f:
                self.assertTrue(f.read() == expected_config_txt)

class TestSnapQuirks(unittest.TestCase):

    def test_get_from_and_to_version(self):
        # Prepare the state for testing
        controller = mock.Mock()
        controller.fromDist = 'disco'
        controller.toDist = 'eoan'
        config = mock.Mock()
        q = DistUpgradeQuirks(controller, config)
        # Call method under test
        q._get_from_and_to_version()
        self.assertEqual(q._from_version, '19.04')
        self.assertEqual(q._to_version, '19.10')

    @mock.patch("subprocess.Popen", MockPopenSnap)
    def test_prepare_snap_replacement_data(self):
        # Prepare the state for testing
        controller = mock.Mock()
        config = mock.Mock()
        q = DistUpgradeQuirks(controller, config)
        q._from_version = "19.04"
        q._to_version = "19.10"
        # Call method under test

        controller.cache = {
            'ubuntu-desktop':
                make_mock_pkg(
                    name="ubuntu-desktop",
                    is_installed=True),
            'core18':
                make_mock_pkg(
                    name="core18",
                    is_installed=True),
            'firefox':
                make_mock_pkg(
                    name="firefox",
                    is_installed=True),
            'gnome-3-28-1804':
                make_mock_pkg(
                    name="gnome-3-28-1804",
                    is_installed=True),
            'gtk-common-themes':
                make_mock_pkg(
                    name="gtk-common-themes",
                    is_installed=True),
            'gnome-calculator':
                make_mock_pkg(
                    name="gnome-calculator",
                    is_installed=True),
            'gnome-characters':
                make_mock_pkg(
                    name="gnome-characters",
                    is_installed=False),
            'gnome-logs':
                make_mock_pkg(
                    name="gnome-logs",
                    is_installed=False),
            'gnome-software':
                make_mock_pkg(
                    name="gnome-software",
                    is_installed=True),
            'snap-not-tracked':
                make_mock_pkg(
                    name="snap-not-tracked",
                    is_installed=True),
        }

        q._prepare_snap_replacement_data()
        # Check if the right snaps have been detected as installed and
        # needing refresh and which ones need installation
        self.maxDiff = None
        self.assertDictEqual(
            q._snap_list,
            {'core20': {
                'channel': 'stable',
                'command': 'install',
                'deb': None, 'snap-id': '1234'},
             'firefox': {
                'channel': 'stable/ubuntu-19.10',
                'command': 'install',
                'deb': 'firefox',
                'snap-id': '1234'},
             'gnome-3-34-1804': {
                'channel': 'stable/ubuntu-19.10',
                'command': 'install',
                'deb': None, 'snap-id': '1234'},
             'gnome-3-38-2004': {
                'channel': 'stable/ubuntu-19.10',
                'command': 'install',
                'deb': None, 'snap-id': '1234'},
             'gnome-logs': {
                'command': 'remove'},
             'snap-store': {
                'channel': 'stable/ubuntu-19.10',
                'command': 'install',
                'deb': 'gnome-software',
                'snap-id': '1234'}})

    def test_is_deb2snap_metapkg_installed(self):
        # Prepare the state for testing
        controller = mock.Mock()
        config = mock.Mock()
        q = DistUpgradeQuirks(controller, config)
        q._from_version = "19.04"
        q._to_version = "19.10"
        controller.cache = {
            'ubuntu-desktop':
                make_mock_pkg(
                    name="ubuntu-desktop",
                    is_installed=True)
        }

        testdata = [
            # (input, expected output)
            ({}, False),
            ({'metapkg': None}, False),
            ({'metapkg': 'ubuntu-desktop'}, True),
            ({'metapkg': 'kubuntu-desktop'}, False),
            ({'metapkg': ['kubuntu-desktop', 'ubuntu-desktop']}, True),
            ({'metapkg': ['kubuntu-desktop', 'lubuntu-desktop']}, False),
        ]

        for data in testdata:
            self.assertEqual(q._is_deb2snap_metapkg_installed(data[0]),
                             data[1],
                             'Expected {1} for input {0}'.format(*data))

    @mock.patch("DistUpgrade.DistUpgradeQuirks.get_arch")
    @mock.patch("urllib.request.urlopen")
    def test_calculate_snap_size_requirements(self, urlopen, arch):
        # Prepare the state for testing
        arch.return_value = 'amd64'
        controller = mock.Mock()
        config = mock.Mock()
        q = DistUpgradeQuirks(controller, config)
        # We mock out _prepare_snap_replacement_data(), as this is tested
        # separately.
        q._prepare_snap_replacement_data = mock.Mock()
        q._snap_list = {
            'test-snap': {'command': 'install',
                          'deb': None, 'snap-id': '2',
                          'channel': 'stable/ubuntu-19.10'},
            'gnome-calculator': {'command': 'install',
                                 'deb': 'gnome-calculator',
                                 'snap-id': '1',
                                 'channel': 'stable/ubuntu-19.10'},
            'gnome-system-monitor': {'command': 'refresh',
                                     'channel': 'stable/ubuntu-19.10'}
        }
        q._to_version = "19.10"
        # Mock out urlopen in such a way that we get a mocked response based
        # on the parameters given but also allow us to check call arguments
        # etc.
        urlopen.side_effect = mock_urlopen_snap
        # Call method under test
        q._calculateSnapSizeRequirements()
        # Check if the size was calculated correctly
        self.assertEqual(q.extra_snap_space, 6218880)
        # Check if we only sent queries for the two command: install snaps
        self.assertEqual(urlopen.call_count, 2)
        # Make sure each call had the right headers and parameters
        for call in urlopen.call_args_list:
            req = call[0][0]
            self.assertIn(b"stable/ubuntu-19.10", req.data)
            self.assertDictEqual(
                req.headers,
                {'Snap-device-series': '16',
                 'Content-type': 'application/json',
                 'Snap-device-architecture': 'amd64'})

    @mock.patch("subprocess.run")
    def test_replace_debs_and_snaps(self, run_mock):
        controller = mock.Mock()
        config = mock.Mock()
        q = DistUpgradeQuirks(controller, config)
        q._snap_list = {
            'core18': {'command': 'refresh',
                       'channel': 'stable'},
            'gnome-3-28-1804': {'command': 'refresh',
                                'channel': 'stable/ubuntu-19.10'},
            'gtk-common-themes': {'command': 'refresh',
                                  'channel': 'stable/ubuntu-19.10'},
            'gnome-calculator': {'command': 'remove'},
            'gnome-characters': {'command': 'remove'},
            'gnome-logs': {'command': 'install',
                           'deb': 'gnome-logs',
                           'snap-id': '1234',
                           'channel': 'stable/ubuntu-19.10'},
            'gnome-system-monitor': {'command': 'install',
                                     'deb': 'gnome-system-monitor',
                                     'snap-id': '1234',
                                     'channel': 'stable/ubuntu-19.10'},
            'snap-store': {'command': 'install',
                           'deb': 'gnome-software',
                           'snap-id': '1234',
                           'channel': 'stable/ubuntu-19.10'}
        }
        q._to_version = "19.10"
        q._replaceDebsAndSnaps()
        # Make sure all snaps have been handled
        self.assertEqual(run_mock.call_count, 8)
        snaps_refreshed = {}
        snaps_installed = {}
        snaps_removed = []
        # Check if all the snaps that needed to be installed were installed
        # and those that needed a refresh - refreshed
        # At the same time, let's check that all the snaps were acted upon
        # while using the correct channel and branch
        for call in run_mock.call_args_list:
            args = call[0][0]
            if args[1] == 'refresh':
                snaps_refreshed[args[4]] = args[3]
            elif args[1] == 'install':
                snaps_installed[args[4]] = args[3]
            elif args[1] == 'remove':
                snaps_removed.append(args[2])
        self.assertDictEqual(
            snaps_refreshed,
            {'core18': 'stable',
             'gnome-3-28-1804': 'stable/ubuntu-19.10',
             'gtk-common-themes': 'stable/ubuntu-19.10'})
        self.assertDictEqual(
            snaps_installed,
            {'gnome-logs': 'stable/ubuntu-19.10',
             'gnome-system-monitor': 'stable/ubuntu-19.10',
             'snap-store': 'stable/ubuntu-19.10'})
        self.assertListEqual(
            snaps_removed,
            ['gnome-calculator',
             'gnome-characters'])
        # Make sure we marked the replaced ones for removal
        # Here we only check if the right number of 'packages' has been
        # added to the forced_obsoletes list - not all of those packages are
        # actual deb packages that will have to be removed during the upgrade
        self.assertEqual(controller.forced_obsoletes.append.call_count, 3)

    @mock.patch("builtins.open", new_callable=mock.mock_open,
                read_data="""\
processor       : 0
cpu             : POWER8 (raw), altivec supported
clock           : 3491.000000MHz
revision        : 2.0 (pvr 004d 0200)

processor       : 1
cpu             : POWER8 (raw), altivec supported
clock           : 3491.000000MHz
revision        : 2.0 (pvr 004d 0200)

timebase        : 512000000
platform        : PowerNV
model           : 8001-22C
machine         : PowerNV 8001-22C
firmware        : OPAL
MMU             : Hash
""")
    @mock.patch("DistUpgrade.DistUpgradeQuirks.get_arch",
                return_value="ppc64el")
    def test_power8_fail(self, arch, mock_file):
        controller = mock.Mock()
        config = mock.Mock()
        q = DistUpgradeQuirks(controller, config)

        q._test_and_fail_on_power8()
        self.assertTrue(len(controller.abort.mock_calls))

        mock_file.assert_called_with("/proc/cpuinfo")

if __name__ == "__main__":
    import logging
    logging.basicConfig(level=logging.DEBUG)
    unittest.main()


from itertools import combinations
import sys
input = sys.stdin.readline

dx = (1,0,-1,0)
dy = (0,1,0,-1)
INF = int(1e9)

def out_of_range(ny:int, nx:int) -> bool:
    return ny < 0 or nx < 0 or ny >= n or nx >= n

def position(val: tuple[int]) -> list[int]:
    return [(num//n, num%n) for num in val]

def cal(val: list[list[int]]):
    res = set()
    tmp = 0
    for y,x in val:
        tmp += board[y][x]
        res.add((y,x))
        for i in range(4):
            ny,nx = dy[i]+y, dx[i]+x
            if out_of_range(ny,nx): return INF
            res.add((ny,nx))
            tmp += board[ny][nx]

    return tmp if len(res) == 15 else INF

n = int(input())
board = [list(map(int,input().split())) for _ in range(n)]

cnt = 0
ans = []

for val in combinations(range(n**2), 3):
    ans.append(cal(position(val)))

print(min(ans))


import subprocess as sp
import sys
import ctypes
import os
import random
import json
import base64
import pathlib
import tempfile
import functools
import operator
import time
import numpy

# ol-install: numpy

# from memory_profiler import profile
import cProfile
import pstats
import io

doProfile = True

def printCSV(pr, path):
    path = pathlib.Path(path)

    result = io.StringIO()
    # pstats.Stats(pr,stream=result).print_stats()
    pstats.Stats(pr,stream=result).sort_stats(pstats.SortKey.CUMULATIVE).print_stats()
    result=result.getvalue()
    # chop the string into a csv-like buffer
    result='ncalls'+result.split('ncalls')[-1]
    result='\n'.join([','.join(line.rstrip().split(None,5)) for line in result.split('\n')])

    with open(path, 'w') as f:
        f.write(result)

# Ideally this would be set somewhere else (e.g. in AWS lambda you can put
# it in /var) but for now this works.
if pathlib.Path('/handler/libsort.so').exists():
    print("Running in OpenLambda")
    os.environ['LD_LIBRARY_PATH'] = '/handler'
import pylibsort

def f(event):
    # Temporary limitation for testing
    if event['arrType'] != 'file':
        return {
                "success" : False,
                "err" : "Function currently only supports file distributed arrays"
                }

    refs = pylibsort.getPartRefs(event)
    rawBytes = pylibsort.readPartRefs(refs)

    try:
        boundaries = pylibsort.sortPartial(rawBytes, event['offset'], event['width'])
    except Exception as e:
        return {
                "success" : False,
                "err" : str(e)
               }

    pylibsort.writeOutput(event, rawBytes, boundaries)

    return {
            "success" : True,
            "err" : ""
           }

def selfTest():
    """Main only used for testing purposes"""
    # nElem = 256
    nElem = 256*(1024*1024)
    # nElem = 1024*1024
    nbyte = nElem*4
    offset = 0
    width = 8
    # width = 16
    narr = 2
    npart = 2
    bytesPerPart = int(nbyte / (narr * npart))

    inBuf = pylibsort.generateInputs(nElem)

    with tempfile.TemporaryDirectory() as tDir:
        tDir = pathlib.Path(tDir)
        pylibsort.SetDistribMount(tDir)

        inArrName = "faasSortTestIn"
        outArrName = "faasSortTestOut"

        # Write source arrays
        inShape = pylibsort.ArrayShape.fromUniform(bytesPerPart, npart)
        refs = []
        for arrX in range(narr):
            arrName = inArrName + str(arrX)
            inArr = pylibsort.fileDistribArray.Create(tDir / arrName, inShape)

            start = (arrX*npart)*bytesPerPart
            end = start + (bytesPerPart*npart)
            inArr.WriteAll(inBuf[start:end])
            for partX in range(npart):
                refs.append({
                    'arrayName': arrName,
                    'partID' : partX,
                    'start' : 0,
                    'nbyte' : -1
                })
            inArr.Close()

        req = {
                "offset" : offset,
                "width" : width,
                "arrType" : "file",
                "input" : refs,
                "output" : outArrName
        }

        if doProfile:
            pr = cProfile.Profile()
            pr.enable()
            resp = f(req)
            pr.disable()
            printCSV(pr, "./faas{}b.csv".format(width))
            pr.dump_stats("./faas{}b.prof".format(width))
        else:
            start = time.time()
            resp = f(req)
            print(time.time() - start)

        if not resp['success']:
            print("FAILURE: Function returned error: " + resp['err'])
            exit(1)

        outArr = pylibsort.fileDistribArray.Open(tDir / outArrName)
        outBuf = outArr.ReadAll()
        boundaries = outArr.shape.starts

        outArr.Destroy()

    pylibsort.checkPartial(inBuf, outBuf, outArr.shape.caps, offset, width)

    print("PASS")

def directInvoke():
    """Call this to directly invoke the function from the command line instead
    of through a FaaS provider, it expects the arguments to be in JSON as
    argv[1]. This function behaves as a main(); it calls exit() directly and
    never returns."""

    dataDir = os.environ.get('OL_SHARED_VOLUME', "")
    if dataDir == "":
        print(json.dumps({ "success" : False, "err" : "OL_SHARED_VOLUME not set, set it to the shared directory for distrib arrays"}))
        exit(1)
    pylibsort.SetDistribMount(pathlib.Path(dataDir))

    try:
        jsonCmd = sys.stdin.read()
        cmd = json.loads(jsonCmd)
    except Exception as e:
        print(json.dumps({ "success" : False, "err" : "Argument parsing error: " + str(e) }))
        exit(1)

    resp = None
    if doProfile:
        pr = cProfile.Profile()
        pr.enable()
        resp = f(cmd)
        pr.disable()
        printCSV(pr, "./faas{}.csv".format(cmd['output']))
        pr.dump_stats("./faas{}.prof".format(cmd['output']))
    else:
        resp = f(cmd)

    print(json.dumps(resp))
    if resp['success']:
        exit(0)
    else:
        exit(1)

# @profile
def testGenerate():
    # sz = 256*1024*1024
    sz = 1024*1024
    testIn = pylibsort.generateInputs(sz)

    start = time.time()
    ints = pylibsort.bytesToInts(testIn)
    print(time.time() - start)
    # with tempfile.TemporaryFile() as f:
    #     f.write(testIn[:])

if __name__ == "__main__":
    # selfTest()
    directInvoke()
    # testGenerate()


#!/usr/bin/env python3
import socket
from threading import Thread

from config import SERVER_IP, SERVER_PORT, CLIENT_CONNECT_TIMEOUT

class Client(object):
    def __init__(self, server_ip, server_port, client_connect_timeout):
        self._server_ip = server_ip
        self._server_port = server_port
        self._client_connect_timeout = client_connect_timeout
        self._socket = None

    def _create_socket(self):
        self._socket = socket.socket()
        self._socket.settimeout(self._client_connect_timeout)
        self._socket.connect((self._server_ip, self._server_port))
        self._socket.settimeout(None)
        print(f"  >> Client is up @ {self._server_ip}:{self._server_port}")

    def _sender(self):
        while True:
            input_text = input()
            self._socket.send(input_text.encode('utf-8'))

    def _receiver(self):
        while True:
            data = self._socket.recv(1024)
            print(data.decode('utf-8'))

    def start(self):
        self._create_socket()

        self._sender_thread = Thread(target=self._sender)
        self._receiver_thread = Thread(target=self._receiver)

        self._sender_thread.start()
        self._receiver_thread.start()

        self._sender_thread.join()
        self._receiver_thread.join()

def main():
    client = Client(
        server_ip=SERVER_IP,
        server_port=SERVER_PORT,
        client_connect_timeout=CLIENT_CONNECT_TIMEOUT,
    )
    client.start()

if __name__ == '__main__':
    main()


from pymysql import IntegrityError
from sqlalchemy import func
from sqlalchemy.orm.exc import MultipleResultsFound
from flask_sqlalchemy import BaseQuery as QueryClass

from miniapp.corelibs.stone import db

class BaseQuery(QueryClass):

    def __iter__(self):
        return QueryClass.__iter__(self._undeleted())

    def from_self(self, *ent):
        return QueryClass.from_self(self._undeleted(), *ent)

    def _undeleted(self):
        mzero = self._mapper_zero()
        if mzero is not None and hasattr(mzero.class_, 'deleted'):
            cri = (mzero.class_.deleted == False)    # noqa
            return self.enable_assertions(False).filter(cri)
        else:
            return self

    def count(self):
        mzero = self._mapper_zero()
        if mzero is not None and hasattr(mzero.class_, 'id'):
            q = self._clone()
            q._set_entities(func.count(mzero.class_.id))
            if q._criterion is not None:
                q = q.filter(q._criterion)
            try:
                return q.scalar()
            except MultipleResultsFound:
                pass
        return super(BaseQuery, self).count()

class Base(db.Model):

    __abstract__ = True
    query_class = BaseQuery

    @classmethod
    def create(cls, _commit=True, **kwargs):
        obj = cls(**kwargs)
        obj.save(_commit)
        return obj

    def update(self, _commit=True, **kwargs):
        for k, v in kwargs.items():
            if hasattr(self, k):
                setattr(self, k, v)
        self.save(_commit)
        return self

    @classmethod
    def get(cls, id, exclude_deleted=True):
        query = db.session.query(cls)
        if hasattr(cls, 'deleted') and exclude_deleted:
            query = query.filter_by(deleted=False)
        return query.filter_by(id=id).first()

    @classmethod
    def paginate(cls, page, per_page, order=None):
        return cls.query.order_by(order).paginate(page, per_page)

    @classmethod
    def all(cls):
        return cls.query.all()

    @classmethod
    def get_multi(cls, ids):
        return cls.query.filter(cls.id.in_(ids)).all()

    def to_dict(self):
        keys = [c.key for c in self.__table__.columns]
        return {k: getattr(self, k) for k in keys}

    def __repr__(self):
        attrs = ', '.join('{0}={1}'.format(repr(k), repr(v))
                          for k, v in self.to_dict().items())
        return '{0}({1})'.format(self.__class__.__name__, attrs)

    def save(self, _commit=True):
        try:
            db.session.add(self)
            if _commit:
                db.session.commit()
        except IntegrityError:
            db.session.rollback()
            raise

        _hooks = ('_clean_cache', '_before_save_hook')
        for each in _hooks:
            if hasattr(self, each) and callable(getattr(self, each)):
                func = getattr(self, each)
                func()

    def delete(self, _hard=False, _commit=True):
        soft_delete = hasattr(self, 'deleted') and _hard is False
        if soft_delete:
            self.deleted = True
            db.session.add(self)
        else:
            db.session.delete(self)
        if _commit:
            db.session.commit()

        if hasattr(self, '_point_mongo'):
            if soft_delete:
                self.delete_props_item()
            else:
                self._destory_props()

        _hooks = ('_clean_cache', '_before_delete_hook')
        for each in _hooks:
            if hasattr(self, each) and callable(getattr(self, each)):
                func = getattr(self, each)
                func()


'''
给定一个链表，删除链表的倒数第 n 个节点，并且返回链表的头结点。
'''
'''
使用有界队列，队列大小为n+1，遍历链表的时候不停向队列里添加节点，遍历完成后，队列的头就是倒数第n+1个节点，队列第二个就是倒数第n个节点
本质上就是使得遍历到链表终点时，能够拿到倒数第n+1个节点
'''
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None
from collections import deque

class Solution(object):
    def removeNthFromEnd(self, head, n):
        """
        :type head: ListNode
        :type n: int
        :rtype: ListNode
        """
        q = deque(maxlen = n + 1)
        current = head
        length = 0
        while current is not None:
            q.append(current)
            current = current.next
            length += 1

        if length == n: # 删除的是头节点
            return head.next

        beforeN = q.popleft()
        n = q.popleft()
        beforeN.next = n.next

        return head


from setuptools import setup, find_packages
from os import path
from io import open

here = path.abspath(path.dirname(__file__))

with open(path.join(here, 'README.md'), encoding='utf-8') as f:
    long_description = f.read()

setup(
	name='Zeek-Indenter',
	version='0.1.0',
	description='Python package to indent Zeek scripts.',
	long_description=long_description,
	url='http://pypi.python.org/pypi/ZeekIndenter/',
	author='Mohan Dhawan',
	author_email='mohan@corelight.com',
	packages=find_packages(),
	python_requires='>=3.6',
	install_requires=['lark-parser'],
	package_data={
		'indenter': ['*.txt', 'utils/zeek.lark', 'utils/zeek-lalr.lark', 'utils/zeek-earley.lark']
	},
	classifiers=[
        'Programming Language :: Python :: 3.6',
    ],
)


from django.shortcuts import render,redirect
from .models import *
from .forms import *
from django.contrib.auth.decorators import login_required

# Create your views here.

@login_required(login_url=('accounts:login'))
def home(request):
  products = Product.objects.all().order_by('-id')
  context = {'products':products}
  return render(request,'products/index.html',context)

@login_required(login_url=('accounts:login'))
def product_detail(request,id):
  product = Product.objects.get(id=id)
  context = {'product':product}

  return render(request,'products/product_detail.html',context)

@login_required(login_url=('accounts:login'))
def issue_item(request, pk):
    issued_item = Product.objects.get(id = pk)
    sales_form = SaleForm(request.POST)

    if request.method == 'POST':
        if sales_form.is_valid():
            new_sale = sales_form.save(commit=False)
            new_sale.item = issued_item
            new_sale.unit_price = issued_item.unit_price
            new_sale.save()
            #To keep track of the stock remaining after sales
            issued_quantity = int(request.POST['quantity'])
            issued_item.total_quantity -= issued_quantity
            issued_item.save()

            return redirect('products:receipt')

    return render (request, 'products/issue_item.html',
     {
    'sales_form': sales_form,
    })

@login_required(login_url=('accounts:login'))
def add_to_stock(request, pk):
    issued_item = Product.objects.get(id = pk)
    form = AddForm(request.POST)

    if request.method == 'POST':
        if form.is_valid():
           #To add to the remaining stock quantity is reducing
            added_quantity = int(request.POST['received_quantity'])
            issued_item.total_quantity += added_quantity
            issued_item.save()
            return redirect('home')

    return render (request, 'products/add_to_stock.html', {'form': form})

@login_required(login_url=('accounts:login'))
def receipt(request):
    sales = Sale.objects.all().order_by('-id')
    return render(request,
    'products/receipt.html',
    {'sales': sales,
    })

@login_required(login_url=('accounts:login'))
def receipt_detail(request, id):
  sale = Sale.objects.get(id=id)
  context = {'sale':sale}

  return render(request,'products/receipt_detail.html',context)

@login_required(login_url=('accounts:login'))
def all_sales(request):
    sales = Sale.objects.all()
    total  = sum([items.amount_received for items in sales])
    change = sum([items.get_change() for items in sales])
    net = total - change
    return render(request, 'products/all_sales.html',
     {
     'sales': sales,
     'total': total,
     'change': change,
     'net': net,
      })


from django.contrib import admin
from payment.models import PaidMember, UserInfo

class PaidMemberAdmin(admin.ModelAdmin):
    """ Premium User Admin """
    list_display = (
        'user',
        'start_date',
        'end_date',
        'subscription',
    )

admin.site.register(PaidMember, PaidMemberAdmin)

class UserInfoAdmin(admin.ModelAdmin):
    """ User Info Admin """
    list_display = (
        'user',
        'first_name',
        'last_name',
        'first_line_address',
        'postcode',
    )

admin.site.register(UserInfo, UserInfoAdmin)