import pymongo
from pymongo import MongoClient
import os

import discord
from discord.ext import commands

import random
import asyncio
import itertools
import sys
import traceback
from async_timeout import timeout
from functools import partial
from collections import deque
from youtube_dl import YoutubeDL
import youtube_dl
import datetime

cluster = MongoClient(os.environ['mongoURL'])
db = cluster["qwiooData"]
collection = db["userData"]

# Suppress noise about console usage from errors
youtube_dl.utils.bug_reports_message = lambda: ''

class VoiceError(Exception):
    pass

client = commands.Bot(command_prefix='??',
                      intents=discord.Intents.all(),
                      activity=discord.Game(name="music | ??help"))
ytdlopts = {
    'format': 'bestaudio/best',
    'extractaudio': True,
    'audioformat': 'mp3',
    'outtmpl': 'downloads/%(extractor)s-%(id)s-%(title)s.%(ext)s',
    'restrictfilenames': True,
    'noplaylist': True,
    'nocheckcertificate': True,
    'ignoreerrors': False,
    'logtostderr': False,
    'quiet': True,
    'no_warnings': True,
    'default_search': 'auto',
    'source_address': '0.0.0.0'  # ipv6 addresses cause issues sometimes
}

ffmpegopts = {
    'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5',
    'options': '-vn'
}

ytdl = YoutubeDL(ytdlopts)

class YTDLError(Exception):
  pass

class VoiceConnectionError(commands.CommandError):
    """Custom Exception class for connection errors."""

class InvalidVoiceChannel(VoiceConnectionError):
    """Exception for cases of invalid Voice Channels."""

class YTDLSource(discord.PCMVolumeTransformer):

    def __init__(self, source, *, data, requester):
        super().__init__(source)
        self.requester = requester

        self.title = data.get('title')
        self.web_url = data.get('webpage_url')
        self.duration = self.parse_duration(int(data.get('duration')))
        self.thumbnail = data.get('thumbnail')

    def __getitem__(self, item: str):
        return self.__getattribute__(item)

    @classmethod
    async def create_source(cls, ctx, search: str, *, loop=None, download=False):
        loop = loop or asyncio.get_event_loop()

        to_run = partial(ytdl.extract_info, url=search, download=download)
        data = await loop.run_in_executor(None, to_run)

        if 'entries' in data:
            # take first item from a playlist
            data = data['entries'][0]

        embed = discord.Embed(title="", description=f"Queued [{data['title']}]({data['webpage_url']}) {datetime.timedelta(seconds=(data['duration']))} [{ctx.author.mention}]", color=0xF8C514)

        embed.set_thumbnail(url=data['thumbnail'])
        await ctx.send(embed=embed)

        if download:
            source = ytdl.prepare_filename(data)
        else:
            return {'webpage_url': data['webpage_url'], 'requester': ctx.author, 'title': data['title'], 'duration': str(datetime.timedelta(seconds=(data['duration'])))}

        return cls(discord.FFmpegPCMAudio(source), data=data, requester=ctx.author)

    @classmethod
    async def regather_stream(cls, data, *, loop):

        loop = loop or asyncio.get_event_loop()
        requester = data['requester']

        to_run = partial(ytdl.extract_info, url=data['webpage_url'], download=False)
        data = await loop.run_in_executor(None, to_run)

        return cls(discord.FFmpegPCMAudio(data['url']), data=data, requester=requester)

    @staticmethod
    def parse_duration(duration: int):
        minutes, seconds = divmod(duration, 60)
        hours, minutes = divmod(minutes, 60)
        days, hours = divmod(hours, 24)

        duration = []
        if days > 0:
            duration.append('{} days'.format(days))
        if hours > 0:
            duration.append('{} hr'.format(hours))
        if minutes > 0:
            duration.append('{} min'.format(minutes))
        if seconds > 0:
            duration.append('{} sec'.format(seconds))

        return ', '.join(duration)

class Spotify(commands.Cog):
    def getTrackID(self, track):
        track = sp.track(track)
        return track["id"]
    def getPlaylistTrackIDs(self, playlist_id):
        ids = []
        playlist = sp.playlist(playlist_id)
        for item in playlist['tracks']['items']:
            track = item['track']
            ids.append(track['id'])
        return ids

class MusicPlayer(commands.Cog):
    __slots__ = ('bot', '_guild', '_channel', 'voice_client', '_cog', 'queue', 'next', 'current', 'np', 'volume')

    def __init__(self, ctx):
        self.bot = ctx.bot
        self._guild = ctx.guild
        self._channel = ctx.channel

        self.voice_client = ctx.voice_client

        self._cog = ctx.cog

        self.queue = asyncio.Queue()
        self.next = asyncio.Event()
        self._loop = False
        self.np = None  # Now playing message
        self.volume = .69
        self.current = None

        ctx.bot.loop.create_task(self.player_loop())

    @property
    def loop(self):
        return self._loop

    @loop.setter
    def loop(self, value: bool):
        self._loop = value

    async def player_loop(self):

        """Our main player loop."""
        await self.bot.wait_until_ready()

        while not self.bot.is_closed():
            self.next.clear()
            if not self._loop:
              try:
                    # Wait for the next song. If we timeout - cancel the player and disconnect
                    async with timeout(300):
                        source = await self.queue.get()
              except asyncio.TimeoutError:
                    return self.destroy(self._guild)

            if self.loop:
                  self.queue.join(source)

            if not isinstance(source, YTDLSource):
                # regather to prevent stream expiration

                try:
                    source = await YTDLSource.regather_stream(source, loop=self.bot.loop)
                except Exception as e:
                    await self._channel.send(f'There was an error processing your song.\n'
                                             f'```css\n[{e}]\n```')
                    continue

            source.volume = self.volume
            self.current = source

            self._guild.voice_client.play(source, after=lambda _: self.bot.loop.call_soon_threadsafe(self.next.set))

            embed = discord.Embed(title="", description=f"[{source.title}]({source.web_url}) [{source.requester.mention}] \n`{source.duration}`", color=0xF8C514)

            embed.set_author(icon_url=self.bot.user.avatar_url, name=f"Now Playing 🎶")

            embed.set_thumbnail(url=source.thumbnail)
            await self._channel.send(embed=embed)

            await self.next.wait()
            source.cleanup()

            self.current = None

    def destroy(self, guild):
        """Disconnect and cleanup the player."""
        return self.bot.loop.create_task(self._cog.cleanup(guild))

class Music(commands.Cog):
    """Music related commands."""

    __slots__ = ('bot', 'players')

    def __init__(self, bot):
        self.bot = bot
        self.players = {}

    async def cleanup(self, guild):
        try:
            await guild.voice_client.disconnect()
        except AttributeError:
            pass

        try:
            del self.players[guild.id]
        except KeyError:
            pass

    async def __local_check(self, ctx):
        """A local check which applies to all commands in this cog."""
        if not ctx.guild:
            raise commands.NoPrivateMessage
        return True

    async def __error(self, ctx, error):
        """A local error handler for all errors arising from commands in this cog."""
        if isinstance(error, commands.NoPrivateMessage):
            try:
                return await ctx.send('This command can not be used in Private Messages.')
            except discord.HTTPException:
                pass
        elif isinstance(error, InvalidVoiceChannel):
            await ctx.send('Error connecting to Voice Channel. '
                           'Please make sure you are in a valid channel or provide me with one')

        print('Ignoring exception in command {}:'.format(ctx.command), file=sys.stderr)
        traceback.print_exception(type(error), error, error.__traceback__, file=sys.stderr)

    def get_player(self, ctx):
        """Retrieve the guild player, or generate one."""
        try:
            player = self.players[ctx.guild.id]
        except KeyError:
            player = MusicPlayer(ctx)
            self.players[ctx.guild.id] = player

        return player

    def _playlist(self, search: str):
      """Returns a dict with all Playlist entries"""
      ydl_opts = {
        'ignoreerrors': True,
        'quit': True,
        'source_address': '0.0.0.0'
      }

      with youtube_dl.YoutubeDL(ydl_opts) as ydl:
          playlist_dict = ydl.extract_info(search, download=False)

          playlistTitle = playlist_dict['title']

          playlist = dict()
          for video in playlist_dict['entries']:
              print()

              if not video:
                  print('ERROR: Unable to get info. Coninuing...')
                  continue

              for prop in ['id', 'title']:
                  print(prop, '--', video.get(prop))
                  playlist[video.get('title')] = 'https://www.youtube.com/watch?v=' + video.get('id')

          return playlist, playlistTitle

    @commands.command(name='join', aliases=['connect', 'j'], invoke_without_subcommand=True)
    async def connect_(self, ctx, *, channel: discord.VoiceChannel=None):
        if not channel:
            try:
                channel = ctx.author.voice.channel
            except AttributeError:
                embed = discord.Embed(title="", description="No channel to join. Please call `,join` from a voice channel.", color=0xF8C514)
                await ctx.send(embed=embed)
                raise InvalidVoiceChannel('No channel to join. Please either specify a valid channel or join one.')

        vc = ctx.voice_client

        if vc:
            if vc.channel.id == channel.id:
                return
            try:
                await vc.move_to(channel)
            except asyncio.TimeoutError:
                raise VoiceConnectionError(f'Moving to channel: <{channel}> timed out.')
        else:
            try:
                await channel.connect()
            except asyncio.TimeoutError:
                raise VoiceConnectionError(f'Connecting to channel: <{channel}> timed out.')
        if (random.randint(0, 1) == 0):
            await ctx.message.add_reaction('👍')
        await ctx.send(f'**Joined `{channel}`**')

    @commands.command(name='loop', aliases=['l'])
    async def _loop(self,ctx):
      player = self.get_player(ctx)
      vc = ctx.voice_client
      if not vc or not vc.is_playing:
            return await ctx.send('Nothing being played at the moment.')
      player.loop = not player.loop
      await ctx.message.add_reaction('✅')
      await ctx.send("Loop is now: " + str(player.loop))

    @commands.command(name='shuffle', aliases=['sf'])
    async def _shuffle(self, ctx):
        #player = self.get_player(ctx)
        player = self.get_player(ctx)

        if len(list(player.queue._queue)) > 1:
          player.queue._queue = random.sample(list(player.queue._queue), len(list(player.queue._queue)))
          player.queue._queue = deque(player.queue._queue)
          print(player.queue._queue)
          await ctx.send("Shuffled queue")
          await ctx.invoke(self.queue_info)

        else:
          await ctx.send("Empty Queue or queue size is 1.")

    @commands.command(name='play', aliases=['sing','p'])
    async def play_(self, ctx, *, search: str):

        playlist = 0
        await ctx.trigger_typing()
        player = self.get_player(ctx)

        vc = ctx.voice_client

        if not vc:
            await ctx.invoke(self.connect_)

        #check if link is a playlist
        # if search link has spotify in it

        if search.__contains__('&list='):
          playlist = 1
          await ctx.send('retrieving playlist...')
          async with ctx.typing():
            playlist, playlistTitle = self._playlist(search)
            for _title, _link in playlist.items():
                try:
                    source = await YTDLSource.create_source(ctx, _link, loop=self.bot.loop)
                    await player.queue.put(source)

                except YTDLError as e:
                    await ctx.send('An error occurred while processing this request: {}'.format(str(e)))

            await ctx.send(f'Enqueued `{playlist.__len__()}` songs from **{playlistTitle}**')

        #continue as usual
        player = self.get_player(ctx)
        if playlist == 1:
          pass
        elif playlist == 0:
          source = await YTDLSource.create_source(ctx, search, loop=self.bot.loop, download=False)
          await player.queue.put(source)

    @commands.command(name='pause')
    async def pause_(self, ctx):
        vc = ctx.voice_client

        if not vc or not vc.is_playing():
            embed = discord.Embed(title="", description="I am currently not playing anything", color=0xF8C514)
            return await ctx.send(embed=embed)
        elif vc.is_paused():
            return

        vc.pause()
        await ctx.send("Paused ⏸")

    @commands.command(name='resume')
    async def resume_(self, ctx):
        vc = ctx.voice_client

        if not vc or not vc.is_connected():
            embed = discord.Embed(title="", description="I'm not connected to a voice channel", color=0xF8C514)
            return await ctx.send(embed=embed)
        elif not vc.is_paused():
            return

        vc.resume()
        await ctx.send("Resuming ⏯")

    @commands.command(name='skip', aliases=['next','s'])
    async def skip_(self, ctx):
        vc = ctx.voice_client
        if not vc or not vc.is_connected():
            embed = discord.Embed(title="", description="I'm not connected to a voice channel", color=0xF8C514)
            return await ctx.send(embed=embed)

        if vc.is_paused():
            pass
        elif not vc.is_playing():
            return

        vc.stop()

    #TO DO
    #better error handling
    #command to add specific favs to queue
    #command to clear favourites
    @commands.command(name = 'favourite', aliases = ['f', 'fav'])
    async def favourite_(self, ctx, *, search):

        user = ctx.author
        myquery = { "_id": user.id}

        ydl_opts = {
          'format': 'bestaudio', 'noplaylist':'True'
        }
        with youtube_dl.YoutubeDL(ydl_opts) as ydl:
          data = ydl.extract_info(f"ytsearch:{search}", download=False)['entries'][0]
        print(data)
        dict = {
            'title': data['title'],
            'webpage_url': data['webpage_url'],
            'duration': str(datetime.timedelta(seconds=(data['duration'])))
          }
        print(dict)
        try:
          if (collection.count_documents(myquery) == 0):
            post = {"_id": user.id, "favourite": [dict]}
            collection.insert_one(post)

          else:
            collection.update_one({'_id' :user.id}, {"$push" : {'favourite': dict}})

          await ctx.channel.send("Added "+ data['title'] +  " to favourites")
        except discord.ext.commands.errors.MissingRequiredArgument:
          await ctx.channel.send("Include song after command")

    @commands.command(name = 'favourites', aliases = ['fs', 'favs'])
    async def favourites_(self, ctx):
        user = ctx.author
        myquery = { "_id": user.id }
        x = collection.find_one(myquery)

        try:
          favs = x['favourite']
          fmt = '\n'.join(f"`{(favs.index(_))}.` [{_['title']}]({_['webpage_url']}) | ` {_['duration']} `\n" for _ in favs)

          embed=discord.Embed(title="Favourites", description=fmt, color=0xF8C514)
          embed.set_footer(text=f"{ctx.author.display_name}", icon_url=ctx.author.avatar_url)
          await ctx.send(embed=embed)

        except TypeError as e:
          await ctx.send(e)

    @commands.command(name= 'removefavourite', aliases = ['rf', 'removefav', 'remfav'])
    async def removeFavourite_(self,ctx, pos : int=None):
      """Removes specified song from user's favourites"""
      user = ctx.author
      myquery = { "_id": user.id}

      #check if user exists in database
      if (collection.count_documents(myquery) > 0):

        x = collection.find_one(myquery)
        favs = x['favourite']

        try:
          await ctx.channel.send("removed " + str(favs[pos]['title']))
          del favs[pos]
          collection.replace_one({'_id' :user.id}, {'favourite': favs})

        except IndexError as e:
          await ctx.channel.send(e)

      else:
        await ctx.channel.send("use ??f to favourite songs")

    @commands.command(name='playfavourites', aliases=['pf','playfav'])
    async def play_favourites_(self,ctx,*, range):
        user = ctx.author
        myquery = { "_id": user.id}

      #check if user exists in database
        if (collection.count_documents(myquery) > 0):
          try:
            x = collection.find_one(myquery)
            favs = x['favourite']

            if range == 'all' or range == 'a':
              to_play = favs
            elif ',' in range:
              start, stop = range.split(',')

              to_play = favs[int(start) : (int(stop)+1)]

            elif len(str(range)) >= 1:

              to_play = favs[(int(range)) : (int(range)+1)]
              print(to_play)

            for song in to_play:
              print(song)
              link = song['webpage_url']
              print(type(link))

              await ctx.invoke(self.bot.get_command('play'), search = link)

          except ValueError as e:
            await ctx.channel.send(e)

        else:
          await ctx.channel.send("use ??f to favourite songs")
#--------------------------------------------------------------------------------

    @commands.command(name='remove', aliases=['rm', 'rem', 'r'])
    async def remove_(self, ctx, pos : int=None):
        """Removes specified song from queue"""

        vc = ctx.voice_client

        if not vc or not vc.is_connected():
            embed = discord.Embed(title="", description="I'm not connected to a voice channel", color=0xF8C514)
            return await ctx.send(embed=embed)

        player = self.get_player(ctx)
        if pos == None:
            player.queue._queue.pop()
        else:
            try:
                s = player.queue._queue[pos-1]
                del player.queue._queue[pos-1]
                embed = discord.Embed(title="", description=f"Removed [{s['title']}]({s['webpage_url']}) [{s['requester'].mention}]", color=0xF8C514)
                await ctx.send(embed=embed)
            except:
                embed = discord.Embed(title="", description=f'Could not find a track for "{pos}"', color=0xF8C514)
                await ctx.send(embed=embed)

    @commands.command(name='clear', aliases=['clr', 'cl', 'cr'])
    async def clear_(self, ctx):
        """Deletes entire queue of upcoming songs."""

        vc = ctx.voice_client

        if not vc or not vc.is_connected():
            embed = discord.Embed(title="", description="I'm not connected to a voice channel", color=0xF8C514)
            return await ctx.send(embed=embed)

        player = self.get_player(ctx)
        player.queue._queue.clear()
        await ctx.send('💣 **Cleared**')

    @commands.command(name='queue', aliases=['q', 'playlist', 'que'])
    async def queue_info(self, ctx):
        """Retrieve a basic queue of upcoming songs."""
        vc = ctx.voice_client

        if not vc or not vc.is_connected():
            embed = discord.Embed(title="", description="I'm not connected to a voice channel", color=0xF8C514)
            return await ctx.send(embed=embed)

        player = self.get_player(ctx)
        if player.queue.empty():
            embed = discord.Embed(title="", description="queue is empty", color=0xF8C514)
            return await ctx.send(embed=embed)

        print(player.queue._queue)
        # Grabs the songs in the queue...
        upcoming = list(itertools.islice(player.queue._queue, 0, int(len(player.queue._queue))))

        fmt = '\n'.join(f"`{(upcoming.index(_)) + 1}.` [{_['title']}]({_['webpage_url']}) | ` {_['duration']} Requested by: {_['requester']}`\n" for _ in upcoming)

        fmt = f"\n__Now Playing__:\n[{vc.source.title}]({vc.source.web_url}) | ` {vc.source.duration} Requested by: {vc.source.requester}`\n\n__Up Next:__\n" + fmt + f"\n**{len(upcoming)} songs in queue**"

        embed = discord.Embed(title=f'Queue for {ctx.guild.name}', description=fmt, color=0xF8C514)
        embed.set_footer(text=f"{ctx.author.display_name}", icon_url=ctx.author.avatar_url)

        await ctx.send(embed=embed)

    @commands.command(name='np', aliases=['song', 'current', 'currentsong', 'playing'],invoke_without_command=True)
    async def now_playing_(self, ctx):
        """Display information about the currently playing song."""
        vc = ctx.voice_client

        if not vc or not vc.is_connected():
            embed = discord.Embed(title="", description="I'm not connected to a voice channel", color=0xF8C514)
            return await ctx.send(embed=embed)

        player = self.get_player(ctx)
        if not player.current:
            embed = discord.Embed(title="", description="I am currently not playing anything", color=0xF8C514)
            return await ctx.send(embed=embed)

        embed = discord.Embed(title="", description=f"[{vc.source.title}]({vc.source.web_url}) [{vc.source.requester.mention}]\n`{vc.source.duration}`", color=0xF8C514)
        embed.set_author(icon_url=self.bot.user.avatar_url, name=f"Now Playing 🎶")
        embed.set_image(url=vc.source.thumbnail)
        msg = await ctx.send(embed=embed)

        first_run = True
        while True:
            if first_run:
              reactmoji = ["⏸","▶","⏩","🎶",'🔊']
              for react in reactmoji:
                          await msg.add_reaction(react)

              def check_react(reaction, user):
                      if reaction.message.id != msg.id:
                          return False
                      if user != ctx.message.author:
                          return False
                      if str(reaction.emoji) not in reactmoji:
                          return False
                      return True
              try:
                      res, user = await self.bot.wait_for('reaction_add', check=check_react)
              except asyncio.TimeoutError:
                      return await msg.clear_reactions()

              if '⏸' in str(res.emoji):
                      print('<<paused>>')
                      ctx.voice_client.pause()

              elif '▶' in str(res.emoji):
                      print('<<resumed>>')
                      ctx.voice_client.resume()

              elif '⏩' in str(res.emoji):
                      print('<<skipped>>')
                      if not vc or not vc.is_connected():
                          embed = discord.Embed(title="", description="I'm not connected to a voice channel", color=0xF8C514)
                          return await ctx.send(embed=embed)

                      if vc.is_paused():
                          pass
                      elif not vc.is_playing():
                          return

                      vc.stop()

              elif '🎶' in str(res.emoji):
                      print('<<Displaying queue>>')
                      await ctx.invoke(self.queue_info)

              elif '🔊' in str(res.emoji):
                      print('<<Displaying volume>>')
                      await ctx.invoke(self.change_volume)

    @commands.command(name='volume', aliases=['vol', 'v'])
    async def change_volume(self, ctx, *, vol: float=None):
        """Change the player volume.
        Parameters
        ------------
        volume: float or int [Required]
            The volume to set the player to in percentage. This must be between 1 and 100.
        """
        vc = ctx.voice_client

        if not vc or not vc.is_connected():
            embed = discord.Embed(title="", description="I am not currently connected to voice", color=0xF8C514)
            return await ctx.send(embed=embed)

        if not vol:
            embed = discord.Embed(title="", description=f"🔊 **{(vc.source.volume)*100}%**", color=0xF8C514)
            return await ctx.send(embed=embed)

        if not 0 < vol < 101:
            embed = discord.Embed(title="", description="Please enter a value between 1 and 100", color=0xF8C514)
            return await ctx.send(embed=embed)

        player = self.get_player(ctx)

        if vc.source:
            vc.source.volume = vol / 100

        player.volume = vol / 100
        embed = discord.Embed(title="", description=f'**`{ctx.author}`** set the volume to **{vol}%**', color=0xF8C514)
        await ctx.send(embed=embed)

    @commands.command(name='leave', aliases=["stop", "dc", "disconnect", "bye"])
    async def leave_(self, ctx):
        """Stop the currently playing song and destroy the player.
        !Warning!
            This will destroy the player assigned to your guild, also deleting any queued songs and settings.
        """
        vc = ctx.voice_client

        if not vc or not vc.is_connected():
            embed = discord.Embed(title="", description="I'm not connected to a voice channel", color=0xF8C514)
            return await ctx.send(embed=embed)

        if (random.randint(0, 1) == 0):
            await ctx.message.add_reaction('👋')
        await ctx.send('**Successfully disconnected**')

        await self.cleanup(ctx.guild)

def setup(bot):
    bot.add_cog(Music(bot))


# -*- coding: utf-8 -*-
from openerp import models, fields, api, _
import time
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
import openerp.addons.decimal_precision as dp
from openerp.exceptions import except_orm

def update_null_and_slash_codes(cr):
    """
    Updates existing codes matching the default '/' or
    empty. Primarily this ensures installation does not
    fail for demo data.
    :param cr: database cursor
    :return: void
    """
    cr.execute("UPDATE product_product "
               "SET default_code = 'PR' || id "
               "WHERE default_code IS NULL OR default_code = '/';")

    cr.execute("""
            update product_product
            set default_code = default_code || id
            where id in
            (
            select pp.id
            from product_product pp INNER JOIN
            (
            select default_code, MAX(id) id
            from product_product
            where default_code in
            (
            select default_code
            from product_product
            where default_code is not NULL
            group by default_code
            having count(1) > 1
            order by default_code
            )
            group by default_code
            order by 1
            ) tmp_pp on pp.default_code = tmp_pp.default_code and pp.id < tmp_pp.id
            order by 1
            )
        """)

import logging
import base64
import urllib2
_logger = logging.getLogger(__name__)

class product_product(models.Model):
    _inherit = "product.product"

    templ_minimum_ids = fields.One2many('product.minimum', 'product_id', string='Minimum Qty')
    default_code = fields.Char(
        string='Reference',
        size=64,
        select=True,
        required=True,
        default='/')

    _sql_constraints = [
        ('default_code_uniq', 'unique(default_code)', 'Product Code must be unique!'),
    ]

    @api.model
    def create(self, vals):
        if 'default_code' not in vals or vals['default_code'] == '/':
            vals['default_code'] = self.env['ir.sequence'].get(
                'product.product')
        if not self.env['res.users'].has_group('streamline_ame_modules.group_ame_create_product'):
            raise except_orm(_('Invalid Action!'), _('User is not in "Creating Product" group.'))
        product_id = super(product_product, self).create(vals)

        user = self.env['res.users'].browse(self._uid)
        vals = {'name': product_id.name,
                'user': user.name,
                'date': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
                'default_code': vals.get('default_code', '')}
        self.action_send_mail(product_id, vals)
        return product_id

    @api.multi
    def write(self, vals):
        if not self.env['res.users'].has_group('streamline_ame_modules.group_ame_edit_product'):
            raise except_orm(_('Invalid Action!'), _('User is not in "Editing Product" group.'))

        for product in self:
            if product.default_code in [False, '/']:
                vals['default_code'] = self.env['ir.sequence'].get(
                    'product.product')
            super(product_product, product).write(vals)
        return True

    @api.one
    def copy(self, default=None):
        if default is None:
            default = {}
        if self.default_code:
            default.update({
                'default_code': self.default_code + _('-copy'),
            })

        return super(product_product, self).copy(default)

    def check_inventory(self, cr, uid, product_ids, location_id, context=None):
        product_inventory = self._product_available(cr, uid,
                product_ids,
                context={'location': location_id})
        warning = {}
        for product in self.browse(cr, uid, product_ids, context):
            for minimum in product.product_tmpl_id.templ_minimum_ids:
                if minimum.location_id and minimum.location_id.id == location_id:
                    if product_inventory[product.id]['qty_available'] > minimum.quantity:
                        warning.update({product.id: minimum.quantity})
        return warning

    def action_send_mail(self, cr, uid, model_id, vals, context=None):
        if not context:
            context = {}

        model = 'product.product'
        email_template_obj = self.pool.get('email.template')
        ir_model_data = self.pool.get('ir.model.data')

        template_ids = email_template_obj.search(cr, uid, [('model_id.model', '=', model)])
        for email_template in ['email_template_create_product', 'email_template_create_product_purchaser']:
            prod_template_id = ir_model_data.get_object_reference(cr, uid, 'streamline_ame_modules', email_template)[1]
            if prod_template_id:
                template_ids = [prod_template_id]

            if not template_ids:
                return {}

            composer_obj = self.pool['mail.compose.message']
            composer_values = {}
            for template_id in template_ids:

                model_obj = self.pool.get(model)
                if model_id:
                    email_ctx={
                        'default_model': model,
                        'default_res_id': model_id,
                        'default_use_template': bool(template_id),
                        'default_template_id': template_id,
                        'default_composition_mode': 'comment',
                    }
                    template_values = [
                        template_id,
                        'comment',
                        model,
                        model_id,
                    ]
                    composer_values.update(composer_obj.onchange_template_id(cr, uid, None, *template_values, context=context).get('value', {}))
                    if not composer_values.get('email_from'):
                        composer_values['email_from'] = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.email
                    if email_template == 'email_template_create_product_purchaser':
                        try:
                            model, group_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'warehouse_extended', 'group_ame_purchaser')
                        except ValueError:
                            return False
                        partner_ids = []
                        user_ids = self.pool.get('res.users').search(cr, uid, [('groups_id', '=', group_id)])
                        for user in self.pool.get('res.users').browse(cr, uid, user_ids):
                            partner_ids += [user.partner_id.id]
                        if partner_ids:
                             composer_values['partner_ids'] = partner_ids
                    # print vals
                    composer_values['body'] = composer_values['body']%vals
                    for key in ['attachment_ids', 'partner_ids']:
                        if composer_values.get(key):
                            composer_values[key] = [(6, 0, composer_values[key])]

                    composer_id = composer_obj.create(cr, uid, composer_values, context=email_ctx)
                    composer_obj.send_mail(cr, uid, [composer_id], context=email_ctx)

        return True

product_product()

class product_template(models.Model):
    _inherit = "product.template"

    templ_minimum_ids = fields.One2many('product.minimum', 'product_tmp_id', string='Minimum Qty')
    living_material_price = fields.Float('Living-Material', digits_compute=dp.get_precision('Product Price'))
    living_labour_price = fields.Float('Living-Labour', digits_compute=dp.get_precision('Product Price'))
    machinery_material_price = fields.Float('Machinery-Material', digits_compute=dp.get_precision('Product Price'))
    machinery_labour_price = fields.Float('Machinery-Labour', digits_compute=dp.get_precision('Product Price'))
    living_material_by_ame = fields.Boolean('By AME')
    living_labour_by_ame = fields.Boolean('By AME')
    machinery_material_by_ame = fields.Boolean('By AME')
    machinery_labour_by_ame = fields.Boolean('By AME')
    active = fields.Boolean('Active', default=False)
    loc_case = fields.Char('Level', size=16)
    loc_area = fields.Char('Area', size=16)

    image_import_url = fields.Char('Image Import URL')
    image_import_local_url = fields.Char('Image Import Local URL')

    @api.multi
    def write(self, vals):
        if not self.env['res.users'].has_group('streamline_ame_modules.group_ame_edit_product'):
            raise except_orm(_('Invalid Action!'), _('User is not in "Editing Product" group.'))
        return super(product_template, self).write(vals)

    @api.model
    def create(self, vals):
        # if vals.get('image_import_url', False):
        #     image = False
        #     try:
        #         image = urllib2.urlopen(vals['image_import_url']).read()
        #         if image:
        #             image = base64.encodestring(image)
        #     except urllib2.URLError as e:
        #         _logger.error(e)
        #     if image:
        #         vals['image'] = image
        # elif vals.get('image_import_local_url', False):
        #     image = False
        #     try:
        #         path_update = vals['image_import_local_url'].replace('\\','/')
        #         path_update = 'file:///' + path_update
        #         image = urllib2.urlopen(path_update).read()
        #         if image:
        #             image = base64.encodestring(image)
        #     except urllib2.URLError as e:
        #         _logger.error(e)
        #     if image:
        #         vals['image'] = image

        if not self.env['res.users'].has_group('streamline_ame_modules.group_ame_create_product'):
            raise except_orm(_('Invalid Action!'), _('User is not in "Creating Product" group.'))
        return super(product_template, self).create(vals)

product_template()


# importações das bibliotecas e funções
from funcoes.wts import webWts
import time
from funcoes.pyauto import selecUser
import threading

def enviar_mensagem(nome, mensagem, minute):
    current_time = time.localtime()
    # Obtém o tempo atual usando a função localtime do módulo time e armazena na variável current_time

    hour = current_time.tm_hour
    # Extrai a hora atual

    hora_envio = mensagem[2]
    # Extrai a hora de envio da mensagem a partir do terceiro elemento da lista mensagem e armazena em hora_envio

    minuto_envio = mensagem[3]
    # Extrai o minuto de envio da mensagem a partir do quarto elemento da lista mensagem e armazena em minuto_envio

    if hour == hora_envio and minute == minuto_envio:
        # Verifica se a hora atual é igual à hora de envio e se o minuto atual é igual ao minuto de envio

        t = threading.Thread(target=selecUser)
        # Threading para clicar no usuario do chrome

        t.start()
        # Inicia a execução da thread t

        webWts(nome, mensagem[1])
        # Chama a função webWts, passando o nome e a mensagem como argumentos, para abrir o WTS e enviar a mensagem

        t.join()
        # Aguarda a conclusão da execução da thread t

        return True
        # Retorna True se a mensagem for enviada com sucesso

    return False
    # Retorna False se a mensagem não for enviada nesta execução


from crypt import methods
from flask import Flask, render_template, request
import numpy as np
from joblib import load
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
import uuid

### THIS IS A TEST CHANGE TO SEE IF IT IS REFELCTED IN GITHUB

def make_picture(training_data_filename, model_in, new_input_arr, output_file):
  # Plot training data with model
  data = pd.read_pickle(training_data_filename)
  data = data[data['Age'] > 0]
  ages = data['Age']
  heights = data['Height']
  x_new = np.array(list(range(19))).reshape(19,1)
  preds = model_in.predict(x_new)

  fig = px.scatter(x=ages, y=heights, title="Height vs Age", labels={'x': 'Age (Years)',
                                                                   'y': 'Height (Inches)'})
  fig.add_trace(
      go.Scatter(x=x_new.reshape(19), y=preds, mode='lines', name='Model'))

  new_preds = model_in.predict(new_input_arr)
  # Plot new predictions
  fig.add_trace(go.Scatter(x=new_input_arr.reshape(len(new_input_arr)),
                          y=new_preds,
                          name='New Outputs',
                          mode='markers',
                          marker=dict(color='purple', size=20, line=dict(color='purple', width=2))) )

  fig.write_image(output_file, width=800, engine='kaleido')
  fig.show()

def floats_string_to_input_arr(floats_str):
  floats = [float(x) for x in [x for x in floats_str.split(',')] if x != '']
  as_np_arr = np.array(floats).reshape(len(floats), 1)
  return as_np_arr

app = Flask(__name__)

@app.route("/", methods=['GET', 'POST'])
def hello_world():
    request_type_str = request.method
    if request_type_str == 'GET':
        return render_template('index.html', href='static/base_pic.svg')
    else:
        text = request.form['text']
        random_str = uuid.uuid4().hex
        #path= f'application/static/{random_str}.svg'
        path= f'/Users/delgadonoriega/Desktop/FlaskTutorialTwo/live-demo-flask-app/application/static/{random_str}.svg'
        #model = load('live-demo-flask/application/model.joblib')
        model= load('/Users/delgadonoriega/Desktop/FlaskTutorialTwo/live-demo-flask-app/application/model.joblib')
        np_arr = floats_string_to_input_arr(text)
        #make_picture('live-demo-flask/application/AgesAndHeights.pkl', model, np_arr, path)
        make_picture('/Users/delgadonoriega/Desktop/FlaskTutorialTwo/live-demo-flask-app/application/AgesAndHeights.pkl', model, np_arr, path)
        return render_template('index.html', href=path[12:])

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

    #sdfwerfwer


# -*- coding: utf-8 -*-
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from MyTools import MyTools
import sqlite3
import os

# 凭证元素类
# noinspection SpellCheckingInspection
class Element:
    def __init__(self):
        self.startPoint = QPoint(0, 0)  # 左上角点
        self.width = 120  # 宽
        self.height = 26  # 高

        self.name = 'name'  # 元素名称
        self.nmajor = 0      # 是否重要字段，1-是则保存到数据仓库字段中，0-否
        self.val = '文本'  # 元素值
        self.text = '文本'  # 显示文本，与self.val关联
        self.type = 'text'  # 当前元素类别,默认文本text
        self.allTypes = ['text', 'num', 'numcap', 'money', 'moneycap', 'check']  # 所有元素类别
        self.allChineseTypes = ['文本', '数字', '数字大写', '金额', '金额大写', '打勾项']  # 所有元素类别中文名称
        self.numTypes = ['num', 'numcap', 'money', 'moneycap']  # 元素数值类别
        self.len = 10  # 元素长度，半角字符数，一个全角字符按2个字符长度计算
        self.font = QFont('宋体', 10, QFont.Normal)  # 默认字体
        # {"name":"宋体","height":180,"width":90, }        #默认字体
        # 以下为元素附加属性
        self.trim = True  # 输入值是否要删除首尾空格
        self.prefix = False  # 是否有前缀
        self.prefixText = '¥'  # 前缀文本，如人民币符号¥等
        self.postfix = False  # 是否有后缀，如大写金额整
        self.postfixText = ''  # 后缀文本
        self.meanCol = False  # 是否均列打印
        self.meanColVal = 0  # 均列打印间隔
        self.checkVal = '√'  # check类型，取值预置为√×*等
        self.hAlign = Qt.AlignLeft  # 水平对齐left、center、right
        self.vAlign = Qt.AlignVCenter  # 垂直对齐 top、center、bottom
        self.lineWrap = False  # 是否折行
        self.printBorder = False  # 是否打印边框

    # 矩形左上角点
    def setStartPoint(self, s):
        self.startPoint = s
        self.adjustPoint()

    # 矩形左上角点
    def getStartPoint(self):
        return self.startPoint

    # 宽
    def setWidth(self, w):
        self.width = int(w)

    # 宽
    def getWidth(self):
        return self.width

    # 高
    def setHeight(self, h):
        self.height = int(h)

    # 高
    def getHeight(self):
        return self.height

    # 元素名称
    def setName(self, e):
        self.name = e

    # 元素名称
    def getName(self):
        return self.name

    # 元素值
    def setVal(self, s):
        mytools = MyTools()
        # 保存同时处理显示文本
        if self.type in self.numTypes:  # 数值类型
            ss = mytools.trim(s)  # 需先删除所有空格，然后判断
            if mytools.legal_numbers(ss):  # 合法数值
                v = float(ss)
                if self.type == 'num':
                    self.val = int(v)
                    self.text = str(int(v))
                elif self.type == 'money':
                    self.val = float('%.2f' % v)
                    self.text = '%.2f' % v
                elif self.type == 'numcap':
                    self.val = int(v)
                    self.text = mytools.convertNumToCap(self.val)
                elif self.type == 'moneycap':
                    self.val = float('%.2f' % v)
                    self.text = mytools.convertNumToChinese(self.val)
            else:  # 非法数值，置空值
                self.val = ''
                self.text = ''
        elif self.type == 'check':  # check类型，只有两个值，空与非空
            v = mytools.trim(s)  # 需先删除所有空格，然后判断
            if v:  # 非空值
                self.val = self.checkVal
                self.text = self.checkVal
            else:
                self.text = ''
                self.val = ''
        else:  # 其他类型，默认处理同text
            if self.trim:  # 是否删除首尾空格
                v = s.strip()
            else:
                v = s
            self.val = v
            self.text = v

        if self.prefix:  # 前缀
            self.text = self.prefixText + self.text
        if self.postfix:  # 后缀
            self.text = self.text + self.postfixText

    # 元素值
    def getVal(self):
        return self.val

    # 显示文本
    def getText(self):
        return self.text

    # 当前元素类别
    def setType(self, t):
        if t in self.allTypes:
            self.type = t
        else:
            self.type = 'text'

    def getType(self):
        return self.type

    def getTypeChinese(self):
        i = self.allTypes.index(self.type)
        return self.allChineseTypes[i]

    def getAllTypes(self):
        return self.allTypes

    def getAllChineseTypes(self):
        return self.allChineseTypes

    # 元素长度
    def setLen(self, l):
        if int(l) > 0:
            self.len = int(l)
        else:
            self.len = 0

    def getLen(self):
        return self.len

    # 字体
    def setFont(self, f):
        self.font = f

    def getFont(self):
        return self.font

    # 各个附加选项
    # 输入值是否要删除首尾空格
    def setTrim(self, t):
        if t:
            self.trim = True
        else:
            self.trim = False

    def getTrim(self):
        return self.trim

    # 是否有前缀
    def setPrefix(self, t):
        if t:
            self.prefix = True
        else:
            self.prefix = False

    def getPrefix(self):
        return self.prefix

    # 前缀文本
    def setPrefixText(self, t):
        self.prefixText = t

    def getPrefixText(self):
        return self.prefixText

    # 是否有后缀
    def setPostfix(self, t):
        if t:
            self.postfix = True
        else:
            self.postfix = False

    def getPostfix(self):
        return self.postfix

    # 后缀文本
    def setPostfixText(self, t):
        self.postfixText = t

    def getPostfixText(self):
        return self.postfixText

    # 是否均列打印
    def setMeanCol(self, t):
        if t:
            self.meanCol = True
        else:
            self.meanCol = False

    def getMeanCol(self):
        return self.meanCol

    # 均列打印值
    def setMeanColVal(self, v):
        self.meanColVal = v

    def getMeanColVal(self):
        return self.meanColVal

    # check类型，取值
    def setCheckVal(self, v):
        self.checkVal = v

    def getCheckVal(self):
        return self.checkVal

    # 水平对齐left、center、right
    def setHAlign(self, v):
        self.hAlign = v

    def getHAlign(self):
        return self.hAlign

    # 垂直对齐 top、center、bottom
    def setVAlign(self, v):
        self.vAlign = v

    def getVAlign(self):
        return self.vAlign

    # 是否折行
    def setLineWrap(self, t):
        if t:
            self.lineWrap = True
        else:
            self.vAlign = False

    def getLineWrap(self):
        return self.lineWrap

    # 是否打印边框
    def setPrintBorder(self, t):
        if t:
            self.printBorder = True
        else:
            self.printBorder = False

    def getPrintBorder(self):
        return self.printBorder

    # 点在矩形中
    def contains(self, e):
        x = e.x() - self.startPoint.x()
        y = e.y() - self.startPoint.y()
        if x < 0 or x > self.width or y < 0 or y > self.height:
            return False
        else:
            return True

    # 点在右边上
    def xcontains(self, e):
        x = e.x() - self.startPoint.x()
        y = e.y() - self.startPoint.y()
        if (self.width - 2 <= x <= self.width + 2) and (0 <= y <= self.height):
            return True
        else:
            return False

    # 点在下边上
    def ycontains(self, e):
        x = e.x() - self.startPoint.x()
        y = e.y() - self.startPoint.y()
        if (0 <= x <= self.width) and (self.height - 2 <= y <= self.height + 2):
            return True
        else:
            return False

    # 移动,x和y分别为X和Y方向的偏移量
    def movedist(self, x, y):
        startPos = QPoint(self.startPoint.x() + x, self.startPoint.y() + y)
        self.startPoint = startPos

# 凭证模板类
# noinspection SpellCheckingInspection
class Voucher:
    def __init__(self):
        self.name = ''  # 凭证名称
        self.text = ''  # 显示的凭证中文名称
        self.width = 180  # 凭证宽度，毫米
        self.height = 100  # 凭证高度，毫米
        self.dpi = 96  # 屏幕dpi
        self.pixelWidth = 850  # 凭证宽度，像素
        self.pixelHeight = 377  # 凭证高度，像素
        self.voucherType = 0  # 凭证分类
        self.elements = {}  # 凭证元素，使用字典保存，元素在表中的序号作为key
        self.background = None  # 凭证背景,base64编码
        self.offsetx = 0  # 横向打印偏移量（不用）
        self.offsety = 0  # 纵向打印偏移量（不用）
        self.leftmargin = 11  # 打印左边距
        self.topmargin = 11  # 打印上边距

    def setName(self, s):
        self.name = s

    def getName(self):
        return self.name

    def setText(self, s):
        self.text = s

    def getText(self):
        return self.text

    # w为宽，h为高，单位为mm
    def setSize(self, w, h):
        self.width = int(w)
        self.height = int(h)

        self.pixelWidth = int(w * self.dpi / 25.4)
        self.pixelHeight = int(h * self.dpi / 25.4)

    def getWidth(self):
        return self.width

    def getHeight(self):
        return self.height

    def getPixelWidth(self):
        return self.pixelWidth

    def getPixelHeight(self):
        return self.pixelHeight

    def setVoucherType(self, vt):
        self.voucherType = vt

    def getVoucherType(self):
        return self.adjustPoint

    # 清空凭证元素列表
    def emptyElements(self):
        self.elements.clear()

    # 追加凭证元素
    def appendElement(self, e):
        n = len(self.elements)  # 将当前凭证数作为key
        ename = "e%04d" % n  # 元素命名：'e'+序号
        e.setName(ename)
        self.elements[n] = e

    # 更新凭证元素
    def updateElement(self, i, e):
        n = len(self.elements)
        if i < 0 or i > n:  # 将非法key，不更新
            return
        self.elements[i] = e

    # 删除制定凭证元素
    def delElement(self, i):
        n = len(self.elements)
        if i < n - 1:  # 非最后一个
            for k in range(i, n - 1):  # 所有元素往前移
                self.elements[k] = self.elements[k + 1]
        # 删除最后一个元素
        self.elements.pop(n - 1)

    # 取指定凭证元素
    def getElement(self, i):
        if len(self.elements) == 0:  # 元素表为空
            return None
        if i >= len(self.elements):
            i = len(self.elements) - 1
        if i < 0:
            i = 0
        return self.elements[i]

    # 元素个数
    def getElementNumbers(self):
        return len(self.elements)

    # 将指定元素位置从i移到k位
    def moveElement(self, i, k):
        if i == k:  # 两个位置相同，无需移动
            return False
        if i >= len(self.elements) or i < 0 or k >= len(self.elements) or k < 0:  # 位置非法，无需移动
            return False
        ei = self.elements[i]  # 保存第i个位置
        if k > i:  # 往后移
            step = 1
        else:  # 往前移
            step = -1
        # 元素移位
        for j in range(i, k, step):
            self.elements[j] = self.elements[j + step]
        self.elements[k] = ei

        return True

    # 凭证背景
    def setBackground(self, p):
        self.background = p

    def getBackground(self):
        return self.background

    # 点在凭证矩形中
    def contains(self, e):
        if (0 <= e.x() <= self.pixelWidth) and (0 <= e.y() <= self.pixelHeight):
            return True
        else:
            return False

    # 保存模板到本地库
    def save(self, dbpath):
        db = dbpath + self.name + ".tdb"
        if not os.path.exists(db):  # 模板库不存在，则先建立
            conn = sqlite3.connect(db)
            c = conn.cursor()
            c.execute('''CREATE TABLE voucher
                (vname           TEXT    PRIMARY KEY NOT NULL,
                vtext            TEXT     NOT NULL,
                vwidth        INT NOT NULL,
                vheight    INT NOT NULL,
                vpixelwidth INT NOT NULL,
                vpixelheight INT NOT NULL);''')
            c.execute('''CREATE TABLE elements
                (ename           Text    PRIMARY KEY NOT NULL,
                epx            int     NOT NULL,
                epy        INT NOT NULL,
                ewidth    INT NOT NULL,
                eheight INT NOT NULL,
                eval TEXT NOT NULL,
                etext TEXT NOT NULL,
                etype TEXT NOT NULL,
                elen int not NULL,
                efont TEXT NOT NULL,
                etrim TEXT NOT NULL,
                eprefix TEXT NOT NULL,
                eprefixText TEXT ,
                epostfix TEXT NOT NULL,
                epostfixText TEXT,
                emeancol TEXT,
                emeancolval int,
                echeckval TEXT,
                ehaligh TEXT,
                evalign TEXT,
                elinewrap TEXT,
                eprintborder TEXT,
                emajor         int NOT NULL);''')
            c.execute('''CREATE TABLE background
                (jpg TEXT NOT NULL);''')

            conn.commit()
            conn.close()

        conn = sqlite3.connect(db)
        c = conn.cursor()

        # 凭证信息
        c.execute('DELETE FROM voucher')
        sql = "INSERT INTO voucher (vname,vtext,vwidth,vheight,vpixelwidth,vpixelheight) \
            values ('%s','%s',%d,%d,%d,%d)" % (
        self.name, self.text, int(self.width), int(self.height), int(self.pixelWidth), int(self.pixelHeight))
        c.execute(sql)
        # 字段信息
        c.execute('DELETE FROM elements')
        for i in range(len(self.elements)):
            # 保存每个字段
            em = self.getElement(i)
            sql = "INSERT INTO elements (ename,epx,epy,ewidth,eheight,eval,etext,etype,elen,efont,etrim,eprefix,eprefixText,epostfix,epostfixText,emeancol,emeancolval,echeckval,ehaligh,evalign,elinewrap,eprintborder,emajor) \
                values ('%s',%d,%d,%d,%d,'%s','%s','%s',%d,'%s','%s','%s','%s','%s','%s','%s',%d,'%s','%s','%s','%s','%s', %d ) " % (
            em.name, int(em.getStartPoint().x()), int(em.getStartPoint().y()), int(em.width), int(em.height), em.val,
            em.text, em.type, int(em.len), em.font.toString(),
            em.trim, em.prefix, em.prefixText, em.postfix, em.postfixText, em.meanCol, int(em.meanColVal), em.checkVal,
            em.hAlign, em.vAlign, em.lineWrap, em.printBorder, int(em.nmajor))
            c.execute(sql)

        # 背景图
        c.execute('DELETE FROM background')
        if self.background is not None:
            # self.background为bytes类型，转换为str后需要删除开头的"b'"及最后的"'"
            sql = "INSERT INTO background (jpg) values ('%s')" % (str(self.background)[2:-1])
            c.execute(sql)
        conn.commit()
        conn.close()

    # 根据凭证名称从本地库中读入
    def load(self, dbpath, name):
        db = dbpath + name + ".tdb"
        return self.loadfromdb(db)

    # 根据凭证名称从本地库中读入
    def loadfromdb(self, db):
        if not os.path.exists(db):  # 模板库不存在
            return None
        conn = sqlite3.connect(db)
        c = conn.cursor()
        sql = "select * from voucher"
        alldata = c.execute(sql)
        for data in alldata:
            self.name = data[0]
            self.text = data[1]  # 显示的凭证中文名称
            self.width = data[2]  # 凭证宽度，毫米
            self.height = data[3]  # 凭证高度，毫米
            self.pixelWidth = data[4]  # 凭证宽度，像素
            self.pixelHeight = data[5]  # 凭证高度，像素
            self.offsetx = 0  # 模板打印偏移量保存在系统库中
            self.offsety = 0

        self.emptyElements()
        sql = "select * from elements order by ename"
        alldata = c.execute(sql)
        for data in alldata:
            em = Element()
            em.name = data[0]  # 元素名称
            em.startPoint = QPoint(int(data[1]), int(data[2]))  # 左上角点
            em.width = int(data[3])  # 宽
            em.height = int(data[4])  # 高
            em.val = data[5]  # 元素值
            em.text = data[6]  # 显示文本，与em.val关联
            em.type = data[7]  # 当前元素类别,默认文本text
            em.len = int(data[8])  # 元素长度，半角字符数，一个全角字符按2个字符长度计算
            em.font.fromString(data[9])  # 字体，转换为QFont
            em.trim = MyTools.str_to_bool(data[10])  # 输入值是否要删除首尾空格
            em.prefix = MyTools.str_to_bool(data[11])  # 是否有前缀
            em.prefixText = data[12]  # 前缀文本，如人民币符号¥等
            em.postfix = MyTools.str_to_bool(data[13])  # 是否有后缀，如大写金额整
            em.postfixText = data[14]  # 后缀文本
            em.meanCol = MyTools.str_to_bool(data[15])  # 是否均列打印
            em.meanColVal = int(data[16])  # 均列打印间隔
            em.checkVal = data[17]  # check类型，取值预置为√×*等
            em.hAlign = int(data[18])  # 水平对齐left、center、right
            em.vAlign = int(data[19])  # 垂直对齐 top、center、bottom
            em.lineWrap = MyTools.str_to_bool(data[20])  # 是否折行
            em.printBorder = MyTools.str_to_bool(data[21])  # 是否打印边框
            em.nmajor = int(data[22])
            self.appendElement(em)

        # 背景
        self.background = None
        sql = "select * from background"
        alldata = c.execute(sql)
        for data in alldata:
            self.background = bytes(data[0], encoding='utf-8')
        conn.close()
        return True

    # 凭证打印
    def paintElements(self, painter):
        for i in range(0, self.getElementNumbers()):
            em = self.getElement(i)

            x0 = em.getStartPoint().x() + self.offsetx - self.leftmargin
            y0 = em.getStartPoint().y() + self.offsety - self.topmargin
            x = em.getWidth()
            y = em.getHeight()
            rect = QRect(x0, y0, x, y)

            txt = em.getText()
            if em.meanCol and em.getType() in ['num', 'money']:  # 均列打印
                txt = txt.replace('.', '')  # 删除其中的小数点
                ft = em.font
                ft.setLetterSpacing(QFont.AbsoluteSpacing, em.meanColVal)  # 设置间隔
                painter.setFont(ft)  # 设置字体
            else:  # 普通文本
                painter.setFont(em.font)  # 设置字体

            painter.drawText(rect, em.getHAlign() | em.getVAlign(), txt)


# Data Preprocessing Template

# Importing the libraries
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

# Importing the dataset
dataset = pd.read_csv('50_Startups.csv')
X = dataset.iloc[:, :-1]
y = dataset.iloc[:, -1:]

# Encoding categorical data
# Encoding the Independent Variable
from sklearn.preprocessing import OneHotEncoder
from sklearn.compose import ColumnTransformer

ct = ColumnTransformer([('encoder', OneHotEncoder(), [3])], remainder='passthrough')
X =ct.fit_transform(X)

#Avoiding the Dummy Variable Trap
X = X[:,1:]

# Splitting the dataset into the Training set and Test set
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)
#X_train[:,2] = X_train[:,2] *2
#Fitting Multiple Linear Regression to the Training set
from sklearn.linear_model import LinearRegression
regressor = LinearRegression()
regressor.fit(X_train,y_train)

#Predicting the Test set results
y_pred = regressor.predict(X_test)
print(regressor.coef_)

plt.scatter(y_pred,y_test,color='red')
plt.plot(range(0,200000,10000),range(0,200000,10000),color = 'blue')
plt.title("Predicted Salary vs Actual Salary(Training Set)")
plt.xlabel("Predicted_salary")
plt.ylabel("Actual Salary")
plt.show()

# =============================================================================
# import statsmodels.api as sm
# X=np.append(arr = np.ones((50,1)).astype(int),values =X,axis=1)
#
# X_opt = X[:,[0,1,2,3,4,5]]
# regressor_ols = sm.OLS(endog=y, exog =X_opt).fit()
# regressor_ols.summary()
#
# X_opt = X[:,[0,1,3,4,5]]
# regressor_ols = sm.OLS(endog=y, exog =X_opt).fit()
# regressor_ols.summary()
#
# X_opt = X[:,[0,3,4,5]]
# regressor_ols = sm.OLS(endog=y, exog =X_opt).fit()
# regressor_ols.summary()
#
# X_opt = X[:,[0,3,5]]
# regressor_ols = sm.OLS(endog=y, exog =X_opt).fit()
# regressor_ols.summary()
#
# X_opt = X[:,[0,3]]
# regressor_ols = sm.OLS(endog=y, exog =X_opt).fit()
# regressor_ols.summary()
#
# X=X_opt[:,1:]
# =============================================================================

# =============================================================================
# X=np.append(arr = np.ones((50,1)).astype(int),values =X,axis=1)
# import statsmodels.api as sm
# def backwardElimination(x, sl):
#     numVars = len(x[0])
#     for i in range(0, numVars):
#         regressor_OLS = sm.OLS(y, x).fit()
#         maxVar = max(regressor_OLS.pvalues.astype(float))
#         if maxVar > sl:
#             for j in range(0, numVars - i):
#                 if (regressor_OLS.pvalues[j].astype(float) == maxVar):
#                     x = np.delete(x, j, 1)
#     regressor_OLS.summary()
#     return x
#
# SL = 0.05
# X_opt = X[:, [0, 1, 2, 3, 4, 5]]
# X_Modeled = backwardElimination(X_opt, SL)
#
# X=X_Modeled
# =============================================================================

# Using both P-values and adj R square values
X=np.append(arr = np.ones((50,1)).astype(int),values =X,axis=1)
import statsmodels.api as sm
def backwardElimination(x, SL):
    numVars = len(x[0])
    temp = np.zeros((50,6)).astype(int)
    for i in range(0, numVars):
        regressor_OLS = sm.OLS(y, x).fit()
        maxVar = max(regressor_OLS.pvalues.astype(float))
        adjR_before = regressor_OLS.rsquared_adj.astype(float)
        if maxVar > SL:
            for j in range(0, numVars - i):
                if (regressor_OLS.pvalues[j].astype(float) == maxVar):
                    temp[:,j] = x[:, j]
                    x = np.delete(x, j, 1)
                    tmp_regressor = sm.OLS(y, x).fit()
                    adjR_after = tmp_regressor.rsquared_adj.astype(float)
                    if (adjR_before >= adjR_after):
                        x_rollback = np.hstack((x, temp[:,[0,j]]))
                        x_rollback = np.delete(x_rollback, j, 1)
                        print (regressor_OLS.summary())
                        return x_rollback
                    else:
                        continue
    regressor_OLS.summary()
    return x

SL = 0.05
X_opt = X[:, [0, 1, 2, 3, 4, 5]]
X_Modeled = backwardElimination(X_opt, SL)

X=X_Modeled

#Predicting the results
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)

#X_train[:,1] = X_train[:,1] *2
regressor = LinearRegression()
regressor.fit(X_train,y_train)
y_pred_opt = regressor.predict(X_test)

print(regressor.coef_)

plt.scatter(y_pred_opt,y_test,color='red')
plt.plot(range(0,200000,10000),range(0,200000,10000),color = 'blue')
plt.title("New Predicted Salary vs Actual Salary(Training Set)")
plt.xlabel("New Predicted salary")
plt.ylabel("Actual Salary")
plt.show()
#Check the results using MSE(mean squared error)
from sklearn.metrics import mean_squared_error
mse1 = mean_squared_error(y_pred,y_test)
mse2 = mean_squared_error(y_pred_opt,y_test)

rmse1=mse1**0.5
rmse2=mse2**0.5
print("\nRMSE - Just Linear Regression is {:.2f}\n\
RMSE - Backward Elimination using P and adj-Rsquared values is {:.2f}".format(rmse1,rmse2))

Machine Learning A-Z New/Part 2 - Regression/Section 5 - Multiple Linear Regression/own_multiple_regression.py


import preRun

import nodes
import world
import gui
import util
import constants as cst

node_list = []

new_world = world.World(6,6)

SU_list = []
PU_list = []
### SU
for i in range(20):
    newN = nodes.Nodes(i,False,new_world,False)
    node_list.append(newN)
    SU_list.append(newN)
# ### PU
# for i in range(8, 9):
#     newN = nodes.Nodes(i,False,new_world, True)
#     node_list.append(newN)
#     PU_list.append(newN)

# for pu in PU_list:
#     pu.set_PU_Color()

### Creating a GUI to display the node and the annimations
new_GUI = gui.GUI()
new_GUI.open_GUI()
### Setting the world into the GUI
new_GUI.set_World(new_world)
new_GUI.set_Nodes(node_list)

for n in node_list :
        n.sense_In_Range_Nodes()
# for pu in PU_list:
#     pu.set_PU_Color()

#util.best_coloring(node_list, PU_list)

v = node_list[0].complete_graph_coloring1()
count = util.count_channel_reused_PU(node_list, SU_list, PU_list)
reste = util.count_coloring_proportion(node_list)
alledges = len(util.get_all_edges(node_list))
print("count", count)
print("reste", reste)
print("all edges", alledges)
print("rec", v)

new_GUI.color_refresh(node_list)

print("-----------------------------------")
for n in node_list:

    tmp = n.get_used_channel()

    id_list = []
    for v in n.in_Range_Nodes :
        id_list.append(v.id)

    print(n.id, n.randomChan, n.free_Channels)
#    print (f"forbidden channels : {n.get_forbidden_channels()}")
#    print (f"Final coloring for node {n.id} {n.coloring} ")
#     print (f"Transmission range : {n.transmission_Range}")
#     print (f"Neighbour : {id_list}")
#     if n.isPU:
#     print (f"Channel PU {n.PU_channel}")
#     print (f"channels : {n.sense_free_channels(PU_list)}")
#     print (f"channel usage in the range of {n.id}: {tmp}\n\n")
# print (f"re-utilisation = {count}" )

# m = node_list[0]
# e = (0, 3)
# print(m.PU_channel)
# print(util.is_chan_used(e,m.PU_channel,node_list))
# print(util.PU_whithin_two_hops(m))

new_GUI.loop()


class Solution:
    def searchInsert(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        head=0
        tail=len(nums)
        while head!=tail:
            i=(head+tail)//2
            if nums[i]==target:
                return i
            elif nums[i]<target:
                head=i+1
            else:
                tail=i
        return head

"""
48 ms, faster than 27.14% of Python3 online submissions for Search Insert Position.
i use binary search to accomplish this task, because the test case is short so its
advantage doesn't show up, but its time complexity is O(log2n), and search one by one
cost n times search.
note:we should pay extremely attention to the index of list, whether plus one, minus 1,
whether it's out of the range of a list blabla....
"""


import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer, TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import accuracy_score
from sklearn.metrics import confusion_matrix
from sklearn.metrics import plot_confusion_matrix
from sklearn.svm import LinearSVC
import json

with open("/Users/hugo/Cincinnati/ADV_ENGR/my_env/Project_ADV_ENGR/json/all.json", "r") as read_file:
    data = json.load(read_file)

Review_label = []

for i in range(len(data)):
    a = data[i]["comment"]
    b = data[i]["label"]
    Review_label.append([a,b])

df = pd.DataFrame(Review_label)
df.columns = ["review","label"]

for i in range(len(df)):
    if df["label"][i] == "Bug":
        df["label"][i] = 1
    elif df["label"][i] == "Feature":
        df["label"][i] = 2
    elif df["label"][i] == "Rating":
        df["label"][i] = 3
    elif df["label"][i] == "UserExperience":
        df["label"][i] = 4

X_train, X_test, Y_train, Y_test = train_test_split(df['review'],
                                                    df['label'],
                                                    test_size=0.2,
                                                    stratify=df['label'])

print('Size of Training Data ', X_train.shape[0])
print('Size of Test Data ', X_test.shape[0])

Y_train = Y_train.astype('int')
Y_test = Y_test.astype('int')

#countv = CountVectorizer(min_df = 3, ngram_range=(1,5), stop_words="english")
countv = TfidfVectorizer(min_df = 3, ngram_range=(1,5), stop_words="english")
X_train_tf = countv.fit_transform(X_train).toarray()
print(X_train_tf)
model1 = LinearSVC()
model1.fit(X_train_tf, Y_train)

X_test_tf = countv.transform(X_test)
Y_pred_LinearSVC = model1.predict(X_test_tf)
print ('Accuracy Score: - ', accuracy_score(Y_test, Y_pred_LinearSVC))

#print(confusion_matrix(Y_test, Y_pred))

plot_confusion_matrix(model1,X_test_tf,
                      Y_test, values_format='d',
                      cmap=plt.cm.Blues)
plt.title("Confusion matrix for MultinomialNB, mind_df = 3, ngram_range=(1,5)")
plt.show()

x = []
y = []

for C in range(1,100,5):
    clf = LinearSVC(C=C)
    clf.fit(X_train_tf,Y_train)

    X_test_tf = countv.transform(X_test)

    Y_pred = clf.predict(X_test_tf)

    """ tree.plot_tree(clf)
    plt.show() """

    x.append(C)
    y.append(accuracy_score (Y_pred,Y_test))

plt.xlabel("C")
plt.ylabel("Accuracy score")
plt.plot(x,y)

plt.show()


from turtle import Turtle
import random

COLORS = ["red", "orange", "yellow", "green", "blue", "purple"]
STARTING_MOVE_DISTANCE = 5
MOVE_INCREMENT = 10

class CarManager(Turtle):
    def __init__(self):
        super().__init__()
        self.hideturtle()
        self.carlist = []
        self.carspeed = STARTING_MOVE_DISTANCE

    def createcar(self):
        chance = random.randint(1, 5)
        if chance == 1:
            newcar = Turtle("square")
            newcar.penup()
            newcar.color(random.choice(COLORS))
            newcar.shapesize(stretch_wid=1, stretch_len=2)
            newcar.goto(300, random.randint(-250, 250))
            self.carlist.append(newcar)

    def run(self):
        for car in self.carlist:
            car.backward(self.carspeed)

    def speedup(self):
        self.carspeed += MOVE_INCREMENT
        for car in self.carlist:
            car.backward(self.carspeed)


import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
from string import Template
import pandas as pd

e = pd.read_csv("FILE_NAME.csv")
server = smtplib.SMTP(host='smtp.gmail.com', port=587)
server.starttls()
server.login('YOUREMAIL@gmail.com','YOURPASSWORD')

body = ("""
Hi there

This is the body of the email

Thank you
""")
subject = "This is the subject of the email"
fromaddr='abc@gmail.com'
for index, row in e.iterrows():
    print (row["EMAIL_COLUMN_NAME"]+row["ATTACHMENT_COLUMN_NAME"])
    msg = MIMEMultipart()
    msg['From'] = fromaddr
    msg['Subject'] = subject
    msg.attach(MIMEText(body, 'plain'))
    filename = row["ATTACHMENT_COLUMN_NAME"]
    toaddr = row["EMAIL_COLUMN_NAME"]
    attachment = open(row["ATTACHMENT_COLUMN_NAME"], "rb")
    part = MIMEBase('application', 'octet-stream')
    part.set_payload((attachment).read())
    encoders.encode_base64(part)
    part.add_header('Content-Disposition', "attachment; filename= %s" % filename)
    msg.attach(part)
    text = msg.as_string()
    server.sendmail(fromaddr, toaddr, text)

print("Emails sent successfully")

server.quit()


def crop(x, wrg, hrg, is_random=False, row_index=0, col_index=1):
    """Randomly or centrally crop an image.

    Parameters
    ----------
    x : numpy.array
        An image with dimension of [row, col, channel] (default).
    wrg : int
        Size of width.
    hrg : int
        Size of height.
    is_random : boolean,
        If True, randomly crop, else central crop. Default is False.
    row_index: int
        index of row.
    col_index: int
        index of column.

    Returns
    -------
    numpy.array
        A processed image.

    """
    h, w = x.shape[row_index], x.shape[col_index]

    if (h < hrg) or (w < wrg):
        raise AssertionError("The size of cropping should smaller than or equal to the original image")

    if is_random:
        h_offset = int(np.random.uniform(0, h - hrg))
        w_offset = int(np.random.uniform(0, w - wrg))
        # tl.logging.info(h_offset, w_offset, x[h_offset: hrg+h_offset ,w_offset: wrg+w_offset].shape)
        return x[h_offset:hrg + h_offset, w_offset:wrg + w_offset]
    else:  # central crop
        h_offset = int(np.floor((h - hrg) / 2.))
        w_offset = int(np.floor((w - wrg) / 2.))
        h_end = h_offset + hrg
        w_end = w_offset + wrg
        return x[h_offset:h_end, w_offset:w_end]


from blueprints import db
from flask_restful import fields

class User_details(db.Model):
    __tablename__ = 'user_details'
    user_details_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    nama = db.Column(db.String(30), unique=True, nullable=False)
    alamat = db.Column(db.String(50), nullable=False)
    email = db.Column(db.String(50), nullable=False)
    nomor_hp = db.Column(db.String(50), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.user_id'), nullable=False, unique=True)

    response_fields = {
        'user_details_id': fields.Integer,
        'nama': fields.String,
        'alamat': fields.String,
        'email': fields.String,
        'nomor_hp': fields.String,
        'user_id': fields.Integer
    }

    def __init__(self, nama, alamat, email, nomor_hp, user_id):
        self.nama = nama
        self.alamat = alamat
        self.email = email
        self.nomor_hp = nomor_hp
        self.user_id = user_id

    def __repr__(self):
        return '<User %r>' % self.user_id


from server.organism.models import Organism
from server.chromosome.models import Chromosome, Assemb
from server.chromosome.interf import deleteChromosome

from server.utils import log as LOG
from config.settings import DEBUG

def getOrganisms():
    LOG.INFO("Rozpoczynam pobieranie wszystkich organizmow.")
    organisms = Organism.objects.all().values()
    LOG.INFO("Zakonczylem pobieranie wszystkich organizmow.")
    return organisms

def getOrganismsByID(organism_id):
    LOG.INFO("Rozpoczynam pobieranie obiektu organizmu o ID: " + str(organism_id))
    organism = Organism.objects.filter(id = organism_id).values()
    try:
        organism_ret = organism[0]
    except IndexError:
        LOG.WARN("Nie istnieje organizm o ID: " + str(organism_id))
        return None
    LOG.INFO("Zakonczylem pobieranie obiektu organizmu o ID: " + str(organism_id))
    return organism_ret

def addOrganism(org_name, org_desc, chrs_count):
    LOG.INFO("Rozpoczynam dodawanie organizmu: " + str(org_name) + ". Ilosc chromosomow: " + str(chrs_count) + ". Opis: " + str(org_desc))
    organism = None
    try:
        organism = Organism(name=str(org_name), description=str(org_desc))
        organism.save()
        LOG.DEBUG("Dodano organizm: " + str(organism.id))
    except Exception:
        LOG.WARN("Blad podczas dodawania nowego organizmu: " + str(org_name))
        return None

    try:
        # Dodanie wszystkich chromosomow
        for i in range(chrs_count):
            chr = Chromosome(name=("Chromosome " + str(i+1)), organism_id=int(organism.id))
            chr.save()
            LOG.DEBUG("Dodano chromosom: " + str(chr.name) + " (" + str(chr.id) + ")" + " do organizmu: " + str(chr.organism_id))
    except Exception:
        LOG.WARN("Blad podczas dodawania nowego chromosomu do organizmu: " + str(org_name))
        return None

    LOG.INFO("Zakonczylem dodawanie organizmu: " + str(org_name))
    return organism.id

def deleteOrganism(org_id):
    LOG.INFO("Rozpoczynam usuwanie organizmu o ID: " + str(org_id))
    try:
        o = Organism.objects.get(id = int(org_id))
    except Organism.DoesNotExist:
        LOG.WARN("Brak organizmu o ID: " + str(org_id))
        return None
    o.delete()

    LOG.DEBUG("Usuwam wszystkie chromosomy organizmu: " + str(org_id) + " wraz z podleglymi strukturami")
    # Usuniecie wszystkich chromosomow ze wszystkimi strukturami
    chrs = Chromosome.objects.filter(organism_id = int(org_id))
    for chromosome in chrs:
        LOG.DEBUG("Usuwam chromosome: " + str(chromosome.id) + " z organizmu: " + str(org_id))
        deleteChromosome(chromosome.id)

    LOG.DEBUG("Usuwam wszystkie typy asemblacji z organizmu: " + str(org_id))
    # Usuniecie wszystkich typow asemblacji
    Assemb.objects.filter(organism_id = int(org_id)).delete()

    LOG.INFO("Zakonczylem usuwanie organizmu o ID: " + str(org_id))
    return True


import webapp2
import json
import logging

from google.appengine.api import users

from models.account import *

class RequestController(webapp2.RequestHandler):
    account = None

    def checkAccount(self):
        user = users.get_current_user()
        if user == None:
            self.invalid_value('not logged in')
            return False
        req = self.request
        self.account_name = req.get('account_name')
        self.account_owner = req.get('account_owner')
        self.account_user = self.request.get('account_user')
        self.email = user.email()
        account_found = find_account(self.request)
        if (type(account_found) == 'String'):
            self.invalid_value(account_found)
            return False

        # verify that access to this account is permitted to this user
        if self.account_user != user.email():
            self.invalid_value('user mismatch')
            return true

        self.account = account_key(self.account_name, self.account_owner)
        return True

    def get_object(self, i):
        return {'id': i.id, 'name': i.name, 'active': i.active}

    def get(self):
        logging.info('in RequestController get()')
        if not self.checkAccount():
            return;
        query = self.clsRef.query(ancestor=self.account).order(self.clsRef.name)
        start_offset = int(self.request.get('start'))
        limit = self.request.get('limit')
        if limit=='':
            instances = query.fetch()
        else:
            limit = int(limit)
            instances = query.fetch(limit, offset=start_offset)
        list = []
        for i in instances:
            list.append(self.get_object(i))
        self.response.out.write(json.dumps({ \
            'user_name': self.email, \
            'account_name': self.account_name, \
            'account_owner': self.account_owner, \
            'rows': list}))

    def post(self):
        logging.info('in RequestController post()')
        if not self.checkAccount():
            return;
        req = self.request
        id = req.get('id')
        if id == None:
            self.invalid_value('id not specified')
            return
        else:
            try:
                id = int(id);
            except:
                self.invalid_value('id')
                return
        if (self.request.get('action') == 'delete'):
            self.delete_instance(id)
            return
        name = req.get('name')
        if name == None or name == '':
            self.invalid_value('name must be specified')
            return
        is_active = req.get('active') == 'true'
        p = None
        if id == 0:
            if self.get_by_name(name) != None:
                self.invalid_value(self.objectName + ' exists: ' + name)
                return
            i = self.clsRef(parent=self.account)
            # find the largest type ID x for this account,
            # and return new type ID that is x+1
            q = self.clsRef.query(ancestor=self.account).order(-self.clsRef.id)
            results = q.fetch(1)
            new_id = 1
            for old in results:
                new_id = old.id + 1
            set_value_result = i.set_values(new_id, name, active, req)
            if set_values_result != True:
                self.invalid_value(set_values_result)
                return
            i.put()
            resp = json.dumps(({'success': 1, 'id': new_id}))
            self.response.out.write(resp)
        else:
            record_to_change = None
            for p in self.clsRef.query(ancestor=self.account).fetch():
                if p.id == id:
                    record_to_change = p
                else:
                    if p.name == name:
                        self.invalid_value('expense type exists: ' + name)
                        return
            if record_to_change == None:
                self.invalid_value('unable to find ' + self.objectName + \
                    ' with id=' + id)
                return
            set_value_result = record_to_change.set_values(id, \
                name, is_active, req)
            if set_values_result != True:
                self.invalid_value(set_values_result)
                return
            record_to_change.put()
            resp = json.dumps(({'success': 1, 'id': record_to_change.id}))
            self.response.out.write(resp)
            return

    def delete_instance(self, id):
        p = self.get_by_id(id)
        if p != None:
            p.key.delete()
            self.response.out.write(json.dumps(({'success': 1, 'id': id})))
        else:
            self.invalid_value('Delete failed: ID not found')

    def invalid_value(self, field):
        self.response.out.write(json.dumps(({'success': 0, 'errors': 'Invalid value recieved: ' + field})))

    def operation_failed(self, msg):
        self.response.out.write(json.dumps(({'success': 0, 'errors': 'Operation failed: ' + msg})))

    def get_by_id(self, id):
        for i in self.clsRef.query(ancestor=self.account).fetch():
            if i.id == id:
                return i
        return None

    def get_by_name(self, name):
        for i in self.clsRef.query(ancestor=self.account).fetch():
            if i.name == name:
                return i
        return None


class Car:
    def __init__(self, th_name, th_color, th_speed, th_is_police):
        self.name = th_name
        self.color = th_color
        self.speed = th_speed
        self.is_police = th_is_police

    def show_speed(self):
        print(f"Speed({self.name}) = {self.speed}")

    def go(self):
        print(f"Car {self.name} go!!!")

    def stop(self):
        print(f"Car {self.name} stop!!!")

    def get_color(self):
        print(f"Color ({self.name}) is {self.color}")

    def get_is_police(self):
        print(f"{self.name} is police") if self.is_police else print(f"{self.name} is not police")

    def turn(self, direction):
        print(f"Car ({self.name}) go {direction}")

class TownCar(Car):
    def __init__(self, th_name, th_color, th_speed):
        self.name = th_name
        self.color = th_color
        self.speed = int(th_speed)
        self.is_police = False

    def show_speed(self):
        if self.speed > 60:
            print(f"Speed car({self.name}) > 60")
        else:
            print(f"Speed({self.name}) = {self.speed}")

class WorkCar(Car):
    def __init__(self, th_name, th_color, th_speed):
        self.name = th_name
        self.color = th_color
        self.speed = int(th_speed)
        self.is_police = False

    def show_speed(self):
        if self.speed > 40:
            print(f"Speed car({self.name}) > 40")
        else:
            print(f"Speed({self.name}) = {self.speed}")

class SportCar(Car):
    def __init__(self, th_name, th_color):
        self.name = th_name
        self.color = th_color
        self.speed = 300
        self.is_police = False

class PoliceCar(Car):
    def __init__(self, th_name, th_color, th_speed):
        self.name = th_name
        self.color = th_color
        self.speed = int(th_speed)
        self.is_police = True

car = Car("Moskvich", "green", 140, False)
car.get_color()
car.go()
car.stop()
car.get_is_police()
car.show_speed()
car.turn("left")

workCar1 = WorkCar("GAZ", "blue", 60)
workCar1.get_color()
workCar1.go()
workCar1.stop()
workCar1.get_is_police()
workCar1.show_speed()
workCar1.turn("right")

workCar2 = WorkCar("ZIL", "yellow", 40)
workCar2.get_color()
workCar2.go()
workCar2.stop()
workCar2.get_is_police()
workCar2.show_speed()
workCar2.turn("back")

townCar1 = TownCar("Mini", "blue", 70)
townCar1.get_color()
townCar1.go()
townCar1.stop()
townCar1.get_is_police()
townCar1.show_speed()
townCar1.turn("right")

townCar2 = TownCar("Smart", "yellow", 50)
townCar2.get_color()
townCar2.go()
townCar2.stop()
townCar2.get_is_police()
townCar2.show_speed()
townCar2.turn("back")

sportCar = SportCar("Ferrari", "red")
sportCar.get_color()
sportCar.go()
sportCar.stop()
sportCar.get_is_police()
sportCar.show_speed()
sportCar.turn("right")

policeCar = PoliceCar("Ford", "blue", 70)
policeCar.get_is_police()
policeCar.go()
policeCar.get_color()
policeCar.stop()
policeCar.show_speed()
policeCar.turn("back")


import csv
import string

def texttocsv(name):
    y=string.lower(open(name+'.txt').read())
    w=open(name+'.csv','w')
    writer=csv.writer(w)
    for c in range(0,len(y)-100):
        row=[]
        for x in range(0,99):
            row.append(y[x+c])
        writer.writerow(row)


"""

"""

import unittest

class MyTest(unittest.TestCase):
    def test(self):
        self.assertEqual(BS([1, 2, 3, 4, 5], 3, start=0, end=4), 2)
        self.assertEqual(BS([1, 2, 4, 4, 5], 3, start=0, end=4), -1)
        self.assertEqual(BS([1, 2, 4, 4, 4, 5], 5, start=0, end=5), 5)

def BS (an_array: list, to_find: int, start: int, end: int):
    middle_index = int((start + end)/2)
    if middle_index >= len(an_array):
        return -1
    if an_array[middle_index] == to_find:
        return middle_index
    if start==end:
        return -1
    elif an_array[middle_index] < to_find:
        return BS(an_array, to_find, middle_index, end)
    elif an_array[middle_index] > to_find:
        return BS(an_array, to_find, start, middle_index)

    pass

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


# final_branch

import scrapy
from scrapy.http import HtmlResponse
from les6.items import BookItem

class Book24Spider(scrapy.Spider):
    name = 'book24'
    allowed_domains = ['book24.ru']
    start_urls = ['https://book24.ru/catalog/ezotericheskie-khudozhestvennye-knigi-1664']
    pagination = int(2)

    def parse(self, response: HtmlResponse):
        vac_links = response.xpath("//a[@class='product-card__image-link smartLink']//@href").extract()
        next_page = self.start_urls[0] + f'/page-{self.pagination}'
        self.pagination += 1
        for element in vac_links:
            yield response.follow(element, callback=self.book_parse)
        if next_page:
            yield response.follow(next_page, callback=self.parse)

    def book_parse(self, response: HtmlResponse):
        title = response.xpath("//h1[@class='product-detail-page__title']/text()").extract_first().replace('\n', '').replace('  ','')
        book_link = response.url
        author = response.xpath("//span[@itemprop='author']/meta[@itemprop='name']/@content").extract_first()
        new_price = response.xpath("//meta[@property='product:price:amount']/@content").extract_first()
        old_price = response.xpath("//span[@class='app-price product-sidebar-price__price-old']/text()").extract_first()
        rate = response.xpath("//meta[@itemprop='ratingValue']/@content").extract_first()
        src = Book24Spider.allowed_domains[0]
        scrap = 'book24_ru'
        item = BookItem(title=title, link=book_link, author=author, new_price=new_price, \
                        old_price=old_price, rate=rate, source=src, scrap=scrap)
        yield item