#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Aug  3 09:05:19 2020

@author: josephamico
"""

from selenium import webdriver
import time
import pandas as pd

##--Web scrape the data from Tarleton website--##

## Call webdriver, establish options, provide path to Chrome driver, establish function
options = webdriver.ChromeOptions()
options.add_argument('--ignore-certificate-errors')
options.add_argument('--incognito')
options.add_argument('--headless') # Prevents launching of a browser window
driver = webdriver.Chrome('/usr/local/bin/chromedriver', options = options) # Pass chromedriver path and options to webdriver
time.sleep(1)

## Access website and pull html info
url = 'https://www.tarleton.edu/scripts/deathrow/'
driver.get(url)
time.sleep(7) # Allow enough time for website to load
button = driver.find_element_by_xpath('/html/body/div[1]/div[4]/div[1]/div/fieldset[1]/ul/li[1]/a') # xpath to View All Button
button.click() #Select, or 'click', View All button on website
time.sleep(5) # Allow enough time for website to load
page_source = driver.page_source #Download full HTML from current webpage

## Parse html with pandas and close chrome session
html_df_list = pd.read_html(page_source) # Parse HTML using pandas
driver.quit() #Close chrome session

################################
## Create and Clean Dataframe ##
################################

## Create dataframe
deathDF = html_df_list[0] # Pull needed dataframe out of dataframe list
deathDF.head()
deathDF.columns

##--Clean Information Column--##

## Find missing values
deathDF.Information.str.contains(r'(Gender:\sPlea:)').sum()
deathDF.Information.str.contains(r'(Plea:\sStatement Type:)').sum()
deathDF.Information.str.contains(r'(Statement Type:\sExecution Type:)').sum()
deathDF.Information.str.contains(r'(Execution Type:\sState:)').sum()
## Replace missing values with 'None'
deathDF['Information'] = deathDF.Information.str.replace(r'(Gender:\sPlea:)','Gender: None  Plea:')
deathDF['Information'] = deathDF.Information.str.replace(r'(Plea:\sStatement Type:)','Plea: None  Statement Type:')
deathDF['Information'] = deathDF.Information.str.replace(r'(Statement Type:\sExecution Type:)'
                                                         ,'Statement Type: None  Execution Type:')
deathDF['Information'] = deathDF.Information.str.replace(r'(Execution Type:\sState:)','Execution Type: None  State:')
## Remove column names from strings
deathDF['Information'] = deathDF.Information.str.replace(r'(Gender:)', '')
deathDF['Information'] = deathDF.Information.str.replace(r'(Plea:)', '')
deathDF['Information'] = deathDF.Information.str.replace(r'(Statement Type:)','')
deathDF['Information'] = deathDF.Information.str.replace(r'(Execution Type:)', '')
deathDF['Information'] = deathDF.Information.str.replace(r'(State:)', '')
# deathDF['Information'] = deathDF.Information.str.replace(r'(Lethal Injection)', '')
# deathDF['Information'] = deathDF.Information.str.replace(r'(Electrocution)', '')
# deathDF['Information'] = deathDF.Information.str.replace(r'(Firing Squad)', '')
# deathDF['Information'] = deathDF.Information.str.replace(r'(Gas Chamber)', '')
# deathDF['Information'] = deathDF.Information.str.replace(r'(Hanging)', '')
# deathDF['Information'] = deathDF.Information.str.replace(r'(Lethal Gas)', '')
# deathDF.Information.str.split('  ', expand = True)

## Split the column into seperate columns
deathDF[['Name', 'Gender', 'Plea', 'Statement Type'
         , 'Execution Type', 'State']] = deathDF.Information.str.split('  ', expand = True)
## Check for null values
deathDF.isna().sum()
## Drop Information Column
deathDF = deathDF.drop('Information', axis = 1)
deathDF.columns

##--Clean Dates Column--##

## Find missing values
deathDF.Dates.str.contains(r'(Crime:\sExecution:)').sum()
## Replace missing dates with None
deathDF['Dates'] = deathDF.Dates.str.replace(r'(Crime:\sExecution:)', 'Crime: None  Execution:')
deathDF['Dates'] = deathDF.Dates.str.replace(r'(Crime:)', '')
deathDF['Dates'] = deathDF.Dates.str.replace(r'(Execution:)', '')
## Split column into seperate columns
deathDF[['Crime_Date', 'Execution_Date']] = deathDF.Dates.str.split('  ', expand = True)
## Check for null values
deathDF.isna().sum()
## Drop Dates column
deathDF = deathDF.drop('Dates', axis = 1)
## Check columns
deathDF.columns

##--Clean Last Statement Column--##
## Split column on source
deathDF[['Last_Statement', 'Source']] = deathDF['Last Statement'].str.split('Source:', expand = True)
## Drop Last Statement Column
deathDF.drop('Last Statement', axis = 1, inplace = True)
## Check columns
deathDF.columns

## Export to CSV
outfile_path = '/Users/josephamico/OneDrive - Syracuse University/Semester 8_Summer 2020/IST 736 - Text Mining/Project'
deathDF.to_csv(outfile_path + '/Tarleton_Last_Statements.csv', index = False)


import numpy as np
import os
from keras import backend as K
from keras.models import Sequential
from keras.layers.core import Dense, Activation, Dropout, Lambda, Flatten
from keras.layers.convolutional import Conv2D, MaxPooling2D
from keras.layers.normalization import BatchNormalization
from keras.optimizers import SGD, RMSprop, Adam
from keras.preprocessing.image import ImageDataGenerator
from keras.utils import multi_gpu_model
import tensorflow as tf
from keras.callbacks import ModelCheckpoint, ReduceLROnPlateau, EarlyStopping
import pickle

path = "/nfs/turbo/intmed-bnallamo-turbo/wsliu/Data/UC_colonoscopy/"
model_path = path + 'models/'

batch_size=32

train_datagen = ImageDataGenerator(
        rotation_range=180,
        width_shift_range=0.2,
        height_shift_range=0.2,
        shear_range=0.1,
        zoom_range=0.2,
        horizontal_flip=True,
        vertical_flip=True,
        fill_mode='nearest',
        rescale=1./255)

test_datagen = ImageDataGenerator(rescale=1./255)

train_generator = train_datagen.flow_from_directory(
        path+'split_patients/train/',  # this is the target directory
        target_size=(256, 320),
        batch_size=batch_size,
        class_mode='categorical')

validation_generator = test_datagen.flow_from_directory(
        path+'split_patients/validation/',
        target_size=(256, 320),
        batch_size=batch_size,
        shuffle=False,
        class_mode='categorical')

model = Sequential()
model.add(Conv2D(32, (3, 3), input_shape=(256, 320, 3), padding='same', activation='relu'))
model.add(Conv2D(32, (3, 3), padding='same', activation='relu'))
model.add(BatchNormalization())
model.add(MaxPooling2D((2, 2), strides=(2,2)))

model.add(Conv2D(32, (3, 3), padding='same', activation='relu'))
model.add(Conv2D(32, (3, 3), padding='same', activation='relu'))
model.add(BatchNormalization())
model.add(MaxPooling2D((2, 2), strides=(2,2)))

model.add(Conv2D(64, (3, 3), padding='same', activation='relu'))
model.add(Conv2D(64, (3, 3), padding='same', activation='relu'))
model.add(BatchNormalization())
model.add(MaxPooling2D((2, 2), strides=(2,2)))

model.add(Conv2D(128, (3, 3), padding='same', activation='relu'))
model.add(Conv2D(128, (3, 3), padding='same', activation='relu'))
model.add(BatchNormalization())
model.add(MaxPooling2D((2,2), strides=(2,2)))

model.add(Conv2D(128, (3, 3), padding='same', activation='relu'))
model.add(Conv2D(128, (3, 3), padding='same', activation='relu'))
model.add(BatchNormalization())
model.add(MaxPooling2D((2,2), strides=(2,2)))

model.add(Flatten())
model.add(Dense(256))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(4))
model.add(Activation('sigmoid'))

adam = Adam()
model.compile(loss='categorical_crossentropy',
              optimizer=adam,
              metrics=['accuracy'])

checkpointer = ModelCheckpoint(filepath=model_path+'splitp0201.h5', verbose=0, save_best_only=True, save_weights_only=True)
reduce_lr = ReduceLROnPlateau(monitor='loss', factor=0.3, patience=10, min_lr=1.e-7)
earlystop = EarlyStopping(monitor='loss', patience=30)

history = model.fit_generator(
            train_generator,
            steps_per_epoch=train_generator.samples // (batch_size),
            epochs=200,
            validation_data=validation_generator,
            validation_steps=validation_generator.samples // (batch_size),
            callbacks = [checkpointer, reduce_lr, earlystop],
            verbose=2);

model.save_weights(model_path+'splitp0201f.h5')

with open('output/splitp0201.pkl', 'wb') as f:
    pickle.dump(history.history, f, -1)


from pandemic.client import BaseSimulator
import os
from pprint import pprint
import uuid

class AmphoraSimulator(BaseSimulator):

    # An example of logging simulation metrics somewhere

    def __init__(self, params=None, baseline=None):
        super().__init__(params=params, baseline=baseline)
        self.credentials = os.environ.get('AMPHORA')

    def start_of_run_callback(self):
        super().start_of_run_callback()
        self.run_id = str(uuid.uuid4())

    def end_of_day_callback(self):
        super().end_of_day_callback()
        payload = {'run_id':self.run_id,
                   'day':self.state['day'],
                   'metrics':self.daily_metrics(),
                   'positions':self.state['positions'],
                   'status': self.state['status']
                   }
        print('Pretending to send')
        pprint(payload)

if __name__=="__main__":
    os.environ['AMPHORA'] = 'Collosal Oca'
    simulator = AmphoraSimulator(baseline='town')
    simulator.run()


"""掘金 单线程同步 rpc
"""

# coding: utf-8
# client.py

import json
import time
import struct
import socket
import logging

logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')

logger = logging.getLogger("server")

class Client(object):
    def __init__(self, host: str, port: int):
        self.host = host
        self.port = port
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(("localhost", 8080))
        self.conn = s

    def run(self, conn_num: int):
        for i in range(conn_num):
            out, result = self.rpc("ping", f"ireader {i}")
            logger.info(f"out: {out}, ret:{result}")
            time.sleep(1)
        # 完成任务之后连接关闭
        self.conn.close()

    def rpc(self, action, params):
        request = json.dumps({"action": action, "params": params}).encode("utf-8")
        length_prefix = struct.pack("I", len(request))
        self.conn.sendall(length_prefix)
        self.conn.sendall(request)
        length_prefix = self.conn.recv(4)
        length, = struct.unpack("I", length_prefix)
        body = self.conn.recv(length)
        response = json.loads(body)
        return response["out"], response["result"]

if __name__ == '__main__':
    client = Client("127.0.0.1", 8080)
    client.run(10)


'''
quick script test to download files and store the content
'''

import requests, os

print(os.getcwd())

url = 'http://www.textfiles.com/computers/accel.txt'  # update url accordingly
fileName = 'test'  # name the file to be written without the extension

downloadFile = requests.get(url)
writtenFile = '%s.txt' % fileName

if downloadFile.status_code == 200:
    print('File downloaded to the variable successfully')
else:
    print('File download error. Try again')

print('')
with open(writtenFile, 'wb') as f:
    for x in downloadFile.iter_content(1000):
        f.write(x)

with open(writtenFile, 'r') as f:
    tempStorage = f.read()

print(tempStorage)


from textwrap import dedent
from tambo import Transport
import activate
import prepare

class LVM(object):

    help = 'Use LVM and LVM-based technologies like dmcache to deploy OSDs'

    _help = dedent("""
    Use LVM and LVM-based technologies like dmcache to deploy OSDs

    {sub_help}
    """)

    mapper = {
        'activate': activate.Activate,
        'prepare': prepare.Prepare,
    }

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

    def print_help(self, sub_help):
        return self._help.format(sub_help=sub_help)

    def main(self):
        options = [['--log', '--logging']]
        parser = Transport(self.argv, mapper=self.mapper,
                           options=options, check_help=False,
                           check_version=False)
        parser.parse_args()
        parser.catch_help = self.print_help(parser.subhelp())
        parser.mapper = self.mapper
        if len(self.argv) <= 1:
            return parser.print_help()
        parser.dispatch()
        parser.catches_help()


from testify import *

import blueox
from blueox import context

class SimpleTestCase(TestCase):
    def test(self):
        with context.Context('test'):
            assert True

class SimpleSetTestCase(TestCase):
    @setup
    def build_context(self):
        self.context = context.Context('test')

    def test(self):
        with self.context:
            self.context.set('foo', True)

        assert_equal(self.context.data['foo'], True)

class NestedIDTestCase(TestCase):
    def test(self):
        with context.Context('test', 5):
            with context.Context('.foo') as c:
                assert_equal(c.name, 'test.foo')
                assert_equal(c.id, 5)

class NestedOverlapIDTestCase(TestCase):
    def test(self):
        with context.Context('test.bar', 5):
            with context.Context('.bar.foo') as c:
                assert_equal(c.name, 'test.bar.foo')
                assert_equal(c.id, 5)

class ModuleLevelTestCase(TestCase):
    def test(self):
        with blueox.Context('test', 5):
            blueox.set('foo', True)

class EmptyModuleLevelTestCase(TestCase):
    def test(self):
        blueox.set('foo', True)

class SampleTestCase(TestCase):
    def test(self):
        enabled = []
        for _ in range(100):
            context = blueox.Context('test', 5, sample=('test', 0.25))
            enabled.append(1 if context.enabled else 0)

        assert 40 > sum(enabled) > 15

class ParentSampleTestCase(TestCase):
    def test(self):
        enabled = []
        for _ in range(100):
            parent_context = blueox.Context('test', 5)
            with parent_context:
                sub_enabled = []
                for _ in range(10):
                    context = blueox.Context('.sub', sample=('..', 0.25))
                    sub_enabled.append(1 if context.enabled else 0)
                    enabled.append(1 if context.enabled else 0)
                assert all(sub_enabled) or not any(sub_enabled)

        assert 400 > sum(enabled) > 150

class ContextWrapTestCase(TestCase):
    @setup
    def build_function(self):
        @blueox.context_wrap('foo')
        def my_function(value):
            blueox.set('value', value)
            self.context = context.current_context()
            return True

        self.function = my_function

    def test(self):
        assert_equal(self.function('test'), True)

        assert self.context
        assert not self.context.writable
        assert_equal(self.context.to_dict()['body']['value'], 'test')


# Distributed under MIT License
# Copyright (c) 2021 Remi BERTHOLET
""" Motion detection only work with ESP32CAM (Requires specially modified ESP32CAM firmware to handle motion detection.) """
import sys
import uasyncio
import video
from gc import collect
from tools import useful, jsonconfig, lang, linearfunction, tasking
from server.notifier import Notifier
from server.server   import Server
from server.presence import Presence
from motion.historic import Historic
from video.video     import Camera

class MotionConfig(jsonconfig.JsonConfig):
	""" Configuration class of motion detection """
	def __init__(self):
		jsonconfig.JsonConfig.__init__(self)
		# Indicates if the motion is activated
		self.activated = False

		# Suspend the motion detection when presence detected
		self.suspendOnPresence = True

		# Minimum difference contigous threshold to detect movement
		self.differencesDetection = 4

		# Sensitivity in percent (100% = max sensitivity, 0% = min sensitivity)
		self.sensitivity=80

		# Max images in motion historic
		self.maxMotionImages=10

		# Glitch threshold of image ignored (sometime the camera bug)
		self.thresholdGlitch=2

		# Threshold of minimum image to detect motion
		self.thresholdMotion=3

		# Number of images before camera stabilization
		self.stabilizationCamera=8

		# Turn on the led flash when the light goes down
		self.lightCompensation = True

		# Notify motion
		self.notify = True

		# Empty mask is equal disable masking
		self.mask = b""

class ImageMotion:
	""" Class managing a motion detection image """
	baseIndex = [0]
	motionBaseId = [0]
	created = [0]
	def __init__(self, motion, config):
		""" Constructor """
		self.motion = motion
		self.baseIndex[0] += 1
		self.created[0] += 1
		self.index    = self.baseIndex[0]
		self.filename = None
		self.motionId = None
		self.date     = useful.dateToString()
		self.filename = useful.dateToFilename()
		path = useful.dateToPath()[:-1]
		if path[-1] in [0x30,0x31,0x32]:
			path = path[:-1] + b"00"
		else:
			path = path[:-1] + b"30"
		self.path     = path
		self.motionDetected = False
		self.config = config
		self.comparison = None

	def deinit(self):
		""" Destructor """
		self.created[0] -= 1
		if self.created[0] >= 32:
			print("Destroy %d"%self.created[0])
		if self.motion:
			self.motion.deinit()

	def setMotionId(self, motionId = None):
		""" Set the unique image identifier """
		if motionId == None:
			self.motionBaseId[0] += 1
			self.motionId = self.motionBaseId[0]
		else:
			if self.motionId == None:
				self.motionId = motionId
			else:
				print("Motion id already set")

	def getMotionId(self):
		""" Get the unique image identifier """
		return self.motionId

	def getFilename(self):
		""" Get the storage filename """
		return "%s Id=%d D=%d"%(self.filename, self.index, self.getDiffCount())

	def getMessage(self):
		""" Get the message of motion """
		return "%s %s D=%d"%(useful.tostrings(lang.motion_detected), self.date[-8:], self.getDiffCount())

	def getInformations(self):
		""" Return the informations of motion """
		if self.comparison != None:
			result    = self.comparison.copy()
		else:
			result = {}
		result["image"]    = self.getFilename() + ".jpg"
		result["path"]     = self.path
		result["index"]    = self.index
		result["date"]     = self.date
		result["motionId"] = self.motionId
		return result

	async def save(self):
		""" Save the image on sd card """
		return await Historic.addMotion(useful.tostrings(self.path), self.getFilename(), self.motion.getImage(), self.getInformations())

	def compare(self, previous, extractShape=True):
		""" Compare two motion images to get differences """
		res = self.motion.compare(previous.motion, extractShape)
		self.comparison = res
		return res

	def getMotionDetected(self):
		""" Get the motion detection status """
		return self.motionDetected

	def setMotionDetected(self):
		""" Set the motion detection status """
		self.motionDetected = True

	def get(self):
		""" Get the image captured """
		return self.motion.getImage()

	def getComparison(self):
		""" Return the comparison result """
		return self.comparison

	def getDiffCount(self):
		""" Get the difference contigous """
		if self.comparison:
			return self.comparison["diff"]["count"]
		return 0

	def getDiffHisto(self):
		""" Get the histogram difference """
		if self.comparison:
			return self.comparison["diff"]["diffhisto"]
		return 0

	def getDifferences(self):
		""" Get the differences """
		if self.comparison:
			return self.comparison["diff"]["diffs"]
		return ""

	def resetDifferences(self):
		""" Reset the differences, used during the camera stabilization image """
		self.comparison = None

	def getSize(self):
		""" Return the size of image buffer """
		return self.motion.getSize()

	def refreshConfig(self):
		""" Refresh the motion detection configuration """
		if self.motion != None:
			mask = useful.tobytes(self.config.mask)
			if not b"/" in mask:
				mask = b""
			errorLight = linearfunction.getFx(self.config.sensitivity, linearfunction.getLinear(100,8,0,64))
			self.motion.configure(\
				{
					"mask":mask,
					"errorLights":[[0,1],[128,errorLight],[192, errorLight],[256,errorLight]],
					"errorHistos":[[0,0],[32,32],[128,128],[256,256]]
				})

class SnapConfig:
	""" Store last motion information """
	info = None

	@staticmethod
	def get(width=None, height=None):
		""" Get the last motion information """
		if width != None and height != None:
			SnapConfig.info = SnapConfig(width, height)
		elif SnapConfig.info == None:
			SnapConfig.info = SnapConfig()
		return SnapConfig.info

	def __init__(self, width=800, height=600):
		""" Constructor """
		self.width  = width
		self.height = height
		if (((self.width/8) % 8) == 0):
			self.square_x = 64
		else:
			self.square_x = 40

		if (((self.height/8) % 8) == 0):
			self.square_y = 64
		else:
			self.square_y = 40
		self.diff_x = self.width  // self.square_x
		self.diff_y = self.height // self.square_y
		self.max = self.diff_x * self.diff_y

class Motion:
	""" Class to manage the motion capture """
	def __init__(self, config= None, pirDetection=False):
		self.images = []
		self.index  = 0
		self.config = config
		self.pirDetection = pirDetection
		self.imageBackground = None
		self.mustRefreshConfig = True
		self.quality = 15
		self.previousQuality = 0
		self.flashLevel = 0

	def __del__(self):
		""" Destructor """
		self.cleanup()

	def cleanup(self):
		""" Clean up all images """
		for image in self.images:
			if id(image) != id(self.imageBackground):
				image.deinit()
		self.images = []
		if self.imageBackground:
			self.imageBackground.deinit()
		self.imageBackground = None

	def open(self):
		""" Open camera """
		if video.Camera.open():
			return True
		else:
			return False

	def resume(self):
		""" Resume the camera, restore the camera configuration after an interruption """
		video.Camera.framesize(b"%dx%d"%(SnapConfig.get().width, SnapConfig.get().height))
		video.Camera.pixformat(b"JPEG")
		video.Camera.quality(self.quality)
		video.Camera.brightness(0)
		video.Camera.contrast(0)
		video.Camera.saturation(0)
		video.Camera.hmirror(0)
		video.Camera.vflip(0)
		video.Camera.flash(self.flashLevel)

		detected, changePolling = self.detect(False)
		if detected == False:
			self.cleanup()

	async def capture(self):
		""" Capture motion image """
		result = None
		# If enough image taken
		if len(self.images) >= self.config.maxMotionImages:
			# Get older image
			image = self.images.pop()

			# If motion detected on image, on battery the first five images are sent
			if image.getMotionDetected() or (self.pirDetection and image.index <= 3):
				# Notification of motion
				result = (image.getMessage(), image)

				# Save image to sdcard
				if await image.save() == False:
					if self.config.notify:
						await Notifier.notify(lang.failed_to_save)
			else:
				# Destroy image
				self.deinitImage(image)

		motion = video.Camera.motion()

		# Light can be compensed with flash led
		if self.config.lightCompensation:
			# If it has enough light
			if motion.getLight() >= 32:
				# If flash led working
				if self.flashLevel >= 2:
					# Reduce light of flash led
					self.flashLevel -= 2
					video.Camera.flash(self.flashLevel)
			# If it has not enough light
			if motion.getLight() <= 24:
				# If flash to low
				if self.flashLevel <= 192:
					# Increase the light of flash led
					self.flashLevel += 2
					video.Camera.flash(self.flashLevel)
		else:
			# If flash led working and compensation disabled
			if self.flashLevel > 0:
				# Stop flash led
				self.flashLevel = 0
				video.Camera.flash(self.flashLevel)

		image = ImageMotion(motion, self.config)
		if self.mustRefreshConfig:
			image.refreshConfig()
			self.mustRefreshConfig = False
		self.images.insert(0, image)
		self.index += 1
		return result

	def refreshConfig(self):
		""" Force the refresh of motion configuration """
		self.mustRefreshConfig = True

	def isStabilized(self):
		""" Indicates if the camera is stabilized """
		# If the PIR detection force the stabilization
		if self.pirDetection == True:
			stabilized = True
		# If the camera not stabilized
		elif len(self.images) < self.config.stabilizationCamera and len(self.images) < self.config.maxMotionImages:
			stabilized = False
		else:
			stabilized = True
		return stabilized

	def isDetected(self, comparison):
		""" Indicates if motion detected """
		if comparison:
			# If image seem not equal to previous
			if comparison["diff"]["count"] >= self.config.differencesDetection:
				return True
		return False

	def adjustQuality(self, current):
		""" Adjust the image quality according to the size of image to"""
		if len(self.images) >= self.config.maxMotionImages:
			changed = False
			size = current.getSize()
			if size > 62*1024:
				if self.quality < 63:
					self.quality += 1
					changed = True
					video.Camera.quality(self.quality, False)
			else:
				if self.quality >= 1:
					if size < 50*1024:
						self.quality -= 1
						changed = True
						video.Camera.quality(self.quality, False)
			if changed == False:
				if self.previousQuality != self.quality:
					self.previousQuality = self.quality

	def compare(self, display=True):
		""" Compare all images captured and search differences """
		differences = {}
		if len(self.images) >= 2:
			current = self.images[0]

			self.adjustQuality(current)

			# Compute the motion identifier
			for previous in self.images[1:]:
				# # If image not already compared
				comparison = current.compare(previous, False)

				# If camera not stabilized
				if self.isStabilized() == False:
					# Reject the differences
					current.resetDifferences()
					break

				# If image seem equal to previous
				if not self.isDetected(comparison):
					# Reuse the motion identifier
					current.setMotionId(previous.motionId)
					break
			else:
				# Create new motion id
				current.setMotionId()

				# Compare the image with the background if existing and extract modification
				if self.imageBackground != None:
					comparison = current.compare(self.imageBackground, True)

			# Compute the list of differences
			diffs = ""
			index = 0
			for image in self.images:
				differences.setdefault(image.getMotionId(), []).append(image.getMotionId())
				if image.getMotionId() != None:
					if image.index % 10 == 0:
						trace = "_"
					else:
						trace = " "
					if image.index > index:
						index = image.index
					diffs += "%d:%d%s%s"%(image.getMotionId(), image.getDiffCount(), chr(0x41 + ((256-image.getDiffHisto())//10)), trace)
			if display:
				sys.stdout.write("\r%s %s (%d) "%(useful.dateToString()[12:], diffs, index))
		return differences

	def deinitImage(self, image):
		""" Release image allocated """
		if image:
			if not image in self.images:
				if image != self.imageBackground:
					image.deinit()

	def detect(self, display=True):
		""" Detect motion """
		detected = False
		changePolling = False

		# Compute the list of differences
		differences = self.compare(display)

		# Too many differences found
		if len(list(differences.keys())) >= self.config.thresholdMotion:
			detected = True
			changePolling = True
		# If no differences
		elif len(list(differences.keys())) == 1:
			image = self.imageBackground
			self.imageBackground = self.images[0]
			self.deinitImage(image)
			detected = False
		# If not enough differences
		elif len(list(differences.keys())) <= self.config.thresholdGlitch:
			detected = True
			changePolling = True
			# Check if it is a glitch
			for diff in differences.values():
				if len(diff) <= 1:
					# Glitch ignored
					detected = False
					break
		# Not detected
		else:
			detected = False

		if detected:
			# Mark all motion images
			for image in self.images:
				# If image seem not equal to previous
				if self.isDetected(image.getComparison()):
					image.setMotionDetected()
		return detected, changePolling

class Detection:
	""" Asynchronous motion detection object """
	def __init__(self, pirDetection):
		""" Constructor """
		self.pirDetection = pirDetection
		self.loadConfig()
		self.motion = None

		self.batteryLevel = -2
		if self.pirDetection == True:
			self.pollingFrequency = 3
		else:
			self.pollingFrequency = 100
		self.detection = None
		self.activated = None
		self.refreshConfigCounter = 0

	def loadConfig(self):
		""" Load motion configuration """
		# Open motion configuration
		self.motionConfig      = MotionConfig()
		if self.motionConfig.load() == False:
			self.motionConfig.save()

	def refreshConfig(self):
		""" Refresh the configuration : it can be changed by web page """
		if self.refreshConfigCounter % 11 == 0:
			# If configuration changed
			if self.motionConfig.isChanged():
				self.motionConfig.load()
				useful.syslog("Change motion config %s"%self.motionConfig.toString(), display=False)
				if self.motion:
					self.motion.refreshConfig()
		self.refreshConfigCounter += 1

	async def run(self):
		""" Main asynchronous task """
		await tasking.taskMonitoring(self.detect)

	async def detect(self):
		""" Detect motion """
		result = False
		# Wait the server resume
		await Server.waitResume()

		# Release previously alocated image
		self.releaseImage()

		# If the motion detection activated
		if await self.isActivated():
			# Capture motion
			result = await self.capture()
		else:
			await uasyncio.sleep(3)
			result = True

		# Refresh configuration when it changed
		self.refreshConfig()

		return result

	async def isActivated(self):
		""" Indicates if the motion detection is activated according to configuration or presence """
		result = False

		# If motion activated
		if self.motionConfig.activated:
			# If motion must be suspended on presence
			if self.motionConfig.suspendOnPresence:
				# If home is empty
				if Presence.isDetected() == False:
					result = True
			else:
				result = True

		# If state of motion changed
		if self.activated != result:
			# If notification enabled
			if self.motionConfig.notify:
				if result:
					await Notifier.notify(lang.motion_detection_on)
				else:
					await Notifier.notify(lang.motion_detection_off)
			self.activated = result

		# If camera activated and motion activated
		if Camera.isActivated() and result:
			result = True
		else:
			result = False

		# If motion disabled
		if result == False:
			# Wait moment before next loop
			await uasyncio.sleep_ms(500)
		return result

	async def initMotion(self):
		""" Initialize motion detection """
		firstInit = False

		# If motion not initialized
		if self.motion == None:
			self.motion = Motion(self.motionConfig, self.pirDetection)
			if self.motion.open() == False:
				self.motion = None
				raise Exception("Cannot open camera")
			else:
				firstInit = True

		# If the camera configuration changed
		if video.Camera.isModified() or firstInit:
			# Restore motion configuration
			self.motion.resume()
			video.Camera.clearModified()

	def releaseImage(self):
		""" Release motion image allocated """
		# If detection
		if self.detection:
			message, image = self.detection
			# Release image buffer
			self.motion.deinitImage(image)

		# Force garbage collection each 20 images
		if self.motion:
			if self.motion.index %30 == 0:
				collect()

	async def capture(self):
		""" Capture motion """
		result = False

		# If camera not stabilized speed start
		if self.motion and self.motion.isStabilized() == True:
			await uasyncio.sleep_ms(self.pollingFrequency*100 if Server.isSlow() else self.pollingFrequency)

		try:
			# Waits for the camera's availability
			reserved = await video.Camera.reserve(self, timeout=60)

			# If reserved
			if reserved:
				# Initialize motion detection
				await self.initMotion()

				# Capture motion image
				self.detection = await self.motion.capture()

				# If motion detected
				if self.detection != None:
					# Notify motion with push over
					message, image = self.detection
					if self.motionConfig.notify:
						await Notifier.notify(message, image.get())
				# Detect motion
				detected, changePolling = self.motion.detect()

				# If motion found
				if changePolling == True:
					# Speed up the polling frequency
					self.pollingFrequency = 10
					Historic.setMotionState(True)
				else:
					# Slow down the polling frequency
					self.pollingFrequency = 50
					Historic.setMotionState(False)
				result = True
			else:
				if self.motionConfig.notify:
					await Notifier.notify(lang.motion_detection_suspended)
				result = True

		finally:
			if reserved:
				await video.Camera.unreserve(self)
		return result

async def detectMotion(pirDetection):
	""" Asynchronous motion detection main routine """
	detection = Detection(pirDetection)
	await detection.run()


"""
How to run:
python find_HSV_pixels.py <image path>
"""

import argparse
import cv2
import os

from guiutils import HSV

def main():
    parser = argparse.ArgumentParser(description='Visualizes the line for hough transform.')
    parser.add_argument('filename')

    args = parser.parse_args()

    img = cv2.imread(args.filename)

    cv2.imshow('input', img)

    edge_finder = HSV(img, 0, 255, 1)

    print ("Edge parameters:")
    print ("Layer: %s" % edge_finder.layer())
    print ("Threshold1: %f" % edge_finder.threshold1())
    print ("Threshold2: %f" % edge_finder.threshold2())

    (head, tail) = os.path.split(args.filename)

    (root, ext) = os.path.splitext(tail)

    smoothed_filename = os.path.join("output_images", root + "-smoothed" + ext)
    edge_filename = os.path.join("output_images", root + "-edges" + ext)

    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()


from urllib import parse, request

#输出结果文件
resultFile = open('/app/naming/yangxu.txt','wb')

i = 0

#0x9fa6  0x4eff

for ch in range(0x4e00,0x9fa6):
  data = {}
  data['word1'] = '杨'
  data['word2'] =  '旭' + chr(ch)
  data['st'] = '2'
  data['FrontType'] = '1'
  data['Submit'] = '开始测算'

  babyname = '\n杨' + '旭' + chr(ch)+','
  babynamel = babyname.encode('utf-8')

  url_values = parse.urlencode(data)

  url = 'http://www.1518.com/s'
  full_url = url + '?' + url_values
  resource = request.urlopen(full_url)

  #解析html文本
  #print f.read()
  html_str = resource.read() #.decode('utf-8',errors="ignore")
  #html_str = requests.get(full_url).text
  #encoding = extract(str(html_bytes).lower(), 'charset=', '"')
  #html_str = html_bytes.decode('gb2312')
  #html_str = html_bytes.decode("utf8")

  score_str = b'<div class="name_num">'
  p = html_str.find(score_str)
  print(p)
  # if not p == -1:
  #     score_bytes = html_str[p+22:p+24]
  #     score = str(score_bytes).replace('<','').replace('>','')
  #     #输出到文件
  #     resultFile.write(babynamel)
  #     resultFile.write(score.encode('utf-8'))
  #     i = i + 1
  #     print('\n %s', i)
  #     print('%s %s', babynamel,score.encode('utf-8'))

resultFile.close();


from flask import jsonify, make_response, request, url_for
from app import app
from functools import wraps
from app.models import User, postItem

def post_required(f):
    """
    Decorator to ensure that a valid post id is sent in the url path parameters
    :param f:
    :return:
    """

    @wraps(f)
    def decorated_function(*args, **kwargs):
        post_id_ = request.view_args['post_id']
        try:
            int(post_id_)
        except ValueError:
            return response('failed', 'Provide a valid post Id', 401)
        return f(*args, **kwargs)

    return decorated_function

def response(status, message, status_code):
    """
    Make an http response helper
    :param status: Status message
    :param message: Response Message
    :param status_code: Http response code
    :return:
    """
    return make_response(jsonify({
        'status': status,
        'message': message
    })), status_code

def response_with_post_item(status, item, status_code):
    """
    Http response for response with a post item.
    :param status: Status Message
    :param item: postItem
    :param status_code: Http Status Code
    :return:
    """
    return make_response(jsonify({
        'status': status,
        'item': item.json()
    })), status_code

def response_with_pagination(items, previous, nex, count):
    """
    Get the post items with the result paginated
    :param items: Items within the post
    :param previous: Url to previous page if it exists
    :param nex: Url to next page if it exists
    :param count: Pagination total
    :return: Http Json response
    """
    return make_response(jsonify({
        'status': 'success',
        'previous': previous,
        'next': nex,
        'count': count,
        'items': items
    })), 200

def get_user_post(current_user, post_id):
    """
    Query the user to find and return the post specified by the post Id
    :param post_id: post Id
    :param current_user: User
    :return:
    """
    user_post = User.get_by_id(current_user.id).posts.filter_by(id=post_id).first()
    return user_post

def get_paginated_items(post, post_id, page, q):
    """
    Get the items from the post and then paginate the results.
    Items can also be search when the query parameter is set.
    Construct the previous and next urls.
    :param q: Query parameter
    :param post: post
    :param post_id: post Id
    :param page: Page number
    :return:
    """

    if q:
        pagination = postItem.query.filter(postItem.name.like("%" + q.lower().strip() + "%")) \
            .order_by(postItem.create_at.desc()) \
            .filter_by(post_id=post_id) \
            .paginate(page=page, per_page=app.config['post_AND_ITEMS_PER_PAGE'], error_out=False)
    else:
        pagination = post.items.order_by(postItem.create_at.desc()).paginate(page=page, per_page=app.config[
            'post_AND_ITEMS_PER_PAGE'], error_out=False)

    previous = None
    if pagination.has_prev:
        if q:
            previous = url_for('items.get_items', q=q, post_id=post_id, page=page - 1, _external=True)
        else:
            previous = url_for('items.get_items', post_id=post_id, page=page - 1, _external=True)
    nex = None
    if pagination.has_next:
        if q:
            nex = url_for('items.get_items', q=q, post_id=post_id, page=page + 1, _external=True)
        else:
            nex = url_for('items.get_items', post_id=post_id, page=page + 1, _external=True)
    return pagination.items, nex, pagination, previous


# _*_coding: utf-8_*_

import json
import time

import requests

from public import params
from 测试用例.接口自动化.接口自动化_V1 import lcl_data

BaseUrl = params.BaseUrl
ParaDir = params.ParaFile

headers = {
        'Content-Tpye': 'application/json;charset=utf-8'
    }

def lcl_data_workorder(sheet, row):
    time.sleep(1)
    ordercode = "IT_WO_" + str(time.time())
    print(ordercode)
    dl = lcl_data(sheet, row)
    dl['code'] = ordercode
    # print(dl)
    return dl

def workorder_create(data):
    """工单—创建"""
    url = BaseUrl + '/ime-container/imeWorkOrder/insertWorkOrder.action'
    # print(data)
    try:
        req = requests.post(url, headers=headers, data=json.dumps(data)).content.decode()
        return req
    except Exception as e:
        return e

def workorder_modify(data):
    """工单-修改"""
    url = BaseUrl + '/ime-container/imeWorkOrder/modifyWorkOrder.action'
    # print(data)
    try:
        req = requests.post(url, headers=headers, data=json.dumps(data)).content.decode()
        return req
    except Exception as e:
        return e

def workorder_refecreaate(data):
    """工单-参照订单生成"""
    url = BaseUrl + '/ime-container/imeWorkOrder/insertWorkOrderByPlanOrder.action'
    # print(data)
    try:
        req = requests.post(url, headers=headers, data=json.dumps(data)).content.decode()
        return req
    except Exception as e:
        return e

def workorder_savesort(flgid, wogidlist):
    """工单-编排保存"""
    url = BaseUrl + '/ime-container/imeWorkOrder/saveWorkOrderSort.action?factoryLineGid=' + flgid
    data = {
        "ids": wogidlist,
        "dateStr": "2018-01-01 00:00:00"
    }
    print(url)
    print(data)
    try:
        req = requests.post(url, headers=headers, data=json.dumps(data)).content.decode()
        return req
    except Exception as e:
        return e

def workorder_release(wogidlist):
    """工单-下发"""
    url = BaseUrl + '/ime-container/imeWorkOrder/releaseWorkOrder.action'
    try:
        req = requests.post(url, headers=headers, data=json.dumps(wogidlist)).content.decode()
        return req
    except Exception as e:
        return e

if __name__ == '__main__':
    pass

测试用例/接口自动化/接口自动化_V1/生产执行/工单/workorder_public.py


from sense_hat import SenseHat
from time import sleep

sense = SenseHat()

r = (255,0,0)
b = (0,0,0)
w = (255,255,255)
g = (218,165,32)
ng = (218,165,32)

x = 1
y = 1

maze = [[r,r,r,r,r,r,r,r],
        [r,b,b,b,b,b,b,g],
        [r,r,r,b,r,b,b,r],
        [r,b,r,b,r,r,r,r],
        [r,b,b,b,b,b,b,r],
        [r,b,r,r,r,r,b,r],
        [r,b,b,r,b,b,b,r],
        [r,r,r,r,r,g,r,r]]

maze2 =[[r,r,r,r,r,r,r,r],
        [r,b,r,b,b,b,b,r],
        [r,b,r,b,r,b,r,r],
        [r,b,b,b,r,b,g,r],
        [r,b,r,b,r,r,r,r],
        [r,b,r,b,b,b,b,r],
        [r,b,r,b,r,r,b,r],
        [r,r,r,r,r,r,ng,r]]

game_over = False

def check_wall(x,y,new_x,new_y):
  if maze[new_y][new_x] != r:
    return new_x, new_y
  elif maze[new_y][x] != r:
    return x, new_y
  elif maze[y][new_x] != r:
    return new_x, y
  else:
    return x,y

def move_marble(pitch, roll, x, y):
  new_x = x
  new_y = y
  if 1 < pitch < 179 and x != 0:
    new_x -= 1
  elif 181 < pitch < 359 and x != 7:
    new_x += 1
  elif 1 < roll < 179 and y != 7:
    new_y += 1
  elif 181 < roll < 359 and y != 0:
    new_y -= 1
  new_x, new_y = check_wall(x,y,new_x,new_y)
  return new_x, new_y

while game_over == False:
  pitch = sense.get_orientation()['pitch']
  roll = sense.get_orientation()['roll']
  x,y = move_marble(pitch, roll, x,y)
  if maze[y][x] == g:
    sense.show_message("Level 2")
    maze = maze2
  if maze[y][x] == g:
    sense.show_message("Win!!")
    game_over = True
  maze[y][x] = w
  sense.set_pixels(sum(maze,[]))
  sleep(0.01)
  maze[y][x] = b


from django.contrib import admin
from home.models import Setting, ContactMessage
class SettingAdmin(admin.ModelAdmin):
    list_display = ['title',  'company', 'update_at', 'status']

class ContactMessageAdmin(admin.ModelAdmin):
    list_display = ['name',  'subject', 'update_at', 'status']
    readonly_fields = ('name', 'subject', 'email', 'message', 'ip')
    list_filter= ['status',]

admin.site.register(Setting, SettingAdmin)
admin.site.register(ContactMessage, ContactMessageAdmin)


from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from django.utils import timezone
from django.utils.translation import activate, ugettext, ugettext_lazy
from transactions.models import Account, Currency
from . import queries
import json
import datetime as dt
import requests
from pprint import pprint
import re

DATE_FORMAT = "%Y-%m-%d"
UAH = "UAH"

def get_colors():
    colors = ["#FF0F00"]
    try:
        with open('analysis/static/analysis/colors.json') as f:
            colors = json.loads(f.read())
            colors.reverse()
    except Exception as e:
        print(e)
    return colors

def convert_str_to_date(str_date):
    """Return date or None if it's impossible convert."""

    if not str_date:
        return None

    try:
        d = dt.datetime.strptime(str_date, DATE_FORMAT)
    except ValueError:
        d = None
    return d

def get_currencies_exchange():
    """Return average currencies exchange."""

    currencies_exchange = {}

    url_cash = "https://api.privatbank.ua/p24api/pubinfo?json&exchange&coursid=5"
    url_card = "https://api.privatbank.ua/p24api/pubinfo?exchange&json&coursid=11"

    cash_data = get_request_json_data(url_cash)
    card_data = get_request_json_data(url_card)

    if cash_data:

        for cash in cash_data:
            if cash.get("base_ccy", None) == UAH:
                currencies_exchange[cash['ccy']] = float(cash['sale'])

    if card_data:

        for card in card_data:
            if card.get("base_ccy", None) == UAH:
                if currencies_exchange.get(card["ccy"], None):
                    currencies_exchange[card['ccy']] = (currencies_exchange[card['ccy']] + float(card['sale']))/2
                else:
                    currencies_exchange[card['ccy']] = float(card['sale'])

    return currencies_exchange

def get_request_json_data(url):
    """Return data in json or None"""
    try:
        req = requests.get(url)
        data = json.loads(req.text)
    except Exception as e:
        print(e)
        data = None
    finally:
        return data

def get_context_for_stat(request, without_currencies=False):

    # get start, end and currency from request if defined
    start, end, currency = None, None, None
    if request.method == "GET":

        start = convert_str_to_date(request.GET.get('start', None))
        end = convert_str_to_date(request.GET.get('end', None))

        if not without_currencies:
            currency = request.GET.get("currency", None)
            if currency == "All":
                currency = None

    # get last month if start and end is not defined
    if not start:
        start = timezone.now() - dt.timedelta(days=30)
    if not end:
        end = timezone.now()

    context = {
        "start": start.strftime(DATE_FORMAT),
        "end": end.strftime(DATE_FORMAT),
    }

    if not without_currencies:
        # get all currency codes
        context["currencies"] = [currency.code for currency in Currency.objects.filter(user=request.user)]
        context["currencies_exchange"] = get_currencies_exchange()

        # if currencies is not defined, get exchange of currencies and
        # calculate value to one currencies UAH
        currencies_exchange = {} if currency != None else context["currencies_exchange"]

    kwargs = locals()
    del kwargs['request']
    del kwargs['without_currencies']

    return kwargs

@login_required
def balance(request):
    """Show the balance for every currency and account"""

    context = {}
    colors, c = get_colors(), 0
    colors_length = len(colors)-1
    account_data, currencies = [], []
    currencies_exchange = get_currencies_exchange()
    amount_of_balance = 0

    # get all accounts and their balance
    for account in Account.objects.filter(user=request.user):
        account_data.append(
            {
                'title': str(account.account_name),
                'balance': int(account.balance),
                'currency': str(account.currency),
                'value_field': str(account.account_name).replace(' ', ''),
                'color': colors[c]
            }
        )
        # get unique currencies
        if str(account.currency) not in currencies:
            currencies.append(str(account.currency))
        # choose color
        c += 1
        if c > colors_length:
            c = 0

    # build data for chart
    chart_data = []
    for currency in currencies:
        chart_item = {'currency': currency}
        for item in account_data:
            if currency == item['currency']:
                chart_item[item['value_field']]= item['balance']
                amount_of_balance += item['balance'] * currencies_exchange.get(item['currency'], 1)
        chart_data.append(chart_item)

    context['account_data'] = json.dumps(account_data)
    context['chart_data'] = json.dumps(chart_data)
    context['amount_of_balance'] = round(amount_of_balance, 2)
    context['currencies_exchange'] = currencies_exchange
    context['analysis_active'] = 'active'
    context['account_balance_active'] = 'active'

    return render(request, 'analysis/balance.html', context)

@login_required
def account_currency_stat(request):
    """Return data for last month"""

    kws = get_context_for_stat(request, True)
    context, start, end = kws['context'], kws['start'], kws['end']

    # data is list of tuple: fist column is currency code,
    # second is account name, third is amount of costs||incomes,
    # forth is type of article (1=cost, 0=income)
    data = queries.get_accounts_currencies_stat(start.strftime(DATE_FORMAT),
                                                end.strftime(DATE_FORMAT),
                                                str(request.user.id))

    colors, c = get_colors(), 0
    colors_length = len(colors) - 1
    account_data, currencies = [], []
    amount_of_costs, amount_of_incomes = 0, 0
    currencies_exchange = get_currencies_exchange()

    # get all accounts and their amount of consts and incomes
    for item in data:

        # calculate amount of costs and incomes
        if item[3] == 0:
            amount_of_incomes += item[2]*currencies_exchange.get(item[0], 1)
        else:
            amount_of_costs += (-item[2])*currencies_exchange.get(item[0], 1)

        account_data.append(
            {
                'title':  ("Cost of " if item[3]==1 else "Income of ") + str(item[1]),
                'amount': int(item[2]),
                'currency': str(item[0]),
                'value_field': str(item[1]).replace(' ', '')+str(item[3]),
                'color': colors[c]
            }
        )
        # get unique currencies
        if str(item[0]) not in currencies:
            currencies.append(str(item[0]))
        # choose color
        c += 1
        if c > colors_length:
            c = 0

    # build data for chart
    chart_data = []
    types = [
        {'type': "Cost ", "amount": "item['amount'] < 0"},
        {'type': "Income ", "amount": "item['amount'] > 0"},
    ]
    for currency in currencies:
        for type in types:
            chart_item = {'currency': type['type'] + currency}
            for item in account_data:
                if currency == item['currency'] and eval(type['amount']):
                    chart_item[item['value_field']] = item['amount']
            if len(chart_item.keys())>1:
                chart_data.append(chart_item)

    context['account_data'] = json.dumps(account_data)
    context['chart_data'] = json.dumps(chart_data)
    context['amount_of_costs'] = round(amount_of_costs, 2)
    context['amount_of_incomes'] = round(amount_of_incomes,2)
    context['profit'] = amount_of_incomes - amount_of_costs
    context['currencies_exchange'] = currencies_exchange
    context['account_currency_stat_active'] = 'active'
    context['analysis_active'] = 'active'

    return render(request, 'analysis/account_currency_stat.html', context)

@login_required
def costs_incomes_stat(request):

    kws = get_context_for_stat(request)
    context, start, end =kws['context'], kws['start'], kws['end']
    currency, currencies, currencies_exchange = kws['currency'], kws['context']['currencies'], kws['currencies_exchange']

    # data is list of tuple: fist column is currency code,
    # second is cost or income name, third is amount
    data = queries.get_costs_incomes_stat(start.strftime(DATE_FORMAT),
                                                end.strftime(DATE_FORMAT),
                                                str(request.user.id))

    costs_data, incomes_data = [], []
    amount_of_costs, amount_of_incomes = 0, 0
    for item in data:

        # if currency is defined and isn't equal current,
        # filtered this one
        if currency != None and currency != item[0]:
            continue

        # calculate exchange currency. if it is not found, input 1
        exchange = currencies_exchange.get(item[0], 1)

        value = round(abs(item[2])*exchange, 2)
        if item[2]<0:
            amount_of_costs += value
            costs_data.append(
                {"cost": item[1], "value": value}
            )
        else:
            amount_of_incomes += value
            incomes_data.append(
                {"income": item[1], "value": value}
            )

    context['costs_data'] = json.dumps(costs_data)
    context['incomes_data'] = json.dumps(incomes_data)
    context['amount_of_costs'] = amount_of_costs
    context['amount_of_incomes'] = amount_of_incomes
    context['profit'] = amount_of_incomes-amount_of_costs
    context['currency'] = currency
    context['costs_incomes_stat_active'] = 'active'
    context['analysis_active'] = 'active'

    return render(request, 'analysis/costs_incomes_stat.html', context)

@login_required
def costs_incomes_history(request):

    kws = get_context_for_stat(request)
    context, start, end = kws['context'], kws['start'], kws['end']
    currency, currencies, currencies_exchange = kws['currency'], kws['context']['currencies'], kws['currencies_exchange']

    # data is list of tuple: fist column is currency code,
    # second is date, third is amount, forth type (1=cost, 0=income)
    data = queries.get_costs_incomes_stat_history(start.strftime(DATE_FORMAT),
                                                  end.strftime(DATE_FORMAT),
                                                  str(request.user.id))

    # get unique date
    dates, deletes = [], []
    for i, item in enumerate(data):
        # if currency is defined and isn't equal current,
        # filtered this one
        if currency != None and currency != item[0]:
            deletes.insert(0, i)
            continue
        # input unique date
        if item[1] not in dates:
            dates.append(item[1])

    # delete data
    for i in deletes:
        del data[i]

    # build data for chart
    chart_data, pre_ay, pre_by = [], 0, 0
    for date in dates:

        chart_item = {
            "date": date.strftime(DATE_FORMAT),
            "ay": pre_ay,
            "by": pre_by,
        }

        deletes = []
        for i, item in enumerate(data):
            if item[1] != date:
                break
            # delete items that is calculated now
            deletes.insert(0, i)
            # calculate exchange currency. if it is not found, input 1
            exchange = currencies_exchange.get(item[0], 1)
            if item[3] == 1:
                chart_item["ay"] += round(abs(item[2])*exchange, 2)
            else:
                chart_item["by"] += round(abs(item[2])*exchange, 2)

        # delete iterated item
        for i in deletes:
            del data[i]

        # save previous value
        pre_ay, pre_by = round(float(chart_item['ay']), 2), round(float(chart_item['by']), 2)
        chart_data.append(chart_item)

    context['chart_data'] = json.dumps(chart_data)
    context['currency'] = currency
    context['costs_incomes_history_active'] = 'active'
    context['analysis_active'] = 'active'

    return render(request, 'analysis/costs_incomes_history.html', context)

@login_required
def shops_stat(request):

    kws = get_context_for_stat(request)
    context, start, end =kws['context'], kws['start'], kws['end']
    currency, currencies, currencies_exchange = kws['currency'], kws['context']['currencies'], kws['currencies_exchange']

    # data is list of tuple: fist column is currency code,
    # second is shop name, third is amount
    data = queries.get_shops_stat(start.strftime(DATE_FORMAT),
                                  end.strftime(DATE_FORMAT),
                                  str(request.user.id))

    chart_data = []
    amount_of_costs, amount_of_incomes = 0, 0
    colors = get_colors()
    colors_length, c = len(colors)-1, 0

    # get unique shops and delete filter
    data_delete, shops = [], []
    for i, item in enumerate(data):
        # if currency is defined and isn't equal current,
        # filtered this one
        if currency != None and currency != item[0]:
            data_delete.insert(0, i)
            continue

        if item[1] not in shops:
            shops.append(item[1])

    for i in data_delete:
        del data[i]

    # calculate chart data
    for shop in shops:

        item_cost = {
            "shop": "Cost of " + shop,
            "value": 0,
            "color": colors[c],
        }
        item_income ={
            "shop": "Income of " + shop,
            "value": 0,
            "color": colors[c],
        }

        data_delete = []
        for i, item in enumerate(data):

            if item[1] != shop:
                break

            data_delete.insert(0, i)

            # calculate exchange currency. if it is not found, input 1
            exchange = currencies_exchange.get(item[0], 1)

            value = round(item[2]*exchange, 2)
            if value<0:
                amount_of_costs += abs(value)
                item_cost["value"] += value
            else:
                amount_of_incomes += value
                item_income["value"] += value

        for i in data_delete:
            del data[i]

        if item_cost["value"] != 0:
            chart_data.append(item_cost)
        if item_income['value'] != 0:
            chart_data.append(item_income)

        c += 1
        if c > colors_length:
            c = 0

    context['chart_data'] = json.dumps(chart_data)
    context['amount_of_costs'] = amount_of_costs
    context['amount_of_incomes'] = amount_of_incomes
    context['profit'] = amount_of_incomes-amount_of_costs
    context['currency'] = currency
    context['shops_stat_active'] = 'active'
    context['analysis_active'] = 'active'

    return render(request, 'analysis/shops_stat.html', context)


#!/usr/bin/env python3

'''

Helper for apps that use PDS databases (that were imported into
SQLite3 databases).

Most routines in this module are private to the module (i.e., those
starting with "_").  There's only a handful of public functions.

'''

import datetime
import pathlib
import re

import PDS

##############################################################################
#
# Public values

# Keys for types of emails
pkey  = 'preferred_emails'
npkey = 'non_preferred_emails'

date_never = datetime.date.fromisoformat('1899-12-30')

##############################################################################

# Which database number to use?
# At ECC, the active database is 1.
_database = 1

def _get_db_num():
    return _database

#-----------------------------------------------------------------------------

# These values are not in the database -- they are hard-coded (!)
def _find_member_types():
    member_types = {
        0 : 'Head of Household',
        1 : 'Spouse',
        2 : 'Adult',
        3 : 'Young Adult',
        4 : 'Child',
        5 : 'Other',
    }

    return member_types

#-----------------------------------------------------------------------------

# Normalize some flags to actual Python booleans
def _normalize_boolean(item, src, dest=None) -> None:
    if dest is None:
        dest=src

    if src not in item:
        item[dest] = False
    elif item[src] == '' or item[src] == 0 or not item[src]:
        item[dest] = False
        if src != dest:
            del item[src]
    elif item[src] == 1:
        item[dest] = True
        if src != dest:
            del item[src]

#-----------------------------------------------------------------------------

# Represent filenames with a Pathlib object, so that it's equally accessible
# when running on Windows and Linux.
def _normalize_filename(item, src) -> None:
    if src not in item:
        return

    if not item[src]:
        del item[src]
        return

    item[src] = pathlib.PureWindowsPath(item[src])

#-----------------------------------------------------------------------------

def _normalize_date(item, sentinel=True):
    if item is None or item == '0000-00-00':
        if sentinel:
            return date_never
        else:
            return None
    else:
        return datetime.date.fromisoformat(item)

#-----------------------------------------------------------------------------

# Compute a salutation for the Head of Household ("HoH" and spouse) for each
# familiy.  PDS allows there to be multiple HoHs and multiple spouse Members in
# any given Family, so be sure to account for that.
#
# Make the salutation be of the form:
#
# first/nickname [and first/nickname [...]] last_name [and first/nickname [and first/nickname [...]] last_name [...]
#
# Examples:
#
# - Andrew and Betty Smith
# - Andrew Smith and Betty Johnson
# - Andrew and Betty Smith and Joseph Johnson
# - Andrew and Betty Smith and Joseph and Geraldine Johnson
#
def _compute_family_hoh_and_spouse_salutations(families, log):
    def _add(last_names, member):
        last = member['last']
        if last not in last_names:
            last_names[last] = list()
        last_names[last].append(member)

    #-----------------------------------------------------------

    for fid in sorted(families.keys()):
        family     = families[fid]

        last_names = dict()
        hoh        = list()
        spouses    = list()

        for member in family['members']:
            last = member['last']

            if 'Head' in member['type']:
                hoh.append(member)
                _add(last_names, member)
            if 'Spouse' in member['type']:
                spouses.append(member)
                _add(last_names, member)

        salutation = ''
        for last_name in sorted(last_names.keys()):
            first_names = list()
            for member in last_names[last_name]:
                if 'nickname' in member and member['nickname'] is not None:
                    first_names.append(member['nickname'])
                elif member['first'] is not None:
                    first_names.append(member['first'])
                else:
                    first_names.append("***UNKNOWN***")
                    log.error("Unknown first name")

            if len(salutation) > 0:
                salutation += ' and '
            salutation += f"{' and '.join(first_names)} {last_name}"

        family['hoh_and_spouse_salutation'] = salutation

#-----------------------------------------------------------------------------

def _load_families(pds, columns=None,
                   active_only=True, log=None):
    db_num = _get_db_num()

    if not columns:
        columns = list()
    columns.append('Name')
    columns.append('MailingName')
    columns.append('ParKey')
    columns.append('StreetAddress1')
    columns.append('StreetAddress2')
    columns.append('StreetCityRec')
    columns.append('StreetZip')
    columns.append('StatDescRec')
    columns.append('PictureFile')
    columns.append('EnvelopeUser')
    columns.append('Visitor')
    columns.append('SendNoMail')
    columns.append('PDSInactive{num}'.format(num=db_num))

    where = ('Fam_DB.CensusFamily{db_num}=1'
             .format(db_num=db_num))
    if active_only:
        where += (' AND '
                  '(Fam_DB.PDSInactive{db_num}=0 OR '
                  'FAM_DB.PDSInactive{db_num} is null)'
                  .format(db_num=db_num))

    families = PDS.read_table(pds, 'Fam_DB', 'FamRecNum',
                              columns=columns, log=log,
                              where=where)

    for f in families.values():
        _normalize_boolean(f, src=f'PDSInactive{db_num}', dest="Inactive")
        _normalize_boolean(f, src='SendNoMail')
        _normalize_boolean(f, src='EnvelopeUser')
        _normalize_filename(f, src='PictureFile')

    return families

#-----------------------------------------------------------------------------

def _load_members(pds, columns=None,
                  active_only=True, log=None):
    db_num = _get_db_num()

    if not columns:
        columns = list()
    columns.append('Name')
    columns.append('FamRecNum')
    columns.append('DateOfBirth')
    columns.append('MonthOfBirth')
    columns.append('DayOfBirth')
    columns.append('YearOfBirth')
    columns.append('Gender')
    columns.append('MaritalStatusRec')
    columns.append('MemberType')
    columns.append('PictureFile')
    columns.append('Location')
    columns.append('LanguageRec')
    columns.append('EthnicDescRec')
    columns.append('User3DescRec') # Skills
    columns.append('User4DescRec') # Occupation
    columns.append('Deceased')
    columns.append('PDSInactive{num}'.format(num=db_num))

    where = ('Mem_DB.CensusMember{db_num}=1'
             .format(db_num=db_num))
    if active_only:
        where += (' AND '
                  'Mem_DB.deceased=0 AND '
                  '(Mem_DB.PDSInactive{db_num}=0 OR '
                  'Mem_DB.PDSInactive{db_num} is null)'
                  .format(db_num=db_num))

    members = PDS.read_table(pds, 'Mem_DB', 'MemRecNum',
                             columns=columns, log=log,
                             where=where)

    for m in members.values():
        _normalize_boolean(m, src='Deceased')
        _normalize_boolean(m, src=f'PDSInactive{db_num}', dest="Inactive")
        _normalize_filename(m, src='PictureFile')
        m['date_of_birth'] = _normalize_date(m['DateOfBirth'], sentinel=False)

    return members

#-----------------------------------------------------------------------------

def _link_families_members(families, members):
    # Make a copy because we don't to delete Members from the
    # main/actual list
    members_copy = members.copy()

    for fid, f in families.items():
        family_members = list()
        for mid in members_copy:
            m = members[mid]

            frn = m['FamRecNum']
            if fid == frn:
                family_members.append(m)
                m['family'] = f

        # Delete all the Members we found from the main list of active
        # members (because we already found their families)
        for m in family_members:
            del members_copy[m['MemRecNum']]

        f['members'] = family_members

#-----------------------------------------------------------------------------

def _delete_non_parishioners(families, members):
    to_delete = list()

    # Look for family ParKey >= 10,000
    for fid, f in families.items():
        parkey = int(f['ParKey'])
        if parkey >= 9000 or f['Visitor']:
            f = families[fid]
            for m in f['members']:
                mid = m['MemRecNum']
                del members[mid]

            to_delete.append(fid)

    for fid in to_delete:
        del families[fid]

#-----------------------------------------------------------------------------

def _link_family_emails(families, emails):
    for f in families.values():
        f[pkey]  = list()
        f[npkey] = list()

    for e in emails.values():
        if not e['FamEmail']:
            continue

        fid = e['MemRecNum']
        if fid not in families:
            continue

        f = families[fid]
        if e['EMailOverMail']:
            key = pkey
        else:
            key = npkey

        addr = '{name} <{addr}>'.format(name=f['Name'],
                                        addr=e['EMailAddress'].strip())
        e['full_address'] = addr
        f[key].append(e)

#-----------------------------------------------------------------------------

def _link_family_city_states(families, city_states):
    for f in families.values():
        csid = f['StreetCityRec']
        if csid and csid in city_states:
            f['city_state'] = city_states[csid]['CityState']
        else:
            # Several places in our Python assume that there is a
            # value in the "city_state" entry.  So rather than go
            # check all of those places, just put an empty string
            # there if there actually is no value.
            f['city_state'] = ''

#-----------------------------------------------------------------------------

def _link_family_statuses(families, fam_status_types):
    for f in families.values():
        id = f['StatDescRec']
        if id in fam_status_types:
            f['status'] = fam_status_types[id]['Description']

#-----------------------------------------------------------------------------

def link_family_or_member_phones(family_or_member, phones, phone_types):
    for p in phones.values():
        family_or_member_id = p['Rec']
        if family_or_member_id not in family_or_member:
            continue

        f = family_or_member[family_or_member_id]
        if 'phones' not in f:
            f['phones'] = list()

        ptr = p['PhoneTypeRec']
        phone_type = ''
        if ptr in phone_types:
            phone_type = phone_types[ptr]['Description']

        _normalize_boolean(p, 'Unlisted')
        f['phones'].append({
            'number'   : p['Number'],
            'type'     : phone_type,
            'unlisted' : p['Unlisted'],
        })

#-----------------------------------------------------------------------------

def _link_family_phones(families, phones, phone_types):
    link_family_or_member_phones(families, phones, phone_types)

#-----------------------------------------------------------------------------

def _link_family_keywords(families, keywords, fam_keywords):
    for fk in fam_keywords.values():
        fid = fk['FamRecNum']
        if fid not in families:
            continue

        f = families[fid]
        if 'keywords' not in f:
            f['keywords'] = list()
        keyword = keywords[fk['DescRec']]['Description']
        f['keywords'].append(keyword)

#-----------------------------------------------------------------------------

def _link_member_types(members, types):
    for m in members.values():
        m['type'] = types[m['MemberType']]

#-----------------------------------------------------------------------------

def _link_member_emails(members, emails):
    for m in members.values():
        m[pkey]  = list()
        m[npkey] = list()

    for e in emails.values():
        if e['FamEmail']:
            continue

        mid = e['MemRecNum']
        if mid not in members:
            continue

        m = members[mid]
        if e['EMailOverMail']:
            key = pkey
        else:
            key = npkey

        addr = '{name} <{addr}>'.format(name=m['email_name'],
                                        addr=e['EMailAddress'].strip())
        e['full_address'] = addr
        m[key].append(e)

#-----------------------------------------------------------------------------

def _link_member_phones(members, phones, phone_types):
    link_family_or_member_phones(members, phones, phone_types)

#-----------------------------------------------------------------------------

def _link_member_keywords(members, keywords, mem_keywords):
    for mk in mem_keywords.values():
        mid = mk['MemRecNum']
        if mid not in members:
            continue

        m = members[mid]
        if 'keywords' not in m:
            m['keywords'] = list()
        keyword = keywords[mk['DescRec']]['Description']
        m['keywords'].append(keyword)

#-----------------------------------------------------------------------------

def _link_member_birth_places(members, birth_places):
    for b in birth_places.values():
        mid = b['AskMemNum']
        if mid not in members:
            continue

        m = members[mid]
        m['birth_place'] = b['BirthPlace']

#-----------------------------------------------------------------------------

def _link_member_ministries(members, ministries, mem_ministries, statuses):
    _link_member_mintal(members, 'ministries', ministries, 'MinDescRec',
                        mem_ministries, statuses)

def _link_member_talents(members, talents, mem_talents, statuses):
    _link_member_mintal(members, 'talents', talents, 'TalDescRec',
                        mem_talents, statuses)

def _link_member_mintal(members, desc, things, thing_index_field,
                        mem_things, statuses):
    akey = f'active_{desc}'
    ikey = f'inactive_{desc}'

    for member in members.values():
        member[akey] = list()
        member[ikey] = list()

    for mt in mem_things.values():
        mid = mt['MemRecNum']
        if mid not in members:
            continue
        m = members[mid]

        status_id = mt['StatusDescRec']
        if not status_id:
            continue
        if status_id not in statuses:
            continue
        status = statuses[status_id]
        mem_list_name = akey
        if status['Active'] != 1:
            mem_list_name = ikey

        thing_id = mt[thing_index_field]

        # Deep copy the ministry record so that we can add some more
        # data in it about this specific member
        thing = things[thing_id].copy()
        thing['active'] = status['Active']
        thing['status'] = status['Description']
        thing['start']  = _normalize_date(mt['StartDate'])
        thing['end']    = _normalize_date(mt['EndDate'])

        m[mem_list_name].append(thing)

#-----------------------------------------------------------------------------

def _link_member_marriage_dates(members, mem_dates, mdtid):
    for md in mem_dates.values():
        if md['DescRec'] != mdtid:
            continue

        mid = md['MemRecNum']
        if mid and mid not in members:
            continue
        m = members[mid]
        m['marriage_date'] = _normalize_date(md['Date'])

#-----------------------------------------------------------------------------

training_req_results = {
    0   :   "Pending",
    1   :   "Yes",
    2   :   "No",
    3   :   "Positive",
    4   :   "Negative",
    5   :   "Received",
    6   :   "Incomplete",
    7   :   "Cleared",
    8   :   "Cleared / Restrictions",
    9   :   "Not Cleared",
    10  :   "Illegible",
    11  :   "Submitted",
    12  :   "Inactive",
    13  :   "Expired",
    14  :   "Archived",
}

def _link_member_requirements(members, mem_reqs, req_types):
    for mr in mem_reqs.values():
        mid = mr['MemRecNum']
        if mid not in members:
            continue

        id = mr['ReqResult']
        if id in training_req_results:
            result = training_req_results[id]
        else:
            result = f'Unknown result {id}'

        m = members[mid]
        key = 'requirements'
        if key not in m:
            m[key] = list()

        m[key].append({
            'description' : req_types[mr['ReqDescRec']]['Description'],
            'start_date'  : _normalize_date(mr['ReqDate']),
            'end_date'    : _normalize_date(mr['ExpirationDate']),
            'result'      : result,
            'note'        : mr['ReqNote'],
        })

#-----------------------------------------------------------------------------

def _link_member_id(members, member_source_field, member_dest_field,
                    values, value_source_field='Description'):
    for member in members.values():
        id = member[member_source_field]
        if id and id in values:
            value = values[id]
            member[member_dest_field] = value[value_source_field]

#-----------------------------------------------------------------------------

# Transform the list of all family fund history (i.e., individual
# contributions) to be:
#
# families['funding'][fid][year][fund_id], a dictionary containing:
#
# * 'fund': PDS DB entry from FundSetup_DB
# * 'history': array of entries, one per contribution of the family that year
# on that fund, each entry containing a dictionary of:
#     * 'activity': name of fund from FuncAct (don't both copying over
#        other data -- the fund name is really the only important thing)
#     * 'fund_id': same as fund_id index in "funding"
#     * 'year': same as year index in "fundung"
#     * 'item': detailed dictionary of information about the contribution.
#       'FEAmt', 'FEComment', 'FEDate' are probably the only relevant fields
#       from this dictionary.
def _link_family_funds(funds, fund_periods, fund_activities,
                       families, all_family_funds, all_family_fund_rates,
                       all_family_fund_history, log):
    # Make a cross reference dictionary of funds by fund ID+year.  It will be
    # used below.
    fund_xref = dict()
    for period in fund_periods.values():
        fund_id = period['FundNumber']
        fund_year = period['FundYear']
        fund = funds[period['SetupRecNum']]

        if fund_year not in fund_xref:
            fund_xref[fund_year] = dict()
        if fund_id not in fund_xref[fund_year]:
            fund_xref[fund_year][fund_id] = dict()

        fund_xref[fund_year][fund_id] = fund

    # Similarly, make a family fund rate cross reference dictionary indexed by
    # family fund IDs, to be used for direct lookups, below.
    family_fund_rate_xref = dict()
    for family_fund_rate in all_family_fund_rates.values():
        family_fund_id = family_fund_rate['FundRecNum']
        family_fund_rate_xref[family_fund_id] = family_fund_rate

    # Do the main work of this method in a standalone dictionary for simplicity.
    # We'll link it into the main "families" dictionary at the end.
    funding = dict()
    for item in all_family_fund_history.values():
        # Make sure this family is in the families dictionary (e.g., if we only
        # have the active families, make sure this is an active family)
        fid = item['FEFamRec']
        if fid not in families:
            continue

        # Transform the item date string into a datetime.date
        item['FEDate'] = _normalize_date(item['FEDate'])

        family_fund = all_family_funds[item['FEFundRec']]
        fund_id     = family_fund['FDFund']
        year        = family_fund['FDYear']
        fund        = fund_xref[year][fund_id]

        # Sometimes activity_id will be None.  Thanks PDS!
        activity_id = item['ActRecNum']
        if activity_id and activity_id in fund_activities:
            activity = fund_activities[activity_id]['Activity']
        else:
            activity = 'None'

        # If the family pledged, they'll have a fund_rate.  If not, they won't.
        family_fund_id = family_fund['FDRecNum']
        if family_fund_id in family_fund_rate_xref:
            fund_rate = family_fund_rate_xref[family_fund_id]
        else:
            fund_rate = None

        # Create the multi-levels in the output
        if fid not in funding:
            funding[fid] = dict()
        if year not in funding[fid]:
            funding[fid][year] = dict()
        if fund_id not in funding[fid][year]:
            funding[fid][year][fund_id] = {
                "fund"      : fund,
                "fund_rate" : fund_rate,
                "history"   : list(),
            }

        funding[fid][year][fund_id]['history'].append({
            "fund_id"  : fund_id,
            "year"     : year,
            "activity" : activity,
            "item"     : item,
        })

    # Now assign the results back to families[fid]['funding']
    for fid in funding:
        # Make sure this family is in the families dictionary (e.g., if we only
        # have the active families, make sure this is an active family). This is
        # technicaly redundant with above, but hey -- defensive programming,
        # right?
        if fid not in families:
            continue

        families[fid]['funds'] = funding[fid]

#-----------------------------------------------------------------------------

def _find_member_marriage_date_type(date_types):
    for dtid, dt in date_types.items():
        if dt['Description'] == 'Marriage':
            return dtid

    return None

#-----------------------------------------------------------------------------

# A full Family name will be formatted:
#
#    Last,First(spouse last,spouse first,spouse title,spouse suffix),Title,Suffix
#
# (spouse) information may not be there
# (spouse last) will not be there if the info is the same
#
# If Middle, Nickname, or Maiden are not provided, those terms
# (including "{}", "()", and "[]") are not included.  E.g., if only
# the nickname is provided:
#
#    Squyres,Jeffrey(Jeff)
#
# If Prefix and Suffix are not provided, those terms are not there,
# either (including the commas).  If only Suffix is supplied, then the
# comma will be there for the Prefix, but it will be empty.  Example:
#
#    Squyres,Jeffrey{Michael}(Jeff),,Esq.
#
# There are no cases in Epiphany's database where someone does not
# have both a first and a last name.  So I didn't even bother trying
# to figure out how that would be stored.

def _parse_family_name(name, log=None):
    parts = name.split(',')
    last = parts[0]

    prefix = None
    if len(parts) > 2:
        prefix = parts[2]
        if prefix == '':
            prefix = None

    suffix = None
    if len(parts) > 3:
        suffix = parts[3]

    # The "more" field may have the middle, nickname, and maiden name.
    # Parse those out.
    first = None
    middle = None
    nickname = None
    maiden = None
    if len(parts) > 1:
        more = parts[1]
        result = re.match('([^\(\{\[]+)', more)
        if result:
            first = result[1]
        else:
            first = 'Unknown'

        result = re.search('\{(.+)\}', more)
        if result:
            middle = result[1]

        result = re.search('\((.+)\)', more)
        if result:
            nickname = result[1]

        result = re.search('\[(.+)\]', more)
        if result:
            maiden = result[1]

    if log:
        log.debug("Last: {l}, First: {f}, Middle: {m}, Nickname: {n}, Maiden: {maiden}, Prefix: {pre}, Suffix: {suff}"
                  .format(l=last,f=first,m=middle,n=nickname,maiden=maiden,pre=prefix,suff=suffix))

    return last, first, middle, nickname, maiden, prefix, suffix

#-----------------------------------------------------------------------------

# A full Member name will be formatted:
#
#    Last,First{Middle}(Nickname}[Maiden],Prefix,Suffix
#
# If Middle, Nickname, or Maiden are not provided, those terms
# (including "{}", "()", and "[]") are not included.  E.g., if only
# the nickname is provided:
#
#    Squyres,Jeffrey(Jeff)
#
# If Prefix and Suffix are not provided, those terms are not there,
# either (including the commas).  If only Suffix is supplied, then the
# comma will be there for the Prefix, but it will be empty.  Example:
#
#    Squyres,Jeffrey{Michael}(Jeff),,Esq.
#
# There are no cases in Epiphany's database where someone does not
# have both a first and a last name.  So I didn't even bother trying
# to figure out how that would be stored.

def _parse_member_name(name, log=None):
    parts = name.split(',')
    last = parts[0]

    prefix = None
    if len(parts) > 2:
        prefix = parts[2]
        if prefix == '':
            prefix = None

    suffix = None
    if len(parts) > 3:
        suffix = parts[3]

    # The "more" field may have the middle, nickname, and maiden name.
    # Parse those out.
    first = None
    middle = None
    nickname = None
    maiden = None
    if len(parts) > 1:
        more = parts[1]
        result = re.match('([^\(\{\[]+)', more)
        if result:
            first = result.group(1)
        else:
            first = 'Unknown'

        result = re.search('\{(.+)\}', more)
        if result:
            middle = result.group(1)

        result = re.search('\((.+)\)', more)
        if result:
            nickname = result.group(1)

        result = re.search('\[(.+)\]', more)
        if result:
            maiden = result.group(1)

    if log:
        log.debug("Last: {l}, First: {f}, Middle: {m}, Nickname: {n}, Maiden: {maiden}, Prefix: {pre}, Suffix: {suff}"
                  .format(l=last,f=first,m=middle,n=nickname,maiden=maiden,pre=prefix,suff=suffix))

    return last, first, middle, nickname, maiden, prefix, suffix

def _parse_member_names(members):
    for _, m in members.items():
        name = m['Name']
        (last, first, middle, nickname, maiden,
         prefix, suffix) = _parse_member_name(name)

        m['first']    = first
        m['middle']   = middle
        m['last']     = last
        m['nickname'] = nickname
        m['maiden']   = maiden
        m['prefix']   = prefix
        m['suffix']   = suffix

        field = 'full_name'
        m[field]     = ''
        if prefix:
            m[field] += prefix + ' '
        if first:
            m[field] += first + ' '
        if nickname:
            m[field] += '("' + nickname + '") '
        if middle:
            m[field] += middle + ' '
        if last:
            m[field] += last
        if maiden:
            m[field] += ' (maiden: ' + maiden + ')'
        if suffix:
            m[field] += ', ' + suffix

        if nickname:
            m['email_name'] = '{nick} {last}'.format(nick=nickname, last=last)
        else:
            m['email_name'] = '{first} {last}'.format(first=first, last=last)

#-----------------------------------------------------------------------------

def _make_emails_lower_case(emails):
    key = 'EMailAddress'
    for e in emails.values():
        addr = e[key].lower().strip()
        e[key] = addr

#-----------------------------------------------------------------------------

# Load PDS Families and Members.  Return them as 2 giant hashes,
# appropriately cross-linked to each other.
def load_families_and_members(filename=None, pds=None,
                              active_only=True, parishioners_only=True,
                              log=None):

    if pds and filename:
        raise Exception("Cannot supply both filename *and* PDS SQLite3 cursor -- only supply one or the other")

    if filename:
        pds = PDS.connect(filename)

    city_states = PDS.read_table(pds, 'City_DB', 'CityRec',
                                 columns=['CityState'], log=log)
    statuses    = PDS.read_table(pds, 'StatusType_DB', 'StatusDescRec',
                                 columns=['Description', 'Active'], log=log)
    ministries  = PDS.read_table(pds, 'MinType_DB', 'MinDescRec',
                                 columns=['Description'], log=log)
    talents     = PDS.read_table(pds, 'TalType_DB', 'TalDescRec',
                                 columns=['Description'], log=log)
    birth_places= PDS.read_table(pds, 'Ask_DB', 'AskRecNum',
                                 columns=['AskMemNum', 'BirthPlace'], log=log)
    date_places = PDS.read_table(pds, 'DatePlace_DB', 'DatePlaceRecNum',
                                 log=log)
    date_types  = PDS.read_table(pds, 'DateType_DB', 'DescRec',
                                 columns=['Description'], log=log)
    phone_types = PDS.read_table(pds, 'PhoneTyp_DB', 'PhoneTypeRec',
                                 columns=['Description'], log=log)
    req_types   = PDS.read_table(pds, 'ReqType_DB', 'ReqDescRec',
                                 columns=['Description', 'Expires'], log=log)
    emails      = PDS.read_table(pds, 'MemEMail_DB', 'EMailRec',
                                 columns=['MemRecNum', 'EMailAddress',
                                          'EMailOverMail', 'FamEmail'],
                                 log=log)
    languages   = PDS.read_table(pds, 'LangType_DB', 'LanguageRec',
                                 columns=['Description'],
                                 log=log)
    mem_phones  = PDS.read_table(pds, 'MemPhone_DB', 'PhoneRec',
                                 columns=['Rec', 'Number', 'PhoneTypeRec', 'Unlisted'],
                                 log=log)
    mem_keyword_types = PDS.read_table(pds, 'MemKWType_DB', 'DescRec',
                                 columns=['Description'], log=log)
    mem_keywords= PDS.read_table(pds, 'MemKW_DB', 'MemKWRecNum',
                                 columns=['MemRecNum', 'DescRec'],
                                 log=log)
    mem_ministries=PDS.read_table(pds, 'MemMin_DB', 'MemKWRecNum',
                                  columns=['MinDescRec', 'MemRecNum',
                                           'StatusDescRec', 'StartDate', 'EndDate'],
                                  log=log)
    mem_talents =PDS.read_table(pds, 'MemTal_DB', 'MemKWRecNum',
                                  columns=['TalDescRec', 'MemRecNum',
                                           'StatusDescRec', 'StartDate', 'EndDate'],
                                  log=log)
    mem_dates   = PDS.read_table(pds, 'MemDates_DB', 'MemDateRecNum',
                                 columns=['MemRecNum', 'Date',
                                          'DescRec'],
                                 log=log)
    mem_ethnics = PDS.read_table(pds, 'EthType_DB', 'EthnicDescRec',
                                 columns=['Description'], log=log)
    mem_3kw     = PDS.read_table(pds, 'User3KW_DB', 'User3DescRec',
                                 columns=['Description'], log=log)
    mem_4kw     = PDS.read_table(pds, 'User4KW_DB', 'User4DescRec',
                                 columns=['Description'], log=log)
    mem_reqs    = PDS.read_table(pds, 'MemReq_DB', 'MemReqRecNum',
                                 columns=['MemRecNum', 'ReqDescRec',
                                          'ReqDate', 'ReqResult',
                                          'ReqNote', 'ExpirationDate'])

    relationship_types = PDS.read_table(pds, 'RelType_DB', 'RelDescRec',
                                        columns=['Description'], log=log)
    marital_statuses = PDS.read_table(pds, 'MemStatType_DB', 'MaritalStatusRec',
                                      columns=['Description'], log=log)

    fam_keyword_types = PDS.read_table(pds, 'FamKWType_DB', 'DescRec',
                                 columns=['Description'], log=log)
    fam_keywords= PDS.read_table(pds, 'FamKW_DB', 'FamKWRecNum',
                                 columns=['FamRecNum', 'DescRec'],
                                 log=log)
    fam_status_types = PDS.read_table(pds, 'FamStatType_DB', 'StatDescRec',
                                      columns=['Description'], log=log)
    fam_phones  = PDS.read_table(pds, 'FamPhone_DB', 'PhoneRec',
                                 columns=['Rec', 'Number', 'PhoneTypeRec', 'Unlisted'],
                                 log=log)

    # Descriptions of each fund
    funds = PDS.read_table(pds, 'FundSetup_DB', 'SetupRecNum',
                                      columns=['FundNumber',
                                                'FundKey',
                                                'FundName'], log=log)
    # Each fund also has one or more time periods associated with it
    fund_periods = PDS.read_table(pds, 'FundPeriod_DB', 'FundPeriodRecNum',
                                columns=['SetupRecNum', 'FundNumber',
                                         'FundYear', 'FundStart', 'FundEnd'],
                                log=log)
    # When a Family contributes, each contribution is assocaited with
    # a "funding activity"
    fund_activities = PDS.read_table(pds, 'FundAct_DB', 'ActRecNum',
                                  columns=['FundRecNum',
                                            'GroupName',
                                            'Activity',
                                            'Function',
                                            'GroupOrder',
                                            'pdsorder'], log=log)

    # Families' activities with relation to the established funds (there is one
    # entry for each family for each fund to which that family has contributed).
    fam_funds = PDS.read_table(pds, 'FamFund_DB', 'FDRecNum',
                            columns=['FDFamRec', 'FDYear', 'FDFund',
                                    'FDOrder', 'MemRecNum', 'Comment'],
                            log=log)
    # Pledging information from the family
    fam_fund_rates = PDS.read_table(pds, 'FamFundRate_DB', 'RateRecNum',
                            columns=['FundRecNum', 'FDStartDate', 'FDEndDate',
                                    'FDRate', 'FDRateAdj', 'FDNumber',
                                    'FDPeriod', 'FDTotal',
                                    'Batch', 'BatchDate'])
    # A listing of each individual contribution from each family,
    # cross-referenced to fam_funds.
    fam_fund_history = PDS.read_table(pds, 'FamFundHist_DB', 'FERecNum',
                                columns=['FEDate', 'ActRecNum', 'FEFundRec',
                                        'FEFamRec', 'FEAmt', 'FEBatch',
                                        'MemRecNum', 'FEChk', 'FEComment'],
                                log=log)

    member_types = _find_member_types()
    mdtid        = _find_member_marriage_date_type(date_types)

    _make_emails_lower_case(emails)

    families = _load_families(pds=pds,
                              active_only=active_only,
                              log=log)
    members  = _load_members(pds=pds,
                             active_only=active_only,
                             log=log)

    _link_families_members(families, members)

    if parishioners_only:
        _delete_non_parishioners(families, members)

    _link_family_emails(families, emails)
    _link_family_city_states(families, city_states)
    _link_family_statuses(families, fam_status_types)
    _link_family_phones(families, fam_phones, phone_types)
    _link_family_keywords(families, fam_keyword_types, fam_keywords)

    _parse_member_names(members)
    _link_member_types(members, member_types)
    _link_member_emails(members, emails)
    _link_member_phones(members, mem_phones, phone_types)
    _link_member_keywords(members, mem_keyword_types, mem_keywords)
    _link_member_birth_places(members, birth_places)
    _link_member_ministries(members, ministries, mem_ministries, statuses)
    _link_member_talents(members, talents, mem_talents, statuses)
    _link_member_marriage_dates(members, mem_dates, mdtid)
    _link_member_requirements(members, mem_reqs, req_types)

    _link_member_id(members, 'MaritalStatusRec', 'marital_status', marital_statuses)
    _link_member_id(members, 'LanguageRec', 'language', languages)
    _link_member_id(members, 'EthnicDescRec', 'ethnic', mem_ethnics)
    _link_member_id(members, 'User3DescRec', 'skills', mem_3kw)
    _link_member_id(members, 'User4DescRec', 'occupation', mem_4kw)

    _link_family_funds(funds, fund_periods, fund_activities,
                       families, fam_funds, fam_fund_rates, fam_fund_history,
                       log)

    # Compute family HoH+Spouse salutations
    _compute_family_hoh_and_spouse_salutations(families, log)

    return pds, families, members

##############################################################################

def _get_sorted_addrs(entries):
    addrs = list()
    for entry in entries:
        addrs.append(entry['EMailAddress'].strip())

    return sorted(addrs)

# If a Member or Family has one or more preferred email addresses,
# return them (as an array).  If there are no preferred email
# addresses, return None.
def find_preferred_email(member_or_family):
    mof = member_or_family
    if pkey in mof and len(mof[pkey]) > 0:
        return _get_sorted_addrs(mof[pkey])
    else:
        return [ ]

# Return either the Member/Family preferred email addresses, or, if
# there are no preferred addresses, return the first (by sorted order)
# non-preferred email address (if it exists).  If no email addresses
# exist, return an empty list.
def find_any_email(member_or_family):
    mof = member_or_family
    addrs = find_preferred_email(mof)
    if addrs:
        return addrs
    elif npkey in mof and len(mof[npkey]) > 0:
        addr = _get_sorted_addrs(mof[npkey])[0]
        return [ addr ]
    else:
        return [ ]


n = int(input())
max_num = -9999999999999999
min_num = 9999999999999999
for i in range(n):
    number = int(input())
    if number < min_num:
        min_num = number
    if number > max_num:
        max_num = number
print(f"Max number: {max_num}")
print(f"Min number: {min_num}")


"""crop face from image """

import cv2

face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')

img = cv2.imread('cz.jpg')

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)

for (x, y, w, h) in faces:
    cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
    sub_face = gray[y:y + h, x:x + w]

cv2.imwrite("croped_face.jpg", sub_face)
cv2.imshow('img', img)

while 1 :
    k = cv2.waitKey(30) & 0xff
    if k == 27:
        cv2.destroyAllWindows()
        break


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# author='Jingle,RRJC.CO.LTD'

from Common.Data import InputData
from pyhessian.client import HessianProxy
from Utils.Jar import HandleJar
from Common.Exception import HandleException
from Utils.DB import HandleDB
import time
from Common.Log import Log

class HESSIAN_REQ(object):

    def __init__(self, interfacename, casename):
        self.inputdata = InputData.INPUTDATA().hessian_indata(interfacename, casename)
        self.host = self.inputdata['host']
        self.params = self.inputdata['params']
        self.jarname = self.inputdata['jarname']
        self.classname = self.inputdata['classname']
        self.funcname = self.inputdata['funcname']
        self.ruler = HandleDB.HandleDB().db_readruler(interfacename)

    def entity2input(self, entity):
        classname = entity['classname2']
        para = {}
        for k in entity['para']:
            para[k] = {}
            para[k]['value'] = entity['para'][k]['value']
            para[k]['funcname'] = entity['para'][k]['funcname2']
        return classname, para

    def gen_params(self):
        inputpara = {}
        for k in self.params:
            if self.ruler[k]['entity'] == None:
                inputpara[k] = {}
                inputpara[k]['value'] = self.params[k]
                inputpara[k]['funcname'] = self.ruler[k]['funcname1']
            else:
                inputpara[k] = {}
                (classname, para) = self.entity2input(self.ruler[k]['entity'])
                jd = HandleJar.HandleJar().entityjar(self.jarname, para, classname)
                inputpara[k]['value'] = jd
                inputpara[k]['funcname'] = self.ruler[k]['funcname']
        if self.classname == None or self.funcname == None:
            for k in inputpara:
                inputpara[k] = inputpara[k]['value']
            return inputpara
        else:
            entity = HandleJar.HandleJar().entityjar(self.jarname, inputpara, self.classname)
            return entity

    # 访问HESSIAN接口服务器
    def proxy(self, paras):
        proxy = HessianProxy(self.host)
        s = "result = proxy.%s(%s)"%(self.funcname, str(paras))
        exec(s)
        exec ('return result')

def hessian_runner(interfacename, casename):
    p = HESSIAN_REQ(interfacename, casename)
    paras = p.gen_params()
    res = p.proxy(paras)

    return res

if __name__ == '__main__':

    para = HandleJar.HandleJar().valuejar('rrjc-user-api.jar', 'LoginInEntity', '')