# -*- coding: utf-8 -*-

import xbmc
import xbmcgui
import utilities
from utilities import Debug, notification
import copy

progress = xbmcgui.DialogProgress()

class Sync():

	def __init__(self, show_progress=False, run_silent=False, library="all", api=None):
		self.traktapi = api
		self.show_progress = show_progress
		self.run_silent = run_silent
		self.library = library
		if self.show_progress and self.run_silent:
			Debug("[Sync] Sync is being run silently.")
		self.sync_on_update = utilities.getSettingAsBool('sync_on_update')
		self.notify = utilities.getSettingAsBool('show_sync_notifications')
		self.notify_during_playback = not (xbmc.Player().isPlayingVideo() and utilities.getSettingAsBool("hide_notifications_playback"))
		self.simulate = utilities.getSettingAsBool('simulate_sync')
		if self.simulate:
			Debug("[Sync] Sync is configured to be simulated.")

		_opts = ['ExcludePathOption', 'ExcludePathOption2', 'ExcludePathOption3']
		_vals = ['ExcludePath', 'ExcludePath2', 'ExcludePath3']
		self.exclusions = []
		for i in range(3):
			if utilities.getSettingAsBool(_opts[i]):
				_path = utilities.getSetting(_vals[i])
				if _path != "":
					self.exclusions.append(_path)

	def isCanceled(self):
		if self.show_progress and not self.run_silent and progress.iscanceled():
			Debug("[Sync] Sync was canceled by user.")
			return True
		elif xbmc.abortRequested:
			Debug('XBMC abort requested')
			return True
		else:
			return False

	def updateProgress(self, *args, **kwargs):
		if self.show_progress and not self.run_silent:
			kwargs['percent'] = args[0]
			progress.update(**kwargs)

	def checkExclusion(self, file):
		for _path in self.exclusions:
			if file.find(_path) > -1:
				return True
		return False

	''' begin code for episode sync '''
	def traktLoadShows(self):
		self.updateProgress(10, line1=utilities.getString(1485), line2=utilities.getString(1486))

		Debug('[Episodes Sync] Getting episode collection from trakt.tv')
		library_shows = self.traktapi.getShowLibrary()
		if not isinstance(library_shows, list):
			Debug("[Episodes Sync] Invalid trakt.tv show list, possible error getting data from trakt, aborting trakt.tv collection update.")
			return False

		self.updateProgress(12, line2=utilities.getString(1487))

		Debug('[Episodes Sync] Getting watched episodes from trakt.tv')
		watched_shows = self.traktapi.getWatchedEpisodeLibrary()
		if not isinstance(watched_shows, list):
			Debug("[Episodes Sync] Invalid trakt.tv watched show list, possible error getting data from trakt, aborting trakt.tv watched update.")
			return False

		shows = []
		i = 0
		x = float(len(library_shows))
		# reformat show array
		for show in library_shows:
			if show['title'] is None and show['imdb_id'] is None and show['tvdb_id'] is None:
				# has no identifing values, skip it
				continue

			y = {}
			w = {}
			for s in show['seasons']:
				y[s['season']] = s['episodes']
				w[s['season']] = []
			show['seasons'] = y
			show['watched'] = w
			show['in_collection'] = True
			if show['imdb_id'] is None:
				show['imdb_id'] = ""
			if show['tvdb_id'] is None:
				show['tvdb_id'] = ""

			shows.append(show)

			i = i + 1
			y = ((i / x) * 8) + 12
			self.updateProgress(int(y), line2=utilities.getString(1488))

		i = 0
		x = float(len(watched_shows))
		for watched_show in watched_shows:
			if watched_show['title'] is None and watched_show['imdb_id'] is None and watched_show['tvdb_id'] is None:
				# has no identifing values, skip it
				continue

			if watched_show['imdb_id'] is None:
				watched_show['imdb_id'] = ""
			if watched_show['tvdb_id'] is None:
				watched_show['tvdb_id'] = ""
			show = utilities.findShow(watched_show, shows)
			if show:
				for s in watched_show['seasons']:
					show['watched'][s['season']] = s['episodes']
			else:
				y = {}
				w = {}
				for s in watched_show['seasons']:
					w[s['season']] = s['episodes']
					y[s['season']] = []
				watched_show['seasons'] = y
				watched_show['watched'] = w
				watched_show['in_collection'] = False
				shows.append(watched_show)

			i = i + 1
			y = ((i / x) * 8) + 20
			self.updateProgress(int(y), line2=utilities.getString(1488))

		self.updateProgress(28, line2=utilities.getString(1489))

		return shows

	def xbmcLoadShowList(self):
		Debug("[Episodes Sync] Getting show data from XBMC")
		data = utilities.xbmcJsonRequest({'jsonrpc': '2.0', 'method': 'VideoLibrary.GetTVShows', 'params': {'properties': ['title', 'imdbnumber', 'year']}, 'id': 0})
		if not data:
			Debug("[Episodes Sync] xbmc json request was empty.")
			return None

		if not 'tvshows' in data:
			Debug('[Episodes Sync] Key "tvshows" not found')
			return None

		shows = data['tvshows']
		Debug("[Episodes Sync] XBMC JSON Result: '%s'" % str(shows))

		# reformat show array
		for show in shows:
			show['in_collection'] = True
			show['tvdb_id'] = ""
			show['imdb_id'] = ""
			id = show['imdbnumber']
			if id.startswith("tt"):
				show['imdb_id'] = id
			if id.isdigit():
				show['tvdb_id'] = id
			del(show['imdbnumber'])
			del(show['label'])
		return shows

	def xbmcLoadShows(self):
		self.updateProgress(1, line1=utilities.getString(1480), line2=utilities.getString(1481))

		tvshows = self.xbmcLoadShowList()
		if tvshows is None:
			return None

		self.updateProgress(2, line2=utilities.getString(1482))

		i = 0
		x = float(len(tvshows))
		Debug("[Episodes Sync] Getting episode data from XBMC")
		for show in tvshows:
			show['seasons'] = {}
			show['watched'] = {}
			data = utilities.xbmcJsonRequest({'jsonrpc': '2.0', 'method': 'VideoLibrary.GetEpisodes', 'params': {'tvshowid': show['tvshowid'], 'properties': ['season', 'episode', 'playcount', 'uniqueid', 'file']}, 'id': 0})
			if not data:
				Debug("[Episodes Sync] There was a problem getting episode data for '%s', aborting sync." % show['title'])
				return None
			if not 'episodes' in data:
				Debug("[Episodes Sync] '%s' has no episodes in XBMC." % show['title'])
				continue
			episodes = data['episodes']
			for e in episodes:
				if self.checkExclusion(e['file']):
					continue
				_season = e['season']
				_episode = e['episode']
				if not _season in show['seasons']:
					show['seasons'][_season] = {}
					show['watched'][_season] = []
				if not _episode in show['seasons'][_season]:
					show['seasons'][_season][_episode] = {'id': e['episodeid'], 'episode_tvdb_id': e['uniqueid']['unknown']}
				if e['playcount'] > 0:
					if not _episode in show['watched'][_season]:
						show['watched'][_season].append(_episode)

			i = i + 1
			y = ((i / x) * 8) + 2
			self.updateProgress(int(y), line2=utilities.getString(1483))

		self.updateProgress(10, line2=utilities.getString(1484))

		return tvshows

	def countEpisodes(self, shows, watched=False, collection=True, all=False):
		count = 0
		p = 'watched' if watched else 'seasons'
		for show in shows:
			if all:
				for s in show[p]:
					count += len(show[p][s])
			else:
				if 'in_collection' in show and not show['in_collection'] == collection:
					continue
				for s in show[p]:
					count += len(show[p][s])
		return count

	def getShowAsString(self, show, short=False):
		p = []
		if 'seasons' in show:
			for season in show['seasons']:
				s = ""
				if short:
					s = ", ".join(["S%02dE%02d" % (season, i) for i in show['seasons'][season]])
				else:
					episodes = ", ".join([str(i) for i in show['seasons'][season]])
					s = "Season: %d, Episodes: %s" % (season, episodes)
				p.append(s)
		else:
			p = ["All"]
		return "%s [tvdb: %s] - %s" % (show['title'], show['tvdb_id'], ", ".join(p))

	def traktFormatShow(self, show):
		data = {'title': show['title'], 'tvdb_id': show['tvdb_id'], 'year': show['year'], 'episodes': []}
		if 'imdb_id' in show:
			data['imdb_id'] = show['imdb_id']
		for season in show['seasons']:
			for episode in show['seasons'][season]:
				data['episodes'].append({'season': season, 'episode': episode})
		return data

	def compareShows(self, shows_col1, shows_col2, watched=False, restrict=False):
		shows = []
		p = 'watched' if watched else 'seasons'
		for show_col1 in shows_col1:
			show_col2 = utilities.findShow(show_col1, shows_col2)
			if show_col2:
				season_diff = {}
				show_col2_seasons = show_col2[p]
				for season in show_col1[p]:
					a = show_col1[p][season]
					if season in show_col2_seasons:
						b = show_col2_seasons[season]
						diff = list(set(a).difference(set(b)))
						if len(diff) > 0:
							if restrict:
								t = list(set(show_col2['seasons'][season]).intersection(set(diff)))
								if len(t) > 0:
									eps = {}
									for ep in t:
										eps[ep] = show_col2['seasons'][season][ep]
									season_diff[season] = eps
							else:
								eps = {}
								for ep in diff:
									eps[ep] = ep
								season_diff[season] = eps
					else:
						if not restrict:
							if len(a) > 0:
								season_diff[season] = a
				if len(season_diff) > 0:
					show = {'title': show_col1['title'], 'tvdb_id': show_col1['tvdb_id'], 'year': show_col1['year'], 'seasons': season_diff}
					if 'imdb_id' in show_col1 and show_col1['imdb_id']:
						show['imdb_id'] = show_col1['imdb_id']
					if 'imdb_id' in show_col2 and show_col2['imdb_id']:
						show['imdb_id'] = show_col2['imdb_id']
					if 'tvshowid' in show_col1:
						show['tvshowid'] = show_col1['tvshowid']
					if 'tvshowid' in show_col2:
						show['tvshowid'] = show_col2['tvshowid']
					shows.append(show)
			else:
				if not restrict:
					if 'in_collection' in show_col1 and show_col1['in_collection']:
						if self.countEpisodes([show_col1], watched=watched) > 0:
							show = {'title': show_col1['title'], 'tvdb_id': show_col1['tvdb_id'], 'year': show_col1['year'], 'seasons': show_col1[p]}
							if 'tvshowid' in show_col1:
								show['tvshowid'] = show_col1['tvshowid']
							shows.append(show)
		return shows

	def traktAddEpisodes(self, shows):
		if len(shows) == 0:
			self.updateProgress(46, line1=utilities.getString(1435), line2=utilities.getString(1490))
			Debug("[Episodes Sync] trakt.tv episode collection is up to date.")
			return

		Debug("[Episodes Sync] %i show(s) have episodes (%d) to be added to your trakt.tv collection." % (len(shows), self.countEpisodes(shows)))
		for show in shows:
			Debug("[Episodes Sync] Episodes added: %s" % self.getShowAsString(show, short=True))

		self.updateProgress(28, line1=utilities.getString(1435), line2="%i %s" % (len(shows), utilities.getString(1436)), line3=" ")

		i = 0
		x = float(len(shows))
		for show in shows:
			if self.isCanceled():
				return

			epCount = self.countEpisodes([show])
			title = show['title'].encode('utf-8', 'ignore')

			i = i + 1
			y = ((i / x) * 18) + 28
			self.updateProgress(int(y), line1=utilities.getString(1435), line2=title, line3="%i %s" % (epCount, utilities.getString(1437)))

			s = self.traktFormatShow(show)
			if self.simulate:
				Debug("[Episodes Sync] %s" % str(s))
			else:
				self.traktapi.addEpisode(s)

		self.updateProgress(46, line1=utilities.getString(1435), line2=utilities.getString(1491) % self.countEpisodes(shows))

	def traktRemoveEpisodes(self, shows):
		if len(shows) == 0:
			self.updateProgress(98, line1=utilities.getString(1445), line2=utilities.getString(1496))
			Debug('[Episodes Sync] trakt.tv episode collection is clean')
			return

		Debug("[Episodes Sync] %i show(s) will have episodes removed from trakt.tv collection." % len(shows))
		for show in shows:
			Debug("[Episodes Sync] Episodes removed: %s" % self.getShowAsString(show, short=True))

		self.updateProgress(82, line1=utilities.getString(1445), line2=utilities.getString(1497) % self.countEpisodes(shows), line3=" ")

		i = 0
		x = float(len(shows))
		for show in shows:
			if self.isCanceled():
				return

			epCount = self.countEpisodes([show])
			title = show['title'].encode('utf-8', 'ignore')

			s = self.traktFormatShow(show)
			if self.simulate:
				Debug("[Episodes Sync] %s" % str(s))
			else:
				self.traktapi.removeEpisode(s)

			i = i + 1
			y = ((i / x) * 16) + 82
			self.updateProgress(int(y), line2=title, line3="%i %s" % (epCount, utilities.getString(1447)))

		self.updateProgress(98, line2=utilities.getString(1498) % self.countEpisodes(shows), line3=" ")

	def traktUpdateEpisodes(self, shows):
		if len(shows) == 0:
			self.updateProgress(64, line1=utilities.getString(1438), line2=utilities.getString(1492))
			Debug("[Episodes Sync] trakt.tv episode playcounts are up to date.")
			return

		Debug("[Episodes Sync] %i show(s) are missing playcounts on trakt.tv" % len(shows))
		for show in shows:
			Debug("[Episodes Sync] Episodes updated: %s" % self.getShowAsString(show, short=True))

		self.updateProgress(46, line1=utilities.getString(1438), line2="%i %s" % (len(shows), utilities.getString(1439)), line3=" ")

		i = 0
		x = float(len(shows))
		for show in shows:
			if self.isCanceled():
				return

			epCount = self.countEpisodes([show])
			title = show['title'].encode('utf-8', 'ignore')

			i = i + 1
			y = ((i / x) * 18) + 46
			self.updateProgress(70, line2=title, line3="%i %s" % (epCount, utilities.getString(1440)))

			s = self.traktFormatShow(show)
			if self.simulate:
				Debug("[Episodes Sync] %s" % str(s))
			else:
				self.traktapi.updateSeenEpisode(s)

		self.updateProgress(64, line2="%i %s" % (len(shows), utilities.getString(1439)))

	def xbmcUpdateEpisodes(self, shows):
		if len(shows) == 0:
			self.updateProgress(82, line1=utilities.getString(1441), line2=utilities.getString(1493))
			Debug("[Episodes Sync] XBMC episode playcounts are up to date.")
			return

		Debug("[Episodes Sync] %i show(s) shows are missing playcounts on XBMC" % len(shows))
		for s in ["%s" % self.getShowAsString(s, short=True) for s in shows]:
			Debug("[Episodes Sync] Episodes updated: %s" % s)

		self.updateProgress(64, line1=utilities.getString(1441), line2="%i %s" % (len(shows), utilities.getString(1439)), line3=" ")

		episodes = []
		for show in shows:
			for season in show['seasons']:
				for episode in show['seasons'][season]:
					episodes.append({'episodeid': show['seasons'][season][episode]['id'], 'playcount': 1})

		#split episode list into chunks of 50
		chunked_episodes = utilities.chunks([{"jsonrpc": "2.0", "method": "VideoLibrary.SetEpisodeDetails", "params": episodes[i], "id": i} for i in range(len(episodes))], 50)
		i = 0
		x = float(len(chunked_episodes))
		for chunk in chunked_episodes:
			if self.isCanceled():
				return
			if self.simulate:
				Debug("[Episodes Sync] %s" % str(chunk))
			else:
				utilities.xbmcJsonRequest(chunk)

			i = i + 1
			y = ((i / x) * 18) + 64
			self.updateProgress(int(y), line2=utilities.getString(1494))

		self.updateProgress(82, line2=utilities.getString(1495) % len(episodes))

	def syncEpisodes(self):
		if not self.show_progress and self.sync_on_update and self.notify and self.notify_during_playback:
			notification('%s %s' % (utilities.getString(1400), utilities.getString(1406)), utilities.getString(1420)) #Sync started
		if self.show_progress and not self.run_silent:
			progress.create("%s %s" % (utilities.getString(1400), utilities.getString(1406)), line1=" ", line2=" ", line3=" ")

		xbmcShows = self.xbmcLoadShows()
		if not isinstance(xbmcShows, list) and not xbmcShows:
			Debug("[Episodes Sync] XBMC show list is empty, aborting tv show Sync.")
			if self.show_progress and not self.run_silent:
				progress.close()
			return

		traktShows = self.traktLoadShows()
		if not isinstance(traktShows, list):
			Debug("[Episodes Sync] Error getting trakt.tv show list, aborting tv show sync.")
			if self.show_progress and not self.run_silent:
				progress.close()
			return

		if utilities.getSettingAsBool('add_episodes_to_trakt') and not self.isCanceled():
			traktShowsAdd = self.compareShows(xbmcShows, traktShows)
			self.traktAddEpisodes(traktShowsAdd)

		if utilities.getSettingAsBool('trakt_episode_playcount') and not self.isCanceled():
			traktShowsUpdate = self.compareShows(xbmcShows, traktShows, watched=True)
			self.traktUpdateEpisodes(traktShowsUpdate)

		if utilities.getSettingAsBool('xbmc_episode_playcount') and not self.isCanceled():
			xbmcShowsUpadate = self.compareShows(traktShows, xbmcShows, watched=True, restrict=True)
			self.xbmcUpdateEpisodes(xbmcShowsUpadate)

		if utilities.getSettingAsBool('clean_trakt_episodes') and not self.isCanceled():
			traktShowsRemove = self.compareShows(traktShows, xbmcShows)
			self.traktRemoveEpisodes(traktShowsRemove)

		if not self.show_progress and self.sync_on_update and self.notify and self.notify_during_playback:
			notification('%s %s' % (utilities.getString(1400), utilities.getString(1406)), utilities.getString(1421)) #Sync complete

		if not self.isCanceled() and self.show_progress and not self.run_silent:
			self.updateProgress(100, line1=" ", line2=utilities.getString(1442), line3=" ")
			progress.close()

		Debug("[Episodes Sync] Shows on trakt.tv (%d), shows in XBMC (%d)." % (len(utilities.findAllInList(traktShows, 'in_collection', True)), len(xbmcShows)))
		Debug("[Episodes Sync] Episodes on trakt.tv (%d), episodes in XBMC (%d)." % (self.countEpisodes(traktShows), self.countEpisodes(xbmcShows)))
		Debug("[Episodes Sync] Complete.")

	''' begin code for movie sync '''
	def traktLoadMovies(self):
		self.updateProgress(5, line2=utilities.getString(1462))

		Debug("[Movies Sync] Getting movie collection from trakt.tv")
		movies = self.traktapi.getMovieLibrary()
		if not isinstance(movies, list):
			Debug("[Movies Sync] Invalid trakt.tv movie list, possible error getting data from trakt, aborting trakt.tv collection update.")
			return False

		self.updateProgress(6, line2=utilities.getString(1463))

		Debug("[Movies Sync] Getting seen movies from trakt.tv")
		watched_movies = self.traktapi.getWatchedMovieLibrary()
		if not isinstance(watched_movies, list):
			Debug("[Movies Sync] Invalid trakt.tv movie seen list, possible error getting data from trakt, aborting trakt.tv watched update.")
			return False

		self.updateProgress(8, line2=utilities.getString(1464))

		i = 0
		x = float(len(movies))
		# reformat movie arrays
		for movie in movies:
			movie['plays'] = 0
			movie['in_collection'] = True
			if movie['imdb_id'] is None:
				movie['imdb_id'] = ""
			if movie['tmdb_id'] is None:
				movie['tmdb_id'] = ""

			i = i + 1
			y = ((i / x) * 6) + 8
			self.updateProgress(int(y), line2=utilities.getString(1465))

		i = 0
		x = float(len(watched_movies))
		for movie in watched_movies:
			if movie['imdb_id'] is None:
				movie['imdb_id'] = ""
			if movie['tmdb_id'] is None:
				movie['tmdb_id'] = ""
			else:
				movie['tmdb_id'] = unicode(movie['tmdb_id'])
			m = utilities.findMovie(movie, movies)
			if m:
				m['plays'] = movie['plays']
			else:
				movie['in_collection'] = False
				movies.append(movie)

			i = i + 1
			y = ((i / x) * 6) + 14
			self.updateProgress(int(y), line2=utilities.getString(1465))

		self.updateProgress(20, line2=utilities.getString(1466))

		return movies

	def xbmcLoadMovies(self):
		self.updateProgress(1, line2=utilities.getString(1460))

		Debug("[Movies Sync] Getting movie data from XBMC")
		data = utilities.xbmcJsonRequest({'jsonrpc': '2.0', 'id': 0, 'method': 'VideoLibrary.GetMovies', 'params': {'properties': ['title', 'imdbnumber', 'year', 'playcount', 'lastplayed', 'file']}})
		if not data:
			Debug("[Movies Sync] XBMC JSON request was empty.")
			return

		if not 'movies' in data:
			Debug('[Movies Sync] Key "movies" not found')
			return

		movies = data['movies']
		Debug("[Movies Sync] XBMC JSON Result: '%s'" % str(movies))

		i = 0
		x = float(len(movies))

		xbmc_movies = []

		# reformat movie array
		for movie in movies:
			if self.checkExclusion(movie['file']):
				continue
			if movie['lastplayed']:
				movie['last_played'] = utilities.sqlDateToUnixDate(movie['lastplayed'])
			movie['plays'] = movie.pop('playcount')
			movie['in_collection'] = True
			movie['imdb_id'] = ""
			movie['tmdb_id'] = ""
			id = movie['imdbnumber']
			if id.startswith("tt"):
				movie['imdb_id'] = id
			if id.isdigit():
				movie['tmdb_id'] = id
			del(movie['imdbnumber'])
			del(movie['lastplayed'])
			del(movie['label'])
			del(movie['file'])

			xbmc_movies.append(movie)

			i = i + 1
			y = ((i / x) * 4) + 1
			self.updateProgress(int(y))

		self.updateProgress(5, line2=utilities.getString(1461))

		return xbmc_movies

	def sanitizeMovieData(self, movie):
		data = copy.deepcopy(movie)
		if 'in_collection' in data:
			del(data['in_collection'])
		if 'movieid' in data:
			del(data['movieid'])
		if not data['tmdb_id']:
			del(data['tmdb_id'])
		return data

	def countMovies(self, movies, collection=True):
		if len(movies) > 0:
			if 'in_collection' in movies[0]:
				return len(utilities.findAllInList(movies, 'in_collection', collection))
			else:
				return len(movies)
		return 0

	def compareMovies(self, movies_col1, movies_col2, watched=False, restrict=False):
		movies = []
		for movie_col1 in movies_col1:
			movie_col2 = utilities.findMovie(movie_col1, movies_col2)
			if movie_col2:
				if watched:
					if (movie_col2['plays'] == 0) and (movie_col1['plays'] > movie_col2['plays']):
						if 'movieid' not in movie_col1:
							movie_col1['movieid'] = movie_col2['movieid']
						movies.append(movie_col1)
				else:
					if 'in_collection' in movie_col2 and not movie_col2['in_collection']:
						movies.append(movie_col1)
			else:
				if not restrict:
					if 'in_collection' in movie_col1 and movie_col1['in_collection']:
						if watched and (movie_col1['plays'] > 0):
							movies.append(movie_col1)
						elif not watched:
							movies.append(movie_col1)
		return movies

	def traktAddMovies(self, movies):
		if len(movies) == 0:
			self.updateProgress(40, line2=utilities.getString(1467))
			Debug("[Movies Sync] trakt.tv movie collection is up to date.")
			return

		titles = ", ".join(["%s (%s)" % (m['title'], m['imdb_id']) for m in movies])
		Debug("[Movies Sync] %i movie(s) will be added to trakt.tv collection." % len(movies))
		Debug("[Movies Sync] Movies added: %s" % titles)

		self.updateProgress(20, line2="%i %s" % (len(movies), utilities.getString(1426)))

		chunked_movies = utilities.chunks([self.sanitizeMovieData(movie) for movie in movies], 50)
		i = 0
		x = float(len(chunked_movies))
		for chunk in chunked_movies:
			if self.isCanceled():
				return
			params = {'movies': chunk}
			if self.simulate:
				Debug("[Movies Sync] %s" % str(params))
			else:
				self.traktapi.addMovie(params)

			i = i + 1
			y = ((i / x) * 20) + 20
			self.updateProgress(int(y), line2=utilities.getString(1477))

		self.updateProgress(40, line2=utilities.getString(1468) % len(movies))

	def traktRemoveMovies(self, movies):
		if len(movies) == 0:
			self.updateProgress(98, line2=utilities.getString(1474))
			Debug("[Movies Sync] trakt.tv movie collection is clean, no movies to remove.")
			return

		titles = ", ".join(["%s (%s)" % (m['title'], m['imdb_id']) for m in movies])
		Debug("[Movies Sync] %i movie(s) will be removed from trakt.tv collection." % len(movies))
		Debug("[Movies Sync] Movies removed: %s" % titles)

		self.updateProgress(80, line2="%i %s" % (len(movies), utilities.getString(1444)))

		chunked_movies = utilities.chunks([self.sanitizeMovieData(movie) for movie in movies], 50)
		i = 0
		x = float(len(chunked_movies))
		for chunk in chunked_movies:
			if self.isCanceled():
				return
			params = {'movies': chunk}
			if self.simulate:
				Debug("[Movies Sync] %s" % str(params))
			else:
				self.traktapi.removeMovie(params)

			i = i + 1
			y = ((i / x) * 20) + 80
			self.updateProgress(int(y), line2=utilities.getString(1476))

		self.updateProgress(98, line2=utilities.getString(1475) % len(movies))

	def traktUpdateMovies(self, movies):
		if len(movies) == 0:
			self.updateProgress(60, line2=utilities.getString(1469))
			Debug("[Movies Sync] trakt.tv movie playcount is up to date")
			return

		titles = ", ".join(["%s (%s)" % (m['title'], m['imdb_id']) for m in movies])
		Debug("[Movies Sync] %i movie(s) playcount will be updated on trakt.tv" % len(movies))
		Debug("[Movies Sync] Movies updated: %s" % titles)

		self.updateProgress(40, line2="%i %s" % (len(movies), utilities.getString(1428)))

		# Send request to update playcounts on trakt.tv
		chunked_movies = utilities.chunks([self.sanitizeMovieData(movie) for movie in movies], 50)
		i = 0
		x = float(len(chunked_movies))
		for chunk in chunked_movies:
			if self.isCanceled():
				return
			params = {'movies': chunk}
			if self.simulate:
				Debug("[Movies Sync] %s" % str(params))
			else:
				self.traktapi.updateSeenMovie(params)

			i = i + 1
			y = ((i / x) * 20) + 40
			self.updateProgress(int(y), line2=utilities.getString(1478))

		self.updateProgress(60, line2=utilities.getString(1470) % len(movies))

	def xbmcUpdateMovies(self, movies):
		if len(movies) == 0:
			self.updateProgress(80, line2=utilities.getString(1471))
			Debug("[Movies Sync] XBMC movie playcount is up to date.")
			return

		titles = ", ".join(["%s (%s)" % (m['title'], m['imdb_id']) for m in movies])
		Debug("[Movies Sync] %i movie(s) playcount will be updated in XBMC" % len(movies))
		Debug("[Movies Sync] Movies updated: %s" % titles)

		self.updateProgress(60, line2="%i %s" % (len(movies), utilities.getString(1430)))

		#split movie list into chunks of 50
		chunked_movies = utilities.chunks([{"jsonrpc": "2.0", "method": "VideoLibrary.SetMovieDetails", "params": {"movieid": movies[i]['movieid'], "playcount": movies[i]['plays']}, "id": i} for i in range(len(movies))], 50)
		i = 0
		x = float(len(chunked_movies))
		for chunk in chunked_movies:
			if self.isCanceled():
				return
			if self.simulate:
				Debug("[Movies Sync] %s" % str(chunk))
			else:
				utilities.xbmcJsonRequest(chunk)

			i = i + 1
			y = ((i / x) * 20) + 60
			self.updateProgress(int(y), line2=utilities.getString(1472))

		self.updateProgress(80, line2=utilities.getString(1473) % len(movies))

	def syncMovies(self):
		if not self.show_progress and self.sync_on_update and self.notify and self.notify_during_playback:
			notification('%s %s' % (utilities.getString(1400), utilities.getString(1402)), utilities.getString(1420)) #Sync started
		if self.show_progress and not self.run_silent:
			progress.create("%s %s" % (utilities.getString(1400), utilities.getString(1402)), line1=" ", line2=" ", line3=" ")

		xbmcMovies = self.xbmcLoadMovies()
		if not isinstance(xbmcMovies, list) and not xbmcMovies:
			Debug("[Movies Sync] XBMC movie list is empty, aborting movie Sync.")
			if self.show_progress and not self.run_silent:
				progress.close()
			return

		traktMovies = self.traktLoadMovies()
		if not isinstance(traktMovies, list):
			Debug("[Movies Sync] Error getting trakt.tv movie list, aborting movie Sync.")
			if self.show_progress and not self.run_silent:
				progress.close()
			return

		if utilities.getSettingAsBool('add_movies_to_trakt') and not self.isCanceled():
			traktMoviesToAdd = self.compareMovies(xbmcMovies, traktMovies)
			self.traktAddMovies(traktMoviesToAdd)

		if utilities.getSettingAsBool('trakt_movie_playcount') and not self.isCanceled():
			traktMoviesToUpdate = self.compareMovies(xbmcMovies, traktMovies, watched=True)
			self.traktUpdateMovies(traktMoviesToUpdate)

		if utilities.getSettingAsBool('xbmc_movie_playcount') and not self.isCanceled():
			xbmcMoviesToUpdate = self.compareMovies(traktMovies, xbmcMovies, watched=True, restrict=True)
			self.xbmcUpdateMovies(xbmcMoviesToUpdate)

		if utilities.getSettingAsBool('clean_trakt_movies') and not self.isCanceled():
			traktMoviesToRemove = self.compareMovies(traktMovies, xbmcMovies)
			self.traktRemoveMovies(traktMoviesToRemove)

		if not self.isCanceled() and self.show_progress and not self.run_silent:
			self.updateProgress(100, line1=utilities.getString(1431), line2=" ", line3=" ")
			progress.close()

		if not self.show_progress and self.sync_on_update and self.notify and self.notify_during_playback:
			notification('%s %s' % (utilities.getString(1400), utilities.getString(1402)), utilities.getString(1421)) #Sync complete

		Debug("[Movies Sync] Movies on trakt.tv (%d), movies in XBMC (%d)." % (len(traktMovies), self.countMovies(xbmcMovies)))
		Debug("[Movies Sync] Complete.")

	def syncCheck(self, media_type):
		if media_type == 'movies':
			return utilities.getSettingAsBool('add_movies_to_trakt') or utilities.getSettingAsBool('trakt_movie_playcount') or utilities.getSettingAsBool('xbmc_movie_playcount') or utilities.getSettingAsBool('clean_trakt_movies')
		else:
			return utilities.getSettingAsBool('add_episodes_to_trakt') or utilities.getSettingAsBool('trakt_episode_playcount') or utilities.getSettingAsBool('xbmc_episode_playcount') or utilities.getSettingAsBool('clean_trakt_episodes')

		return False

	def sync(self):
		Debug("[Sync] Starting synchronization with trakt.tv")

		if self.syncCheck('movies'):
			if self.library in ["all", "movies"]:
				self.syncMovies()
			else:
				Debug("[Sync] Movie sync is being skipped for this manual sync.")
		else:
			Debug("[Sync] Movie sync is disabled, skipping.")

		if self.syncCheck('episodes'):
			if self.library in ["all", "episodes"]:
				self.syncEpisodes()
			else:
				Debug("[Sync] Episode sync is being skipped for this manual sync.")
		else:
			Debug("[Sync] Episode sync is disabled, skipping.")

		Debug("[Sync] Finished synchronization with trakt.tv")


import unittest
import pickle

import sys
sys.path.append('..')
import spacerail.draw

class TestTopologyOutput(unittest.TestCase):

    def test_files(self):
        from os.path import isfile, join, dirname, abspath
        from os import listdir
        path = "./draw_cases"
        path = join(dirname(abspath(__file__)), path)
        tests = [f for f in listdir(path) if isfile(join(path, f)) and \
                f.endswith(".topo")]
        for x in tests:
            with self.subTest(filename=x):
                self.dofile(join(path,x))

    def dofile(self, f):
        def _round(x):
            return (int(round(10.0*x[0])), int(round(10.0*x[1])))

        with open(f) as fx:
            contents = fx.read()
        topo = spacerail.draw.DrawTopology._parse_topo(contents)
        topo.solve()
        lines = topo.lines()
        lineset = frozenset( (_round(a),_round(b)) for a,b in lines)
        print(lineset)

        with open(f+".output.pickle","wb") as fx:
            pickle.dump(lineset,fx)

        with open(f+".output.svg","w") as fx:
            fx.write(topo.svg())

        with open(f+".correct.pickle", 'rb') as fx:
            correct_lineset = pickle.load(fx)
            assert(lineset == correct_lineset)

if __name__ == '__main__':
    unittest.main()


###############################################
#
# Author: John Gordley
# Professor: Aniruddha Gokhale
# Vanderbilt University
#
# Purpose: Simple publisher script that comes and goes and does not perform is_ready
#
# Created: Spring 2023
#
###############################################

# import the needed packages
import time   # for sleep
import argparse  # for argument parsing
import configparser  # for configuration parsing
import logging  # for logging. Use it in place of print statements.
import random  # needed in the topic selection using random numbers
import sys
import atexit

# Import our topic selector. Feel free to use alternate way to
# get your topics of interest
from topic_selector import TopicSelector

# Now import our CS6381 Middleware
from CS6381_MW.ActivePublisherMW import PublisherMW

# import any other packages you need.

##################################
#       PublisherAppln class
##################################

class PublisherAppln ():

    ########################################
    # constructor
    ########################################
    def __init__(self, logger):
        self.iters = None   # number of iterations of publication
        self.name = None  # our name (some unique name)
        self.topiclist = None  # the different topics that we publish on
        self.lookup = None  # one of the diff ways we do lookup
        self.dissemination = None  # direct or via broker
        self.mw_obj = None  # handle to the underlying Middleware object
        self.logger = logger  # internal logger for print statements
        self.num_topics = None  # number of topics we want to publish

    ########################################
    # configure/initialize
    ########################################
    def configure(self, args):
        ''' Initialize the object '''

        try:
            # Here we initialize any internal variables
            self.logger.debug("PublisherAppln::configure")

            # initialize our variables
            self.name = args.name  # our name
            self.iters = args.iters  # num of iterations
            self.num_topics = args.num_topics

            # Now, get the configuration object
            self.logger.debug("PublisherAppln::configure - parsing config.ini")
            config = configparser.ConfigParser()
            config.read(args.config)
            self.lookup = config["Discovery"]["Strategy"]
            self.dissemination = config["Dissemination"]["Strategy"]

            # Now get our topic list of interest
            self.logger.debug("PublisherAppln::configure - selecting our topic list")
            ts = TopicSelector()
            self.topiclist = ts.interest(self.num_topics)

            # Now setup up our underlying middleware object to which we delegate
            # everything
            self.mw_obj = PublisherMW(self.logger, self.num_topics, self.lookup)

            # pass remainder of the args to the m/w object
            self.mw_obj.configure(args)

            atexit.register(self.mw_obj.clean_exit, self.name)

            self.logger.info(f"PublisherAppln - {self.name} configured with topics: {self.topiclist}")

        except Exception as e:
            raise e

    ########################################
    # driver program
    ########################################
    def driver(self):
        ''' Driver program '''

        try:
            self.logger.debug("PublisherAppln::driver")

            # dump our contents (debugging purposes)
            self.dump()

            # First ask our middleware to register ourselves with the discovery service
            self.logger.info(f"PublisherAppln - Attempting to register with Discovery service")
            result = self.mw_obj.register(self.name, self.topiclist)
            self.logger.info(f"PublisherAppln - Result of registration: {result}")
            if result != '1':
                self.logger.info(f"PublisherAppln - Failed to register. Exiting...")
                sys.exit(1)

            time.sleep(10)

            # Now disseminate
            ts = TopicSelector()
            for i in range(self.iters):
                # I leave it to you whether you want to disseminate all the topics of interest in
                # each iteration OR some subset of it. Please modify the logic accordingly.
                # Here, we choose to disseminate on all topics that we publish.  Also, we don't care
                # about their values. But in future assignments, this can change.
                for topic in self.topiclist:
                    # dissemination_data = topic + ":" + ts.gen_publication (topic)

                    self.mw_obj.disseminate(topic, ts.gen_publication(topic))

                    # time.sleep(random.randrange(1, 5))
                    time.sleep(2)

            self.logger.info(f"PublisherAppln - Dissemination complete after {self.iters} rounds")

            # Gracefully exit
            self.mw_obj.clean_exit(self.name)

        except Exception as e:
            raise e

    ########################################
    # dump the contents of the object
    ########################################
    def dump(self):
        ''' Pretty print '''

        try:
            self.logger.debug("**********************************")
            self.logger.debug("PublisherAppln::dump")
            self.logger.debug("------------------------------")
            self.logger.debug("     Name: {}".format(self.name))
            self.logger.debug("     Lookup: {}".format(self.lookup))
            self.logger.debug(
                "     Dissemination: {}".format(self.dissemination))
            self.logger.debug("     TopicList: {}".format(self.topiclist))
            self.logger.debug("     Iterations: {}".format(self.iters))
            self.logger.debug("**********************************")

        except Exception as e:
            raise e

###################################
#
# Parse command line arguments
#
###################################

def parseCmdLineArgs():
    # instantiate a ArgumentParser object
    parser = argparse.ArgumentParser(description="Publisher Application")

    # Now specify all the optional arguments we support
    # At a minimum, you will need a way to specify the IP and port of the lookup
    # service, the role we are playing, what dissemination approach are we
    # using, what is our endpoint (i.e., port where we are going to bind at the
    # ZMQ level)

    parser.add_argument("-n", "--name", required=True, default="pub",
                        help="Some name assigned to us. Keep it unique per publisher")

    parser.add_argument("-a", "--addr", required=True, default="localhost",
                        help="IP addr of this publisher to advertise (default: localhost)")

    parser.add_argument("-p", "--port", default="5577",
                        help="Port number on which our underlying publisher ZMQ service runs, default=5577")

    parser.add_argument("-d", "--discovery", required=True, default="localhost:5555",
                        help="IP Addr:Port combo for the discovery service, default localhost:5555")

    parser.add_argument("-t", "--num_topics", type=int, choices=range(1,
                        10), default=1, help="number of topics to select")

    parser.add_argument("-c", "--config", default="config.ini",
                        help="configuration file (default: config.ini)")

    parser.add_argument("-i", "--iters", type=int, default=1000,
                        help="number of publication iterations (default: 1000)")

    parser.add_argument("-l", "--loglevel", type=int, default=logging.INFO, choices=[
                        logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL], help="logging level, choices 10,20,30,40,50: default 10=logging.DEBUG")

    return parser.parse_args()

###################################
#
# Main program
#
###################################
def main():

    # obtain a system wide logger and initialize it to debug level to begin with
    logging.debug(
        "Main - acquire a child logger and then log messages in the child")
    logger = logging.getLogger("PubAppln")

    # first parse the arguments
    logger.debug("Main: parse command line arguments")
    args = parseCmdLineArgs()

    # reset the log level to as specified
    logger.debug("Main: resetting log level to {}".format(args.loglevel))
    logger.setLevel(args.loglevel)
    logger.debug("Main: effective log level is {}".format(
        logger.getEffectiveLevel()))

    # Obtain a publisher application
    logger.debug("Main: obtain the object")
    pub_app = PublisherAppln(logger)

    # configure the object
    pub_app.configure(args)

    # now invoke the driver program
    pub_app.driver()

###################################
#
# Main entry point
#
###################################
if __name__ == "__main__":

    # set underlying default logging capabilities
    logging.basicConfig(level=logging.INFO,
                        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')

    main()


import re
p,t = map(int, input().split(" "))
count = int(0)
for _ in range (p):
  pas = True
  for i in range (t):
    if re.search("([A-Z])", input()[1:]):
      pas = False
  if pas:
    count+=1
print(count)


from flask import g, jsonify, redirect, request, Response, abort
import pandas as pd
import json
from dateutil.parser import parse, ParserError

from .models import StationMap
from . import app

@app.errorhandler(400)
def custom400(error):
    response = jsonify({'message': error.description['message']})
    response.status_code = 400
    return response

@app.route("/healthz")
def healthz():
    return jsonify(success=True)

@app.route("/v1/locations")
def list_location():
    """Endpoint returning a list of Station
    ---
    responses:
      200:
        examples:
          ["Jurong East","Bukit Batok","Bukit Gombak","Choa Chu Kang"]
    """
    return jsonify(app.config['station_map'].get_location_list())

@app.route("/v1/route",methods=['POST'])
def find_route():
    """Endpoint returning route from source to destination
    ---
    parameters:
      - name: source
        in: formData
        type: string
        required: true
      - name: destination
        in: formData
        type: string
        required: true
    responses:
      200:
        description: route from source to destination
    """
    source = request.form.get('source')
    destination = request.form.get('destination')
    if not source or not destination:
        abort(400, {'message': 'Missing variables'})
    if len(app.config['station_map'].filter_by_station_name(source))==0:
        abort(404)
    if len(app.config['station_map'].filter_by_station_name(destination))==0:
        abort(404)
    route = app.config['station_map'].find_route_by_station_name(source, destination)
    result = {'number_station':len(route), 'route':route,'instruction':app.config['station_map'].get_instruction_from_route(route)}
    return jsonify(result)

@app.route("/v1/route/time",methods=['POST'])
def find_route_time_constraint():
    """Endpoint returning route from source to destination with time constraint
    ---
    parameters:
      - name: source
        in: formData
        type: string
        required: true
      - name: destination
        in: formData
        type: string
        required: true
      - name: start_time
        in: formData
        type: string
        required: true
    responses:
      200:
        description: route from source to destination
    """
    source = request.form.get('source')
    destination = request.form.get('destination')
    start_time = request.form.get('start_time')
    if not source or not destination or not start_time:
        abort(400, {'message': 'Missing variables'})
    if len(app.config['station_map'].filter_by_station_name(source))==0:
        abort(404)
    if len(app.config['station_map'].filter_by_station_name(destination))==0:
        abort(404)
    try:
      time_obj = parse(start_time)
    except (ParserError, TypeError, OverflowError) as e:
      abort(400, {'message': 'Startime: Wrong datetime format. It should be yyyy-mm-ddTHH:MM:SS+TZ or yyyy-mm-ddTHH:MM'})
    route, time = app.config['station_map'].find_route_with_time_constraint(source, destination, time_obj)
    if route is None:
      return jsonify({'time':time, 'route':[],
        'instruction':['Cannot find any path from given source and destination, some stations are not operation now']})
    result = {'time':time, 'number_station':len(route), 'route':route,'instruction':app.config['station_map'].get_instruction_from_route(route)}
    return jsonify(result)

if __name__ == '__main__':
    app.run(host="0.0.0.0",debug=True, port=8050)


from app.models.schema import ImportDevicesOut
from app.services.auth import get_admin_active_user, get_manager_active_user
from app.services.migration import (
    import_devices,
    import_workshop_events,
    import_factory_worker_infos,
)
from fastapi import APIRouter, Depends, File, Response, UploadFile, Form
from app.core.database import AuditActionEnum, User, AuditLogHeader
from fastapi.exceptions import HTTPException
from typing import List

router = APIRouter(prefix="/migration")

@router.post("/devices", tags=["migration"], status_code=201, response_model=ImportDevicesOut)
async def import_devices_from_excel(
    file: UploadFile = File(...),
    user: User = Depends(get_manager_active_user),
):
    if file.filename.split(".")[1] != "xlsx":
        raise HTTPException(415)

    try:
        device_ids, params = await import_devices(file)
        await AuditLogHeader.objects.create(
            table_name="devices",
            action=AuditActionEnum.DATA_IMPORT_SUCCEEDED.value,
            user=user,
        )
        return ImportDevicesOut(device_ids=device_ids, parameter=params.to_csv())
    except Exception as e:
        await AuditLogHeader.objects.create(
            table_name="devices",
            action=AuditActionEnum.DATA_IMPORT_FAILED.value,
            user=user,
            description="Import devices layout failed",
        )
        raise HTTPException(status_code=400, detail=repr(e))

@router.post("/workshop-eventbook", tags=["migration"], status_code=201,
    responses={
        201: {
            "content": {"image/csv": {}},
            "description": "Return parameters in csv format",
        },
        400: {"description": "There's is an error in your document."},
        415: {"description": "The file you uploaded is not in correct format.",},
    }
)
async def import_workshop_eventbooks_from_excel(
    file: UploadFile = File(...),
    # clear_all: bool = Form(default=False),
    user: User = Depends(get_manager_active_user),
):
    if file.filename.split(".")[1] != "xlsx" and file.filename.split(".")[1] != "xls":
        raise HTTPException(415)

    try:
        params = await import_workshop_events(file)
        return Response(
            content=params.to_csv(),
            status_code=201,
            media_type='text/csv'
        )
    except Exception as e:
        await AuditLogHeader.objects.create(
            table_name="categorypris",
            action=AuditActionEnum.DATA_IMPORT_FAILED.value,
            user=user,
            description="Import workshop eventbooks failed",
        )
        raise HTTPException(status_code=400, detail=repr(e))

@router.post("/factory-worker-infos", tags=["migration"], status_code=201,
    responses={
        201: {
            "content": {"image/csv": {}},
            "description": "Return parameters in csv format",
        },
        400: {"description": "There's is an error in your document."},
        415: {"description": "The file you uploaded is not in correct format.",},
    }
)
async def import_factory_worker_infos_from_excel(
    workshop_name: str = Form(default="第九車間", description="要匯入員工資訊的車間名稱"),
    file: UploadFile = File(...),
    user: User = Depends(get_manager_active_user),
):
    if file.filename.split(".")[1] != "xlsx":
        raise HTTPException(415)

    try:
        params = await import_factory_worker_infos(workshop_name, file)
        await AuditLogHeader.objects.create(
            table_name="users",
            action=AuditActionEnum.DATA_IMPORT_SUCCEEDED.value,
            user=user,
        )

        return Response(
            content=params.to_csv(),
            status_code=201,
            media_type='text/csv'
        )
    except Exception as e:
        await AuditLogHeader.objects.create(
            table_name="users",
            action=AuditActionEnum.DATA_IMPORT_FAILED.value,
            user=user,
        )
        raise e


#coding: utf-8
import math

import numpy as np

class WarpMLS:
    def __init__(self, src, src_pts, dst_pts, dst_w, dst_h, trans_ratio=1.):
        self.src = src
        self.src_pts = src_pts
        self.dst_pts = dst_pts
        self.pt_count = len(self.dst_pts)
        self.dst_w = dst_w
        self.dst_h = dst_h
        self.trans_ratio = trans_ratio
        self.grid_size = 100
        self.rdx = np.zeros((self.dst_h, self.dst_w))
        self.rdy = np.zeros((self.dst_h, self.dst_w))

    @staticmethod
    def __bilinear_interp(x, y, v11, v12, v21, v22):
        return (v11 * (1 - y) + v12 * y) * (1 - x) + (v21 * (1 - y) + v22 * y) * x

    def generate(self):
        self.calc_delta()
        return self.gen_img()

    def calc_delta(self):
        w = np.zeros(self.pt_count, dtype=np.float32)

        if self.pt_count < 2:
            return

        i = 0
        while 1:
            if self.dst_w <= i < self.dst_w + self.grid_size - 1:
                i = self.dst_w - 1
            elif i >= self.dst_w:
                break

            j = 0
            while 1:
                if self.dst_h <= j < self.dst_h + self.grid_size - 1:
                    j = self.dst_h - 1
                elif j >= self.dst_h:
                    break

                sw = 0
                swp = np.zeros(2, dtype=np.float32)
                swq = np.zeros(2, dtype=np.float32)
                new_pt = np.zeros(2, dtype=np.float32)
                cur_pt = np.array([i, j], dtype=np.float32)

                k = 0
                for k in range(self.pt_count):
                    if i == self.dst_pts[k][0] and j == self.dst_pts[k][1]:
                        break

                    w[k] = 1. / ((i - self.dst_pts[k][0]) * (i - self.dst_pts[k][0]) +
                                 (j - self.dst_pts[k][1]) * (j - self.dst_pts[k][1]))

                    sw += w[k]
                    swp = swp + w[k] * np.array(self.dst_pts[k])
                    swq = swq + w[k] * np.array(self.src_pts[k])

                if k == self.pt_count - 1:
                    pstar = 1 / sw * swp
                    qstar = 1 / sw * swq

                    miu_s = 0
                    for k in range(self.pt_count):
                        if i == self.dst_pts[k][0] and j == self.dst_pts[k][1]:
                            continue
                        pt_i = self.dst_pts[k] - pstar
                        miu_s += w[k] * np.sum(pt_i * pt_i)

                    cur_pt -= pstar
                    cur_pt_j = np.array([-cur_pt[1], cur_pt[0]])

                    for k in range(self.pt_count):
                        if i == self.dst_pts[k][0] and j == self.dst_pts[k][1]:
                            continue

                        pt_i = self.dst_pts[k] - pstar
                        pt_j = np.array([-pt_i[1], pt_i[0]])

                        tmp_pt = np.zeros(2, dtype=np.float32)
                        tmp_pt[0] = np.sum(pt_i * cur_pt) * self.src_pts[k][0] - \
                                    np.sum(pt_j * cur_pt) * self.src_pts[k][1]
                        tmp_pt[1] = -np.sum(pt_i * cur_pt_j) * self.src_pts[k][0] + \
                                    np.sum(pt_j * cur_pt_j) * self.src_pts[k][1]
                        tmp_pt *= (w[k] / miu_s)
                        new_pt += tmp_pt

                    new_pt += qstar
                else:
                    new_pt = self.src_pts[k]

                self.rdx[j, i] = new_pt[0] - i
                self.rdy[j, i] = new_pt[1] - j

                j += self.grid_size
            i += self.grid_size

    def gen_img(self):
        src_h, src_w = self.src.shape[:2]
        dst = np.zeros_like(self.src, dtype=np.float32)

        for i in np.arange(0, self.dst_h, self.grid_size):
            for j in np.arange(0, self.dst_w, self.grid_size):
                ni = i + self.grid_size
                nj = j + self.grid_size
                w = h = self.grid_size
                if ni >= self.dst_h:
                    ni = self.dst_h - 1
                    h = ni - i + 1
                if nj >= self.dst_w:
                    nj = self.dst_w - 1
                    w = nj - j + 1

                di = np.reshape(np.arange(h), (-1, 1))
                dj = np.reshape(np.arange(w), (1, -1))
                delta_x = self.__bilinear_interp(di / h, dj / w,
                                                 self.rdx[i, j], self.rdx[i, nj],
                                                 self.rdx[ni, j], self.rdx[ni, nj])
                delta_y = self.__bilinear_interp(di / h, dj / w,
                                                 self.rdy[i, j], self.rdy[i, nj],
                                                 self.rdy[ni, j], self.rdy[ni, nj])
                nx = j + dj + delta_x * self.trans_ratio
                ny = i + di + delta_y * self.trans_ratio
                nx = np.clip(nx, 0, src_w - 1)
                ny = np.clip(ny, 0, src_h - 1)
                nxi = np.array(np.floor(nx), dtype=np.int32)
                nyi = np.array(np.floor(ny), dtype=np.int32)
                nxi1 = np.array(np.ceil(nx), dtype=np.int32)
                nyi1 = np.array(np.ceil(ny), dtype=np.int32)

                dst[i:i + h, j:j + w] = self.__bilinear_interp(np.tile(np.expand_dims(ny - nyi, axis=-1), (1, 1, 3)),
                                                               np.tile(np.expand_dims(nx - nxi, axis=-1), (1, 1, 3)),
                                                               self.src[nyi, nxi],
                                                               self.src[nyi, nxi1],
                                                               self.src[nyi1, nxi],
                                                               self.src[nyi1, nxi1]
                                                               )

                # for di in range(h):
                #     for dj in range(w):
                #         # print(ni, nj, i, j)
                #         delta_x = self.__bilinear_interp(di / h, dj / w, self.rdx[i, j], self.rdx[i, nj],
                #                                          self.rdx[ni, j], self.rdx[ni, nj])
                #         delta_y = self.__bilinear_interp(di / h, dj / w, self.rdy[i, j], self.rdy[i, nj],
                #                                          self.rdy[ni, j], self.rdy[ni, nj])
                #         nx = j + dj + delta_x * self.trans_ratio
                #         ny = i + di + delta_y * self.trans_ratio
                #         nx = min(src_w - 1, max(0, nx))
                #         ny = min(src_h - 1, max(0, ny))
                #         nxi = int(nx)
                #         nyi = int(ny)
                #         nxi1 = math.ceil(nx)
                #         nyi1 = math.ceil(ny)
                #
                #         dst[i + di, j + dj] = self.__bilinear_interp(ny - nyi, nx - nxi,
                #                                                      self.src[nyi, nxi],
                #                                                      self.src[nyi, nxi1],
                #                                                      self.src[nyi1, nxi],
                #                                                      self.src[nyi1, nxi1]
                #                                                      )

        dst = np.clip(dst, 0, 255)
        dst = np.array(dst, dtype=np.uint8)

        return dst

def distort(src, segment):
    img_h, img_w = src.shape[:2]

    cut = img_w // segment
    thresh = cut // 3
    # thresh = img_h // segment // 3
    # thresh = img_h // 5

    src_pts = list()
    dst_pts = list()

    src_pts.append([0, 0])
    src_pts.append([img_w, 0])
    src_pts.append([img_w, img_h])
    src_pts.append([0, img_h])

    dst_pts.append([np.random.randint(thresh), np.random.randint(thresh)])
    dst_pts.append([img_w - np.random.randint(thresh), np.random.randint(thresh)])
    dst_pts.append([img_w - np.random.randint(thresh), img_h - np.random.randint(thresh)])
    dst_pts.append([np.random.randint(thresh), img_h - np.random.randint(thresh)])

    half_thresh = thresh * 0.5

    for cut_idx in np.arange(1, segment, 1):
        src_pts.append([cut * cut_idx, 0])
        src_pts.append([cut * cut_idx, img_h])
        dst_pts.append([cut * cut_idx + np.random.randint(thresh) - half_thresh,
                        np.random.randint(thresh) - half_thresh])
        dst_pts.append([cut * cut_idx + np.random.randint(thresh) - half_thresh,
                        img_h + np.random.randint(thresh) - half_thresh])

    trans = WarpMLS(src, src_pts, dst_pts, img_w, img_h)
    dst = trans.generate()

    return dst

def stretch(src, segment):
    img_h, img_w = src.shape[:2]

    cut = img_w // segment
    thresh = cut * 4 // 5
    # thresh = img_h // segment // 3
    # thresh = img_h // 5

    src_pts = list()
    dst_pts = list()

    src_pts.append([0, 0])
    src_pts.append([img_w, 0])
    src_pts.append([img_w, img_h])
    src_pts.append([0, img_h])

    dst_pts.append([0, 0])
    dst_pts.append([img_w, 0])
    dst_pts.append([img_w, img_h])
    dst_pts.append([0, img_h])

    half_thresh = thresh * 0.5

    for cut_idx in np.arange(1, segment, 1):
        move = np.random.randint(thresh) - half_thresh
        src_pts.append([cut * cut_idx, 0])
        src_pts.append([cut * cut_idx, img_h])
        dst_pts.append([cut * cut_idx + move, 0])
        dst_pts.append([cut * cut_idx + move, img_h])

    trans = WarpMLS(src, src_pts, dst_pts, img_w, img_h)
    dst = trans.generate()

    return dst

def perspective(src):
    img_h, img_w = src.shape[:2]

    thresh = img_h // 2

    src_pts = list()
    dst_pts = list()

    src_pts.append([0, 0])
    src_pts.append([img_w, 0])
    src_pts.append([img_w, img_h])
    src_pts.append([0, img_h])

    dst_pts.append([0, np.random.randint(thresh)])
    dst_pts.append([img_w, np.random.randint(thresh)])
    dst_pts.append([img_w, img_h - np.random.randint(thresh)])
    dst_pts.append([0, img_h - np.random.randint(thresh)])

    trans = WarpMLS(src, src_pts, dst_pts, img_w, img_h)
    dst = trans.generate()

    return dst

# def distort(src, segment):
#     img_h, img_w = src.shape[:2]
#     dst = np.zeros_like(src, dtype=np.uint8)
#
#     cut = img_w // segment
#     thresh = img_h // 8
#
#     src_pts = list()
#     # dst_pts = list()
#
#     src_pts.append([-np.random.randint(thresh), -np.random.randint(thresh)])
#     src_pts.append([-np.random.randint(thresh), img_h + np.random.randint(thresh)])
#
#     # dst_pts.append([0, 0])
#     # dst_pts.append([0, img_h])
#     dst_box = np.array([[0, 0], [0, img_h], [cut, 0], [cut, img_h]], dtype=np.float32)
#
#     half_thresh = thresh * 0.5
#
#     for cut_idx in np.arange(1, segment, 1):
#         src_pts.append([cut * cut_idx + np.random.randint(thresh) - half_thresh,
#                         np.random.randint(thresh) - half_thresh])
#         src_pts.append([cut * cut_idx + np.random.randint(thresh) - half_thresh,
#                         img_h + np.random.randint(thresh) - half_thresh])
#
#         # dst_pts.append([cut * i, 0])
#         # dst_pts.append([cut * i, img_h])
#
#         src_box = np.array(src_pts[-4:-2] + src_pts[-2:-1] + src_pts[-1:], dtype=np.float32)
#
#         # mat = cv2.getPerspectiveTransform(src_box, dst_box)
#         # print(mat)
#         # dst[:, cut * (cut_idx - 1):cut * cut_idx] = cv2.warpPerspective(src, mat, (cut, img_h))
#
#         mat = get_perspective_transform(dst_box, src_box)
#         dst[:, cut * (cut_idx - 1):cut * cut_idx] = warp_perspective(src, mat, (cut, img_h))
#         # print(mat)
#
#     src_pts.append([img_w + np.random.randint(thresh) - half_thresh,
#                     np.random.randint(thresh) - half_thresh])
#     src_pts.append([img_w + np.random.randint(thresh) - half_thresh,
#                     img_h + np.random.randint(thresh) - half_thresh])
#     src_box = np.array(src_pts[-4:-2] + src_pts[-2:-1] + src_pts[-1:], dtype=np.float32)
#
#     # mat = cv2.getPerspectiveTransform(src_box, dst_box)
#     # dst[:, cut * (segment - 1):] = cv2.warpPerspective(src, mat, (img_w - cut * (segment - 1), img_h))
#     mat = get_perspective_transform(dst_box, src_box)
#     dst[:, cut * (segment - 1):] = warp_perspective(src, mat, (img_w - cut * (segment - 1), img_h))
#
#     return dst


# It is difficult to invoke the Python coverage tool externally with Jython, so
# it is being invoked internally here:
from __future__ import division
import net.grinder.script.Grinder

package_path = net.grinder.script.Grinder.grinder.getProperties().getProperty(
    "grinder.package_path")
import sys

sys.path.append(package_path)
from coverage import coverage

cov = coverage()
cov.start()

import time
import utils
import ingest
import ingestenum
import query
import annotationsingest
import unittest
import random
import math
import grinder

try:
    from com.xhaus.jyson import JysonCodec as json
except ImportError:
    import json
import pprint

pp = pprint.pprint
sleep_time = -1
get_url = None
post_url = None
post_payload = None

def mock_sleep(cls, x):
    global sleep_time
    sleep_time = x

class MockReq():
    def POST(self, url, payload):
        global post_url, post_payload
        post_url = url
        post_payload = payload
        return url, payload

    def GET(self, url):
        global get_url
        get_url = url
        return url

class BluefloodTests(unittest.TestCase):
    def setUp(self):
        self.real_shuffle = random.shuffle
        self.real_randint = random.randint
        self.real_time = utils.AbstractThread.time
        self.real_sleep = utils.AbstractThread.sleep
        self.tm = ingest.ThreadManager(net.grinder.script.Grinder.grinder)
        req = MockReq()
        ingest.IngestThread.request = req
        ingestenum.EnumIngestThread.request = req
        annotationsingest.AnnotationsIngestThread.request = req
        for x in query.QueryThread.query_types:
            x.query_request = req
        random.shuffle = lambda x: None
        random.randint = lambda x, y: 0
        utils.AbstractThread.time = lambda x: 1000
        utils.AbstractThread.sleep = mock_sleep

        test_config = {'report_interval': (1000 * 6),
                       'num_tenants': 3,
                       'enum_num_tenants': 4,
                       'annotations_num_tenants': 3,
                       'metrics_per_tenant': 7,
                       'enum_metrics_per_tenant': 2,
                       'annotations_per_tenant': 2,
                       'batch_size': 3,
                       'ingest_concurrency': 2,
                       'enum_ingest_concurrency': 2,
                       'query_concurrency': 20,
                       'annotations_concurrency': 2,
                       'singleplot_per_interval': 11,
                       'multiplot_per_interval': 10,
                       'search_queries_per_interval': 9,
                       'enum_search_queries_per_interval': 9,
                       'enum_single_plot_queries_per_interval': 10,
                       'enum_multiplot_per_interval': 10,
                       'annotations_queries_per_interval': 8,
                       'name_fmt': "int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.%d",
                       'num_nodes': 2}

        ingest.default_config.update(test_config)

    def test_init_process(self):
        # confirm that threadnum 0 is an ingest thread
        t1 = self.tm.setup_thread(0)
        self.assertEqual(type(t1), ingest.IngestThread)

        # confirm that the threadnum after all ingest threads is
        # EnumIngestThread
        t1 = self.tm.setup_thread(
            ingestenum.default_config['enum_ingest_concurrency'])
        self.assertEqual(type(t1), ingestenum.EnumIngestThread)

        # confirm that the threadnum after all ingest threads is a query thread
        t1 = self.tm.setup_thread(ingest.default_config['ingest_concurrency'] +
                                  ingestenum.default_config[
                                      'enum_ingest_concurrency'])
        self.assertEqual(type(t1), query.QueryThread)

        # confirm that the threadnum after all ingest+query threads is an
        # annotations query thread
        t1 = self.tm.setup_thread(ingest.default_config['ingest_concurrency'] +
                                  ingestenum.default_config[
                                      'enum_ingest_concurrency'] +
                                  ingest.default_config['query_concurrency'])
        self.assertEqual(type(t1), annotationsingest.AnnotationsIngestThread)

        # confirm that a threadnum after all valid thread types raises an
        # exception
        tot_threads = (
            ingest.default_config['ingest_concurrency'] +
            ingest.default_config['enum_ingest_concurrency'] +
            ingest.default_config['query_concurrency'] +
            ingest.default_config['annotations_concurrency'])
        self.assertRaises(Exception, self.tm.setup_thread, tot_threads)

        # confirm that the correct batches of ingest metrics are created for
        # worker 0
        self.tm.create_all_metrics(0)

        # confirm annotationsingest
        self.assertEqual(annotationsingest.AnnotationsIngestThread.annotations,
                         [[0, 0], [0, 1], [1, 0], [1, 1]])

        thread = annotationsingest.AnnotationsIngestThread(0)
        self.assertEqual(thread.slice, [[0, 0], [0, 1]])

        thread = annotationsingest.AnnotationsIngestThread(1)
        self.assertEqual(thread.slice, [[1, 0], [1, 1]])

        # confirm enum metrics ingest
        self.assertEqual(ingestenum.EnumIngestThread.metrics,
                         [
                             [[0, 0], [0, 1], [1, 0]],
                             [[1, 1]]
                         ])

        thread = ingestenum.EnumIngestThread(0)
        self.assertEqual(thread.slice, [[[0, 0], [0, 1], [1, 0]]])

        thread = ingestenum.EnumIngestThread(1)
        self.assertEqual(thread.slice, [[[1, 1]]])

        # confirm metrics ingest
        self.assertEqual(ingest.IngestThread.metrics,
                         [[[0, 0], [0, 1], [0, 2]],
                          [[0, 3], [0, 4], [0, 5]],
                          [[0, 6], [1, 0], [1, 1]],
                          [[1, 2], [1, 3], [1, 4]],
                          [[1, 5], [1, 6]]])

        # confirm that the correct batch slices are created for individual
        # threads
        thread = ingest.IngestThread(0)
        self.assertEqual(thread.slice,
                         [[[0, 0], [0, 1], [0, 2]],
                          [[0, 3], [0, 4], [0, 5]],
                          [[0, 6], [1, 0], [1, 1]]])
        thread = ingest.IngestThread(1)
        self.assertEqual(thread.slice,
                         [[[1, 2], [1, 3], [1, 4]],
                          [[1, 5], [1, 6]]])

        # confirm that the number of queries is correctly distributed across
        #  each thread in this worker process

        num_query_nodes = query.default_config['num_nodes']
        single_plot_queries_agent0 = int(math.ceil(
            query.default_config['singleplot_per_interval'] / num_query_nodes))
        multi_plot_queries_agent0 = int(math.ceil(
            query.default_config['multiplot_per_interval'] / num_query_nodes))
        search_queries_agent0 = int(math.ceil(
            query.default_config[
                'search_queries_per_interval'] / num_query_nodes))
        enum_search_queries_agent0 = int(math.ceil(
            query.default_config[
                'enum_search_queries_per_interval'] / num_query_nodes))
        enum_single_plot_queries_agent0 = int(math.ceil(
            query.default_config[
                'enum_single_plot_queries_per_interval'] / num_query_nodes))
        enum_multi_plot_queries_agent0 = int(math.ceil(
            query.default_config[
                'enum_multiplot_per_interval'] / num_query_nodes))
        annotation_queries_agent0 = int(math.ceil(
            query.default_config[
                'annotations_queries_per_interval'] / num_query_nodes))

        self.assertEqual(
            query.QueryThread.queries,
            ([query.SinglePlotQuery] * single_plot_queries_agent0 +
             [query.MultiPlotQuery] * multi_plot_queries_agent0 +
             [query.SearchQuery] * search_queries_agent0 +
             [query.EnumSearchQuery] * enum_search_queries_agent0 +
             [query.EnumSinglePlotQuery] * enum_single_plot_queries_agent0 +
             [query.AnnotationsQuery] * annotation_queries_agent0) +
            [query.EnumMultiPlotQuery] * enum_multi_plot_queries_agent0)

        thread = query.QueryThread(0)
        self.assertEqual(thread.slice, [query.SinglePlotQuery] * 2)

        thread = query.QueryThread(3)
        self.assertEqual(thread.slice, [query.MultiPlotQuery] * 2)

        thread = query.QueryThread(6)
        self.assertEqual(thread.slice, [query.SearchQuery] * 2)

        thread = query.QueryThread(9)
        self.assertEqual(thread.slice, [query.EnumSearchQuery] * 2)

        thread = query.QueryThread(12)
        self.assertEqual(thread.slice, [query.EnumSinglePlotQuery] * 2)

        thread = query.QueryThread(14)
        self.assertEqual(thread.slice, [query.AnnotationsQuery] * 2)

        thread = query.QueryThread(16)
        self.assertEqual(thread.slice, [query.EnumMultiPlotQuery] * 1)

        # confirm that the correct batches of ingest metrics are created for
        # worker 1
        self.tm.create_all_metrics(1)
        self.assertEqual(ingest.IngestThread.metrics,
                         [[[2, 0], [2, 1], [2, 2]],
                          [[2, 3], [2, 4], [2, 5]],
                          [[2, 6]]])

        self.assertEqual(annotationsingest.AnnotationsIngestThread.annotations,
                         [[2, 0], [2, 1]])

        thread = ingest.IngestThread(0)
        self.assertEqual(thread.slice,
                         [[[2, 0], [2, 1], [2, 2]],
                          [[2, 3], [2, 4], [2, 5]]])
        thread = ingest.IngestThread(1)
        self.assertEqual(thread.slice,
                         [[[2, 6]]])

        # confirm that the correct batches of queries are created for worker 1
        single_plot_queries_agent1 = \
            query.default_config['singleplot_per_interval'] - \
            single_plot_queries_agent0
        multi_plot_queries_agent1 = \
            query.default_config['multiplot_per_interval'] - \
            multi_plot_queries_agent0
        search_queries_agent1 = \
            query.default_config['search_queries_per_interval'] - \
            search_queries_agent0
        enum_search_queries_agent1 = \
            query.default_config['enum_search_queries_per_interval'] - \
            enum_search_queries_agent0
        enum_single_plot_queries_agent1 = \
            query.default_config['enum_single_plot_queries_per_interval'] - \
            enum_single_plot_queries_agent0
        annotation_queries_agent1 = \
            query.default_config['annotations_queries_per_interval'] - \
            annotation_queries_agent0
        enum_multi_plot_queries_agent1 = \
            query.default_config['enum_multiplot_per_interval'] - \
            enum_multi_plot_queries_agent0

        self.assertEqual(
            query.QueryThread.queries,
            ([query.SinglePlotQuery] * single_plot_queries_agent1 +
             [query.MultiPlotQuery] * multi_plot_queries_agent1 +
             [query.SearchQuery] * search_queries_agent1 +
             [query.EnumSearchQuery] * enum_search_queries_agent1 +
             [query.EnumSinglePlotQuery] * enum_single_plot_queries_agent1 +
             [query.AnnotationsQuery] * annotation_queries_agent1) +
            [query.EnumMultiPlotQuery] * enum_multi_plot_queries_agent1)

        thread = query.QueryThread(0)
        self.assertEqual(thread.slice, [query.SinglePlotQuery] * 2)

        thread = query.QueryThread(4)
        self.assertEqual(thread.slice, [query.MultiPlotQuery] * 2)

        thread = query.QueryThread(6)
        self.assertEqual(thread.slice, [query.SearchQuery] * 2)

        thread = query.QueryThread(8)
        self.assertEqual(thread.slice, [query.EnumSearchQuery] * 2)

        thread = query.QueryThread(10)
        self.assertEqual(thread.slice, [query.EnumSinglePlotQuery] * 2)

        thread = query.QueryThread(12)
        self.assertEqual(thread.slice, [query.AnnotationsQuery] * 1)

        thread = query.QueryThread(16)
        self.assertEqual(thread.slice, [query.EnumMultiPlotQuery] * 1)

    def test_generate_payload(self):
        self.tm.create_all_metrics(1)
        thread = ingest.IngestThread(0)
        payload = json.loads(
            thread.generate_payload(0, [[2, 3], [2, 4], [2, 5]]))
        valid_payload = [{u'collectionTime': 0,
                          u'metricName': u'int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.3',
                          u'metricValue': 0,
                          u'tenantId': u'2',
                          u'ttlInSeconds': 172800,
                          u'unit': u'days'},
                         {u'collectionTime': 0,
                          u'metricName': u'int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.4',
                          u'metricValue': 0,
                          u'tenantId': u'2',
                          u'ttlInSeconds': 172800,
                          u'unit': u'days'},
                         {u'collectionTime': 0,
                          u'metricName': u'int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.5',
                          u'metricValue': 0,
                          u'tenantId': u'2',
                          u'ttlInSeconds': 172800,
                          u'unit': u'days'}]
        self.assertEqual(payload, valid_payload)

    def test_generate_enum_payload(self):
        self.tm.create_all_metrics(1)
        thread = ingestenum.EnumIngestThread(0)
        payload = json.loads(thread.generate_payload(1, [[2, 1], [2, 2]]))
        valid_payload = [{u'timestamp': 1,
                          u'tenantId': u'2',
                          u'enums': [{u'value': u'e_g_1_0',
                                      u'name': utils.generate_enum_metric_name(
                                          1)}]},
                         {u'timestamp': 1,
                          u'tenantId': u'2',
                          u'enums': [{u'value': u'e_g_2_0',
                                      u'name': utils.generate_enum_metric_name(
                                          2)}]}
                         ]
        self.assertEqual(payload, valid_payload)

    def test_generate_annotations_payload(self):
        self.tm.create_all_metrics(1)
        thread = annotationsingest.AnnotationsIngestThread(0)
        payload = json.loads(thread.generate_payload(0, 3))
        valid_payload = {
            'what': 'annotation int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.3',
            'when': 0,
            'tags': 'tag',
            'data': 'data'}
        self.assertEqual(payload, valid_payload)

    def test_annotationsingest_make_request(self):
        global sleep_time
        thread = annotationsingest.AnnotationsIngestThread(0)
        thread.slice = [[2, 0]]
        thread.position = 0
        thread.finish_time = 10000
        valid_payload = {
            "what": "annotation int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.0",
            "when": 1000, "tags": "tag", "data": "data"}

        url, payload = thread.make_request(pp)
        # confirm request generates proper URL and payload
        self.assertEqual(
            url,
            'http://qe01.metrics-ingest.api.rackspacecloud.com/v2.0/2/events')
        self.assertEqual(eval(payload), valid_payload)

        # confirm request increments position if not at end of report interval
        self.assertEqual(thread.position, 1)
        self.assertEqual(thread.finish_time, 10000)
        thread.position = 2
        thread.make_request(pp)

        # confirm request resets position at end of report interval
        self.assertEqual(sleep_time, 9000)
        self.assertEqual(thread.position, 1)
        self.assertEqual(thread.finish_time, 16000)

    def test_ingest_make_request(self):
        global sleep_time
        thread = ingest.IngestThread(0)
        thread.slice = [[[2, 0], [2, 1]]]
        thread.position = 0
        thread.finish_time = 10000
        valid_payload = [
            {"collectionTime": 1000, "ttlInSeconds": 172800, "tenantId": "2",
             "metricValue": 0, "unit": "days",
             "metricName": "int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.0"},
            {"collectionTime": 1000, "ttlInSeconds": 172800, "tenantId": "2",
             "metricValue": 0, "unit": "days",
             "metricName": "int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.1"}]

        url, payload = thread.make_request(pp)
        # confirm request generates proper URL and payload
        self.assertEqual(url,
                         'http://qe01.metrics-ingest.api.rackspacecloud.com/v2.0/tenantId/ingest/multi')
        self.assertEqual(eval(payload), valid_payload)

        # confirm request increments position if not at end of report interval
        self.assertEqual(thread.position, 1)
        self.assertEqual(thread.finish_time, 10000)
        thread.position = 2
        thread.make_request(pp)
        # confirm request resets position at end of report interval
        self.assertEqual(sleep_time, 9000)
        self.assertEqual(thread.position, 1)
        self.assertEqual(thread.finish_time, 16000)

    def test_ingest_enum_make_request(self):
        global sleep_time
        thread = ingestenum.EnumIngestThread(0)
        thread.slice = [[[2, 0], [2, 1]]]
        thread.position = 0
        thread.finish_time = 10000
        valid_payload = [{'tenantId': '2', 'timestamp': 1000, 'enums': [
            {'value': 'e_g_0_0', 'name': utils.generate_enum_metric_name(0)}]},
                         {'tenantId': '2', 'timestamp': 1000, 'enums': [
                             {'value': 'e_g_1_0',
                              'name': utils.generate_enum_metric_name(1)}]}]

        url, payload = thread.make_request(pp)
        # confirm request generates proper URL and payload
        self.assertEqual(url,
                         'http://qe01.metrics-ingest.api.rackspacecloud.com/v2.0/tenantId/ingest/aggregated/multi')
        self.assertEqual(eval(payload), valid_payload)

        # confirm request increments position if not at end of report interval
        self.assertEqual(thread.position, 1)
        self.assertEqual(thread.finish_time, 10000)
        thread.position = 2
        thread.make_request(pp)
        # confirm request resets position at end of report interval
        self.assertEqual(sleep_time, 9000)
        self.assertEqual(thread.position, 1)
        self.assertEqual(thread.finish_time, 16000)

    def test_query_make_request(self):
        thread = query.QueryThread(0)
        thread.slice = [query.SinglePlotQuery, query.SearchQuery,
                        query.MultiPlotQuery, query.AnnotationsQuery,
                        query.EnumSearchQuery, query.EnumSinglePlotQuery,
                        query.EnumMultiPlotQuery]
        thread.position = 0
        thread.make_request(pp)
        self.assertEqual(get_url,
                         "http://qe01.metrics.api.rackspacecloud.com/v2.0/0/views/int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.0?from=-86399000&to=1000&resolution=FULL")

        random.randint = lambda x, y: 10
        thread.make_request(pp)
        self.assertEqual(get_url,
                         "http://qe01.metrics.api.rackspacecloud.com/v2.0/10/metrics/search?query=int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.*")

        random.randint = lambda x, y: 20
        thread.make_request(pp)
        self.assertEqual(post_url,
                         "http://qe01.metrics.api.rackspacecloud.com/v2.0/20/views?from=-86399000&to=1000&resolution=FULL")
        self.assertEqual(eval(post_payload), [
            "int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.0",
            "int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.1",
            "int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.2",
            "int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.3",
            "int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.4",
            "int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.5",
            "int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.6",
            "int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.7",
            "int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.8",
            "int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.9"])

        random.randint = lambda x, y: 30
        thread.make_request(pp)
        self.assertEqual(get_url,
                         "http://qe01.metrics.api.rackspacecloud.com/v2.0/30/events/getEvents?from=-86399000&until=1000")

        random.randint = lambda x, y: 40
        thread.make_request(pp)
        self.assertEqual(get_url,
                         "http://qe01.metrics.api.rackspacecloud.com/v2.0/40/metrics/search?query=enum_grinder_int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.*&include_enum_values=true")

        random.randint = lambda x, y: 50
        thread.make_request(pp)
        self.assertEqual(get_url,
                         "http://qe01.metrics.api.rackspacecloud.com/v2.0/50/views/enum_grinder_int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.50?from=-86399000&to=1000&resolution=FULL")

        random.randint = lambda x, y: 4
        thread.make_request(pp)
        self.assertEqual(post_url,
                         "http://qe01.metrics.api.rackspacecloud.com/v2.0/4/views?from=-86399000&to=1000&resolution=FULL")
        self.assertEqual(eval(post_payload), [
            "enum_grinder_int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.0",
            "enum_grinder_int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.1",
            "enum_grinder_int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.2",
            "enum_grinder_int.abcdefg.hijklmnop.qrstuvw.xyz.ABCDEFG.HIJKLMNOP.QRSTUVW.XYZ.abcdefg.hijklmnop.qrstuvw.xyz.met.3"])

    def tearDown(self):
        random.shuffle = self.real_shuffle
        random.randint = self.real_randint
        utils.AbstractThread.time = self.real_time
        utils.AbstractThread.sleep = self.real_sleep

# if __name__ == '__main__':
unittest.TextTestRunner().run(
    unittest.TestLoader().loadTestsFromTestCase(BluefloodTests))

cov.stop()
cov.save()

class TestRunner:
    def __init__(self):
        pass

    def __call__(self):
        pass


import numpy as np
import os
import warnings
from skimage.io import imread
from skimage.transform import resize
from pylibdl.data import Dataset, DataLoader
from pylibdl.modules import *
import random

warnings.filterwarnings('ignore')

def validate(model, val_data, batch_size=128):
    val_loader = DataLoader(val_data, batch_size, shuffle=False, drop_last=False)
    is_train = model.is_train
    model.eval()
    accs = []
    with libdl.no_grad():
        for imgs, labels in val_loader:
            pred = model(imgs)
            accs.append((np.argmax(pred.data, axis=0) == np.argmax(labels.data, axis=0)).mean())
    model.train(is_train)
    return np.mean(accs)

class DistractedDriver(Dataset):

    label_names = [
        'safe driving',
        'texting - right',
        'talking on the phone - right',
        'texting - left',
        'talking on the phone - left',
        'operating the radio',
        'drinking',
        'reaching behind',
        'hair and makeup',
        'talking to passenger'
    ]

    mean = np.array([0.3142706, 0.3803778, 0.37310703]).reshape((3, 1, 1))
    std = np.array([0.29078071, 0.33230701, 0.33428186]).reshape((3, 1, 1))

    @staticmethod
    def preprocess_data(path):
        random.seed(0)
        files = [[] for _ in range(10)]
        with open(os.path.join(path, 'driver_imgs_list.csv')) as f:
            f.readline()
            for l in f.readlines():
                l = l.split(',')
                n = l[2].strip('\n')  # filename
                c = int(l[1][1:])  # class
                files[c].append((n, c))

        for f in files:
            random.shuffle(f)

        val = [i for f in files for i in f[:128]]
        train = [i for f in files for i in f[128:]]

        with open(os.path.join(path, 'lval'), 'wb') as f:
            pickle.dump(val, f)
        with open(os.path.join(path, 'ltrain'), 'wb') as f:
            pickle.dump(train, f)

    def __init__(self, path, val=False, size=(128, 128)):

        if not os.path.exists(os.path.join(path, 'lval')):
            DistractedDriver.preprocess_data(path)

        with open(os.path.join(path, 'lval' if val else 'ltrain'), 'rb') as f:
            self.data = pickle.load(f)

        self.path = path
        self.size = size

    @staticmethod
    def normalize(x):
        return (x - DistractedDriver.mean) / DistractedDriver.std

    @staticmethod
    def denormalize(x):
        return x * DistractedDriver.std + DistractedDriver.mean

    def __getitem__(self, i):
        n, c = self.data[i]
        img = imread(os.path.join(self.path, 'imgs', 'train', f'c{c}', n))
        img = resize(img, self.size, anti_aliasing=False)
        lc = np.zeros(10)
        lc[c] = 1
        return self.normalize(img.transpose((2, 0, 1))), lc

    def __len__(self):
        return len(self.data)


import nltk
#nltk.download('nps_chat')
#nltk.download('punkt')
posts = nltk.corpus.nps_chat.xml_posts()[:10000]

def show_all():
    print(set(post.get('class') for post in posts))

def dialogue_act_features(post):
    features = {}
    for word in nltk.word_tokenize(post):
        features['contains({})'.format(word.lower())] = True
    return features

def prepare():
    global classifier, dialogue_act_features

    featuresets = [(dialogue_act_features(post.text), post.get('class')) for post in posts]
    size = int(len(featuresets) * 0.1)
    train_set, test_set = featuresets[size:], featuresets[:size]
    classifier = nltk.NaiveBayesClassifier.train(train_set)

def append_punc(raw_text, txt_cls):
    if raw_text[-1] in '.?!':
        return raw_text

    if txt_cls in ['Emphasis', 'yAnswer', 'Statement', 'Clarify', 'nAnswer', 'Continuer', 'Reject', 'System', 'Accept', 'Emotion', 'Other']:
        raw_text += '.'
    elif txt_cls in ['Greet', 'Bye']:
        raw_text += '!'
    elif txt_cls in ['ynQuestion', 'whQuestion']:
        raw_text += '?'

    return raw_text

def infer(raw_text):
    global classifier, dialogue_act_features
    return classifier.classify(dialogue_act_features(raw_text))


import numpy
import math
import arcade

# --- Set up the constants

# Size of the screen
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 600
SCREEN_TITLE = "Bouncing Rectangle Example"

# Size of the rectangle
RECT_WIDTH = 50
RECT_HEIGHT = 50

age_range =             [20, 40, 60, 80]
#questo è ok
Speed_range =           [1.5, 1.8, 2.1, 2.4, 2.7, 3.0]
#questo è ok
μ_global_range =        [0.1, 0.8]
#questo è ok
reaction_time_range =   [1.5, 3.0, 4.5]
#questo è fisso
fixed_value =           250

age = numpy.random.choice(
#questo è ok
age_range, p=[0.22, 0.54, 0.10, 0.14])
#questo è ok
Speed = numpy.random.choice(
Speed_range, p=[0.05, 0.10, 0.35, 0.35, 0.10, 0.05])
#questo è ok
reaction_time = numpy.random.choice(
reaction_time_range, p=[0.8, 0.18, 0.02])
#questo è ok
μ_value = numpy.random.choice(
μ_global_range, p=[0.01, 0.99])
#questo è ok
skill_factor = 0#fov calculations

if age == 20 or age == 80:
    skill_factor = 0.6
elif age == 40:
    skill_factor = 0.0
elif age == 60:
    skill_factor = 0.2
#print("Skill", skill_factor)

if skill_factor == 0.6:
    R_dist = ((math.pow(Speed, 2.0) *
                    reaction_time)/(3.6 - skill_factor))

#print("R_dist", R_dist)
elif skill_factor == 0.0:
    R_dist = ((math.pow(Speed, 2.0) * reaction_time)/(3.6 + skill_factor))

#print("R_dist", R_dist)
elif skill_factor == 0.2:
    R_dist = ((math.pow(Speed, 2.0) * reaction_time)/(3.6 - skill_factor))
    print("R_dist", R_dist)

B_dist = ((math.pow(Speed, 2.0) /(fixed_value * μ_value)))
print("B_dist",B_dist)

FOV_length = R_dist + B_dist

print(FOV_length)

def on_draw(delta_time):

    arcade.start_render()
    arcade.draw_line(270,0,270,600, arcade.color.WINE)
    arcade.draw_line(330,0,330,600, arcade.color.WINE)
    hitbox_list = arcade.SpriteList()
    car_list = arcade.SpriteList()
    car = arcade.Sprite("../Concept Art/Blocks/car.png", 1, center_x=300, center_y=300)
    hitbox = arcade.Sprite("../Concept Art/hitbox.png", FOV_length, center_x=300, center_y=300)
    hitbox_list.append(hitbox)
    hitbox_list.draw()

def main():
    arcade.open_window(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
    arcade.set_background_color(arcade.color.WHITE)

    # Tell the computer to call the draw command at the specified interval.
    arcade.schedule(on_draw, 1 / 80)

    # Run the program
    arcade.run()

if __name__ == "__main__":
    main()


from __future__ import absolute_import
from __future__ import division

import torch
import torch.nn as nn

def open_all_layers(model):
    """
    Open all layers in model for training.
    """
    model.train()
    for p in model.parameters():
        p.requires_grad = True

def open_specified_layers(model, open_layers):
    """
    Open specified layers in model for training while keeping
    other layers frozen.

    Args:
    - model (nn.Module): neural net model.
    - open_layers (list): list of layers names.
    """
    if isinstance(model, nn.DataParallel):
        model = model.module

    for layer in open_layers:
        assert hasattr(model, layer), "'{}' is not an attribute of the model, please provide the correct name".format(layer)

    for name, module in model.named_children():
        if name in open_layers:
            #print(module)
            module.train()
            for p in module.parameters():
                p.requires_grad = True
        else:
            module.eval()
            for p in module.parameters():
                p.requires_grad = False

def adjust_learning_rate(optimizer, iters, LUT):
    # decay learning rate by 'gamma' for every 'stepsize'
    for (stepvalue, base_lr) in LUT:
        if iters < stepvalue:
            lr = base_lr
            break

    for param_group in optimizer.param_groups:
        param_group['lr'] = lr
    return lr

def adjust_lambda(iters, LUT):
    for (stepvalue, base_lambda) in LUT:
        if iters < stepvalue:
            lambda_xent = base_lambda
            break
    return lambda_xent

def set_bn_to_eval(m):
    # 1. no update for running mean and var
    # 2. scale and shift parameters are still trainable
    classname = m.__class__.__name__
    if classname.find('BatchNorm') != -1:
        m.eval()

def count_num_param(model):
    num_param = sum(p.numel() for p in model.parameters()) / 1e+06
    if hasattr(model, 'classifier') and isinstance(model.classifier, nn.Module):
        # we ignore the classifier because it is unused at test time
        num_param -= sum(p.numel() for p in model.classifier.parameters()) / 1e+06
    return num_param

def one_hot(labels_train):
    """
    Turn the labels_train to one-hot encoding.
    Args:
        labels_train: [batch_size, num_train_examples]
    Return:
        labels_train_1hot: [batch_size, num_train_examples, K]
    """
    labels_train = labels_train.cpu()
    nKnovel = 1 + labels_train.max()
    labels_train_1hot_size = list(labels_train.size()) + [nKnovel,]
    labels_train_unsqueeze = labels_train.unsqueeze(dim=labels_train.dim())
    labels_train_1hot = torch.zeros(labels_train_1hot_size).scatter_(len(labels_train_1hot_size) - 1, labels_train_unsqueeze, 1)
    return labels_train_1hot


# -*- coding: utf-8 -*-

from bson.objectid import ObjectId
import datetime
import os, re
import json
import pickle
import unittest
import pandas as pd
from mbio.api.database.whole_transcriptome.api_base import ApiBase

class SrnaPredict(ApiBase):
    def __init__(self, bind_object):
        super(SrnaPredict, self).__init__(bind_object)
        self._project_type = 'tool_lab'

    def add_srna_main(self, main_id=None, project_sn='tool_lab', task_id='tool_lab', params=None):
        if main_id is None:
            name = "srna_predict"+'_'
            time_now = datetime.datetime.now()
            name += time_now.strftime("%Y%m%d_%H%M%S")
            main_info = dict(
                project_sn=project_sn,
                task_id=task_id,
                version="v1",
                name=name,
                created_ts=time_now.strftime('%Y-%m-%d %H:%M:%S'),
                desc='srna_predict',
                params=[],
                status="start",
            )
            main_id = self.create_db_table('srna_predict', [main_info])
        else:
            main_id = ObjectId(main_id)
            table1_dict = {
                "column": [
                    {"field": "sample_name", "filter": "false", "sort": "false", "title": "Sample name","type": "string"},
                    {"field": "srna_num", "filter": "false", "sort": "false", "title": "sRNA Num","type": "int"},
                    {"field": "average_length", "filter": "false", "sort": "false", "title": "Average Length（bp）","type": "int"},
                    {"field": "percent", "filter": "false", "sort": "false", "title": "Percent（%）","type": "float"}],
                "condition": {}}
            table1_info = json.dumps(table1_dict, sort_keys=False, separators=(',', ':'))
            table2_dict = {
                "column": [
                    {"field": "sample_name", "filter": "false", "sort": "false", "title": "Sample name", "type": "string"},
                    {"field": "id", "filter": "false", "sort": "false", "title": "ID", "type": "string"},
                    {"field": "location", "filter": "false", "sort": "false", "title": "Location", "type": "string"},
                    {"field": "acc_num", "filter": "false", "sort": "false", "title": "Acc Num", "type": "string"},
                    {"field": "family", "filter": "false", "sort": "false", "title": "Family", "type": "string"},
                    {"field": "description", "filter": "false", "sort": "false", "title": "Description", "type": "string"},
                    {"field": "srna_start", "filter": "false", "sort": "false", "title": "sRNA Start", "type": "int"},
                    {"field": "srna_end", "filter": "false", "sort": "false", "title": "sRNA End", "type": "int"},
                    {"field": "srna_length", "filter": "false", "sort": "false", "title": "sRNA Length（bp）", "type": "int"},
                    {"field": "strand", "filter": "false", "sort": "false", "title": "Strand", "type": "string"},
                    {"field": "evalue", "filter": "false", "sort": "false", "title": "E-value", "type": "float"},
                    {"field": "score", "filter": "false", "sort": "false", "title": "Score", "type": "float"}],
                "condition": {}}
            table2_info = json.dumps(table2_dict, sort_keys=False, separators=(',', ':'))
            try:
                self.update_db_record('srna_predict', main_id, status="end", main_id=main_id,
                                      stat_table=table1_info, detail_table=table2_info)
            except Exception as e:
                self.bind_object.logger.error("导入housegene数据出错:%s" % e)
            else:
                self.bind_object.logger.info("导入housegene数据成功")
        return main_id

    def add_srna_detail(self, main_id, file_path, project_sn='tool_lab', task_id='tool_lab', params=None):
        if main_id is None:
            name = "srna_predict"+'_'
            time_now = datetime.datetime.now()
            name += time_now.strftime("%Y%m%d_%H%M%S")
            main_info = dict(
                project_sn=project_sn,
                task_id=task_id,
                version="v1",
                name=name,
                created_ts=time_now.strftime('%Y-%m-%d %H:%M:%S'),
                desc='srna_predict',
                params=[],
                status="start",
            )
            main_id = self.create_db_table('srna_predict', [main_info])
        else:
            main_id = ObjectId(main_id)
        if not isinstance(main_id,ObjectId):
            main_id = ObjectId(main_id)

        insert_data1 = []; insert_data2 = []; num = 0; srna_length = 0
        for file in os.listdir(file_path):
            if file != "length_stat.txt":
                sample_name = "_".join(file.split("_")[:-1])
                break
        with open(file_path + '/' + sample_name + '_assembly.tblout') as f,open(file_path + "/length_stat.txt") as v:
            data2 = v.readlines()
            all_length = int(data2[0])
            data = f.readlines()
            for i in data:
                tmp = re.split(r'\s+',i)
                if not tmp[0].startswith("#"):
                    num += 1
                    if len(str(num)) == 1:
                        srna_id = "sRNA00" + str(num)
                    elif len(str(num)) == 2:
                        srna_id = "sRNA0" + str(num)
                    elif len(str(num)) == 3:
                        srna_id = "sRNA" + str(num)
                    insert_data1.append({
                        "sample_name": sample_name,
                        "id": srna_id,
                        "location": tmp[3],
                        "acc_num": tmp[2],
                        "family": tmp[1],
                        "description": " ".join(tmp[26:]).rstrip(),
                        "srna_start": int(tmp[9]),
                        "srna_end": int(tmp[10]),
                        "srna_length":  abs(int(tmp[10]) - int(tmp[9])) + 1,
                        "strand": tmp[11],
                        "evalue": float(tmp[17]),
                        "score": round(float(tmp[16]),1),
                        "spre_id": main_id
                    })
                    srna_length += (abs(int(tmp[10]) - int(tmp[9])) + 1)
            if num ==0:
                insert_data2.append({
                    "sample_name": sample_name,
                    "srna_num": 0,
                    "average_length": "-",
                    "Percent": "-",
                    "spre_id": main_id
                })
            else:
                insert_data2.append({
                    "sample_name": sample_name,
                    "srna_num": num,
                    "average_length": srna_length/num,
                    "percent": round(float(srna_length) / all_length * 100,2),
                    "spre_id": main_id
                })

        try:
            self.create_db_table('srna_predict_detail', insert_data1)
            self.create_db_table('srna_predict_stat', insert_data2)
        except Exception as e:
            self.bind_object.logger.error("导入housegene数据出错:%s" % e)
        else:
            self.bind_object.logger.info("导入housegene数据成功")