import os
import time
import logging
from datetime import datetime

import gi
from gi.repository import Gtk

from gajim.plugins.gui import GajimPluginConfigDialog
from gajim.plugins import GajimPlugin
from gajim.plugins.plugins_i18n import _
from gajim.plugins.helpers import log_calls
from gajim.common import app
from gajim.common import ged
from gajim.common import helpers
from gajim.common import configpaths

from gajim import gtkgui_helpers
from gajim.gtk.dialogs import InputDialog, WarningDialog

log = logging.getLogger('gajim.p.set_location')

CHAMPLAIN_AVAILABLE = True

try:
    gi.require_version('Clutter', '1.0')
    gi.require_version('GtkClutter', '1.0')
    gi.require_version('Champlain', '0.12')
    gi.require_version('GtkChamplain', '0.12')
    from gi.repository import Clutter, GtkClutter
    GtkClutter.init([]) # Must be initialized before importing those:
    from gi.repository import Champlain, GtkChamplain
except:
    log.exception('To view the map, you have to install all dependencies')
    CHAMPLAIN_AVAILABLE = False

class SetLocationPlugin(GajimPlugin):
    @log_calls('SetLocationPlugin')
    def init(self):
        self.description = _('Set information about your current geographical '
            'or physical location. \nTo be able to set your location on the '
            'built-in map, you need to have gir1.2-gtkchamplain and '
            'gir1.2-gtkclutter-1.0 installed')
        self.config_dialog = SetLocationPluginConfigDialog(self)
        self.config_default_values = {
            'alt': (1609, ''),
            'area': ('Central Park', ''),
            'building': ('The Empire State Building', ''),
            'country': ('United States', ''),
            'countrycode': ('US', ''),
            'description': ('Bill\'s house', ''),
            'floor': ('102', ''),
            'lat': (39.75, ''),
            'locality': ('New York City', ''),
            'lon': (-104.99, ''),
            'postalcode': ('10027', ''),
            'region': ('New York', ''),
            'room': ('Observatory', ''),
            'street': ('34th and Broadway', ''),
            'text': ('Northwest corner of the lobby', ''),
            'uri': ('http://beta.plazes.com/plazes/1940:jabber_inc', ''),
            'presets': ({'default': {}}, ''), }

    @log_calls('SetLocationPlugin')
    def activate(self):
        app.ged.register_event_handler('signed-in', ged.POSTGUI,
            self.on_signed_in)
        self.send_locations()

    @log_calls('SetLocationPlugin')
    def deactivate(self):
        self._data = {}
        for acct in app.connections:
            app.connections[acct].get_module('UserLocation').send(self._data)
        app.ged.remove_event_handler('signed-in', ged.POSTGUI,
            self.on_signed_in)

    def on_signed_in(self, network_event):
        self.send_locations(network_event.conn.name)

    def send_locations(self, acct=False):
        self._data = {}
        timestamp = time.time()
        timestamp = datetime.utcfromtimestamp(timestamp)
        timestamp = timestamp.strftime('%Y-%m-%dT%H:%M:%SZ')
        self._data['timestamp'] = timestamp
        for name in self.config_default_values:
            self._data[name] = self.config[name]

        if not acct:
            # Set geo for all accounts
            for acct in app.connections:
                if app.config.get_per('accounts', acct, 'publish_location'):
                    app.connections[acct].get_module('UserLocation').send(
                        self._data)
        elif app.config.get_per('accounts', acct, 'publish_location'):
            app.connections[acct].get_module('UserLocation').send(self._data)

class SetLocationPluginConfigDialog(GajimPluginConfigDialog):
    def init(self):
        self.GTK_BUILDER_FILE_PATH = self.plugin.local_file_path(
                'config_dialog.ui')
        self.xml = Gtk.Builder()
        self.xml.set_translation_domain('gajim_plugins')
        self.xml.add_objects_from_file(self.GTK_BUILDER_FILE_PATH,
                ['config_box'])
        config_box = self.xml.get_object('config_box')
        self.get_child().pack_start(config_box, True, True, 0)
        self.xml.connect_signals(self)
        self.connect('hide', self.on_hide)
        self.connect('show', self.on_show)
        self.is_active = None

        self.preset_combo = self.xml.get_object('preset_combobox')
        self.preset_liststore = Gtk.ListStore(str)
        self.preset_combo.set_model(self.preset_liststore)
        cellrenderer = Gtk.CellRendererText()
        self.preset_combo.pack_start(cellrenderer, True)
        self.preset_combo.add_attribute(cellrenderer, 'text', 0)
        #self.plugin.config['presets'] = {'default': {}}

    @log_calls('SetLocationPlugin.SetLocationPluginConfigDialog')
    def on_run(self):
        if not self.is_active:
            pres_keys = sorted(self.plugin.config['presets'].keys())
            for key in pres_keys:
                self.preset_liststore.append((key,))

        for name in self.plugin.config_default_values:
            if name == 'presets':
                continue
            widget = self.xml.get_object(name)
            widget.set_text(str(self.plugin.config[name]))

        map_placeholder = self.xml.get_object('map_placeholder')
        dependency_bar = self.xml.get_object('dependency_warning')

        if CHAMPLAIN_AVAILABLE and not self.is_active:
            map_placeholder.set_no_show_all(True)
            map_placeholder.hide()
            dependency_bar.hide()
            map_box = self.xml.get_object('map_box')
            map_box.set_size_request(400, -1)

            embed = GtkChamplain.Embed()

            self.view = embed.get_view()
            self.view.set_reactive(True)
            self.view.set_property('kinetic-mode', True)
            self.view.set_property('zoom-level', 12)
            self.view.connect('button-release-event', self.map_clicked,
                              self.view)

            scale = Champlain.Scale()
            scale.connect_view(self.view)
            self.view.add_child(scale)

            lat = self.plugin.config['lat']
            lon = self.plugin.config['lon']
            if not self.is_valid_coord(lat, lon):
                self.lat = self.lon = 0.0
                self.xml.get_object('lat').set_text('0.0')
                self.xml.get_object('lon').set_text('0.0')
            self.view.center_on(self.lat, self.lon)

            self.path_to_image = os.path.abspath(gtkgui_helpers.get_icon_path(
                'org.gajim.Gajim', 16))
            map_box.pack_start(embed, expand=True, fill=True, padding=0)

            self.is_active = True
            self.layer = Champlain.MarkerLayer()
            texture = Clutter.Texture()
            texture.set_from_file(self.path_to_image)
            texture.set_size(32,32)
            self.marker = Champlain.Label.new_with_image(texture)
            self.marker.set_location(self.lat, self.lon)
            self.marker.set_text(_('Your location'))
            self.view.add_layer(self.layer)
            self.layer.add_marker(self.marker)
            self.markers_is_visible = False
            self.xml.get_object('lat').connect('changed', self.on_latlon_changed)
            self.xml.get_object('lon').connect('changed', self.on_latlon_changed)
            self.layer.animate_in_all_markers()
            self.contacts_layer = Champlain.MarkerLayer()

    def on_show(self, widget):
        if CHAMPLAIN_AVAILABLE:
            self.contacts_layer.remove_all()
            self.view.center_on(self.lat, self.lon)
            self.show_contacts()

    def on_hide(self, widget):
        for name in self.plugin.config_default_values:
            if name in ['presets', 'lat', 'lon']:
                continue
            widget = self.xml.get_object(name)
            self.plugin.config[name] = widget.get_text()

        lat = self.xml.get_object('lat').get_text()
        lon = self.xml.get_object('lon').get_text()
        if self.is_valid_coord(lat, lon):
            self.plugin.config['lat'] = lat
            self.plugin.config['lon'] = lon
            if self.plugin.active:
                self.plugin.activate()
        else:
            self.plugin.config['lat'] = '0.0'
            self.plugin.config['lon'] = '0.0'
            error_text = _('Latitude or Longitude field contains an invalid value')
            WarningDialog(_('Wrong coordinates'), error_text, self)

    def map_clicked(self, actor, event, view):
        x, y = event.x, event.y
        lat, lon = view.x_to_longitude(x), view.y_to_latitude(y)
        if event.button == 3:
            self.marker.set_location(lat, lon)
            self.xml.get_object('lon').set_text(str(lat))
            self.xml.get_object('lat').set_text(str(lon))
        if event.button == 2:
            if self.markers_is_visible:
                self.contacts_layer.animate_out_all_markers()
            else:
                self.contacts_layer.animate_in_all_markers()
            self.markers_is_visible = not self.markers_is_visible

    def is_valid_coord(self, lat, lon):
        try:
            self.lat = float(lat)
            self.lon = float(lon)
        except ValueError as e:
            return
        if not -85 < self.lat < 85 or not -180 < self.lon < 180:
            return
        return True

    def on_latlon_changed(self, widget):
        lat = self.xml.get_object('lat').get_text()
        lon = self.xml.get_object('lon').get_text()
        if self.is_valid_coord(lat, lon):
            self.marker.set_location(self.lat, self.lon)
            self.view.go_to(self.lat, self.lon)

    def show_contacts(self):
        data = {}
        accounts = app.contacts._accounts
        for account in accounts:
            if not app.account_is_connected(account):
                continue
            for contact in accounts[account].contacts._contacts:
                pep = accounts[account].contacts._contacts[contact][0].pep
                if 'location' not in pep:
                    continue
                lat = pep['location'].data.get('lat', None)
                lon = pep['location'].data.get('lon', None)
                if not lat or not lon:
                    continue
                name = accounts[account].contacts.get_first_contact_from_jid(
                    contact).get_shown_name()
                data[contact] = (lat, lon, name)

        self.contacts_layer = Champlain.MarkerLayer()
        for jid in data:
            path = self.get_path_to_generic_or_avatar(self.path_to_image,
                jid=jid, suffix='')
            texture = Clutter.Texture()
            texture.set_from_file(path)
            texture.set_size(32,32)
            marker = Champlain.Label.new_with_image(texture)
            marker.set_text(data[jid][2])
            marker.set_location(float(data[jid][0]), float(data[jid][1]))
            self.contacts_layer.add_marker(marker)

        self.view.add_layer(self.contacts_layer)
        self.contacts_layer.animate_in_all_markers()
        self.markers_is_visible = True

    def get_path_to_generic_or_avatar(self, generic, jid=None, suffix=None):
        """
        Choose between avatar image and default image

        Returns full path to the avatar image if it exists, otherwise returns full
        path to the image.  generic must be with extension and suffix without
        """
        if jid:
            # we want an avatar
            puny_jid = helpers.sanitize_filename(jid)
            path_to_file = os.path.join(
                configpaths.get('AVATAR'), puny_jid) + suffix
            path_to_local_file = path_to_file + '_local'
            for extension in ('.png', '.jpeg'):
                path_to_local_file_full = path_to_local_file + extension
                if os.path.exists(path_to_local_file_full):
                    return path_to_local_file_full
            for extension in ('.png', '.jpeg'):
                path_to_file_full = path_to_file + extension
                if os.path.exists(path_to_file_full):
                    return path_to_file_full
        return os.path.abspath(generic)

    def on_preset_button_clicked(self, widget):
        def on_ok(preset_name):
            if preset_name == '':
                return
            preset = {}
            for name in self.plugin.config_default_values:
                if name == 'presets':
                    continue
                widget = self.xml.get_object(name)
                preset[name] = widget.get_text()
            preset = {preset_name: preset}
            presets = dict(list(self.plugin.config['presets'].items()) + \
                list(preset.items()))
            if preset_name not in list(self.plugin.config['presets'].keys()):
                iter_ = self.preset_liststore.append((preset_name,))
            self.plugin.config['presets'] = presets
        self.set_modal(False)
        InputDialog(_('Save as Preset'),
                    _('Please type a name for this preset'),
                    'default', is_modal=True, ok_handler=on_ok)

    def on_preset_combobox_changed(self, widget):
        model = widget.get_model()
        active = widget.get_active()
        if active < 0:
            self.xml.get_object('del_preset').set_sensitive(False)
            return
        pres_name = model[active][0]
        for name in list(self.plugin.config['presets'][pres_name].keys()):
            widget = self.xml.get_object(name)
            widget.set_text(str(self.plugin.config['presets'][pres_name][name]))

        self.xml.get_object('del_preset').set_sensitive(True)

    def on_del_preset_clicked(self, widget):
        active = self.preset_combo.get_active()
        active_iter = self.preset_combo.get_active_iter()
        name = self.preset_liststore[active][0]
        presets = self.plugin.config['presets']
        del presets[name]
        self.plugin.config['presets'] = presets
        self.preset_liststore.remove(active_iter)


#!/usr/local/bin/python3
# -*- coding: utf-8 -*-
from typing import List
class Solution:
    def decompressRLElist(self, nums: List[int]) -> List[int]:
        len_ = len(nums)
        res = []
        for i in range(0, len_, 2):
            print(i)
            a = nums[i]
            b = nums[i + 1]
            res += [b for j in range(a)]
        return res
s = Solution()
print(s.decompressRLElist([55,11,70,26,62,64]))


import matplotlib.pyplot as plt
import numpy as np
import csv

# Initialize and Read data from CSV
base_link_x_odom_camera = []
base_link_y_odom_camera = []

#*******************************************************************************
#           Parameters
#*******************************************************************************
file_name = 'drift-base_link_odom_camera_is1500.csv'

#  Define waypoints
Strecke_1 = [[2.080, -1.544]]
numberPoints = len(Strecke_1) # number points of Ground_Truth
data_soll = Strecke_1;

#*******************************************************************************
#           Get data from .csv
#*******************************************************************************

del base_link_x_odom_camera[:]
del base_link_y_odom_camera[:]
with open(file_name,'r') as csvfile:
  next(csvfile)
  plots = csv.reader(csvfile, delimiter=',')

  for row in plots:
      # don't forget the multiply by -1
      base_link_x_odom_camera.append(np.multiply(1, float(row[6])))
      base_link_y_odom_camera.append(np.multiply(1, float(row[7])))

x_err_1 = np.empty((numberPoints, len(base_link_x_odom_camera)))
y_err_1 = np.empty((numberPoints, len(base_link_x_odom_camera)))
err_abs_1 = np.empty((numberPoints, len(base_link_x_odom_camera)))
err_min_1 = np.empty((numberPoints, 1))
n_1 = np.empty((numberPoints, 1))

#*******************************************************************************
#           Min calulation
#*******************************************************************************

#  Assumptions : - The min point from odom are the closest to Strecke_1, if the
#  robot drift, you could not have the real min which that mean it pass not in
#  the right moment moment where you think.
    # print(Strecke_1[i][0])
x_err_1 = np.subtract(data_soll[0][0], base_link_x_odom_camera)
y_err_1 = np.subtract(data_soll[0][1], base_link_y_odom_camera)
err_abs_1 = np.power(np.add(np.power(x_err_1, 2), np.power(y_err_1, 2)), 0.5)
err_min_1 = min(err_abs_1)
n_1 = err_abs_1.tolist().index(min(err_abs_1))
    # end of the loop

# print(np.var(base_link_x_odom_camera))
# print(np.var(base_link_y_odom_camera))

plt.rcParams.update({'font.size': 30})

# print(Strecke_1[int(1)][int(1)])
f = plt.figure(1, figsize=(30, 21))
plt.plot(0, 0, 'o' ,color='black', markersize=10, label="Origin, variance on x : " + str(np.var(base_link_x_odom_camera))+", variance on y : " + str(np.var(base_link_y_odom_camera)))
plt.plot(Strecke_1[int(0)][int(0)], Strecke_1[int(0)][int(1)], 'o' ,color='red', markersize=10, label="Ground truth Point, error = " + str(err_min_1))
plt.plot(base_link_x_odom_camera, base_link_y_odom_camera, label='Robot position in camera frame')
plt.plot(label='Variance on x : ' + str(np.var(base_link_x_odom_camera)))
plt.xlabel('x [m]')
plt.ylabel('y [m]')
plt.legend(numpoints=1, bbox_to_anchor=(0., 1.02, 1., .102), loc=1,
           ncol=1, mode="expand", borderaxespad=0.)#bbox_to_anchor=(0., 1.02, 1., .102)
f.savefig(file_name+'.png')
# plt.close(f)

plt.show()


from .common_server import *

GS_BUCKET_NAME = "joinflyline"

COMPRESS_URL = os.getenv(
    "COMPRESS_URL", f"https://storage.googleapis.com/{GS_BUCKET_NAME}/"
)

MIDDLEWARE = [
    "apps.common.middleware.UrlRedirectMiddleware",
    *MIDDLEWARE
]

SITE_URL = os.getenv("SITE_URL", "https://joinflyline.com")


# Author: Cole Carter ctc5367@psu.edu
# Collaborator: eric zhang ecz5032@psu.edu
# Collaborator: Andrew Wang aqw5628@psu.edu
# Collaborator: Ryan Attia rka5347@psu.edu
# Section: 5
# Breakout: 14

def sum_n(n):
  if n > 0:
    return  n + sum_n(n-1)
  else:
    return 0

def print_n(s, n):
  if n > 0:
    print(s)
    print_n(s, n-1)

def run():
  num = input("Enter an int: ")
  num = int(num)
  print(f"sum is {sum_n(num)}.")

  s = input("Enter a string: ")
  print_n(s, num)

if __name__ ==  "__main__":
  run()


from lxml.etree import tostring
import datetime
from lxml.etree import Element, SubElement
from ckan.model import Package, Session
from ckan.lib import helpers
from pylons import config

class URNHelper(object):
    @classmethod
    def list_packages(cls):
        xmlns = "urn:nbn:se:uu:ub:epc-schema:rs-location-mapping"

        def locns(loc):
            return "{%s}%s" % (xmlns, loc)
        xsi = "http://www.w3.org/2001/XMLSchema-instance"
        schemaLocation = "urn:nbn:se:uu:ub:epc-schema:rs-location-mapping http://urn.kb.se/resolve?urn=urn:nbn:se:uu:ub:epc-schema:rs-location-mapping&godirectly"
        records = Element("{" + xmlns + "}records",
                         attrib={"{" + xsi + "}schemaLocation": schemaLocation},
                         nsmap={'xsi': xsi, None: xmlns})
        q = Session.query(Package)
        q = q.filter(Package.name.ilike('urn:nbn:fi:csc-kata%'))
        pkgs = q.all()
        prot = SubElement(records, locns('protocol-version'))
        prot.text = '3.0'
        datestmp = SubElement(records, locns('datestamp'), attrib={'type': 'modified'})
        now = datetime.datetime.now().isoformat()
        datestmp.text = now
        for pkg in pkgs:
            record = SubElement(records, locns('record'))
            header = SubElement(record, locns('header'))
            datestmp = SubElement(header, locns('datestamp'), attrib={'type': 'modified'})
            datestmp.text = now
            identifier = SubElement(header, locns('identifier'))
            identifier.text = pkg.name
            destinations = SubElement(header, locns('destinations'))
            destination = SubElement(destinations, locns('destination'), attrib={'status': 'activated'})
            datestamp = SubElement(destination, locns('datestamp'), attrib={'type': 'activated'})
            url = SubElement(destination, locns('url'))
            url.text = "%s%s" % (config.get('ckan.site_url', ''),
                             helpers.url_for(controller='package',
                                       action='read',
                                       id=pkg.name))
        return tostring(records)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import numpy as np
np.random.seed(15122017)
import matplotlib.pylab as plt
plt.close('all')
import gedi

data = np.loadtxt('datasets/dataset0.txt', usecols = (0,1,2))
t = data[:,0]
rv = data[:,1]
rverr = data[:,2]

### Errors ###
lognormalyerr = np.random.lognormal(1,0.2,size=len(t))/1000

### Planet ###
t1,pl1 = gedi.rvfunction.kepler(P=23, e = 0.01, K = 20, w=np.pi/2, t=t)
pl1 = np.array(pl1)/1000
plt.figure()
plt.errorbar(t, rv, yerr=rverr ,fmt='.')
plt.errorbar(t1, pl1, yerr=lognormalyerr ,fmt='.')

rvs7 = (rv+rverr + pl1+lognormalyerr)
yerr = lognormalyerr
plt.figure()
plt.errorbar(t1, rvs7, yerr=yerr, fmt='.')
plt.show()

data = np.vstack((t,rvs7))
data = np.vstack((data,yerr)).T
np.savetxt("dataset7.txt", data, delimiter = ' ')


__author__ = 'sei'

import os
import re

import numpy as np
from scipy.optimize import minimize, curve_fit
from scipy.signal import savgol_filter

#from plotsettings import *

from gauss_detect import *
import matplotlib.gridspec as gridspec
import matplotlib.pyplot as plt
import seaborn as sns
import PIL
from matplotlib import ticker
from adjustText import adjust_text

path = '/home/sei/Spektren/8/'

#samples = ['p45m_did5_par5']
samples = ['8_C3_horzpol','8_C4_horzpol','8_D2_horzpol','8_D3_horzpol']

def lorentz(x, amplitude, xo, sigma):
    g = amplitude * np.power(sigma / 2, 2) / (np.power(sigma / 2, 2) + np.power(x - xo, 2))
    return g.ravel()

# https://www.webpages.uidaho.edu/brauns/vibspect1.pdf
def asymlorentz(x, amplitude, x0, sigma, asy):
    sigma = 2 * sigma/(1 + np.exp(asy*(x-x0)) )
    g = lorentz(x,amplitude,x0,sigma)
    return g.ravel()

def three_lorentz(x,c, a0,a1,a2, xo0, xo1, xo2, fwhm0, fwhm1, fwhm2):
    g = lorentz(x,a0,xo0,fwhm0)+lorentz(x,a1,xo1,fwhm1)+lorentz(x,a2,xo2,fwhm2)+c
    return g.ravel()

def three_lorentz_asy(x,c, a0,a1,a2, xo0, xo1, xo2, fwhm0, fwhm1, fwhm2,asy0,asy1,asy2,m):
    g = asymlorentz(x,a0,xo0,fwhm0,asy0)+asymlorentz(x,a1,xo1,fwhm1,asy1)+asymlorentz(x,a2,xo2,fwhm2,asy2)+c+m*x
    return g.ravel()

def four_lorentz_asy(x,c, a0,a1,a2,a3, xo0, xo1, xo2,xo3, fwhm0, fwhm1, fwhm2,fwhm3, asy0,asy1,asy2,asy3):
    g = asymlorentz(x,a0,xo0,fwhm0,asy0)+asymlorentz(x,a1,xo1,fwhm1,asy1)+asymlorentz(x,a2,xo2,fwhm2,asy2)+asymlorentz(x,a3,xo3,fwhm3,asy3)+c
    return g.ravel()

def four_lorentz(x,c, a0,a1,a2,a3, xo0, xo1, xo2,xo3, fwhm0, fwhm1, fwhm2,fwhm3):
    g = lorentz(x,a0,xo0,fwhm0)+lorentz(x,a1,xo1,fwhm1)+lorentz(x,a2,xo2,fwhm2)+lorentz(x,a3,xo3,fwhm3)+c
    return g.ravel()

def two_lorentz(x,c, a0,a1, xo0, xo1, fwhm0, fwhm1):
    g = lorentz(x,a0,xo0,fwhm0)+lorentz(x,a1,xo1,fwhm1)+c
    return g.ravel()

def two_lorentz_asy(x,c, a0,a1, xo0, xo1, fwhm0, fwhm1,asy0,asy1):
    g = asymlorentz(x,a0,xo0,fwhm0,asy0)+asymlorentz(x,a1,xo1,fwhm1,asy1)+c
    return g.ravel()

letters = [chr(c) for c in range(65, 91)]

for sample in samples:
    print(sample)

    savedir = path + sample + '/'

    try:
        os.mkdir(savedir + "fitted/")
    except:
        pass

    files = []
    for file in os.listdir(savedir+ 'specs/'):
        if re.fullmatch(r"([A-Z]{1}[0-9]{1})(.csv)$", file) is not None:
            files.append(file)

    #files = ['A1.csv','B1.csv','C1.csv']

    last_popt = None
    for i in range(len(files)):
        file = files[i]
        wl, counts = np.loadtxt(open(savedir+'specs/' + file, "rb"), delimiter=",", skiprows=6, unpack=True)

        filtered = savgol_filter(counts, 27, 1, deriv=0, delta=1.0, axis=-1, mode='interp', cval=0.0)

        x = wl
        y = counts

        mask = ((wl > 450) & (wl < 900))
        x = x[mask]
        y = y[mask]

        #def four_lorentz_asy(x,c, a0,a1,a2,a3, xo0, xo1, xo2,xo3, fwhm0, fwhm1, fwhm2,fwhm3, asy0,asy1,asy2,asy3):
        #if last_popt is not None:
        #    p0 = last_popt
        #else:
        p0 = [-0.004,  0.03,0.005, 0.005, 0.005,  440,510, 575, 620,  150,50, 50,50]

        bounds = [(-np.inf,0,0,0,0,                        300,500,520,580,  10,10,10,10),
                  (np.inf,np.inf,y.max(),y.max(),y.max(),  450,520,620,900,  1000,1000,1000,1000)]

        # plt.plot(x, y, linestyle='', marker='.')
        # plt.plot(x, four_lorentz(x, p0[0], p0[1], p0[2], p0[3], p0[4], p0[5], p0[6], p0[7], p0[8], p0[9],p0[10],p0[11],p0[12]),
        #          linestyle='', marker='.')
        # plt.show()
        # plt.close()

        try:
            popt, pcov = curve_fit(four_lorentz, x, y, p0,bounds=bounds,max_nfev=1000*len(x))
            perr = np.sqrt(np.diag(pcov))
            #print(popt)
            print(np.round(popt[5:9]))
            last_popt = popt

            fig = plt.figure()
            ax = fig.add_subplot(111)

            ax.plot(x, lorentz(x,popt[1],popt[5],popt[9])+popt[0])
            ax.plot(x, lorentz(x,popt[2],popt[6],popt[10])+popt[0])
            ax.plot(x, lorentz(x,popt[3],popt[7],popt[11])+popt[0])
            ax.plot(x, lorentz(x,popt[4],popt[8],popt[12])+popt[0])

            ax.plot(x, y, linestyle='', marker='.')
            y_fit = four_lorentz(x, popt[0], popt[1], popt[2], popt[3], popt[4], popt[5], popt[6], popt[7], popt[8],
                                      popt[9],popt[10],popt[11],popt[12])
            ax.plot(x, y_fit,color='black')
            idx1 = (np.abs(x - popt[6])).argmin()
            idx2 = (np.abs(x - popt[7])).argmin()
            idx3 = (np.abs(x - popt[8])).argmin()

            texts = []
            texts.append(ax.text(x[idx1],y_fit[idx1],str(int(round(popt[6])))))
            texts.append(ax.text(x[idx2],y_fit[idx2],str(int(round(popt[7])))))
            texts.append(ax.text(x[idx3],y_fit[idx3],str(int(round(popt[8])))))

            adjust_text(texts, x,y, only_move={'points':'y', 'text':'y'},
                        arrowprops=dict(arrowstyle="->", color='k', lw=1),
                        expand_points=(1.7, 1.7),
                        )#force_points=0.1)

            plt.tight_layout()
            plt.savefig(savedir + "fitted/" + file[:-4] + ".png")
            #plt.show()
            plt.close()

            f = open(savedir + "fitted/" + file[:-4] + ".csv", 'w')
            f.write("x0,x0_err,amp,amp_err,sigma,sigma_err" + "\r\n")
            f.write(str(popt[6])+','+str(perr[6]) +','+ str(popt[2])+','+str(perr[2]) +','+ str(popt[10])+','+str(perr[10])  +"\r\n")
            f.write(str(popt[7])+','+str(perr[7]) +','+ str(popt[3])+','+str(perr[3]) +','+ str(popt[11])+','+str(perr[11])  +"\r\n")
            f.write(str(popt[8])+','+str(perr[8]) +','+ str(popt[4])+','+str(perr[4]) +','+ str(popt[12])+','+str(perr[12])  +"\r\n")

            f.close()

        except (RuntimeError,ValueError) as e:
            print(e)
            print(file + ', could not fit three lorentzians, probably not a dimer.')
            fig = plt.figure()
            ax = fig.add_subplot(111)
            ax.plot(x, y_fit)
            plt.tight_layout()
            plt.savefig(savedir + "fitted/" + file[:-4] + ".png")
            #plt.show()
            plt.close()
        # newfig(0.9)
        # plt.plot(wl[mask], counts[mask], color="grey", linewidth=0.5)
        # plt.plot(wl[mask], filtered[mask], color="black", linewidth=0.5)
        # plt.ylabel(r'$I_{df}\, /\, a.u.$')
        # plt.xlabel(r'$\lambda\, /\, nm$')
        # plt.xlim((minwl, maxwl))
        # plt.ylim([np.min(filtered[mask]), np.max(filtered[mask]) * 1.2])
        # plt.tight_layout()
        # #plt.savefig(savedir + "plots/" + file[:-4] + ".pdf", dpi=300)
        # #plt.savefig(savedir + "plots/" + file[-4] + ".pgf")
        # plt.show()
        # plt.close()

    # #plt.tight_layout(.5)
    # gs1.update(wspace=0.1, hspace=0.1) # set the spacing between axes.
    # #plt.show()
    # ax1 = plt.subplot(gs1[nx, :])
    # m = plt.cm.ScalarMappable(cmap=cm)
    # # m.set_array(np.linspace(0,1,len(wl)))
    # m.set_array(wl[mask][::10])
    # cb = plt.colorbar(m, cax=ax1, orientation='horizontal')
    # tick_locator = ticker.MaxNLocator(nbins=5)
    # cb.locator = tick_locator
    # cb.update_ticks()
    # cb.ax.tick_params(axis='y', direction='out')
    # cb.set_label(r'$\lambda\, /\, nm$')
    #
    # plt.savefig(savedir+"overview/" + sample +"_overview.pdf", dpi= 300)
    # plt.savefig(savedir+"overview/" + sample +"_overview.pgf")
    # plt.close()


class Warrior:
    def __init__(self):
        self.health = 50
        self.attack = 5
        self.defense = 0
        self.is_alive = True

    def __sub__(self, other):
        if other.attack > self.defense:
            self.health = self.health - other.attack + self.defense
        if self.health < 1:
            self.is_alive = False

class Rookie(Warrior):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.health = 50
        self.attack = 1

class Knight(Warrior):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.health = 50
        self.attack = 7
        self.is_alive = True

class Defender(Warrior):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.health = 60
        self.attack = 3
        self.defense = 2

def fight(unit_1, unit_2):
    turn = True
    while (unit_1.is_alive and unit_2.is_alive):
        if turn:
            unit_2 - unit_1
            turn = not turn
        else:
            unit_1 - unit_2
            turn = not turn
    if unit_1.is_alive:
        return True
    else:
        return False

class Army:
    def __init__(self):
        self.army_people = {}

    def add_units(self, fighter, number):
        x = fighter.__name__
        self.army_people[x] = self.army_people.get(x, 0) + number

class Battle:
    def __init__(self):
        self.battle_order = [Rookie, Warrior, Knight, Defender]

    def fight(self, my_army, enemy_army):
        def set_voin(army):
            if len(army.army_people) != 0:
                for i in self.battle_order:
                    if army.army_people.get(i.__name__, 0) != 0:
                        voin = i()
                        army.army_people[i.__name__] -= 1
                        if army.army_people[i.__name__] == 0:
                            del army.army_people[i.__name__]
                        break
                return voin
            return False

        voin1 = set_voin(my_army)
        voin2 = set_voin(enemy_army)
        while True:
            if fight(voin1, voin2):
                voin2 = set_voin(enemy_army)
            else:
                voin1 = set_voin(my_army)
            if voin1 == False:
                return False
            elif voin2 == False:
                return True

if __name__ == '__main__':
    unit_1 = Defender()
    unit_2 = Rookie()
    fight(unit_1, unit_2)
    print(unit_1.__class__.__name__)
    print(unit_2.__class__.__name__)
    print(unit_1.health)
    print(unit_2.health)


# -*- coding: utf-8 -*-
from tencentcloud.common import credential
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
# 导入对应产品模块的 client models。
from tencentcloud.cvm.v20170312 import cvm_client, models
from conf import config_env

class Tencentecs(object):
    def __init__(self, secretid, secretkey, region_id):
        self.secretid = secretid
        self.secretkey = secretkey
        self.cert = credential.Credential(self.secretid, self.secretkey)
        self.region_id = region_id

    def _get_cvm(self):
        self.client = cvm_client.CvmClient(self.cert, self.region_id)
        req = models.DescribeInstancesRequest()
        resp = self.client.DescribeZones(req)
        print(resp.to_json_string())

if __name__ == '__main__':
    for username, account in config_env.tencentAccount.items():
        for region_id in config_env.tencentRegion:
            ecs = Tencentecs(account['secretid'], account['secretkey'], region_id)
            ecs._get_cvm()

# try:
#     # 实例化一个认证对象，入参需要传入腾讯云账户 secretId，secretKey
#     cred = credential.Credential("AKIDkUL7ZNtX0JWacVcrPn9Ogqwt0LcohB8P", "W2Sjv4A52qY7g8PbdbWMetAIGzfGtQtF")
#
#     # 实例化要请求产品(以 CVM 为例)的 client 对象
#     client = cvm_client.CvmClient(cred, "ap-shanghai")
#
#     # 实例化一个请求对象
#     req = models.DescribeZonesRequest()
#
#     # 通过 client 对象调用想要访问的接口，需要传入请求对象
#     resp = client.DescribeZones(req)
#     # 输出 JSON 格式的字符串回包
#     print(resp.to_json_string())
#
# except TencentCloudSDKException as err:
#     print(err)


"""
https://leetcode.com/problems/accounts-merge/

Algorithm:
For each account, draw the edge from the first email to all other emails.
Additionally, we'll remember a map from emails to names on the side.
After finding each connected component using a depth-first search, we'll add that to our answer.

Complexity Analysis:

Time Complexity: Sum of (accounts for i * log(accounts))
Space Complexity: Sum of (accounts for i)
"""
from collections import defaultdict

class Solution:
    def __init__(self):
        self.emailNameMap = {}
        self.seen = set()
        self.graph = defaultdict(set)

    def accountsMerge(self, accounts):
        for account in accounts:
            name = account[0]
            emails = account[1:]
            # For each account, add edges from first email to all other emails.
            for email in emails:
                self.graph[account[1]].add(email)
                self.graph[email].add(account[1])
                self.emailNameMap[email] = name

        def dfs(email, emails):
            self.seen.add(email)
            emails.append(email)
            for neighbor in self.graph[email]:
                if neighbor not in self.seen:
                    dfs(neighbor, emails)

        output = []
        for email in self.graph:
            if email not in self.seen:
                emails = []
                dfs(email, emails)
                output.append([self.emailNameMap[email]] + sorted(emails))

        return output

a = Solution()
accounts = [["John", "johnsmith@mail.com", "john00@mail.com"],
            ["John", "johnnybravo@mail.com"],
            ["John", "johnsmith@mail.com", "john_newyork@mail.com"],
            ["Mary", "mary@mail.com"]]
print(a.accountsMerge(accounts))


import itertools
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
import sklearn.metrics
import io

def plot_confusion_matrix(cm, class_names):
    """
    Returns a matplotlib figure containing the plotted confusion matrix.

    Args:
    cm (array, shape = [n, n]): a confusion matrix of integer classes
    class_names (array, shape = [n]): String names of the integer classes
    """
    # Normalize the confusion matrix.
    cm_norm = np.around(cm.astype('float') / cm.sum(axis=1)[:, np.newaxis], decimals=4)

    figure = plt.figure(figsize=(10, 10))
    plt.imshow(cm_norm, interpolation='nearest', cmap=plt.cm.Blues, vmin=0.0, vmax=1.0)
    plt.title("Confusion matrix")
    plt.colorbar()
    # tick_marks = np.arange(len(class_names))
    # plt.xticks(tick_marks, class_names, rotation=45)
    # plt.yticks(tick_marks, class_names)

    # cm = np.around(cm.astype('float') / cm.sum(axis=1)[:, np.newaxis], decimals=2)

    # Use white text if squares are dark; otherwise black.
    # threshold = cm_norm.max() / 2.
    # for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
    #     color = "white" if cm_norm[i, j] > threshold else "black"
    #     plt.text(j, i, '{}({:.2f}%)'.format(cm[i, j], 100 * cm_norm[i, j]), horizontalalignment="center", color=color)

    plt.tight_layout()
    plt.ylabel('True label')
    plt.xlabel('Predicted label')

    return figure

if __name__ == "__main__":
    cm = np.array([[2, 0, 0], [0, 0, 1], [1, 0, 2]])
    print(cm)
    figure = plot_confusion_matrix(cm, np.array(['0', '1', '2']))

# y_true = [2, 0, 2, 2, 0, 1]
# y_pred = [0, 0, 2, 2, 0, 2]
# cm = sklearn.metrics.confusion_matrix(y_true, y_pred)
# cm = np.array([[2, 0, 0], [0, 0, 1], [1, 0, 2]])
# print(cm, type(cm))
# figure = plot_confusion_matrix(cm, np.array(['0', '1', '2']))
# # plt.show()

# img_d_summary_dir = "./tblog/summaries/img"
# print(img_d_summary_dir)

# sess = tf.InteractiveSession()

# img_d_summary_writer = [
#     tf.summary.FileWriter("./tblog/summaries/img/" + 'train', sess.graph),
#     tf.summary.FileWriter("./tblog/summaries/img/" + 'test', sess.graph),
# ]
# summary = [
#     tfplot.figure.to_summary(figure, tag='train'),
#     tfplot.figure.to_summary(figure, tag='test')
# ]

# for epoch in range(10):
#     for iw, w in enumerate(img_d_summary_writer):
#         w.add_summary(summary[iw], epoch)
#         w.flush()


from statsmodels.tsa.api import ExponentialSmoothing, SimpleExpSmoothing, Holt

class ExponentialSmoothingModel(object):

    def __init__(self, model_type='Simple', smoothing_level=0.9, smoothing_slope=0.9, smoothing_seasonal=0.9,
                 trend='add', seasonal='add', \
                 seasonal_periods=7):
        """
        seasonal_periods - Length of a season. For example 7 means data is weekly.
        """
        self.smoothing_level = smoothing_level
        self.smoothing_slope = smoothing_slope
        self.smoothing_seasonal = smoothing_seasonal
        self.model_type = model_type
        self.fitted_model = None
        self.trend = trend
        self.seasonal = seasonal
        self.seasonal_periods = seasonal_periods

    def fit(self, time_series_data):
        if self.model_type == 'Simple':
            self.fitted_model = SimpleExpSmoothing(time_series_data).fit(smoothing_level=self.smoothing_level)
        if self.model_type == 'Double':
            self.fitted_model = Holt(time_series_data).fit(smoothing_level=self.smoothing_level,
                                                           smoothing_slope=self.smoothing_slope)
        if self.model_type == 'Triple':
            self.fitted_model = ExponentialSmoothing(time_series_data, seasonal_periods=self.seasonal_periods, \
                                                     trend=self.trend, \
                                                     seasonal=self.seasonal).fit(smoothing_level=self.smoothing_level, \
                                                                                smoothing_slope=self.smoothing_slope, \
                                                                                smoothing_seasonal=self.smoothing_seasonal)

    def predict(self, forecast_window):
        return self.fitted_model.forecast(forecast_window)


from vanilla import *
from mojo.UI import *

class markGlyphs(object):
    def __init__(self):
        # The Tool Window
        self.w = FloatingWindow((1800, 300, 200, 195), 'Marking Tool')
        self.w.buttonMark = Button((10, 10, -10, 20), '\u2190 mark', callback=self.toggleMarkDrawer)
        self.w.buttonGroup = Button((10, 40, -10, 20), 'make group \u2192', callback=self.toggleGroupDrawer)
        # mark drawer
        self.d = Drawer((180, 160), self.w)
        self.d.componentsAndOutlinesButton = Button((10, 10, -10, 20), 'comp. + outlines', callback=self.componentsAndOutlinesCallback)
        self.d.componentsButton = Button((10,40,-10,20), 'components', callback=self.componentsCallback)
        self.d.usedAsComponentButton = Button((10,70,-10,20), 'used as components', callback=self.usedAsComponentCallback)
        self.d.markOverlapButton = Button((10,100,-10,20), 'mark overlaps', callback=self.markOverlapCallback)
        # group drawer
        self.g = Drawer((180, 120), self.w, preferredEdge = 'right')
        self.g.componentsAndOutlinesGroupButton = Button((10, 10, -10, 20), 'comp. + outlines', callback=self.componentsAndOutlinesGroupCallback)
        self.g.componentsGroupButton = Button((10, 40, -10, 20), 'components', callback=self.componentsGroupCallback)
        # self.g.usedAsComponentsGroupButton = Button((10,70,-10,20), 'used as components', callback=self.usedAsComponentsGroupCallback)

        self.w.open()
        # self.d.open()

##### Callbacks
    # open mark drawer
    def toggleMarkDrawer(self, sender):
        self.d.toggle()
    # open group drawer
    def toggleGroupDrawer(self, sender):
        self.g.toggle()
    ##### mark Callbacks
    def componentsAndOutlinesCallback(self, sender):
        font = CurrentFont()
        # glyph = CurrentGlyph()
        print('>>> Glyphs combining components and outlines:')
        print('---------------------------------------------')
        for glyph in font:
            if len(glyph.contours) > 0 and len(glyph.components) > 0:
                glyph.prepareUndo('mark components and outlines')
                glyph.markColor = 1, 0, 0.5, 0.35
                glyph.performUndo()
                print(glyph.name, end = " ")
        print('\n')

    def componentsCallback(self,sender):
        font = CurrentFont()
        # glyph = CurrentGlyph()
        print('>>> Glyphs completely made out of components:')
        print('---------------------------------------------')
        for glyph in font:
            if len(glyph.contours) == 0 and len(glyph.components) > 0:
                glyph.prepareUndo('mark components')
                glyph.markColor = 0, 0.25, 0.5, 0.35
                glyph.performUndo()
                print(glyph.name, end = " ")
        print('\n')

    def usedAsComponentCallback(self, sender):
        font = CurrentFont()
        glyph = CurrentGlyph()

        print('>>> These glyphs are used as components')
        print('---------------------------------------')
        for component in glyph.components:
            baseGlyph = font[component.baseGlyph]
            print(component.baseGlyph)
            baseGlyph.prepareUndo('marks glyphs used as components')
            baseGlyph.markColor = 0.5, 0, 1, 0.35
            baseGlyph.performUndo()
        print('\n')

    def markOverlapCallback(self, sender):
        font = CurrentFont()
        # glyph = CurrentGlyph()

        print('>>> Glyphs with overlaps')
        print('------------------------')
        for glyph in font:
            compareGlyph = glyph.copy()
            compareGlyph.removeOverlap()
            if len(glyph) != len(compareGlyph) or glyph.hasOverlap():
                print(glyph.name, end = " ")
                glyph.prepareUndo('mark overlaps')
                glyph.markColor = 0.5, 0, 0.2, 0.75
                glyph.performUndo()
        print('\n')

    ##### group Callbacks
    def componentsAndOutlinesGroupCallback(self, sender):
        contoursAndComponentsGroup = SmartSet()
        contoursAndComponentsGroup.name = 'components and outlines'
        contoursAndComponentsGroup.query = 'Contours > 0 and Components >0'
        addSmartSet(contoursAndComponentsGroup)
        updateAllSmartSets()

    def componentsGroupCallback(self, sender):
        componentsGroup = SmartSet()
        componentsGroup.name = 'components'
        componentsGroup.query = 'Contours == 0 and Components > 0'
        addSmartSet(componentsGroup)
        updateAllSmartSets()

    # def usedAsComponentsGroupCallback(self, sender):
    #     usedAsComponentsGroup = SmartSet()
    #     usedAsComponentsGroup.name = 'used as components'
    #     usedAsComponentsGroup.query = 'Color = 0.5, 0, 1, 0.35'
    #     addSmartSet(usedAsComponentsGroup)
    #     updateAllSmartSets()

markGlyphs()


# get token from https://discordapp.com/developers/applications/me
bot_token = ''

# bot settings
bot_prefix = ['!']
bot_master = 174764205927432192  # The discord ID of the owner
bot_coowners = [174764205927432192]  # The discord ID's of co-owners

# minimum required permissions
# see https://discordapi.com/permissions.html#2080762945
bot_permissions = 2080762945

# load extensions on start/restart
# alternatively load manually with !load after start.
preload_extensions = [
    'char_lookup',          # Get character info
    'dev',                  # Developer tools
    'eve_status',           # Get the status of the server and the player count
    'eve_time',             # Get the time in eve and around the world
    'group_lookup',         # Get corp/alliance info
    'jump_planner',         # Provides the shortcut for dotlan jump planning
    'jump_range',           # Provides the shortcut for dotlan jump range
    'killmail',             # Killmail posting extension
    'location_scout',       # Provides intel on systems/constellations/regions
    'price',                # Price check extension
    'sov_tracker',          # Provides real time info on sov fights

    # still in testing, use at your own risk

    # these require access tokens, please read the wiki for more information
    # 'tokens',               # Required if any in this group are enabled
    # 'eve_notifications',    # Shares notifications
    # 'eve_mail',             # Shares mail
    # 'jabber_relay'          # Completely broken, dont use me yet
    # 'rss',                  # RSS feed aggregator
    # 'eve_rpg'               # Text-based RPG game shib made

    # self-hosting only
    # 'fleet_up',             # Shares upcoming fleet-up operations
]

dm_only = False  # bot responses always sent via direct message
delete_commands = False  # user commands are deleted automatically

# Welcome message for new users
enable_welcome = False
welcome_string = (
    '**Welcome to the server!**\n\n'
    # 'To get roles, type !auth and use the returned auth system link.\n'
    'You can see available commands with `!help`'
)

# Auto Responses - Add more with the format 'trigger': 'Auto response'
# auto_responses = {
#     'auth': 'To get roles on this server visit: '
# }

# Fleet-Up Settings
# add or remove groups as needed, groups must have unique names.
# fleetUp = {
#     'group_id': 12345,  # Fleet-up group ID
#     'user_id': 12345,  # User ID from your fleet-up api-key
#     'api_code': '',  # API Code from your fleet-up api-key
#     'auto_posting': True,  # Change to False if you don't want the bot to automatically post new and upcoming fleets
#     'channel_id': 12345,  # Channel to post fleet-up operations
# }

# RSS settings
# rss = {
#     'channelId': 12345,      # Default channel to which entries are sent
#     'updateInterval': 15,    # Time in minutes to wait between checks for new RSS content
#     'feeds': {
#         'eveNews': {
#             'uri': 'https://www.eveonline.com/rss/news',    # RSS feed URL
#             'channelId': 12345, # Channel to which feed should be sent. Override rss.channelId
#         },
#         'bbc': {
#             'uri': 'https://feeds.bbci.co.uk/news/world/rss.xml?edition=uk'
#         },
#     },
# }


from collections import defaultdict
from dataclasses import dataclass, field
from datetime import datetime
from typing import Any, DefaultDict, Dict, Iterable, List, Set

import datahub.emitter.mce_builder as builder
from datahub.ingestion.api.workunit import MetadataWorkUnit
from datahub.ingestion.source.sagemaker_processors.common import SagemakerSourceReport
from datahub.ingestion.source.sagemaker_processors.jobs import JobDirection, ModelJob
from datahub.ingestion.source.sagemaker_processors.lineage import LineageInfo
from datahub.metadata.com.linkedin.pegasus2avro.metadata.snapshot import (
    MLModelDeploymentSnapshot,
    MLModelGroupSnapshot,
    MLModelSnapshot,
)
from datahub.metadata.com.linkedin.pegasus2avro.mxe import MetadataChangeEvent
from datahub.metadata.schema_classes import (
    DeploymentStatusClass,
    MLModelDeploymentPropertiesClass,
    MLModelGroupPropertiesClass,
    MLModelPropertiesClass,
    OwnerClass,
    OwnershipClass,
    OwnershipTypeClass,
)

ENDPOINT_STATUS_MAP: Dict[str, str] = {
    "OutOfService": DeploymentStatusClass.OUT_OF_SERVICE,
    "Creating": DeploymentStatusClass.CREATING,
    "Updating": DeploymentStatusClass.UPDATING,
    "SystemUpdating": DeploymentStatusClass.UPDATING,
    "RollingBack": DeploymentStatusClass.ROLLING_BACK,
    "InService": DeploymentStatusClass.IN_SERVICE,
    "Deleting": DeploymentStatusClass.DELETING,
    "Failed": DeploymentStatusClass.FAILED,
    "Unknown": DeploymentStatusClass.UNKNOWN,
}

@dataclass
class ModelProcessor:
    sagemaker_client: Any
    env: str
    report: SagemakerSourceReport
    lineage: LineageInfo

    # map from model image file path to jobs referencing the model
    model_image_to_jobs: DefaultDict[str, Set[ModelJob]] = field(
        default_factory=lambda: defaultdict(set)
    )

    # map from model name to jobs referencing the model
    model_name_to_jobs: DefaultDict[str, Set[ModelJob]] = field(
        default_factory=lambda: defaultdict(set)
    )

    # map from model uri to model name
    model_uri_to_name: Dict[str, str] = field(default_factory=dict)
    # map from model image path to model name
    model_image_to_name: Dict[str, str] = field(default_factory=dict)

    def get_all_models(self) -> List[Dict[str, Any]]:
        """
        List all models in SageMaker.
        """

        models = []

        # see https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker.html#SageMaker.Client.list_models
        paginator = self.sagemaker_client.get_paginator("list_models")
        for page in paginator.paginate():
            models += page["Models"]

        return models

    def get_model_details(self, model_name: str) -> Dict[str, Any]:
        """
        Get details of a model.
        """

        # see https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker.html#SageMaker.Client.describe_model
        return self.sagemaker_client.describe_model(ModelName=model_name)

    def get_all_groups(self) -> List[Dict[str, Any]]:
        """
        List all model groups in SageMaker.
        """
        groups = []

        # see https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker.html#SageMaker.Client.list_model_package_groups
        paginator = self.sagemaker_client.get_paginator("list_model_package_groups")
        for page in paginator.paginate():
            groups += page["ModelPackageGroupSummaryList"]

        return groups

    def get_group_details(self, group_name: str) -> Dict[str, Any]:
        """
        Get details of a model group.
        """

        # see https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker.html#SageMaker.Client.describe_model_package_group
        return self.sagemaker_client.describe_model_package_group(
            ModelPackageGroupName=group_name
        )

    def get_all_endpoints(self) -> List[Dict[str, Any]]:

        endpoints = []

        # see https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker.html#SageMaker.Client.list_endpoints
        paginator = self.sagemaker_client.get_paginator("list_endpoints")

        for page in paginator.paginate():
            endpoints += page["Endpoints"]

        return endpoints

    def get_endpoint_details(self, endpoint_name: str) -> Dict[str, Any]:

        # see https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker.html#SageMaker.Client.describe_endpoint
        return self.sagemaker_client.describe_endpoint(EndpointName=endpoint_name)

    def get_endpoint_status(
        self, endpoint_name: str, endpoint_arn: str, sagemaker_status: str
    ) -> str:
        endpoint_status = ENDPOINT_STATUS_MAP.get(sagemaker_status)

        if endpoint_status is None:

            self.report.report_warning(
                endpoint_arn,
                f"Unknown status for {endpoint_name} ({endpoint_arn}): {sagemaker_status}",
            )

            endpoint_status = DeploymentStatusClass.UNKNOWN

        return endpoint_status

    def get_endpoint_wu(self, endpoint_details: Dict[str, Any]) -> MetadataWorkUnit:
        """a
        Get a workunit for an endpoint.
        """

        # params to remove since we extract them
        redundant_fields = {"EndpointName", "CreationTime"}

        endpoint_snapshot = MLModelDeploymentSnapshot(
            urn=builder.make_ml_model_deployment_urn(
                "sagemaker", endpoint_details["EndpointName"], self.env
            ),
            aspects=[
                MLModelDeploymentPropertiesClass(
                    createdAt=int(
                        endpoint_details.get("CreationTime", datetime.now()).timestamp()
                        * 1000
                    ),
                    status=self.get_endpoint_status(
                        endpoint_details["EndpointArn"],
                        endpoint_details["EndpointName"],
                        endpoint_details.get("EndpointStatus", "Unknown"),
                    ),
                    customProperties={
                        key: str(value)
                        for key, value in endpoint_details.items()
                        if key not in redundant_fields
                    },
                )
            ],
        )

        # make the MCE and workunit
        mce = MetadataChangeEvent(proposedSnapshot=endpoint_snapshot)

        return MetadataWorkUnit(
            id=f'{endpoint_details["EndpointName"]}',
            mce=mce,
        )

    def get_model_wu(
        self, model_details: Dict[str, Any], endpoint_arn_to_name: Dict[str, str]
    ) -> MetadataWorkUnit:
        """
        Get a workunit for a model.
        """

        # params to remove since we extract them
        redundant_fields = {"ModelName", "CreationTime"}

        model_image = model_details.get("PrimaryContainer", {}).get("Image")
        model_uri = model_details.get("PrimaryContainer", {}).get("ModelDataUrl")

        model_endpoints = set()

        # get endpoints and groups by model image
        if model_image is not None:
            model_endpoints |= self.lineage.model_image_endpoints[model_image]
            self.model_image_to_name[model_image] = model_details["ModelName"]

        # get endpoints and groups by model uri
        if model_uri is not None:
            model_endpoints |= self.lineage.model_uri_endpoints[model_uri]
            self.model_uri_to_name[model_uri] = model_details["ModelName"]

        # sort endpoints and groups for consistency
        model_endpoints_sorted = sorted(
            [x for x in model_endpoints if x in endpoint_arn_to_name]
        )

        model_training_jobs: Set[str] = set()
        model_downstream_jobs: Set[str] = set()

        # extract model data URLs for matching with jobs
        model_data_urls = []

        for model_container in model_details.get("Containers", []):
            model_data_url = model_container.get("ModelDataUrl")

            if model_data_url is not None:
                model_data_urls.append(model_data_url)
        model_data_url = model_details.get("PrimaryContainer", {}).get("ModelDataUrl")
        if model_data_url is not None:
            model_data_urls.append(model_data_url)

        for model_data_url in model_data_urls:

            data_url_matched_jobs = self.model_image_to_jobs.get(model_data_url, set())
            # extend set of training jobs
            model_training_jobs = model_training_jobs.union(
                {
                    job.job_urn
                    for job in data_url_matched_jobs
                    if job.job_direction == JobDirection.TRAINING
                }
            )
            # extend set of downstream jobs
            model_downstream_jobs = model_downstream_jobs.union(
                {
                    job.job_urn
                    for job in data_url_matched_jobs
                    if job.job_direction == JobDirection.DOWNSTREAM
                }
            )

        # get jobs referencing the model by name
        name_matched_jobs = self.model_name_to_jobs.get(
            model_details["ModelName"], set()
        )
        # extend set of training jobs
        model_training_jobs = model_training_jobs.union(
            {
                job.job_urn
                for job in name_matched_jobs
                if job.job_direction == JobDirection.TRAINING
            }
        )
        # extend set of downstream jobs
        model_downstream_jobs = model_downstream_jobs.union(
            {
                job.job_urn
                for job in name_matched_jobs
                if job.job_direction == JobDirection.DOWNSTREAM
            }
        )

        model_snapshot = MLModelSnapshot(
            urn=builder.make_ml_model_urn(
                "sagemaker", model_details["ModelName"], self.env
            ),
            aspects=[
                MLModelPropertiesClass(
                    date=int(
                        model_details.get("CreationTime", datetime.now()).timestamp()
                        * 1000
                    ),
                    deployments=[
                        builder.make_ml_model_deployment_urn(
                            "sagemaker", endpoint_name, self.env
                        )
                        for endpoint_name in model_endpoints_sorted
                    ],
                    customProperties={
                        key: str(value)
                        for key, value in model_details.items()
                        if key not in redundant_fields
                    },
                    trainingJobs=sorted(list(model_training_jobs)),
                    downstreamJobs=sorted(list(model_downstream_jobs)),
                )
            ],
        )

        # make the MCE and workunit
        mce = MetadataChangeEvent(proposedSnapshot=model_snapshot)

        return MetadataWorkUnit(
            id=f'{model_details["ModelName"]}',
            mce=mce,
        )

    def get_group_wu(self, group_details: Dict[str, Any]) -> MetadataWorkUnit:
        """
        Get a workunit for a model group.
        """

        # params to remove since we extract them
        redundant_fields = {"ModelPackageGroupName", "CreationTime"}

        group_arn = group_details["ModelPackageGroupArn"]

        group_model_names = set()

        if group_arn in self.lineage.group_model_uris:
            model_uris = self.lineage.group_model_uris[group_arn]
            group_model_names |= {
                self.model_uri_to_name[x]
                for x in model_uris
                if x in self.model_uri_to_name
            }

        if group_arn in self.lineage.group_model_images:
            model_images = self.lineage.group_model_images[group_arn]
            group_model_names |= {
                self.model_image_to_name[x]
                for x in model_images
                if x in self.model_uri_to_name
            }

        owners = []

        if group_details.get("CreatedBy", {}).get("UserProfileName") is not None:
            owners.append(
                OwnerClass(
                    owner=group_details["CreatedBy"]["UserProfileName"],
                    type=OwnershipTypeClass.DATAOWNER,
                )
            )

        group_snapshot = MLModelGroupSnapshot(
            urn=builder.make_ml_model_group_urn(
                "sagemaker", group_details["ModelPackageGroupName"], self.env
            ),
            aspects=[
                MLModelGroupPropertiesClass(
                    createdAt=int(
                        group_details.get("CreationTime", datetime.now()).timestamp()
                        * 1000
                    ),
                    description=group_details.get("ModelPackageGroupDescription"),
                    customProperties={
                        key: str(value)
                        for key, value in group_details.items()
                        if key not in redundant_fields
                    },
                    models=sorted(
                        [
                            builder.make_ml_model_urn("sagemaker", model_name, self.env)
                            for model_name in group_model_names
                        ]
                    ),
                ),
                OwnershipClass(owners),
            ],
        )

        # make the MCE and workunit
        mce = MetadataChangeEvent(proposedSnapshot=group_snapshot)

        return MetadataWorkUnit(id=f'{group_details["ModelPackageGroupName"]}', mce=mce)

    def get_workunits(self) -> Iterable[MetadataWorkUnit]:

        endpoints = self.get_all_endpoints()
        # sort endpoints for consistency
        endpoints = sorted(endpoints, key=lambda x: x["EndpointArn"])

        endpoint_arn_to_name = {}

        # ingest endpoints first since we need to know the endpoint ARN -> name mapping
        for endpoint in endpoints:

            endpoint_details = self.get_endpoint_details(endpoint["EndpointName"])

            endpoint_arn_to_name[endpoint["EndpointArn"]] = endpoint_details[
                "EndpointName"
            ]

            self.report.report_endpoint_scanned()
            wu = self.get_endpoint_wu(endpoint_details)
            self.report.report_workunit(wu)
            yield wu

        models = self.get_all_models()
        # sort models for consistency
        models = sorted(models, key=lambda x: x["ModelArn"])

        for model in models:

            model_details = self.get_model_details(model["ModelName"])

            self.report.report_model_scanned()
            wu = self.get_model_wu(model_details, endpoint_arn_to_name)
            self.report.report_workunit(wu)
            yield wu

        groups = self.get_all_groups()
        # sort groups for consistency
        groups = sorted(groups, key=lambda x: x["ModelPackageGroupName"])

        # ingest endpoints first since we need to know the endpoint ARN -> name mapping
        for group in groups:

            group_details = self.get_group_details(group["ModelPackageGroupName"])

            self.report.report_group_scanned()
            wu = self.get_group_wu(group_details)
            self.report.report_workunit(wu)
            yield wu


########################################################
# commons.py: common functions for all compressive monitors
# Author: Jamie Zhu <jimzhu@GitHub>
# Created: 2015/8/17
# Last updated: 2015/8/25
########################################################

import numpy as np
import random

#======================================================#
# Function to remove the entries of data matrix
#======================================================#
def removeEntries(matrix, density, roundId):
    (numRow, numCol) = matrix.shape
    seedId = roundId
    removedMatrix = np.zeros(matrix.shape)
    for i in xrange(numCol):
        randomSequence = range(0, numRow)
        random.seed(seedId + i)
        random.shuffle(randomSequence) # one random sequence
        numSample = int(numRow * density)
        sampleIdx = randomSequence[0 : numSample]
        removedMatrix[sampleIdx, i] = matrix[sampleIdx, i]
    return removedMatrix


# coding: utf-8
import numpy as np
import torch
from torch import nn
from torch.nn import functional as F
from torch.nn.modules.activation import MultiheadAttention

from .embedding.CustomEmbedding import CustomEmbedding

class littleBert(nn.Module):
    def __init__(self, pad_idx=0, bos_idx=1, eos_idx=2, max_len=300, d_model=512, d_embedding=256, n_head=8,
                 dim_feedforward=2048, n_layers=10, dropout=0.1, device=None):
        super(littleBert, self).__init__()

        self.pad_idx = pad_idx
        self.bos_idx = bos_idx
        self.eos_idx = eos_idx
        self.max_len = max_len

        self.dropout = nn.Dropout(dropout)
        self.device = device

        # Source embedding part
        self.src_embedding = CustomEmbedding(d_embedding, d_model, device=self.device, pad_idx=self.pad_idx)

        # Transformer
        self_attn = MultiheadAttention(d_model, n_head, dropout=dropout)
        self.encoders = nn.ModuleList([
            TransformerEncoderLayer(d_model, self_attn, dim_feedforward,
                activation='gelu', dropout=dropout) for i in range(n_layers)])

        # Output of model
        self.linear = nn.Linear(d_model, 1)

    def forward(self, sequence, hour, weekday, location):
        encoder_out = self.src_embedding(sequence, hour, weekday, location)
        # print(encoder_out)
        # return encoder_out
        # print(encoder_out)
        # # src_key_padding_mask = sequence == self.pad_idx

        for i in range(len(self.encoders)):
            encoder_out = self.encoders[i](encoder_out)
        outputs = self.linear(encoder_out)

        return outputs.squeeze(2)

class TransformerEncoderLayer(nn.Module):
    def __init__(self, d_model, self_attn, dim_feedforward=2048, dropout=0.1,
            activation="relu"):

        super(TransformerEncoderLayer, self).__init__()
        self.self_attn = self_attn

        # Implementation of Feedforward model
        self.linear1 = nn.Linear(d_model, dim_feedforward)
        self.dropout = nn.Dropout(dropout)
        self.linear2 = nn.Linear(dim_feedforward, d_model)

        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)
        self.dropout1 = nn.Dropout(dropout)
        self.dropout2 = nn.Dropout(dropout)

    def forward(self, src, src_mask=None, src_key_padding_mask=None):
        src2 = self.self_attn(src, src, src, attn_mask=src_mask,
                              key_padding_mask=src_key_padding_mask)[0]
        src = src + self.dropout1(src2)
        src = self.norm1(src)
        src2 = self.linear2(self.dropout(F.gelu(self.linear1(src))))
        src = src + self.dropout2(src2)
        src = self.norm2(src)
        return src


from Utils.LinkedList import LinkedList
from Utils.Queue import Queue
import enum

class AnimalType(enum.Enum):
    Cat = 1
    Dog = 2

class AnimalNode:
    def __init__(self, name,date):
        self.name = name
        self.date = date

    def print(self):
        print("Printing AnimalNode")
        print(self.name)
        print(self.date)
        print("-----------")

class AnimalShelter:
    def __init__(self):
        self.dogList = LinkedList()
        self.catList = LinkedList()
        self.date = 0

    def enqueue(self,animalName,animalType):
        self.date += 1
        if animalType == AnimalType.Cat:
            node = AnimalNode(animalName,self.date)
            self.catList.insertTail(node)
        elif animalType == AnimalType.Dog:
            node = AnimalNode(animalName, self.date)
            self.dogList.insertTail(node)
        else:
            self.date -= 1

    def findOldestAnimal(self, linkedList):
        oldestAnimalNode = linkedList.head
        date = oldestAnimalNode.data.date
        traverseNode = linkedList.head
        while traverseNode.next is not None:
            if date > traverseNode.next.data.date:
                oldestAnimalNode = traverseNode.next

            traverseNode = traverseNode.next

        return oldestAnimalNode

    def dequeuDog(self):
        if self.dogList.isEmpty():
            print("Error: the list empty")
            return
        else:
            oldestNode = self.findOldestAnimal(self.dogList)
            self.dogList.removeNode(oldestNode.data)
            return oldestNode

    def dequeuCat(self):
        if self.catList.isEmpty():
            print("Error: the list empty")
            return
        else:
            oldestNode = self.findOldestAnimal(self.catList)
            self.catList.removeNode(oldestNode.data)
            return oldestNode

    def dequeueAny(self):
        oldestCatNode = None
        oldestDogNode = None

        if self.catList.isEmpty():
            print("Warning: cat the list empty")
        else:
            oldestCatNode = self.findOldestAnimal(self.catList)

        if self.dogList.isEmpty():
            print("Warning: dog list empty")
        else:
            oldestDogNode = self.findOldestAnimal(self.dogList)

        if oldestDogNode.data.date > oldestCatNode.data.date:
            self.catList.removeNode(oldestCatNode.data)
            return oldestCatNode
        else:
            self.dogList.removeNode(oldestDogNode.data)
            return oldestDogNode

    def printAll(self):
        print("Printing Dog")
        self.dogList.printList()

        print("Printing Cat")
        self.catList.printList()

if __name__ == '__main__':
    a = AnimalShelter()
    a.enqueue("ali",AnimalType.Dog)
    a.enqueue("veli",AnimalType.Dog)
    a.printAll()
    animal = a.dequeuDog()
    animal.data.print()

    a.enqueue("puppy",AnimalType.Cat)
    a.enqueue("kiraz",AnimalType.Cat)
    a.printAll()

    animal = a.dequeueAny()
    animal.data.print()

    a.enqueue("deli",AnimalType.Dog)
    a.printAll()

    animal = a.dequeueAny()
    animal.data.print()


from room import Room
from player import Player
from world import World
from foo import foo

import random
from ast import literal_eval
from collections import deque

#* HELPER METHODS
# rooms2obj takes the world's rooms object and produces a familiar
#    graph adjacency matrix
def rooms2obj(rms):
    ret_grph_work = {}
    ret_grph_vstd = {}

    # Iterate through rooms dict
    for k, rm in rms.items():
        # Initialize a room directive dict value
        tmp_wrk_dict = {
            "n": None,
            "s": None,
            "e": None,
            "w": None
        }
        tmp_vst_dict = {
            "n": True,
            "s": True,
            "e": True,
            "w": True
        }
        if rm.n_to != None:
            tmp_wrk_dict["n"] = rm.n_to.id
            tmp_vst_dict["n"] = False
        if rm.s_to != None:
            tmp_wrk_dict["s"] = rm.s_to.id
            tmp_vst_dict["s"] = False
        if rm.e_to != None:
            tmp_wrk_dict["e"] = rm.e_to.id
            tmp_vst_dict["e"] = False
        if rm.w_to != None:
            tmp_wrk_dict["w"] = rm.w_to.id
            tmp_vst_dict["w"] = False

        # Assign the room directive to the return graph
        ret_grph_work[k] = tmp_wrk_dict
        ret_grph_vstd[k] = tmp_vst_dict

    # Done iterating - return the built graph
    return (ret_grph_work, ret_grph_vstd)

# gen_next_step takes a room and generates the next step to process in the
#    traversal
def gen_next_step(nde):
    # inspect the directive dict for this room (in the working graph)
    nde_status  = graph_vst[nde]

    # Find a key (direction) that has not been inspected/visted
    for dr, vstd in nde_status.items():
        # has this node's direction been visited?
        if vstd:
            # yes, skip to another direction
            continue

        # Found a node direction not visited - return
        nde_drtv = graph_trv[nde]
        return (True, dr, nde_drtv[dr])  # (returned_next_step=True, directive, next_node)

    # Iteration complete: no step identified
    return (False, "", -999)             # (returned_next_step=False)

# gen_back_up_step takes a directive INTO a node and generates
#   the directive needed to step BACK OUT of the node (its inverse)
def gen_back_up_step(dir_in):
    tmp_dict = {
        "n": "s",
        "s": "n",
        "e": "w",
        "w": "e"
    }

    return tmp_dict[dir_in]

# node_paths_exhausted determines if all of the node's directional
#   pathways have been exhausted
def node_paths_exhausted(nde):
    ret_bool = True

    for dir, boul in graph_vst[nde].items():
        ret_bool = (ret_bool and boul)

    return ret_bool

# trav_graph traverses a constructed graph object starting
#   with the passed start node and returns traversed path
def trav_graph(grph, strt):

    # deep_dive traverses down a graph thread recursively
    def deep_dive(nde):

        # node_dive does a deep traversal from the passed node in a recursive manner
        def node_dive(nod):
            # Are we at the end of the dive (no children to traverse to)
            rslt_tup = gen_next_step(nod)
            if not rslt_tup[0]:
                # reached the end of the thread - return the current node
                path_trvse_id.append(nod)  # add node to our running traversal path
                return nod

            # Have a node to continue traversing in this thread
            cur_node = nod
            nxt_node = rslt_tup[2]
            cur_dirt = rslt_tup[1]
            path_trvse_id.append(nod)                       # add to our running traversal path
            path_trvse_drt.append(cur_dirt)                 # add to our running execution of steps ("n","s","e","w")
            path_bkup.append(gen_back_up_step(cur_dirt))    # add directive to get back to the current node
                                                            # from the next node (inverse of cur_dirt)

            # Mark node/directives as visted/inspected
            graph_vst[cur_node][cur_dirt] = True                    # mark the current node/current directive as visited
            graph_vst[nxt_node][gen_back_up_step(cur_dirt)] = True  # mark the next node's back path to the current node
                                                                    # as visited so we don't double back on ourselves

            # traverse deeper into the graph thread by calling node_dive recursively
            #    on the next node
            return node_dive(nxt_node)

        # Trigger the recursive deep dive starting with the passed node
        rt_node = node_dive(nde)
        return rt_node

    # Kick off the action and take a deep dive from the starting node
    current_node = deep_dive(strt)

    # Keep diving while the back up stack has values
    while len(path_bkup) != 0:
        # pop the last back up path directive (to get us to node upstream)
        bk_dir = path_bkup.pop()

        # take a deep dive on this node (after backing up one node)
        bk_nde = graph_trv[current_node][bk_dir]
        path_trvse_drt.append(bk_dir)               # add to our running execution of steps ("n","s","e","w"
        current_node = deep_dive(bk_nde)

        """
        # Are we back at the starting node?
        #   If so: have all paths from the starting node
        #   been visited? If yes: assume we're done
        if current_node == strt:
            if node_paths_exhausted(strt):
                # We're back to the start and all paths from the node
                #   have been traversed.  Assume we're done - break out
                #   of the process
                break
        """

#****************************************
#* MAIN PROC
# Load world
world = World()

# You may uncomment the smaller graphs for development and testing purposes.
# map_file = "maps/test_line.txt"
# map_file = "maps/test_cross.txt"
# map_file = "maps/test_loop.txt"
# map_file = "maps/test_loop_fork.txt"
map_file = "maps/main_maze.txt"

# Loads the map into a dictionary
room_graph=literal_eval(open(map_file, "r").read())
world.load_graph(room_graph)

# Print an ASCII map
world.print_rooms()

# Parse through the "world" object and construct an adjacency matrix
my_graphs       = rooms2obj(world.rooms)
# graph_trv is a graph object used to traverse the world
#   it is a simpler representation of the world
graph_trv       = my_graphs[0]
# graph_vst is a dedicated graph object used to determine if node
#  pathway has already been visited
graph_vst       = my_graphs[1]
# path_trvse_id represents the path taken by node (e.g. "0" -> "4" -> "2", etc.)
path_trvse_id   = []
# path_trvse_drt represents the path taken by directive (e.g. "n" -> "n" -> "w" -> "s", etc.)
path_trvse_drt  = []
# path_bkup is a stack object that represents the steps needed to "back out"
#   of a deep dive into a graph thread of nodes
path_bkup       = deque()

#* Start traversing
trav_graph(graph_trv, world.starting_room.id)

player = Player(world.starting_room)

# Assign the traversal path (for testing)
traversal_path = path_trvse_drt

# TRAVERSAL TEST - DO NOT MODIFY
visited_rooms = set()
player.current_room = world.starting_room
visited_rooms.add(player.current_room)

for move in traversal_path:
    player.travel(move)
    visited_rooms.add(player.current_room)

if len(visited_rooms) == len(room_graph):
    print(f"TESTS PASSED: {len(traversal_path)} moves, {len(visited_rooms)} rooms visited")
else:
    print("TESTS FAILED: INCOMPLETE TRAVERSAL")
    print(f"{len(room_graph) - len(visited_rooms)} unvisited rooms")

"""
#######
# UNCOMMENT TO WALK AROUND
#######
player.current_room.print_room_description(player)
while True:
    cmds = input("-> ").lower().split(" ")
    if cmds[0] in ["n", "s", "e", "w"]:
        player.travel(cmds[0], True)
    elif cmds[0] == "q":
        break
    else:
        print("I did not understand that command.")
"""


# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import absolute_import, print_function, division
from collections import deque

import numpy as np
from six.moves import range

from .neuralnet_helpers import make_network
from .common import masked_mae
from .solver import Solver

class AutoEncoder(Solver):
    """
    Neural network which takes as an input a vector of feature values and a
    binary mask of indicating which features are missing. It's trained
    on reconstructing the non-missing values and hopefully achieves
    generalization due to a "bottleneck" hidden layer that is smaller than
    the input size.
    """

    def __init__(
            self,
            hidden_activation="tanh",
            output_activation="linear",
            hidden_layer_sizes=None,
            optimizer="adam",
            dropout_probability=0,
            batch_size=32,
            l1_penalty=0,
            l2_penalty=0,
            recurrent_weight=0.5,
            n_burn_in_epochs=1,
            missing_input_noise_weight=0,
            output_history_size=25,
            patience_epochs=100,
            min_improvement=0.999,
            max_training_epochs=None,
            init_fill_method="zero",
            min_value=None,
            max_value=None,
            verbose=True):
        Solver.__init__(
            self,
            fill_method=init_fill_method,
            min_value=min_value,
            max_value=max_value)

        self.hidden_activation = hidden_activation
        self.output_activation = output_activation
        self.hidden_layer_sizes = hidden_layer_sizes
        self.optimizer = optimizer
        self.dropout_probability = dropout_probability
        self.batch_size = batch_size
        self.l1_penalty = l1_penalty
        self.l2_penalty = l2_penalty
        self.hidden_layer_sizes = hidden_layer_sizes
        self.recurrent_weight = recurrent_weight
        self.n_burn_in_epochs = n_burn_in_epochs
        self.missing_input_noise_weight = missing_input_noise_weight
        self.output_history_size = output_history_size
        self.patience_epochs = patience_epochs
        self.min_improvement = min_improvement
        self.max_training_epochs = max_training_epochs
        self.verbose = verbose

        # network and its input size get set on first call to complete()
        self.network = None
        self.network_input_size = None

    def _create_fresh_network(self, n_features):
        return make_network(
            n_dims=n_features,
            output_activation=self.output_activation,
            hidden_activation=self.hidden_activation,
            hidden_layer_sizes=self.hidden_layer_sizes,
            dropout_probability=self.dropout_probability,
            l1_penalty=self.l1_penalty,
            l2_penalty=self.l2_penalty,
            optimizer=self.optimizer)

    def _train_epoch(self, X, missing_mask):
        """
        Trains the network for one pass over the data,
        returns the network's predictions on the training data.
        """
        n_samples = len(X)
        n_batches = int(np.ceil(n_samples / self.batch_size))
        X_with_missing_mask = np.hstack([X, missing_mask])
        indices = np.arange(n_samples)
        np.random.shuffle(indices)
        X_shuffled = X_with_missing_mask[indices]

        for batch_idx in range(n_batches):
            batch_start = batch_idx * self.batch_size
            batch_end = (batch_idx + 1) * self.batch_size
            batch_data = X_shuffled[batch_start:batch_end, :]
            self.network.train_on_batch(
                X=batch_data,
                y=batch_data)
        return self.network.predict(X_with_missing_mask)

    def _get_training_params(self, n_samples):
        if not self.max_training_epochs:
            actual_batch_size = min(self.batch_size, n_samples)
            n_updates_per_epoch = int(np.ceil(n_samples / actual_batch_size))
            # heuristic of ~1M updates for each model
            max_training_epochs = int(
                np.ceil(0.5 * 10 ** 6 / n_updates_per_epoch))
            if self.verbose:
                print("[AutoEncoder] Max Epochs: %d" % max_training_epochs)
        else:
            max_training_epochs = self.max_training_epochs

        if not self.patience_epochs:
            patience_epochs = int(np.ceil(max_training_epochs / 100))
            if self.verbose:
                print(
                    ("[AutoEncoder] Default patience"
                     "(# epochs before improvement): %d") % (patience_epochs,))
        else:
            patience_epochs = self.patience_epochs

        return max_training_epochs, patience_epochs

    def solve(self, X, missing_mask):
        n_samples, n_features = X.shape

        if self.network_input_size != n_features:
            # create a network for each distinct input size
            self.network = self._create_fresh_network(n_features)
            self.network_input_size = n_features

        assert self.network is not None, \
            "Network should have been constructed but was found to be None"

        max_training_epochs, patience_epochs = self._get_training_params(
            n_samples)

        observed_mask = ~missing_mask

        best_error_seen = np.inf
        epochs_since_best_error = 0
        recent_predictions = deque([], maxlen=self.output_history_size)

        for epoch in range(max_training_epochs):
            X_pred = self._train_epoch(X=X, missing_mask=missing_mask)
            recent_predictions.append(X_pred)
            observed_mae = masked_mae(
                X_true=X,
                X_pred=X_pred,
                mask=observed_mask)

            if epoch == 0:
                best_error_seen = observed_mae
            elif observed_mae / best_error_seen < self.min_improvement:
                best_error_seen = observed_mae
                epochs_since_best_error = 0
            else:
                epochs_since_best_error += 1

            if self.verbose:
                print("[AutoEncoder] Epoch %d/%d Observed MAE=%f %s" % (
                    epoch + 1,
                    max_training_epochs,
                    observed_mae,
                    " *" if epochs_since_best_error == 0 else ""))
            if patience_epochs and epochs_since_best_error > patience_epochs:
                if self.verbose:
                    print(
                        "Patience exceeded at epoch %d (best MAE=%0.4f)" % (
                            epoch + 1,
                            best_error_seen))
                break

            # start updating the inputs with imputed values after
            # pre-specified number of epochs exceeded
            if epoch >= self.n_burn_in_epochs:
                old_weight = (1.0 - self.recurrent_weight)
                X[missing_mask] *= old_weight
                pred_missing = X_pred[missing_mask]
                X[missing_mask] += self.recurrent_weight * pred_missing
                if self.missing_input_noise_weight:
                    noise = np.random.randn(*pred_missing.shape)
                    X[missing_mask] += (
                        self.missing_input_noise_weight * noise)
        return np.mean(recent_predictions, axis=0)


class SignalNode(object):
    def __init__(self,elem):
        self.elem=elem
        self.next=None

class SignalList(object):
    def __init__(self,node=None):
        self.__head=node

    def is_empty(self):
        return self.__head is None

    def length(self):
        n=0
        cur=self.__head
        while cur:
            n+=1
            cur=cur.next
        return n

    def travel(self):
        cur=self.__head
        while cur:
            print(cur.elem,end=',')
            cur=cur.next
        print('')

    def add(self,item):
        node=SignalNode(item)
        node.next=self.__head
        self.__head=node

    def append(self,item):
        node=SignalNode(item)
        if self.is_empty():
            self.__head=node
        else:
            cur=self.__head
            while cur.next!=None:
                cur=cur.next
            cur.next=node

    def insert(self,pos,item):#pos起始从0开始
        node=SignalNode(item)
        n=0
        pre = self.__head
        if pos<=0:
            self.add(item)
        elif pos>(self.length()-1):
            self.append(item)
        else:
            while n < (pos-1):
                pre = pre.next
                n += 1
            node.next = pre.next
            pre.next = node

    def search(self,item):
        cur=self.__head
        while cur!=None:
            if cur.elem==item:
                return True
            else:
                cur=cur.next
        return False

    def remove(self,item):
        #node=SignalNode(item)
        pre,cur=None,self.__head
        while cur!=None:
            if cur.elem == item:
                if cur==self.__head:
                    cur=cur.next
                else:
                    pre.next=cur.next
                    cur = cur.next
            else:
                pre=cur
                cur=cur.next

    def reverseList(self):
        head=self.__head
        pre, cur = None, head
        while cur:
            tmp = cur.next
            cur.next = pre
            pre = cur
            cur = tmp
        return pre

    # def remove(self,item):
    #     #node=SignalNode(item)
    #     pre,cur=None,self.__head
    #     while cur!=None:
    #         if cur.elem == item:
    #             if cur==self.__head:
    #                 cur=cur.next
    #             else:
    #                 pre.next=cur.next
    #             break
    #         else:
    #             pre=cur
    #             cur=cur.next

if __name__ == "__main__":
    ll = SignalList()
    #print(ll.is_empty())
    #print(ll.length())
    # ll.add(9)

    ll.append(1)
    #print(ll.is_empty())
    #print(ll.length())

    ll.append(2)
    #ll.add(8)
    ll.append(3)
    ll.append(4)
    ll.append(5)
    ll.append(6)
    #ll.travel()
    # ll.add(7)
    # ll.insert(3, 100)
    # ll.insert(4, 100)# 7 1 2 100 3 4 5 6
    # ll.insert(6, 100)
    ll.travel()
    ll.reverseList()
    # ll.search(10000)
    # ll.remove(100)
    # ll.travel()


from datetime import datetime                                                                          # type: ignore
from flask import abort, make_response, Markup, redirect, render_template, request, Response, url_for  # type: ignore
from flask_weasyprint import HTML, render_pdf                                                          # type: ignore
import re

from service import address_utils, api_client, app, title_formatter, title_utils
from service.forms import TitleSearchForm, SigninForm

TITLE_NUMBER_REGEX = re.compile('^([A-Z]{0,3}[1-9][0-9]{0,5}|[0-9]{1,6}[ZT])$')
POSTCODE_REGEX = re.compile(address_utils.BASIC_POSTCODE_REGEX)

USERNAME = 'Darcy Bloggs'

@app.route('/cookies', methods=['GET'])
def cookies():
    return _cookies_page()

@app.route('/login', methods=['GET'])
def signin_page():
    return _login_page()

@app.route('/login', methods=['POST'])
def sign_in():
    title_number = request.args.get('title_number')
    search_term = request.args.get('search_term', title_number)
    display_page_number = int(request.args.get('page') or 1)

    form = SigninForm(csrf_enabled=False)

    if not form.validate():
        # entered invalid login form details so send back to same page with form error messages
        return _login_page(form)
    else:
        next_url = request.args.get('next')
        if next_url:
            return redirect(next_url)
        else:
            return redirect(url_for('find_titles', title_number=title_number, search_term=search_term, page=display_page_number))

@app.route('/logout', methods=['GET'])
def sign_out():
    return redirect(url_for('sign_in'))

@app.route('/titles/<title_number>', methods=['GET'])
def get_title(title_number):
    title = _get_register_title(title_number)

    if title:
        search_term = request.args.get('search_term', title_number)
        display_page_number = int(request.args.get('page') or 1)
        breadcrumbs = _breadcumbs_for_title_details(title_number, search_term, display_page_number)
        show_pdf = True
        full_title_data = None

        return _title_details_page(title, search_term, display_page_number, breadcrumbs, show_pdf, full_title_data)
    else:
        abort(404)

@app.route('/titles/<title_number>.pdf', methods=['GET'])
def display_title_pdf(title_number):
    title = _get_register_title(title_number)
    if title:
        full_title_data = api_client.get_official_copy_data(title_number)
        if full_title_data:
            sub_registers = full_title_data.get('official_copy_data', {}).get('sub_registers')
            if sub_registers:
                html = _create_pdf_template(sub_registers, title, title_number)
                return render_pdf(HTML(string=html))
    abort(404)

@app.route('/title-search', methods=['POST'])
@app.route('/title-search/<search_term>', methods=['POST'])
def find_titles():
    display_page_number = int(request.args.get('page') or 1)

    search_term = request.form['search_term'].strip()
    if search_term:
        return redirect(url_for('find_titles', search_term=search_term, page=display_page_number))
    else:
        # TODO: we should redirect to that page
        return _initial_search_page()

@app.route('/', methods=['GET'])
@app.route('/title-search', methods=['GET'])
@app.route('/title-search/<search_term>', methods=['GET'])
def find_titles_page(search_term=''):
    display_page_number = int(request.args.get('page') or 1)
    page_number = display_page_number - 1  # page_number is 0 indexed

    search_term = search_term.strip()
    if not search_term:
        return _initial_search_page()
    else:
        return _get_address_search_response(search_term, page_number)

def _get_register_title(title_number):
    title = api_client.get_title(title_number)
    return title_formatter.format_display_json(title) if title else None

def _get_address_search_response(search_term, page_number):
    search_term = search_term.upper()
    if _is_title_number(search_term):
        return _get_search_by_title_number_response(search_term, page_number)
    elif _is_postcode(search_term):
        return _get_search_by_postcode_response(search_term, page_number)
    else:
        return _get_search_by_address_response(search_term, page_number)

def _get_search_by_title_number_response(search_term, page_number):
    display_page_number = page_number + 1
    title_number = search_term
    title = _get_register_title(title_number)
    if title:
        # Redirect to the display_title method to display the digital register
        return redirect(url_for('get_title', title_number=title_number,
                                page_number=display_page_number, search_term=search_term))
    else:
        # If title not found display 'no title found' screen
        results = {'number_results': 0}
        return _search_results_page(results, search_term)

def _get_search_by_postcode_response(search_term, page_number):
    postcode = _normalise_postcode(search_term)
    postcode_search_results = api_client.get_titles_by_postcode(postcode, page_number)
    return _search_results_page(postcode_search_results, postcode)

def _get_search_by_address_response(search_term, page_number):
    address_search_results = api_client.get_titles_by_address(search_term, page_number)
    return _search_results_page(address_search_results, search_term)

def _is_title_number(search_term):
    return TITLE_NUMBER_REGEX.match(search_term)

def _is_postcode(search_term):
    return POSTCODE_REGEX.match(search_term)

def _breadcumbs_for_title_details(title_number, search_term, display_page_number):
    search_breadcrumb = {'text': 'Search the land and property register', 'url': url_for('find_titles')}
    results_breadcrumb = {'text': 'Search results', 'url': url_for('find_titles_page', search_term=search_term,
                                                                   page=display_page_number)}
    current_breadcrumb = {'current': 'Viewing {}'.format(title_number)}

    found_title_by_number = title_number.lower() == search_term.lower()

    if found_title_by_number:
        return [search_breadcrumb, current_breadcrumb]
    else:
        return [search_breadcrumb, results_breadcrumb, current_breadcrumb]

def _normalise_postcode(postcode_in):
    # We strip out the spaces - and reintroduce one four characters from end
    no_spaces = postcode_in.replace(' ', '')
    postcode = no_spaces[:len(no_spaces) - 3] + ' ' + no_spaces[-3:]
    return postcode

def _login_page(form=None, show_unauthorised_message=False, next_url=None):
    title_number = request.args.get('title_number')
    search_term = request.args.get('search_term', title_number)
    display_page_number = int(request.args.get('page') or 1)

    if not form:
        form = SigninForm(csrf_enabled=False)

    return render_template(
        'display_login.html',
        form=form,
        username=USERNAME,
        service_notice_html=app.config.get('SERVICE_NOTICE_HTML', None),
        unauthorised_title=None,
        unauthorised_description=None,
        next=next_url,
        title_number=title_number,
        search_term=search_term,
        display_page_number=display_page_number,
    )

def _title_details_page(title, search_term, display_page_number, breadcrumbs, show_pdf, full_title_data):
    return render_template(
        'display_title.html',
        title=title,
        username=USERNAME,
        search_term=search_term,
        display_page_number=display_page_number,
        breadcrumbs=breadcrumbs,
        show_pdf=show_pdf,
        full_title_data=full_title_data,
        is_caution_title=title_utils.is_caution_title(title),
    )

def _initial_search_page():
    return render_template(
        'search.html',
        form=TitleSearchForm(csrf_enabled=False),
        username=USERNAME,
    )

def _search_results_page(results, search_term):
    return render_template(
        'search_results.html',
        search_term=search_term,
        results=results,
        form=TitleSearchForm(csrf_enabled=False),
        username=USERNAME,
        breadcrumbs=[
            {'text': 'Search the land and property register', 'url': url_for('find_titles')},
            {'current': 'Search results'}
        ]
    )

def _cookies_page():
    return render_template('cookies.html', username=USERNAME)

def _create_string_date_only(datetoconvert):
    # converts to example : 12 August 2014
    date = datetoconvert.strftime('%-d %B %Y')
    return date

def _create_string_date_and_time(datetoconvert):
    # converts to example : 12 August 2014 12:34:06
    date = datetoconvert.strftime('%-d %B %Y at %H:%M:%S')
    return date

def _create_pdf_template(sub_registers, title, title_number):
    # TODO use real date - this is reliant on new functionality to check the daylist
    last_entry_date = _create_string_date_and_time(datetime(3001, 2, 3, 4, 5, 6))
    issued_date = _create_string_date_only(datetime.now())
    if title.get('edition_date'):
        edition_date = _create_string_date_only(datetime.strptime(title.get('edition_date'), "%Y-%m-%d"))
    else:
        edition_date = "No date given"
    class_of_title = title.get('class_of_title')
    # need to check for caution title as we don't display Class of title for them
    is_caution = title.get('is_caution_title') is True

    return render_template('full_title.html', title_number=title_number, title=title,
                           last_entry_date=last_entry_date,
                           issued_date=issued_date,
                           edition_date=edition_date,
                           class_of_title=class_of_title,
                           sub_registers=sub_registers,
                           is_caution=is_caution)