#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
.. $Id$
"""

from __future__ import division
from __future__ import print_function
from __future__ import absolute_import

logger = __import__('logging').getLogger(__name__)

import time
import calendar

from zope import component

from zope.component.hooks import getSite
from zope.component.hooks import site as current_site

from nti.asynchronous.scheduled.job import create_scheduled_job

from nti.asynchronous.scheduled.utils import add_scheduled_job

from nti.contenttypes.calendar.interfaces import ICalendarEvent
from nti.contenttypes.calendar.interfaces import ICalendarEventNotifier
from nti.contenttypes.calendar.interfaces import ICalendarEventNotificationValidator
from nti.contenttypes.calendar.interfaces import ICalendarEventURLProvider

from nti.contenttypes.calendar.model import CalendarEventNotificationJob

from nti.dataserver.interfaces import IDataserver

from nti.ntiids.ntiids import find_object_with_ntiid

from nti.site.site import get_site_for_site_names

from nti.site.transient import TrivialSite

EXECUTING_TIME_INTERVAL = 30*60

def generate_executing_time(calendar_event):
    dt = calendar_event.start_time
    return calendar.timegm(dt.utctimetuple()) - EXECUTING_TIME_INTERVAL

def get_site(site_name=None):
    if site_name is None:
        site = getSite()
        site_name = site.__name__ if site is not None else None
    return site_name

def put_job(func, jid, *args, **kwargs):
    job = create_scheduled_job(func,
                               jobid=jid,
                               timestamp=kwargs['original_executing_time'],
                               jargs=args,
                               jkwargs=kwargs,
                               cls=CalendarEventNotificationJob)
    return add_scheduled_job(job)

def add_to_queue(func, calendar_event, jid=None):
    site = get_site()
    ntiid = calendar_event.ntiid
    if ntiid and site:
        jid = '%s_%s_%s' % (ntiid, jid, time.time())
        original_executing_time = generate_executing_time(calendar_event)

        provider = ICalendarEventURLProvider(calendar_event, None)
        event_url = provider() if provider else None

        return put_job(func,
                       jid,
                       site=site,
                       original_executing_time=original_executing_time,
                       event_ntiid=ntiid,
                       event_url=event_url)
    return None

def queue_add(calendar_event):
    return add_to_queue(_execute_notification_job,
                        calendar_event,
                        jid='added')

def queue_modified(calendar_event):
    return add_to_queue(_execute_notification_job,
                        calendar_event,
                        jid='modified')

# job functions

def get_job_site(job_site_name=None):
    old_site = getSite()
    if job_site_name is None:
        job_site = old_site
    else:
        dataserver = component.getUtility(IDataserver)
        ds_folder = dataserver.root_folder['dataserver2']
        with current_site(ds_folder):
            job_site = get_site_for_site_names((job_site_name,))

        if job_site is None or isinstance(job_site, TrivialSite):
            raise ValueError('No site found for (%s)' % job_site_name)
    return job_site

def _execute_notification_job(event_ntiid, original_executing_time, site=None, *args, **kwargs):
    job_site = get_job_site(site)
    with current_site(job_site):
        obj = find_object_with_ntiid(event_ntiid)
        if not ICalendarEvent.providedBy(obj):
            logger.warning("Ignoring the processing of calendar event job, {0} is not a calendar event or was deleted.".format(obj or event_ntiid))
            return

        validator = ICalendarEventNotificationValidator(obj, None)
        if validator and not validator.validate(original_executing_time=original_executing_time):
            logger.warning("Ignoring the processing of outdated calendar event job. event_ntiid={0}".format(event_ntiid))
            return

        notifier = ICalendarEventNotifier(obj, None)
        if notifier:
            notifier.notify(event_url=kwargs.pop('event_url', None))


from builtins import range
from EMAN2_utils import *
from EMAN2 import *
import sys
import math
import re
import numpy

def main():

	usage = """e2tomo_tiltstacker.py <imgs> <options> .
	The options should be supplied in "--option=value" format,
	replacing "option" for a valid option name, and "value" for an acceptable value for that option.

	The program stacks individual .dm3, .tiff, .mrc, or .hdf images into an .mrc (or .st) stack,
	by supplying a common string to all the images to stack.

	For example:
	e2tomo_tiltstacker.py --input=my_imgs --anglesindxinfilename=6

	It also generates a .rawtlt file with tilt angle values if --lowerend, --upperend and --tiltstep are provided.
	"""

	parser = EMArgumentParser(usage=usage,version=EMANVERSION)

	parser.add_argument("--anglesindxinfilename",type=int,default=None,help="""Default=None. The filename of the images will be split at any occurence of the following delimiters: '_', '-', '+', '[' , ']' , ',' , ' ' (the two last ones are a comma and a blank space). Provide the index (position) of the angle in the split filename. For example, if the filename of an image is "my_specimen-oct-10-2015_-50_deg-from_k2 camera.mrc", it will be split into ['my','specimen','oct','10','2015','','50','deg','from','k2','camera','mrc']. The angle '-50', is at position 6 (starting from 0). Therefore, you would provide --anglesindxinfilename=6, assuming all images to be stacked/processed are similarly named. No worries about the minus sign disappearing. The program will look at whether there's a minus sign immediately preceeding the position where the angle info is.""")
	parser.add_argument("--apix",type=float,default=0.0,help="""True apix of images to be written on final stack.""")

	parser.add_argument("--highesttilt",type=float,default=0.0,help="""Highest tilt angle. If not supplied, it will be assumed to be 1* --tiltrange.""")

	parser.add_argument("--input", type=str, default=None, help="""String common all files to process. For example, to process all .mrc files in a directory, you would run e2tomo_tiltstacker.py --input=.mrc <parameters>.""")

	parser.add_argument("--lowesttilt",type=float,default=0.0,help="""Lowest tilt angle. If not supplied, it will be assumed to be -1* --tiltrange.""")

	parser.add_argument("--path",type=str,default='tomostacker',help="""Directory to store results in. The default is a numbered series of directories containing the prefix 'sptstacker'; for example, sptstacker_02 will be the directory by default if 'sptstacker_01' already exists.""")
	parser.add_argument("--ppid", type=int, help="Set the PID of the parent process, used for cross platform PPID",default=-1)
	parser.add_argument("--precheckfiles",action="store_true",default=False,help=""""Make sure that only valid images found by --input=* are processed -if unreadable or bad images are fed to the program, it might crash.""")

	parser.add_argument("--stackregardless",action="store_true",default=False,help=""""Stack images found with the common string provided through --stem2stack, even if the number of images does not match the predicted number of tilt angles.""")

	parser.add_argument("--tag",type=str,default=None,help=""""String to append to the beginning of the tiltseries output filename. The default is filename is 'stack.st'; if tag=xxx, the output will be 'xxx_stack.st' """)
	parser.add_argument("--tiltrange",type=float,default=0.0,help="""If provided, this will make --lowesttilt=-1*tiltrange and --highesttilt=tiltrange. If the range is asymmetric, supply --lowesttilt and --highesttilt directly.""")
	parser.add_argument("--tiltstep",type=float,default=0.0,help="""Step between tilts. Required if using --stem2stack.""")

	parser.add_argument("--verbose", "-v", dest="verbose", action="store", metavar="n",type=int, default=0, help="verbose level [0-9], higher number means higher level of verboseness.")

	(options, args) = parser.parse_args()

	#'''
	#Make sure input file is EMAN2 readable
	#'''

	print("\n--input={}".format(options.input))

	stem =  os.path.basename( options.input.replace('*','') )
	print("\ntherefore, stem={}".format(stem))

	dirname = os.path.dirname( options.input.replace('*','') )
	if not dirname:
		dirname='.'
	files2process = fsindir(directory=dirname,stem=stem)
	print("\nfound raw files2process={}".format(files2process))

	files2process = [dirname + '/' + f for f in files2process]
	print("\nwith full path, files2process={}".format(files2process))

	if options.precheckfiles:
		good=[]
		bad=[]
		for g in files2process:
			try:
				hdr=EMData(g,0,True)
				good.append(g)
			except:
				bad.apppend(g)
		if good:
			files2process = good
		else:
			print("\nERROR: could not find any readable image files with --input={}".format(options.input))
			sys.exit(1)
		if bad:
			print("\nWARNING: excluding the following n={} files because they are not readable (this happens sometimes with 'empty' image files)".format(len(bad)))
			for b in bad:
				print(b)

	files2process.sort(key = lambda s: float(re.search('(\+|-)?\d+(\.\d+)?', s).group()))

	print("\n(e2spt_tomostacker.py)(main) and they've been sorted as follows={}".format(files2process))

	if options.lowesttilt == 0.0 and options.tiltrange:
		options.lowesttilt = -1 * round(float(options.tiltrange),2)

	if options.highesttilt == 0.0 and options.tiltrange:
		options.highesttilt = round(float(options.tiltrange),2)

	print("\nLogging")
	logger = E2init(sys.argv, options.ppid)

	print("\n(e2spt_tomostacker.py)(main) These many img files were found n={} in directory={}".format( len(files2process), dirname) )

	if dirname:
		options.path = dirname + "/" + options.path

	options = makepath( options, 'tomostacker' )

	means=[]
	sigmas=[]
	minima=[]
	maxima=[]

	for f in files2process:
		#intiltimgfile =	intiltsdict[index][0]
		intiltimg = EMData( f, 0 )
		means.append(intiltimg['mean'])
		sigmas.append(intiltimg['sigma'])
		minima.append(intiltimg['minimum'])
		maxima.append(intiltimg['maximum'])
		#stats_dict.update( { index:{'mean':mean,'sigma':sigma,'maximum':maximum,'minimum':minimum} } )

	mean_avg = numpy.mean(means)
	sigma_avg = numpy.mean(sigmas)
	minimum_avg = numpy.mean(minima)
	maximum_avg = numpy.mean(maxima)

	mean_std = numpy.std(means)
	sigma_std = numpy.std(sigmas)
	minimum_std = numpy.std(minima)
	maximum_std = numpy.std(maxima)

	files2process_good = []
	for f in files2process:
		img = EMData( f, 0 )
		mean = img['mean']
		sigma = img['sigma']
		minimum = img['minimum']
		maximum = img['maximum']

		if mean > mean_avg - 2.0*mean_std and mean < mean_avg + 2.0*mean_std:
			files2process_good.append(f)
		else:
			print("\nWARNING: bad image={} excluded; mean={}, sigma={}, max={}, min={}".format(f,mean,sigma,minimum,maximum))

	kk=0

	print("\n(e2spt_tomostacker.py)(stacker) organizing tilt imgs")
	intiltsdict = organizetilts( options, files2process_good )		#Get a dictionary in the form { indexintiltseries:[ tiltfile, tiltangle, damageRank ]},
	print("\n(e2spt_tomostacker.py)(stacker) done organizing tilt imgs")					#where damageRank tells you the order in which the images
																							#were acquired regardless of wether the tilt series goes from
													#-tiltrange to +tiltrange, or 0 to -tiltrange then +tiltstep to +tiltrange, or the opposite of these
	outstackhdf = options.path + '/stack.hdf'
	if options.tag:
		outstackhdf = options.path + '/' + options.tag + 'stack.hdf'
		if "_" not in options.tag[-1:]:
			outstackhdf = options.path + '/' + options.tag + '_stack.hdf'

	if not intiltsdict:
		print("\n(e2spt_tomostacker.py)(stacker) ERROR: intiltsdict is empty: {}".format(intiltsdict))
		sys.exit(1)
	else:
		if options.verbose > 5:
			print("\n(e2spt_tomostacker.py)(stacker) intiltsdict is {}".format(intiltsdict))

	minindx = min(intiltsdict)
	print("\n(e2spt_tomostacker.py)(stacker) minindx is", minindx)
	print("\n(e2spt_tomostacker.py)(stacker) getting image size from the image at the least tilted angle, intiltsdict[ minindx ][0]", intiltsdict[ minindx ][0])

	hdr = EMData( intiltsdict[minindx][0], 0, True )
	nx = hdr['nx']
	ny = hdr['ny']
	print(nx,ny)

	if options.verbose > 5:
		print("\n(e2spt_tomostacker.py)(stacker) outstack is", outstackhdf)
		print("\n(e2spt_tomostacker.py)(stacker) intiltsdict.keys() are={}, because intiltsdict is={}".format(intiltsdict.keys(),intiltsdict))

	finalindexesordered = [x for x in intiltsdict.keys()]
	finalindexesordered.sort()

	damagelist=[]

	for index in finalindexesordered:
		intiltimgfile =	intiltsdict[index][0]

		if options.verbose > 9:
			print("\n(e2spt_tomostacker.py)(stacker) at index {} we have image {}, collected in turn {}".format( index, intiltsdict[index][0], intiltsdict[index][-1] ))

		intiltimg = EMData( intiltimgfile, 0 )
		#mean = intiltimg['mean']
		#sigma = intiltimg['sigma']
		#minimum = intiltimg['minimum']
		#maximum = intiltimg['maximum']

		#if mean > mean_avg - 2.0*mean_std and mean < mean_avg + 2.0*mean_std:

		tiltangle = intiltsdict[index][1]
		intiltimg['spt_tiltangle'] = tiltangle

		damageRank = intiltsdict[index][2]
		intiltimg['damageRank'] = damageRank

		damagelist.append(damageRank)

		intiltimg.write_image( outstackhdf, -1 )
		#print "\nWrote image index", index
		#else:
		#	print("\nWARNING: bad image={} excluded; mean={}, sigma={}, max={}, min={}".format(intiltimgfile,mean,sigma,minimum,maximum))

	orderfilepath = options.path + '/collection_order.txt'
	textwriter(damagelist,options,orderfilepath,invert=0,xvals=None,onlydata=True)

	tmp = options.path + '/tmp.hdf'

	print("\n(e2spt_tomostacker.py)(stacker) reading outstackhdf hdr, for file {}".format(outstackhdf))
	outtilthdr = EMData(outstackhdf,0,True)
	currentapix = outtilthdr['apix_x']

	outstackst = outstackhdf.replace('.hdf','.st')
	stcmd = 'e2proc2d.py	' + outstackhdf + ' ' + outstackst + ' --twod2threed'

	print("\n(e2spt_tomostacker.py)(stacker) stcmd is", stcmd)

	runcmd(options,stcmd)
	os.remove(outstackhdf)

	findir = os.listdir(options.path)
	for f in findir:
		if '~' in f:
			print("\n(e2spt_tiltstacker.py)(stacker) file to remove",f)
			print("in path", options.path + '/' + f)
			os.remove(options.path + '/' + f)

	E2end( logger )
	return

def getangles( options, ntilts, raworder=False ):

	print("There was no .tlt file so I'll generate the angles using lowesttilt=%f, highesttilt=%f, tiltstep=%f" % (options.lowesttilt, options.highesttilt, options.tiltstep))
	generate = floatrange( options.lowesttilt, options.highesttilt, options.tiltstep )
	angles=[ round(float(x),2) for x in generate ]

	if ntilts:
		nangles=len(angles)
		dif=int(math.fabs( ntilts - nangles))
		if nangles < ntilts:
			supplementstart = angles[-1]+options.tiltstep
			supplementend = angles[-1] + dif*options.tiltstep
			angles += [ round(float(x),2) for x in floatrange( supplementstart, supplementend,  options.tiltstep ) ]
		elif nangles > ntilts:
			angles = angles[:-1*dif] #cut the angles list by however many exceeding elements there are, as indicated by dif

	print("BEFORE sorting, angles are", angles)

	print("raworder", raworder)
	print("not raworder", not raworder)

	if not raworder:
		angles.sort()
		angles.reverse()
		print("\n(e2spt_tomostacker.py)(getangles) AFTER REVERSING (ordered from largest to smallest), angles are", angles)

	return angles

def writetlt( angles, options, raworder=False ):

	print("(writetlt) these many angles", len(angles))
	angless = list( angles )

	if not raworder:
		angless.sort()

	if not raworder:
		angless.reverse()

	lines = []

	k=0
	for a in angless:
		line = str(a) + '\n'
		lines.append( line )

		k+=1

	tltfilepath = options.path + '/stack.rawtlt'
	if options.tag:
		tltfilepath = options.path + '/' + options.tag + 'stack.rawtlt'
		if "_" not in options.tag[-1:]:
			outstackhdf = options.path + '/' + options.tag + '_stack.rawtlt'
	textwriter(lines,options,tltfilepath,invert=0,xvals=None,onlydata=True)

	return

def organizetilts( options, intilts, raworder=False ):

	intilts.sort()

	intiltsdict = {}
	angles = []

	if options.anglesindxinfilename:
		collectionindex=0
		anglesdict = {}
		for intilt in intilts:

			extension = os.path.splitext(os.path.basename(intilt))[-1]

			parsedname = intilt.replace(extension,'').replace(',',' ').replace('-',' ').replace('_',' ').replace('[',' ').replace(']',' ').replace('+',' ').split()
			#dividerstoadd = options.anglesindxinfilename - 1
			print('\n(e2spt_tomostacker)(organizetilts) parsedname is',parsedname)
			try:
				angle = float(parsedname[options.anglesindxinfilename])
			except:
				print("\n(e2spt_tomostacker)(organizetilts) invalid angle={}. make sure --anglesindxinfilename is correct! Remember, indexes start from 0".format(parsedname[options.anglesindxinfilename]))
				sys.exit(1)

			charsum = 0
			for i in range(options.anglesindxinfilename):
				charsum += len(parsedname[i])
				#if len(parsedname[i]) == 0:
				charsum += 1
			#charsum += options.anglesindxinfilename

			#sign = intilt[charsum+1]
			sign = intilt[charsum]
			#print("\nby position %d sign is %s" % (charsum+1,sign))

			angle = float(parsedname[options.anglesindxinfilename])
			#print("angle is".format(angle))
			#print("sign is".format(sign))

			if sign == '-':
				angle *= -1
				print("\n(e2spt_tomostacker)(organizetilts) therfore corrected angle to be negative, now it is {}".format(angle))

			#sign2 = intilt.split(str(angle))[0][-1]
			#print "by other means, sign2 is",sign2

			anglesdict.update({angle:[intilt,collectionindex]})

			if angle not in angles:
				angles.append( angle )
			collectionindex+=1			#since there could be parasitic images (two or more images per tilt angle due to failed attempts)
										#collectionindex needs to continue to increase even if the repeat images are excluded to properly dose weight later

		angles.sort()
		angles.reverse()

		writetlt( angles, options )

		#kkkk=0
		finalangles = []

		#print('anglesdict is', anglesdict)
		indexintiltseries = 0
		newindexintiltseries = 0

		for angle in angles:
			#indexintiltseries = kkkk
			#newindexintiltseries = kkkk
			if options.verbose>5:
				print("\n(e2spt_tomostacker)(organizetilts) examining angle {} corresponding to index {}".format(angle,indexintiltseries))
			#{ indexintiltseries:[ imgile, angle, collectionindx]}

			intiltsdict.update( { newindexintiltseries:[ anglesdict[angle][0], angle, anglesdict[angle][1] ]} )
			print("\n(e2spt_tomostacker)(organizetilts) updating intiltsdict with img={}, angle={}, order={}".format(anglesdict[angle][0], angle, anglesdict[angle][1] ) )
			finalangles.append(angle)

			if options.verbose>5:
				print("\n(e2spt_tomostacker)(organizetilts) kept oldindex={}, which after excluding images became newindex={}".format(indexintiltseries,newindexintiltseries))
			newindexintiltseries+=1

			indexintiltseries+=1

		angles=list(finalangles)

	else:
		angles = getangles( options, len(intilts) )			#This returns angles from -tiltrange to +tiltrange if --negativetiltseries is supplied; from +tiltrange to -tiltrange otherwise

		orderedangles = list( angles )

		#print "\n(organizetilts) angles are", angles

		zeroangle = min( [ math.fabs(a) for a in angles] )		#Find the angle closest to 0 tilt, in the middle of the tiltseries
		indexminangle = None
		try:
			indexminangle = angles.index( zeroangle )			#The middle angle (0 tilt) could have been positive
			zeroangle = angles[ indexminangle ]
		except:
			indexminangle = angles.index( -1*zeroangle )		#Or negative. Either way, we find its index in the list of angles
			zeroangle = angles[ indexminangle ]

		angles.sort()
		if not raworder:			#Change angles to go from +tiltrange to -tiltrange if that's the order of the images
			#orderedangles.sort()
			#orderedangles.reverse()

			#angles.sort()
			print("raworder is",raworder)
			angles.reverse()
			print("therefore, angles are reversed (largest to smallest)")

			#print "However, after reversal, they are", orderedangles
			#print "and angles are", angles

		writetlt( angles, options )

		if len( intilts ) != len( orderedangles ):

			if not options.stackregardless:
				print("""\n(e2spt_tomostacker.py)(organizetilts) ERROR: Number of tilt angles
				and tilt images is not equal.""")
				print("""Number of tilt angles = %d ; number of tilt images = %d """ % ( len( orderedangles ), len( intilts ) ))
				sys.exit()
			else:
				print("""\n(e2spt_tomostacker.py)(organizetilts) WARNING: Number of tilt angles
				and tilt images is not equal. Stacking nevertheless since you provided --stackregardless""", options.stackregardless)
				print("""Number of tilt angles = %d ; number of tilt images = %d """ % ( len( orderedangles ), len( intilts ) ))

		indexesintiltseries = range(len(angles))
		collectionindexes = range(len(angles))

		print("indexminangle is", indexminangle)

		if indexminangle != None:
			firstrange = range(0,indexminangle+1)
			secondrange = range(indexminangle+1,len(angles))

			collectionindexes = []
			collectionindexes = list(firstrange) + list(secondrange)

			firstrange.sort()
			firstrange.reverse()

			indexesintiltseries = []
			indexesintiltseries = list(firstrange) + list(secondrange)

		print("collection indexes are", collectionindexes)
		print("indexes in tiltseries are", indexesintiltseries)

		for k in range(len(intilts)):
			#print "\nk={}, ntiltangles={}, ncollectionindexes={}, ntilts={}".format(k,len(indexesintiltseries),len(collectionindexes),len(intilts))
			try:
				tiltangle = orderedangles[k]
				#indexintiltseries = angles.index( orderedangles[k] )

				indexintiltseries = indexesintiltseries[k]
				collectionindex = collectionindexes[k]
				#print "\nnormal"
			except:
				if options.stackregardless:
					print("\nexception triggered")
					tiltangle = orderedangles[k-1] + orderedangles[k-1] - orderedangles[k-2]
					indexintiltseries = indexesintiltseries[k-1] + indexesintiltseries[k-1] - indexesintiltseries[k-2]
					collectionindex = collectionindexes[k-1] + collectionindexes[k-1] - collectionindexes[k-2]

			intiltsdict.update( { indexintiltseries:[ intilts[k],tiltangle,collectionindex ]} )
				#print "\nadded collectionIndex=%d, tiltangle=%f, indexintiltseries=%d" % ( collectionindex, tiltangle, indexintiltseries )

	return intiltsdict

def getindxs( string ):

	parsedindxs = set([])
	stringList = list( string.split(',') )
	#print "\nstringList is", stringList

	intList=set([])
	for i in range( len(stringList) ):
		print("\n\nstringList[i] is", stringList[i])

		if '-' in stringList[i]:
			stringList[i] = stringList[i].split('-')

			x1 = int( stringList[i][0] )
			x2 = int( stringList[i][-1] ) + 1

			#stringList[i] = [ str( ele ) for ele in xrange( x1, x2 ) ]
			intList.union([ ele for ele in xrange( x1, x2 ) ])

		#parsedindxs = parsedindxs.union( set( list( List[i] ) ) )

		#intList = set( list(intList) )
	if intList:
		parsedindxs = [ str(ele) for ele in intList ]
	else:
		parsedindxs = stringList

	#parsedindxs = list( parsedindxs )
	parsedindxs.sort()

	print("\nParsed indexes are", parsedindxs)
	return parsedindxs

def makeimglist( inputf, options ):

	n = EMUtil.get_image_count( inputf )
	if '.ali' in inputf[-4:] or '.mrc' in inputf[-4:] or '.mrcs' in inputf[-5:] or '.st' in inputf[-3:]:
		n = EMData( inputf,0,True )['nz']

	print("input n is", n)
	print("input is",input)

	allindxs = set( [ str(i) for i in range(n) ] )
	finalindxs = set( list( allindxs ) )

	print("\nallindxs are", allindxs)

	print("\nFinalindxs are", finalindxs)

	ints = []
	for id in finalindxs:
		ints.append( int( id ) )

	ints.sort()
	ints.reverse()

	print("\nfinalindx sorted are", ints)
	#final = []
	#for fi in ints:
	#	final.append( str( fi ) )

	lines = []
	for indx in ints:
		lines.append( str(indx) + '\n' )

	listfile = options.path + '/list.lst'
	f= open( listfile,'w' )
	f.writelines( lines )
	f.close()

	print("\nlistfile is", listfile)
	return listfile

def floatrange(start, stop, step):
	print("\nInside floatrange, start, stop and step are", start, stop, step)

	r = start
	kkk=0
	while r <= stop:
		yield r
		#print "r is", r
		r += step
		kkk+=1

		if kkk > 180:
			print("ERROR: Something is wrong with your tiltrange, lowesttilt or highesttilt")
			sys.exit()

	return

if __name__ == "__main__":

	main()


import rospy
import time
from rt2_assignment1.srv import Command

def main():
    """
    This is the main function of the user_interface node.
    It asks the user to start or to stop the robot, by pressing
    1 and 0 respectively, and it calls the service implemented
    in the finite_state_machine node.
    """
    rospy.init_node('user_interface')
    ui_client = rospy.ServiceProxy('/user_interface', Command)
    time.sleep(10)
    rate = rospy.Rate(20)
    x = int(input("\nPress 1 to start the robot "))
    while not rospy.is_shutdown():
        if (x == 1):
            ui_client("start")
            x = int(input("\nPress 0 to stop the robot "))
        else:
            print("Please wait, the robot is going to stop when the position will be reached")
            ui_client("stop")
            x = int(input("\nPress 1 to start the robot "))

if __name__ == '__main__':
    main()


import pygame
import sys
from game import DaBabyKart
from road import Road
from leaderboard import Leaderboard

class Start():

    def __init__(self):
        pygame.init()
        self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
        self.screen_rect = self.screen.get_rect()
        self.image = pygame.image.load('images/dbkart.png')
        self.image_rect = self.image.get_rect()
        self.button_1 = pygame.Rect(self.screen_rect.width / 2 - 100, self.screen_rect.height / 2 - 70, 200, 100) #Ethan helped with buttons
        self.button_2 = pygame.Rect(self.screen_rect.width / 2 - 100, self.screen_rect.height / 2 + 70, 200, 100)
        self.font1 = pygame.font.SysFont('chalkduster.ttf', 75)
        self.play = self.font1.render('Play', True, (255, 255, 255))
        self.quit = self.font1.render('Quit', True, (255,255,255))
        self.dbkart = DaBabyKart()
        self.leaderboard = Leaderboard()
        self.road = Road(self)
        self.click = False

    def run_start(self):
        while True:
            pygame.mixer.music.load('sounds/bop.mp3')
            pygame.mixer.music.play(-1) # plays infinitely
            self.check_events()
            self.display_start()

    def display_start(self):
            self.screen.fill((33, 191, 143))
            for x in range(0, self.screen_rect.width, 64):
                self.screen.blit(self.road.image, (x, self.screen_rect.height / 2 - 180))
            self.screen.blit(self.image, (self.screen_rect.width / 2 - 512 , self.screen_rect.height / 2 - 460))
            pygame.draw.rect(self.screen, (0, 0, 0), self.button_1)
            pygame.draw.rect(self.screen, (0, 0, 0), self.button_2)
            self.screen.blit(self.play, (self.screen_rect.width / 2 - 55, self.screen_rect.height / 2 - 45))
            self.screen.blit(self.quit, (self.screen_rect.width / 2 - 60, self.screen_rect.height / 2 + 100))
            if self.button_1.collidepoint(pygame.mouse.get_pos()): #Josh saved me
                pygame.draw.rect(self.screen, (255, 255, 255), self.button_1)
                if self.click:
                    self.dbkart.run_game()
            if self.button_2.collidepoint(pygame.mouse.get_pos()): #Josh saved me
                pygame.draw.rect(self.screen, (255, 255, 255), self.button_2)
                if self.click:
                    sys.exit()

            pygame.display.flip()

    def check_events(self):
        for event in pygame.event.get():
            if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1:
                    self.click = True
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    sys.exit()

db = Start()
db.run_start()


from flask import Flask, render_template, request
import sqlite3
import plotly.graph_objects as go
app = Flask(__name__)

def get_hotels():
    conn = sqlite3.connect('Final_Project.db')
    cur = conn.cursor()
    query = '''SELECT Id, HotelName, HotelCity, HotelState
    FROM Hotels
    '''
    results = cur.execute(query).fetchall()
    conn.close()
    return results

def get_results(sort_by, sort_order, hotel_id):
    conn = sqlite3.connect('Final_Project.db')
    cur = conn.cursor()
    if sort_by == 'rating':
        sort_column = 'Rating'
    elif sort_by == 'price':
        sort_column = 'AvgPrice'
    else:
        sort_column = 'Distance'

    query = f'''SELECT Name, Rating, AvgPrice, Distance, Link
    FROM Restaurants WHERE HotelId={hotel_id} ORDER BY {sort_column} {sort_order}
    '''
    results = cur.execute(query).fetchall()
    conn.close()
    return results

@app.route('/')
def index():
    results = get_hotels()
    return render_template('index.html', results=results)

@app.route('/results', methods=['POST'])
def results():
    sort_by = request.form['sort']
    sort_order = request.form['dir']
    hotel_id = request.form['hotel']
    results = get_results(sort_by, sort_order, hotel_id)
    arr = ['rating', 'price', 'distance']
    plot_results = request.form.get('plot', False)
    if (plot_results):
        x_vals = [r[0] for r in results]
        y_vals = [r[arr.index(sort_by) + 1] for r in results]
        bars_data = go.Bar(
            x=x_vals,
            y=y_vals
        )
        fig = go.Figure(data=bars_data)
        div = fig.to_html(full_html=False)
        return render_template("plot.html", plot_div=div)
    else:
        return render_template('results.html', sort=sort_by, order=sort_order, results=results)

if __name__ == '__main__':
    app.run(debug=True)


import argparse
import pathlib
import sys

import numpy
import scipy.sparse as sp
import scipy.ndimage as nd

def parse_args(args):
    ap = argparse.ArgumentParser(
        description='Computes the euclidean distance transform for the sparse boundary matrix in the given shape. The boundary matrix contains all voxels on the surface boundaries.')
    ap.add_argument(dest='in_file', help='Path to 2D sparse matrix data file with shape (Samples, Values)',
                    metavar='InFile')
    ap.add_argument('-s', dest='shape', nargs='+', type=int, help='Volume Space Dimensions', metavar='Dimension')
    ap.add_argument('-f', dest='features', type=int, help='The number of features at the beginning of each record',
                    default=0, metavar='Features')
    ap.add_argument('-o', dest='out_file',
                    help='Output file location. Output format is a .npz compressed file with arr_0 as the array name.',
                    default=None, metavar='OutFile')
    ns = ap.parse_args(args)

    ns.in_file = pathlib.Path(ns.in_file)
    if ns.out_file is None:
        ns.out_file = ns.in_file.withstem(ns.in_file.stem + '_edt')
    else:
        ns.out_file = ns.in_file.joinpath(ns.out_file)
        if ns.out_file.suffix != '.npz':
            ns.out_file.joinpath(ns.in_file.stem + '_edt.npz')

    return ns

def compute_edt(mtx, shape):
    edt_output = numpy.zeros(mtx.shape, dtype=numpy.float64)
    for sample_index in range(mtx.shape[0]):
        edt_output[sample_index] = numpy.ravel(
            nd.distance_transform_edt(numpy.reshape(numpy.logical_not(mtx[sample_index].toarray()), shape)))
    return edt_output

if __name__ == '__main__':
    params = parse_args(sys.argv[1:])
    if params.shape is None:
        raise ValueError('Shape undefined.')
    print('Loading data ...', end='')
    mtx = sp.load_npz(params.in_file)[:, params.features:]
    print(' done.\nComputing euclidean distances ...', end='')
    edt = compute_edt(mtx, params.shape)
    print(' done.\nSaving results ...', end='')
    numpy.savez_compressed(params.out_file, edt)
    print(' done.')


from pymd5 import *
import http.client, urllib.parse, sys
import math

url = sys.argv[1]

parsedUrl = urllib.parse.urlparse(url)
query = parsedUrl[4].split("&")
token = query[0][6:]

# Reform Old Hash
newQuery = query[1]
for x in query[2:]:
  newQuery = newQuery + "&"
  newQuery = newQuery + x

# Your code to modify url goes here
msglen = (len(newQuery) + 10) * 8
blocksize = math.ceil(msglen/512) * 512
h = md5(state=bytes.fromhex(token), count = blocksize )
x = "&command3=UnlockAllSafes"
h.update(x.encode())
newToken = str(h.hexdigest())

newQuery = urllib.parse.quote(bytes("token=" + newToken + "&") + bytes(newQuery, "UTF-8") + pymd5.padding(int(msglen)) + bytes(x, "UTF-8"))

parsedUrl = urllib.parse.urlparse(url)
reformedUrl = list(parsedUrl)
reformedUrl[4] = newQuery

parsedUrl = urllib.parse.urlunparse(reformedUrl)
parsedUrl = urllib.parse.urlparse(parsedUrl)

conn = http.client.HTTPConnection(parsedUrl.hostname,parsedUrl.port)
conn.request("GET", parsedUrl.path + "?" + parsedUrl.query)
print(conn.getresponse().read())


# -*- coding: utf-8 -*-
from pandas import DataFrame, Series
from flask import render_template, request, redirect, url_for, jsonify
from . import foodbp as food
from app.food.models import (Person, Farm, AgriType, SampleLot, Produce,
                             Sample, ProduceBreed, GrownProduce, PesticideTest, PesticideResult,
                             ToxicoResult, ToxicoTest, BactResult, BactTest, HealthPerson,
                             HealthServices, SurveyResult, PesticideUse, ParasiteTest, ParasiteResult)
from ..models import Province, District, Subdistrict
from ..main import db

@food.route('/')
def index():
    farms = []
    for farm in db.session.query(Farm).order_by(db.desc(Farm.created_at)):
        subdistrict = Subdistrict.query.get(farm.subdistrict_id).name
        district = District.query.get(farm.district_id).name
        province = Province.query.get(farm.province_id).name
        farms.append({
            'id': farm.id,
            'ref_id': farm.ref_id(),
            'sample_lots': farm.sample_lots,
            'street': farm.street,
            'subdistrict': subdistrict,
            'district': district,
            'province': province,
            'owners': farm.get_owners()
        })
    return render_template('food/index.html', farms=farms)

@food.route('/farm/add/', methods=['POST', 'GET'])
def add_farm():
    errors = []
    if request.method == 'POST':
        street_addr = request.form.get('street_address')
        village = request.form.get('village')
        province_id = request.form.get('province')
        district_id = request.form.get('district')
        subdistrict_id = request.form.get('subdistrict')
        owner_id = request.form.get('owner_id')
        total_size = request.form.get('total_size')
        total_owned_size = request.form.get('total_owned_size')
        total_leased_size = request.form.get('total_leased_size')
        agritype_id = request.form.get('agritype')
        produce = request.form.getlist('selected_produce')

        if not street_addr:
            errors.append(u'โปรดระบุที่อยู่ของแปลงเกษตร')
        if not village:
            errors.append(u'โปรดระบุหมู่บ้าน')
        if not province_id:
            errors.append(u'โปรดระบุจังหวัด')
        if not district_id:
            errors.append(u'โปรดระบุอำเภอ')
        if not subdistrict_id:
            errors.append(u'โปรดระบุตำบล')
        if not total_size:
            errors.append(u'โปรดระบุขนาดแปลงโดยรวม')
        if not agritype_id:
            errors.append(u'โปรดระบุประเภทของแปลงเกษตร')
        if not errors:
            owner = Person.query.get(int(owner_id))
            farm = Farm(street=street_addr,
                        province_id=int(province_id),
                        district_id=int(district_id),
                        subdistrict_id=int(subdistrict_id),
                        village=village,
                        estimated_total_size=float(total_size),
                        estimated_leased_size=float(total_leased_size),
                        estimated_owned_size=float(total_owned_size),
                        agritype_id=int(agritype_id),
                        )
            for prod in produce:
                prod_id, bred_id = map(int, prod.split(','))
                p = Produce.query.get(prod_id)
                b = ProduceBreed.query.get(bred_id)
                if p and b:
                    gp = GrownProduce(produce=p, breed=b)
                elif p:
                    gp = GrownProduce(produce=p, breed=b)
                farm.produce.append(gp)

            db.session.add(farm)
            owner.farms.append(farm)
            db.session.commit()
            return redirect(url_for('food.index'))

    owner_id = request.args.get('owner_id', None)
    if not owner_id:
        redirect(url_for('food.index'))

    owner = Person.query.get(owner_id)

    provinces = []
    districts = []
    subdistricts = []
    for pv in Province.query.all():
        provinces.append({
            'name': pv.name,
            'id': pv.id,
            'code': pv.code
        })

    for ds in District.query.all():
        districts.append({
            'name': ds.name,
            'id': ds.id,
            'code': ds.code,
            'province_id': ds.province_id
        })
    for sd in Subdistrict.query.all():
        subdistricts.append({
            'name': sd.name,
            'id': sd.id,
            'code': sd.code,
            'district_id': sd.district_id
        })
    provinces = sorted(provinces, key=lambda x: x['name'])
    districts = sorted(districts, key=lambda x: x['name'])
    subdistricts = sorted(subdistricts, key=lambda x: x['name'])
    agritypes = []
    for ag in AgriType.query.all():
        agritypes.append({
            'name': ag.name,
            'id': ag.id,
            'desc': ag.desc
        })

    produce = []
    for prod in Produce.query.all():
        if prod.breeds:
            for breed in prod.breeds:
                produce.append({
                    'id': prod.id,
                    'name': prod.name,
                    'breed': breed.name,
                    'breed_id': breed.id,
                    'ref': u'{},{}'.format(prod.id, breed.id)
                })
        else:
            produce.append({
                'id': prod.id,
                'name': prod.name,
                'breed': '',
                'breed_id': 0,
                'ref': u'{},0'.format(prod.id)
            })

    produce = sorted(produce, key=lambda x: x['name'])

    return render_template('food/add_farm.html',
                           provinces=provinces,
                           districts=districts,
                           subdistricts=subdistricts,
                           agritypes=agritypes,
                           owner=owner,
                           errors=errors,
                           produce=produce)

@food.route('/farm/owner/add/', methods=['GET', 'POST'])
def add_farm_owner():
    errors = []
    if request.method == 'POST':
        firstname = request.form.get('firstname', '')
        lastname = request.form.get('lastname', '')
        pid = request.form.get('pid', '')
        if not firstname:
            errors.append(u'โปรดระบุชื่อจริง')
        if not lastname:
            errors.append(u'โปรดระบุชื่อนามสกุล')
        if not pid or not pid.isdigit() or len(pid) != 13:
            errors.append(u'โปรดระบุรหัสบัตรประชาชนให้ถูกต้อง')
        else:
            existing_pid = Person.query.filter_by(pid=pid).first()
            if existing_pid:
                errors.append(u'รหัสบัตรประชาชนที่ท่านกรอก มีในฐานข้อมูลแล้ว')
        if not errors:
            person = Person(firstname=firstname,
                            lastname=lastname,
                            pid=pid)
            db.session.add(person)
            db.session.commit()
            return redirect(url_for('food.list_owners'))
    return render_template('food/add_farm_owner.html', errors=errors)

@food.route('/farm/<int:farm_id>/samplelot/', methods=['POST', 'GET'])
def add_samplelot(farm_id):
    errors = []
    if request.method == 'POST':
        collected_date = request.form.get('collected_date', '')
        if not collected_date:
            errors.append(u'โปรดกรอกข้อมูลวันที่เก็บผลผลิต')
        else:
            lot = SampleLot(
                collected_at=collected_date,
                farm_id=farm_id)
            farm = Farm.query.get(farm_id)
            for grown_produce in farm.produce:
                # automatically adds samples from all grown produce
                sample = Sample(produce=grown_produce)
                lot.samples.append(sample)
            db.session.add(lot)
            db.session.commit()
            return redirect(url_for('food.index'))

    farm = Farm.query.get(farm_id)
    return render_template('food/add_samplelot.html',
                           farm=farm, errors=errors)

@food.route('/farm/<int:farm_id>/tests/lots/<int:lot_id>/add/', methods=['POST', 'GET'])
def add_sample(farm_id, lot_id):
    """Add sample to the sample lot."""

    errors = []
    if request.method == 'POST':
        produce_id = request.form.get('produce', '')
        if not produce_id:
            errors.append(u'กรุณาเลือกชนิดของผลผลิต')
        else:
            lot = SampleLot.query.get(lot_id)
            p = Produce.query.get(produce_id)
            gp = GrownProduce(produce=p)
            sample = Sample(produce=gp)
            lot.samples.append(sample)
            db.session.add(lot)
            db.session.commit()
            return redirect(url_for('food.list_samples',
                            farm_id=farm_id, lot_id=lot_id))

    farm = Farm.query.get(farm_id)
    lot = SampleLot.query.get(lot_id)
    produces = []
    for p in Produce.query.all():
        produces.append({
            'id': p.id,
            'name': p.name
        })

    return render_template('food/add_sample.html',
                           farm=farm, lot=lot, produces=produces)

@food.route('/farm/owner/')
def list_owners():
    owners = db.session.query(Person).order_by(Person.created_at)
    health_info = set()
    for record in db.session.query(HealthPerson):
        name = u'{} {}'.format(record.firstname, record.lastname)
        health_info.add(name)
    return render_template('food/owners.html',
                           owners=owners, health_info=health_info)

@food.route('/farm/owned/<int:owner_id>/')
def list_owned_farm(owner_id):
    owner = Person.query.get(owner_id)
    farms = []
    for farm in owner.farms:
        farms.append({
            'id': farm.id,
            'ref_id': farm.ref_id(),
            'street': farm.street,
            'total_size': farm.estimated_total_size,
            'sample_lots': farm.sample_lots,
            'province': Province.query.get(farm.province_id).name,
            'district': District.query.get(farm.district_id).name,
            'subdistrict': Subdistrict.query.get(farm.subdistrict_id).name,
        })
    return render_template('food/farms.html', owner=owner, farms=farms)

@food.route('/farm/<int:farm_id>/info/')
def display_farm_info(farm_id):
    farm = Farm.query.get(farm_id)
    province = Province.query.get(farm.province_id)
    district = District.query.get(farm.district_id)
    subdistrict = Subdistrict.query.get(farm.subdistrict_id)
    return render_template('food/farm_info.html',
                           farm=farm,
                           subdistrict=subdistrict,
                           district=district,
                           province=province
                           )

@food.route('/farm/edit/<int:farm_id>', methods=['GET', 'POST'])
def edit_farm_info(farm_id):
    if request.method == 'GET':
        farm = Farm.query.get(farm_id)
    elif request.method == 'POST':
        farm_id = request.form.get('farm_id')
        farm = Farm.query.get(int(farm_id))
        estimated_total_size = request.form.get('estimated_total_size')
        estimated_owned_size = request.form.get('estimated_owned_size')
        estimated_leased_size = request.form.get('estimated_leased_size')
        pesticide_use = request.form.get('pesticide_use')
        pesticide_use_date = request.form.get('pesticide_use_date')
        pesticide_use_date = None if pesticide_use_date == '' else pesticide_use_date
        latitude = request.form.get('latitude')
        longitude = request.form.get('longitude')
        if farm:
            farm.estimated_total_size = estimated_total_size
            farm.estimated_owned_size = estimated_owned_size
            farm.estimated_leased_size = estimated_leased_size
            farm.latitude = latitude
            farm.longitude = longitude
            if not farm.pesticide_use:
                pesticide_use = PesticideUse(desc=pesticide_use, last_use=pesticide_use_date)
                db.session.add(pesticide_use)
                farm.pesticide_use = pesticide_use
            else:
                farm.pesticide_use.desc = pesticide_use
                farm.pesticide_use.last_use = pesticide_use_date
            db.session.add(farm)
            db.session.commit()
            return redirect(url_for('food.display_farm_info', farm_id=farm.id))
    return render_template('food/edit_farm_info.html', farm=farm)

@food.route('/farm/<int:farm_id>/tests/lots/')
def list_sample_lots(farm_id):
    farm = Farm.query.get(farm_id)
    return render_template('food/samplelots.html', farm=farm)

@food.route('/farm/<int:farm_id>/tests/lots/<int:lot_id>/samples/', methods=['GET', 'POST'])
def list_samples(farm_id, lot_id):
    if request.method == 'GET':
        farm = Farm.query.get(farm_id)
        lot = SampleLot.query.get(lot_id)
    elif request.method == 'POST':
        farm_id = request.form.get('farm_id')
        lot_id = request.form.get('lot_id')
        produce_id = request.form.get('produce_id')
        p = Produce.query.get(int(produce_id))
        grown_produce = GrownProduce(produce=p)
        farm = Farm.query.get(int(farm_id))
        lot = SampleLot.query.get(int(lot_id))
        farm.produce.append(grown_produce)
        lot.samples.append(Sample(produce=grown_produce))
        db.session.add(grown_produce)
        db.session.add(farm)
        db.session.add(lot)
        db.session.commit()

    produces = Produce.query.all()
    samples = []
    for s in lot.samples:
        grown_produce = GrownProduce.query.get(s.produce_id)
        samples.append({
            'id': s.id,
            'produce': grown_produce.produce.name
        })
    return render_template('food/samples.html',
                           farm=farm, lot=lot,
                           samples=samples,
                           produces=produces)

@food.route('/farm/<int:farm_id>/lot/<int:lot_id>/sample/<int:sample_id>/tests')
def show_results(farm_id, lot_id, sample_id):
    farm = Farm.query.get(farm_id)
    sample = Sample.query.get(sample_id)
    lot = SampleLot.query.get(lot_id)
    return render_template('food/show_results.html', farm=farm, sample=sample, lot=lot)

@food.route('/farm/<int:farm_id>/lots/<int:lot_id>/samples/<int:sample_id>/tests/pesticides/add/')
def add_pesticide_results(farm_id, lot_id, sample_id):
    farm = Farm.query.get(farm_id)
    lot = SampleLot.query.get(lot_id)
    sample = Sample.query.get(sample_id)
    pest_tests = PesticideTest.query.all()
    result_dict = {}
    cutoff_dict = {}
    for res in sample.pesticide_results:
        result_dict[res.test.id] = res.value
        cutoff_dict[res.test.id] = res.cutoff_value
    return render_template('food/pest_results.html',
                           farm=farm, lot=lot,
                           sample=sample,
                           pest_tests=pest_tests,
                           result_dict=result_dict,
                           cutoff_dict=cutoff_dict,
                          )

@food.route('/farm/results/pesticides/', methods=['POST'])
def add_pesticide_results_from_form():
    sample_id = request.form.get('sample_id', None)
    farm_id = request.form.get('farm_id', None)
    lot_id = request.form.get('lot_id', None)
    if sample_id:
        sample = Sample.query.get(sample_id)
        test_results_dict = {}
        for res in sample.pesticide_results:
            test_results_dict[res.test.id] = res
        for pt in PesticideTest.query.all():
            test_value = request.form.get('value_' + str(pt.id), None)
            cutoff_value = request.form.get('cutoff_' + str(pt.id), None)
            if pt.id in test_results_dict:
                res = test_results_dict[pt.id]
                res.value = float(test_value) if test_value else None
                res.cutoff_value = float(cutoff_value) if cutoff_value else 0.0
            else:
                if test_value:
                    cutoff_value = float(cutoff_value) if cutoff_value else 0.0
                    pest_test_result = PesticideResult(sample_id=sample.id,
                                                       test_id=pt.id,
                                                       value=float(test_value),
                                                       cutoff_value=float(cutoff_value))
                else:
                    cutoff_value = float(cutoff_value) if cutoff_value else 0.0
                    pest_test_result = PesticideResult(sample_id=sample.id,
                                                       test_id=pt.id,
                                                       cutoff_value=cutoff_value,
                                                       value=None,
                                                      )
                sample.pesticide_results.append(pest_test_result)
        db.session.add(sample)
        db.session.commit()
        return redirect(url_for("food.list_samples", farm_id=farm_id, lot_id=lot_id))
    else:
        return "
An error has occurred. Please contact the system admin.
"

@food.route('/farm/<int:farm_id>/lots/<int:lot_id>/samples/<int:sample_id>/tests/parasites/add/')
def add_parasite_results(farm_id, lot_id, sample_id):
    farm = Farm.query.get(farm_id)
    lot = SampleLot.query.get(lot_id)
    sample = Sample.query.get(sample_id)
    para_tests = ParasiteTest.query.all()
    result_dict = {}
    for res in sample.parasite_results:
        result_dict[res.test.id] = {'count': res.count, 'comment': res.comment}
    return render_template('food/parasit_results.html', farm=farm, lot=lot,
                           sample=sample, tests=para_tests, result_dict=result_dict)

@food.route('/farm/results/parasites/', methods=['POST'])
def add_parasite_results_from_form():
    sample_id = request.form.get('sample_id', None)
    farm_id = request.form.get('farm_id', None)
    lot_id = request.form.get('lot_id', None)
    if sample_id:
        sample = Sample.query.get(sample_id)
        test_results_dict = {}
        for res in sample.parasite_results:
            test_results_dict[res.test.id] = res
        for pt in ParasiteTest.query.all():
            test_count = request.form.get(str(pt.id)+'_count')
            test_count = int(test_count) if test_count.isdigit() else 0
            test_comment = request.form.get(str(pt.id)+'_comment', None)
            if pt.id in test_results_dict:
                res = test_results_dict[pt.id]
                res.count = test_count
                res.comment = test_comment
                db.session.add(res)
            else:
                if test_count or test_comment:
                    para_test_result = ParasiteResult(sample_id=sample.id,
                                        test_id=pt.id, count=int(test_count),
                                        comment=test_comment)
                    sample.parasite_results.append(para_test_result)
        db.session.add(sample)
        db.session.commit()
        return redirect(url_for("food.list_samples", farm_id=farm_id, lot_id=lot_id))
    else:
        return "
An error has occurred. Please contact the system admin.
"

@food.route('/farm/<int:farm_id>/lots/<int:lot_id>/samples/<int:sample_id>/tests/bacteria/add/')
def add_bacteria_results(farm_id, lot_id, sample_id):
    farm = Farm.query.get(farm_id)
    lot = SampleLot.query.get(lot_id)
    sample = Sample.query.get(sample_id)
    bact_tests = BactTest.query.all()
    result_dict = {}
    for res in sample.bact_results:
        result_dict[res.test.id] = res.value
    return render_template('food/bact_results.html', farm=farm, lot=lot,
                           sample=sample, bact_tests=bact_tests, result_dict=result_dict)

@food.route('/farm/results/bacteria/', methods=['POST'])
def add_bact_results_from_form():
    sample_id = request.form.get('sample_id', None)
    farm_id = request.form.get('farm_id', None)
    lot_id = request.form.get('lot_id', None)
    if sample_id:
        sample = Sample.query.get(sample_id)
        test_results_dict = {}
        for res in sample.bact_results:
            test_results_dict[res.test.id] = res
        for pt in BactTest.query.all():
            test_value = request.form.get(str(pt.id), None)
            if pt.id in test_results_dict:
                res = test_results_dict[pt.id]
                res.value = test_value if test_value else None
            else:
                bact_test_result = BactResult(sample_id=sample.id,
                                    test_id=pt.id, value=test_value)
                sample.bact_results.append(bact_test_result)
        db.session.add(sample)
        db.session.commit()
        return redirect(url_for("food.list_samples", farm_id=farm_id, lot_id=lot_id))
    else:
        return "
An error has occurred. Please contact the system admin.
"

@food.route('/farm/<int:farm_id>/lots/<int:lot_id>/samples/<int:sample_id>/tests/toxicology/add/')
def add_toxicology_results(farm_id, lot_id, sample_id):
    farm = Farm.query.get(farm_id)
    lot = SampleLot.query.get(lot_id)
    sample = Sample.query.get(sample_id)
    tox_tests = ToxicoTest.query.all()
    result_dict = {}
    for res in sample.toxico_results:
        result_dict[res.test.id] = res.value
    return render_template('food/toxico_results.html', farm=farm, lot=lot,
                        sample=sample, tox_tests=tox_tests, result_dict=result_dict)

@food.route('/farm/results/heavymetals/', methods=['POST'])
def add_toxico_results_from_form():
    sample_id = request.form.get('sample_id', None)
    farm_id = request.form.get('farm_id', None)
    lot_id = request.form.get('lot_id', None)
    if sample_id:
        sample = Sample.query.get(sample_id)
        test_results_dict = {}
        for res in sample.toxico_results:
            test_results_dict[res.test.id] = res
        for pt in ToxicoTest.query.all():
            test_value = request.form.get(str(pt.id), None)
            if pt.id in test_results_dict:
                res = test_results_dict[pt.id]
                res.value = float(test_value) if test_value else None
            else:
                if test_value:
                    toxico_test_result = ToxicoResult(sample_id=sample.id,
                                        test_id=pt.id, value=float(test_value))
                else:
                    toxico_test_result = ToxicoResult(sample_id=sample.id,
                                        test_id=pt.id, value=None)
                sample.toxico_results.append(toxico_test_result)
        db.session.add(sample)
        db.session.commit()
        return redirect(url_for("food.list_samples", farm_id=farm_id, lot_id=lot_id))
    else:
        return "
An error has occurred. Please contact the system admin.
"

@food.route('/farm/produce/', methods=['POST', 'GET'])
def list_produce():
    if request.method == 'POST':
        produce = request.form.get('produce')
        if produce:
            db.session.add(Produce(name=produce))
            db.session.commit()
    all_produce = Produce.query.all()
    return render_template('food/list_produce.html',
                           all_produce=all_produce)

@food.route('/farm/produce/<int:produce_id>')
def display_produce_info(produce_id=None):
    if produce_id:
        produce = Produce.query.get(produce_id)
        if produce:
            farms = []
            province_flt = request.args.get('province', None)
            for grown_produce in produce.grown_produces:
                for farm in grown_produce.farms:
                    subdistrict = Subdistrict.query.get(farm.subdistrict_id).name
                    district = District.query.get(farm.district_id).name
                    province = Province.query.get(farm.province_id).name
                    estimated_area_size = float(grown_produce.estimated_area) if \
                                            grown_produce.estimated_area is not None else 0
                    if not province_flt or province_flt == province:
                        farms.append({
                            'id': farm.id,
                            'ref_id': farm.ref_id(),
                            'total_size': farm.estimated_total_size,
                            'total_produce_area_size': estimated_area_size,
                            'street': farm.street,
                            'subdistrict': subdistrict,
                            'district': district,
                            'province': province,
                            'owners': farm.get_owners()
                        })
            if farms:
                data_farms = DataFrame(farms)
                plant_counts = data_farms.groupby(['province'])['province'].count()
                area_total = data_farms.groupby(['province'])['total_size'].sum()
                prod_area_total = data_farms.groupby(['province'])['total_produce_area_size'].sum()
                return render_template("food/produce_info.html",
                                       produce=produce, farms=farms,
                                       plant_counts=plant_counts,
                                       area_total=area_total,
                                       prod_area_total=prod_area_total)
            else:
                return render_template("food/produce_info.html",
                                       produce=produce, farms=farms,
                                       plant_counts=Series(),
                                       area_total=Series(),
                                       prod_area_total=Series())

    else:
        return 'No produce ID specified.'

@food.route('/farm/producer/', methods=['GET'])
def list_farm_producer():
    produce = request.form.get('produce', None)
    if produce:
        farms = db.session.add(Farm)

@food.route('/farm/produce/add', methods=['POST', 'GET'])
def add_produce():
    errors = []
    if request.method == 'POST':
        pname = request.form['produce_name']
        produce = db.session.query(Produce).filter_by(name=pname).first()
        if produce:
            errors.append(u'{} มีในฐานข้อมูลแล้ว กรุณาเพิ่มรายการใหม่'.format(pname))
            print(errors)
        else:
            new_produce = Produce(name=pname)
            db.session.add(new_produce)
            db.session.commit()
            return redirect(url_for('food.index'))
    return render_template('food/add_produce.html', errors=errors)

@food.route('/health/person/')
def show_health_data():
    firstname = request.args.get('firstname', '')
    lastname = request.args.get('lastname', '')
    person = db.session.query(HealthPerson).filter(
                    HealthPerson.firstname==firstname,
                    HealthPerson.lastname==lastname).first()
    if person:
        return render_template('food/health.html',
                    person=person, genders={u'1': u'ชาย', u'2': u'หญิง'})
    else:
        return 'Data not found.'

@food.route('/health/person/lab/')
def display_health_lab_results():
    cmscode = request.args.get('cmscode', None)
    serviceno = request.args.get('serviceno', None)
    service = db.session.query(HealthServices).filter(HealthServices.serviceno==serviceno).first()
    person = db.session.query(HealthPerson).filter(HealthPerson.cmscode==cmscode).first()
    genders = {u'1': u'ชาย', u'2': u'หญิง'}
    return render_template('food/health_lab.html', person=person, service=service,genders=genders)

@food.route('/survey/results/')
def display_survey_results():
    firstname = request.args.get('firstname', None)
    lastname = request.args.get('lastname', None)
    survey = SurveyResult.query.filter(SurveyResult.firstname==firstname, SurveyResult.lastname==lastname).first()
    if survey:
        questions = sorted(survey.questions.iteritems(), key=lambda x: x[1])
        return render_template('food/show_survey_results.html',
                        survey=survey, questions=questions)
    else:
        return 'Not survey data from this person yet.'


from django.db import models

class ShowManager(models.Manager):
    def basic_validator(self, postData):
        error = {}
        if len(postData['name']) < 2:
            errors["name"] = "Name must be at least 2 characters"
        if len(postData['network']) < 3:
            errors["network"] = "Network must be at least 3 characters"
        if len(postData['description']) < 2:
            errors["description"] = "Name must be at least 10 characters"
        return errors

class Show(models.Model):
    title = models.CharField(max_length=255)
    network = models.CharField(max_length=45)
    release_date = models.DateTimeField()
    description = models.CharField(max_length=255)
    created_at = models.DateTimeField(auto_now=True)
    updated_at = models.DateTimeField(auto_now_add=True)
    objects = ShowManager()


from requests import get

class BitrueService:
    def __init__(self):
        self.url = "https://openapi.bitrue.com/api/v1/ticker/bookTicker"

    def start(self, from_, to):
        PARAMS = {"symbol": f"{from_}{to}"}
        headers = {"Accept": "application/json", "Content-Type": "application/json"}
        resp = get(self.url, params=PARAMS, headers=headers)
        inch_data = resp.json()
        return inch_data


import sys
import subprocess
import os

def predict(model_fold_dir, data_fold_dir, cmd, verbose=True):
	for model_data in os.listdir(model_fold_dir):
		m_model = re.match(r".*\.mdl$", model_data)
		if m_model:
			for data in data_fold_dir:
				m_dev = re.match(r".*_dev\.json", data)
				if m_dev:
					model_path = os.path.join(model_fold_dir, model_data)
					dev_path = os.path.join(data_fold_dir, data)
					predict_cmd_format = "python {} {} --model {} --out-dir {}"
					predict_cmd = predict_cmd_format.format(dev_path, cmd, model_path, model_fold_dir)
					if verbose:
						print(predict_cmd)
					subprocess.call(["bash", "-c", predict_cmd])
			raise Exception("Cannot find dev dataset in {}".format(data_fold_dir))
	raise Exception("Cannot find model file in {}".format(model_fold_dir))

if __name__ == "__main__":
	args = sys.argv
	cmd = " ".join(args[1:-2])
	dataset, model_dir = args[-2], args[-1]

	for fold_dir in os.listdir(model_dir):
		data_fold_dir = os.path.join(data_dir, fold_dir)
		model_fold_dir = os.path.join(model_dir, fold_dir)
		try:
			predict(model_fold_dir, data_fold_dir, cmd)
		except Exception as e:
			print(str(e))
			print("Skip prediction of fold {}".format(fold_dir))


import time
from PIL import Image
import os

st = time.time()
#############################################

def main():

    path = input("Enter image folder path: ").strip()
    reduce = float(input("Enter percentage you want to reduce: "))

    imageURL = get_indi_file(path)
    for img in imageURL:
        convertImg(img, reduce)

def get_indi_file(path):
    allFiles = []
    for root, dirs, files in os.walk(path):
        for file in files:
            fullFileName = root+"\\"+file
            allFiles.append(fullFileName)
    return allFiles

def convertImg(imageURL, reduce):

    if imageURL.find(".jpeg") >= 0:
        outputPath = imageURL.replace(".jpeg","-converted.jpeg")
    elif imageURL.find(".jpg") >= 0:
        outputPath = imageURL.replace(".jpg","-converted.jpg")
    elif imageURL.find(".png") >= 0:
        outputPath = imageURL.replace(".png","-converted.png")
    else:
        return 0

    img = Image.open(imageURL)

    width, height = img.size

    print(width,height, end="----New Size: ")

    per = 100/reduce

    width = int(width/per)
    height = int(height/per)

    print(width,height)

    newsize = (width, height)
    img1 = img.resize(newsize)

    img1 = img1.save(outputPath, quality=90, dpi=(300,300))

main()

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

et = time.time()
elapsed_time = et - st
print('Execution time:', elapsed_time, 'seconds')


import torch
import torch.utils.data
from typing import Dict, Iterable, Optional
from collections import defaultdict
from src.configs.training_configs import training_datasets
from src.utils.ProgressBar import ProgressBar
from src.utils.WandbLogger import WandbLogger
from src.utils.types import Sample, TrainingParams
from src.utils.Checkpoint import Checkpoint
from src.utils.constants import PLACEMENT

def train_model(
    model: torch.nn.Module,
    name: str,
    config: TrainingParams,
    device: torch.device,
    fine: bool
) -> None:
    model.to(device)
    optimizer = config['optimizer']
    criterion = config['criterion']

    dataset = training_datasets(config['dataset_config'], fine)

    training_data, validation_data = torch.utils.data.random_split(
        dataset, [0.8, 0.2])

    train_data_loader = torch.utils.data.DataLoader(
        training_data,
        batch_size=config['batch_size'],
        shuffle=True,
        drop_last=False,
    )

    validation_data_loader = torch.utils.data.DataLoader(
        validation_data,
        batch_size=config['batch_size'],
        shuffle=True,
        drop_last=False,
    )

    logger = ProgressBar(len(train_data_loader), config['batch_size'])
    wandb_logger = WandbLogger(config['name'], config)
    checkpoint = Checkpoint(model, f"checkpoint/{name}-{PLACEMENT}.pt")

    scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(
        optimizer,  config['epochs'])

    for epoch in range(1, config['epochs'] + 1):
        print(f"Epoch {epoch}/{config['epochs']}")

        train_one_epoch(
            model,
            train_data_loader,
            criterion,
            optimizer,
            device,
            logger,
            wandb_logger
        )

        score = evaluate(
            model,
            validation_data_loader,
            device,
            criterion,
            wandb_logger,
        )

        scheduler.step()

        checkpoint(score)
        if checkpoint.is_overfitting():
            break

def train_one_epoch(
    model: torch.nn.Module,
    data_loader: Iterable[Sample],
    criterion: torch.nn.Module,
    optimizer: torch.optim.Optimizer,
    device: torch.device,
    logger: Optional[ProgressBar] = None,
    wandb_logger: Optional[WandbLogger] = None,
) -> None:
    model.train(True)
    optimizer.zero_grad()

    for step, (samples, targets) in enumerate(data_loader, start=1):
        samples = samples.to(device, non_blocking=True).requires_grad_(True)
        targets = targets.to(device, non_blocking=True)

        output = model(samples)
        loss = criterion(output, targets)

        loss_value = loss.item()
        loss.backward()

        optimizer.step()
        optimizer.zero_grad()

        if logger is not None:
            logger(step, loss=loss_value)
        if wandb_logger is not None:
            wandb_logger(loss=loss_value)

@torch.no_grad()
def evaluate(
    model: torch.nn.Module,
    data_loader:torch.utils.data.DataLoader,
    device: torch.device,
    criterion: torch.nn.Module,
    wandb_logger: Optional[WandbLogger] = None,
    **kwargs: torch.nn.Module,
) -> float:
    model.eval()
    loss = 0.0
    metrics: Dict[str, float] = defaultdict(float)

    for samples, targets in data_loader:
        samples = samples.to(device, non_blocking=True)
        targets = targets.to(device, non_blocking=True)

        output = model(samples)
        loss += criterion(output, targets).item() / len(data_loader)

        for key, metric in kwargs.items():
            metrics[key] += metric(output, targets).item() / len(data_loader)

    metrics['val_loss'] = loss
    print(' - '.join(': '.join(map(str, x)) for x in metrics.items()))

    if wandb_logger is not None:
        wandb_logger(**metrics)

    return loss


from os.path import exists

#   Initialize WORDS as an empty array
WORDS = []

# A function to reduce redundant code
def invalid_error():
    print("Invalid Input")

#   A function to take confirmation from user
def is_confirmed(text):
    decision = input(f"{text} (y,n) : ")
    if decision.lower() == "y":
        return True
    return False

#   Initialize words from a text file to the program
def init():
    if exists("ReservesDictionary/data.txt"):
        data_file = open("ReservesDictionary/data.txt", "r")
        data = data_file.readlines()
        for line in data:
            if len(line.split("|")) == 3:
                name, description, sample = line.strip().split("|")
                WORDS.append(
                    {
                        "name": name,
                        "description": description,
                        "sample": sample,
                    }
                )
        data_file.close()

#   Function to save all words in a text file
def save_file():
    data_file = open("ReservesDictionary/data.txt", "w")
    data_file.writelines(
        f'{("|".join((str(item[key]) for key in item)))}\n' for item in WORDS
    )
    data_file.close()

#   Take input for a word on adding and updating
def take_word_inputs():
    name = input("Name : ")
    description = input("Description : ")
    sample = input("Sample : ")
    return {"name": name, "description": description, "sample": sample}

#   Function to add new word
def add_word():
    print("New word :")
    WORDS.append(take_word_inputs())
    print_all_words()
    if is_confirmed("Add again ?"):
        add_word()

#   Function to update an existing word
def update_word():
    print_all_words()
    option = int(input("Enter a number to update : "))
    if option <= len(WORDS):
        WORDS[option - 1] = take_word_inputs()
        print_all_words()
        if is_confirmed("Update again?"):
            remove_word()
    else:
        print("Invalid input")

#   Print words from arguments to the console
def print_words(words):
    if len(words) == 0:
        print("\n\nNo word found\n\n")
        return
    index = 0
    for word in words:
        index += 1
        print("\n", index, " .")
        print("Name : ", word["name"])
        print("Description : ", word["description"])
        print("Sample : ", word["sample"], "\n")

#   Print all words to the console
def print_all_words():
    print_words(WORDS)

#   Search for a word
def search_word(query):
    results = []
    for item in WORDS:
        if (
            item["name"].lower().__contains__(query.lower())
            or item["description"].lower().__contains__(query.lower())
            or item["sample"].lower().__contains__(query.lower())
        ):
            results.append(item)
    return results

#   Function to print search result to the console
def show_search_result():
    query = input("Search for word : ")
    print_words(search_word(query))

#   Function to remove exisintg word
def remove_word():
    print_all_words()
    option = int(input("Enter a number to remove : "))
    if option <= len(WORDS):
        del WORDS[option - 1]
        print_all_words()
        if is_confirmed("Delete again?"):
            remove_word()
    else:
        print("Invalid input")

#   Main function containing the menu of the application
def main():
    init()
    while True:
        print(
            """
        Welcome to Reserve Dictionary

        1. View words
        2. Add New word
        3. Update word
        4. Remove word
        5. Search word
        0. Exit
        """
        )
        option = int(input("Enter an option : "))
        if option == 0:
            break
        menus = {
            1: print_all_words,
            2: add_word,
            3: update_word,
            4: remove_word,
            5: show_search_result,
        }
        if menus.keys().__contains__(option):
            menus[option]()
        else:
            print("Invalid Option")
    save_file()

main()


total_amount = 0

while True:
    input_value = input()

    if input_value == "NoMoreMoney":
        break

    amount = float(input_value)

    if amount < 0:
        print("Invalid operation!")
        break

    total_amount += amount
    print(f"Increase: {amount:.2f}")

print(f"Total: {total_amount:.2f}")


import os
from unittest import TestCase
from multifora_api import MlApi

class TestMlApi(TestCase):
    @classmethod
    def setUpClass(cls):
        os.environ["TEST"] = "1"

    def test_get(self):
        api = MlApi(host="http://<server ip>:<port>/")
        api.add_model("LG", "LogisticRegression", {})
        models_dict = api.gel_model_list().to_dict()
        with self.assertRaises(NotFound):
            gmr.get("wrong_type")

    def test_models_available(self):
        api = MlApi(host="http://<server ip>:<port>/")
        model_list = api.models_available()
        base_model_list = [
            "LogisticRegression",
            "RandomForestClassifier",
            "LinearRegression",
            "RandomForestRegressor",
            "DecisionTreeClassifier",
            "DecisionTreeRegressor",
            "KNeighborsClassifier",
            "KNeighborsRegressor",
        ]
        self.assertListEqual(model_list, base_model_list)

class TestGetHyperParamsRest(TestCase):
    @classmethod
    def setUpClass(cls):
        os.environ["TEST"] = "1"

    def test_get(self):
        ghpr = GetHyperParamsRest()

        self.assertIn("hyper_params", ghpr.get("LogisticRegression"))

        with self.assertRaises(NotFound):
            ghpr.get("LogisticRegressionWrong")


from django import forms
from .models import Tag, Post
from django.core.exceptions import ValidationError

class TagForm(forms.ModelForm):
    # наследование от ModelForm позволяет связать модель и форму через класс Meta, определив: модель, поля и стили

    class Meta:
        model = Tag
        fields = ['title', 'slug']

        widgets = {
            'title': forms.TextInput(attrs={'class': 'form-control'}),
            'slug': forms.TextInput(attrs={'class': 'form-control'})
        }

    def clean_slug(self):
        # вообще для получения чего-то из словаря есть специальный метод,
        # но так как мы уже дошли до clean_SLUG, то так писать - нормально
        new_slug = self.cleaned_data['slug'].lower()

        if new_slug == 'create':
            raise ValidationError('Slug may not be "Create"')
        if Tag.objects.filter(slug__iexact=new_slug).count():
            raise ValidationError('Slug must be unique. We have "{}" slug already'.format(new_slug))
        return new_slug

class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ['title', 'slug', 'body', 'tags']

        widgets = {
            'title': forms.TextInput(attrs={'class': 'form-control'}),
            'slug': forms.TextInput(attrs={'class': 'form-control'}),
            'body': forms.Textarea(attrs={'class': 'form-control'}),
            'tags': forms.SelectMultiple(attrs={'class': 'form-control'})
        }

        def clean_slug(self):
            # вообще для получения чего-то из словаря есть специальный метод,
            # но так как мы уже дошли до clean_SLUG, то так писать - нормально
            new_slug = self.cleaned_data['slug'].lower()

            if new_slug == 'create':
                raise ValidationError('Slug may not be "Create"')
            return new_slug


from ejson import serializers
from mock import Mock, call, patch
from datetime import datetime

from eventlib import exceptions, conf, core, tasks

def test_parse_event_name():
    core.parse_event_name('app.Event').should.be.equal(
        ('app.events', 'Event'))

    core.parse_event_name.when.called_with('stuff').should.throw(
        exceptions.InvalidEventNameError,
        'The name "stuff" is invalid. Make sure you are using the '
        '"app.KlassName" format')

    core.parse_event_name.when.called_with('other.stuff.blah').should.throw(
        exceptions.InvalidEventNameError,
        'The name "other.stuff.blah" is invalid. Make sure you are using the '
        '"app.KlassName" format')

@patch('eventlib.core.import_module')
def test_find_event(import_module):
    fake_module = Mock()
    fake_module.Event = 'my-lol-module'

    import_module.return_value = fake_module
    core.find_event('app.Event').should.be.equals('my-lol-module')

    import_module.reset_mock()
    import_module.side_effect = ImportError
    core.find_event.when.called_with('app.Event2').should.throw(
        exceptions.EventNotFoundError,
        'Event "app.Event2" not found. Make sure you have a class '
        'called "Event2" inside the "app.events" module.')

def test_filter_data_values():
    core.filter_data_values({'a': 'b', 'c': 'd'}).should.be.equals(
        {'a': 'b', 'c': 'd'}
    )
    core.filter_data_values({'a': 'b', 'request': None}).should.be.equals(
        {'a': 'b'}
    )

@patch('eventlib.core.datetime')
@patch('eventlib.core.get_ip')
def test_get_default_values_with_request(get_ip, datetime):
    get_ip.return_value = '150.164.211.1'
    datetime.now.return_value = 'tea time!'
    data = {'foo': 'bar', 'request': Mock()}
    core.get_default_values(data).should.be.equals({
        '__datetime__': 'tea time!',
        '__ip_address__': '150.164.211.1',
    })

@patch('eventlib.tasks.process')
def test_celery_process_wrapper(process):
    tasks.process_task('name', 'data')
    process.assert_called_once_with('name', 'data')

@patch('eventlib.conf.settings')
def test_django_integration(settings):
    # Given I mock django conf
    settings.LOCAL_GEOLOCATION_IP = 'CHUCK NORRIS'

    # When I try to access a variable using the getsetting method, then
    # it should contain the mocked values
    conf.getsetting('LOCAL_GEOLOCATION_IP').should.equal('CHUCK NORRIS')

@patch('eventlib.conf.settings')
@patch('eventlib.core.import_module')
def test_importing_events(import_module, settings):
    settings.INSTALLED_APPS = ['foobar', 'test_app']

    core.import_event_modules()
    calls = [call('foobar.events'), call('test_app.events')]
    import_module.assert_has_calls(calls)

    settings.INSTALLED_APPS = ['tester']
    import_module.side_effect = ImportError('P0wned!!!')
    core.import_event_modules()


from itertools import count
import sys
import numpy as np
import cvxopt as co
import pickle
import time
import os

from sklearn.svm import SVC
import matplotlib.pyplot as plt
from cvxopt import matrix as cvxopt_matrix
from cvxopt import solvers as cvxopt_solvers

def extractData(dataDict):
    # number of features
    n=32*32*3
    # treating label 1 as -1 and label 2 as +1
    posClassSize=0
    negClassSize=0

    for j in range(0,dataDict["data"].shape[0]):
        if dataDict["labels"][j]==1:
            negClassSize+=1
        if dataDict["labels"][j]==2:
            posClassSize+=1

    xValue=np.empty([posClassSize+negClassSize,n])
    yValue=np.empty([posClassSize+negClassSize])

    currInd=0

    for j in range(0,dataDict["data"].shape[0]):
        if dataDict["labels"][j]==1:
            # swapped=np.swapaxes(dataDict["data"][j],0,2)
            flattened=dataDict["data"][j].reshape([3072])
            # flattened=swapped.flatten()
            xValue[currInd]=flattened
            yValue[currInd]=-1
            currInd+=1
        if dataDict["labels"][j]==2:
            # swapped=np.swapaxes(dataDict["data"][j],0,2)
            flattened=dataDict["data"][j].reshape([3072])
            # flattened=swapped.flatten()
            xValue[currInd]=flattened
            yValue[currInd]=1
            currInd+=1

    xValue=xValue/255
    return xValue,yValue

def train(trainingDict,C=1,gamma=0.001):
    xValue,yValue=extractData(trainingDict)
    # xValue=xValue[0:10,0:5]
    m,n=xValue.shape
    yValue=yValue.reshape(-1,1)

    # Gaussian Kernel
    # Calculating the H matrix
    H=(-2)*np.matmul(xValue,xValue.T)
    H+=np.sum(np.square(xValue),axis=1).reshape(xValue.shape[0],1)
    H=H.T
    H+=np.sum(np.square(xValue),axis=1).reshape(xValue.shape[0],1)
    H=H.T
    H=np.exp((-gamma)*H)
    H=np.multiply(np.matmul(yValue,yValue.T),H)

    #Converting into cvxopt format
    P=cvxopt_matrix(H)
    q=cvxopt_matrix(-np.ones((m, 1)))
    G=cvxopt_matrix(np.vstack((np.eye(m)*-1,np.eye(m))))
    h=cvxopt_matrix(np.hstack((np.zeros(m), np.ones(m) * C)))
    A=cvxopt_matrix(yValue.reshape(1, -1))
    b=cvxopt_matrix(np.zeros(1))

    #Run solver
    sol=cvxopt_solvers.qp(P,q,G,h,A,b,options={"show_progress":False})
    # sol=cvxopt_solvers.qp(P,q,G,h,A,b)

    alphas=np.array(sol['x'])
    # sol=cvxopt_solvers.qp(P,q,G,h,A,b)

    return alphas,xValue,yValue

def test(alphas,b,xTrainData,yTrainData,testDict,gamma=0.001):

    # Initializing results as predicition being right or wrong
    results=np.zeros([2],dtype=np.float64)
    # alphas=np.array(allPara['x'])

    # Extracting Data
    xValue,yValue=extractData(testDict)

    # Calculating the prediction
    yPred=(-2)*np.matmul(xTrainData,xValue.T)
    yPred=yPred.T
    yPred+=np.sum(np.square(xValue),axis=1).reshape(xValue.shape[0],1)
    yPred=yPred.T
    yPred+=np.sum(np.square(xTrainData),axis=1).reshape(xTrainData.shape[0],1)
    yPred=np.exp((-gamma)*yPred)
    yPred=np.multiply(yPred,alphas.reshape(xTrainData.shape[0],1))
    yPred=np.multiply(yPred,yTrainData.reshape(xTrainData.shape[0],1))
    yPred=np.sum(yPred,axis=0)

    # Adding the intercept term
    yPred+=b

    for i in range(0,yValue.shape[0]):
        if yPred[i]*yValue[i]>0:
            results[0]+=1
        else:
            results[1]+=1

    results=results/np.sum(results)
    results=results*100

    return results

def main():

    trainingDir=sys.argv[1]
    testDir=sys.argv[2]

    trainingData=pickle.load(open(trainingDir+"/train_data.pickle","rb"))
    testData=pickle.load(open(testDir+"/test_data.pickle","rb"))

    print("Model training started")
    trainStart=time.time()
    alphas,xTrainData,yTrainData=train(trainingData)
    trainEnd=time.time()
    print("Model training completed")
    print("\nTraining Time: ",trainEnd-trainStart,"sec")
    # retrieving alphas --> Langrangian Parameters
    # alphas=np.array(allPara['x'])

    indexSorted=np.argsort(alphas.reshape(-1,))[-5:]
    for ind in indexSorted:
        # print("ind: ",ind)
        img=xTrainData[ind].reshape([32,32,3])
        plt.imshow(img)
        plt.savefig(f"sv{ind}.png")
        plt.close()

    inf=float('inf')
    negSupport,posSupport=-inf,inf
    gamma=0.001

    # Finding intercept term - b
    yPred=(-2)*np.matmul(xTrainData,xTrainData.T)
    yPred=yPred.T
    yPred+=np.sum(np.square(xTrainData),axis=1).reshape(xTrainData.shape[0],1)
    yPred=yPred.T
    yPred+=np.sum(np.square(xTrainData),axis=1).reshape(xTrainData.shape[0],1)
    yPred=np.exp((-gamma)*yPred)
    yPred=np.multiply(yPred,alphas.reshape(xTrainData.shape[0],1))
    yPred=np.multiply(yPred,yTrainData.reshape(xTrainData.shape[0],1))
    yPred=np.sum(yPred,axis=0)

    for i in range(0,xTrainData.shape[0]):
        if yTrainData[i]>0:
            posSupport=min(posSupport,yPred[i])
        else:
            negSupport=max(negSupport,yPred[i])

    b =-(negSupport+posSupport)/2

    # retrieving support vectors
    countSupportVectors=np.zeros([2],dtype=np.float64)
    for i in range(0,alphas.shape[0]):
        if alphas[i][0]>1e-5:
            if yTrainData[i]<0:
                countSupportVectors[0]+=1
            else:
                countSupportVectors[1]+=1

     # printing on console
    print("\nNo. of support vectors in Class 1 are ",countSupportVectors[0])
    print("No. of support vectors in Class 2 are ",countSupportVectors[1])
    print("Support Vector percentage in training examples is ",np.sum((countSupportVectors)/xTrainData.shape[0])*100,"%")

    testTestStart=time.time()
    results=test(alphas,b,xTrainData,yTrainData,testData)
    testTestEnd=time.time()
    print("\nTesting Time over testing data set: ",testTestEnd-testTestStart,"sec")
    # print(results)

    print("\nThe accuracy over test data in case of gaussian kernel is: ",results[0],"%\n")

main()


import csv
import sys

if len(sys.argv) < 3:
    sys.exit("Too few command-line arguments")
elif len(sys.argv) > 3:
    sys.exit("Too many command-line arguments")
if sys.argv[1][-4:] != ".csv":
    sys.exit("Not a CSV file")

try:
    with open(sys.argv[1], newline="") as input_file:
        reader = csv.DictReader(input_file)

        with open(sys.argv[2], "w", newline="") as output_file:
            header = ["first", "last", "house"]
            writer = csv.DictWriter(output_file, fieldnames=header)

            writer.writeheader()

            for student in reader:
                last, first = student["name"].split(", ")
                house = student["house"]
                writer.writerow({"first": first, "last": last, "house": house})
except FileNotFoundError:
    sys.exit(f"Could not read {input}")