import sys
from PyQt4 import *
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from PyQt4.phonon import *
from utils.helpers import *
from core.songs import *
from database.database import Db
import pickle

class Mainwindow(QMainWindow):

    def __init__(self):
        QMainWindow.__init__(self)

        #initialize icons
        self.icons = {"play":"images/play.png",
                      "pause":"images/pause.png",
                      "stop":"images/stop.png",
                      "next":"images/next.png",
                      "previous":"images/previous.png",
                      "all_songs":"images/all_songs.png",
                      "playlist":"images/playlist.png",
                      "media_add":"images/media_add.png",
                      "media_remove":"images/media_remove.png",
                      "media_edit":"images/media_edit.png"}

        self.sources = Songs()

        self.setupHelpers()
        self.setupAudioObjects()
        self.setupUi()
        self.setupSignals()

        self.__current_sid = 0

        self.loadAllSongs()
        self.loadAllPlaylists()
        self.loadContextMenu()

    def loadContextMenu(self):
        #table context menu
        self.musicTable.setContextMenuPolicy(Qt.ActionsContextMenu)
        current_actions = self.musicTable.actions()
        if len(current_actions) > 0:
            for action in current_actions:
                self.musicTable.removeAction(action)
        for i in range(self.playlist.count()):
            if not i == 0:

                currentItem = self.playlist.item(i)
                currentData = currentItem.data(Qt.UserRole).toInt()[0]

                playlistContenxt = QAction("Add to %s" % (currentItem.text()), self.musicTable)
                playlistContenxt.setData(currentData)
                self.connect(playlistContenxt, SIGNAL("triggered()"), self.addToPlaylistAction)
                self.musicTable.addAction(playlistContenxt)

        playlistContenxt = QAction("Delete Song", self.musicTable)
        self.connect(playlistContenxt, SIGNAL("triggered()"), self.deleteSong)
        self.musicTable.addAction(playlistContenxt)

    def deleteSong(self):
        to_delete = self.musicTable.selectedItems()
        songs_to_delete = []
        for i in to_delete:
            song_id = i.data(Qt.UserRole).toInt()[0]
            if not song_id == 0:
                songs_to_delete.append(song_id)

        if len(songs_to_delete) > 0:
            for song_id in songs_to_delete:
                Db.execute("DELETE FROM songs WHERE id = %d" % (song_id))
                Db.execute("DELETE FROM playlist_songs WHERE song_id = %d" % (song_id))
            self.sources.clear()
            self.clearMusicTable()
            self.loadAllSongs()

    def addToPlaylistAction(self):
        action = self.sender()
        playlist_id = action.data().toInt()[0]

        to_add = self.musicTable.selectedItems()
        songs_to_add = []
        for i in to_add:
            song_id = i.data(Qt.UserRole).toInt()[0]
            if not song_id == 0:
                songs_to_add.append(song_id)

        if len(songs_to_add) > 0:
            for song_id in songs_to_add:
                sql = "SELECT * FROM playlist_songs WHERE song_id = %d AND playlist_id = %d" % (song_id, playlist_id)
                query = Db.execute(sql)
                if query.size() == 0:
                    Db.insert("playlist_songs", {"playlist_id": playlist_id, "song_id": song_id})
            self.playlist.setCurrentRow(self.getRowByData(playlist_id))

    def getRowByData(self, playlist_id):
        for i in range(self.playlist.count()):
            if not i == 0:
                currentItem = self.playlist.item(i)
                if currentItem.data(Qt.UserRole).toInt()[0] == playlist_id:
                    return i

    def loadAllSongs(self):
        sql = "SELECT s.id, s.title, s.path, s.duration, a.name as artist, al.name as album, g.name as genre FROM songs as s \
                INNER JOIN artists as a ON a.id = s.artist_id \
                INNER JOIN albums as al ON al.id = s.album_id \
                INNER JOIN genres as g ON g.id = s.genre_id ORDER BY s.title ASC"
        query = Db.execute(sql)
        if query:
            while query.next():

                song = Song(id=query.value(0).toInt()[0],
                            title=query.value(1).toString(),
                            path=query.value(2).toString(),
                            duration=query.value(3).toInt()[0],
                            artist=query.value(4).toString(),
                            album=query.value(5).toString(),
                            genre=query.value(6).toString())

                self.sources.addSong(song)
            self.displayAllSongs()

    def loadAllPlaylists(self):

        self.playlist.clear()
        allsongs = QListWidgetItem("All Songs")
        allsongs.setIcon(QIcon(self.icons["all_songs"]))
        self.playlist.addItem(allsongs)

        query = Db.select(sqlTable="playlists", sqlFields=["id", "name"])
        if query:
            while query.next():
                playlistName = QListWidgetItem(query.value(1).toString())
                playlistName.setIcon(QIcon(self.icons["playlist"]))
                playlistName.setData(Qt.UserRole, query.value(0).toInt()[0])
                self.playlist.addItem(playlistName)

        self.playlist.setCurrentRow(0)

    def setupHelpers(self):
        self.phelper = Playerhelper()

    def setupAudioObjects(self):
        self.audioOutput = Phonon.AudioOutput(Phonon.MusicCategory, self)
        self.mediaObject = Phonon.MediaObject(self)
        self.mediaObject.setTickInterval(1000)

        self.tempMediaObject = Phonon.MediaObject()

        Phonon.createPath(self.mediaObject, self.audioOutput)

    #setup ui widgets
    def setupUi(self):

        self.resize(1000, 700)
        self.setWindowTitle("Pysawndz")

        #setup menu
        menubar = QMenuBar()
        file = menubar.addMenu("&File")

        self.importm = QAction("Import ...", self)
        self.importm.setShortcut("Ctrl+A")

#        self.exportm = QAction("Export ...", self)
#        self.exportm.setShortcut("Ctrl+X")
#        self.restorem = QAction("Restore playlist", self)
#        self.restorem.setShortcut("Ctrl+R")

        self.exit = QAction("Bye!", self)
        self.exit.setShortcut("Ctrl+Q")

        file.addAction(self.importm)
#        file.addAction(self.exportm)
#        file.addAction(self.restorem)
        file.addAction(self.exit)
        self.setMenuBar(menubar)

        #setup toolbar buttons
        self.toolbar = self.addToolBar("Controls")

        self.playbtn = QAction(QIcon(self.icons["play"]), "Play", self)
        self.playbtn.setShortcut("Ctrl+P")

        self.pausebtn = QAction(QIcon(self.icons["pause"]), "Pause", self)
        self.pausebtn.setShortcut("Ctrl+A")

        self.stopbtn = QAction(QIcon(self.icons["stop"]), "Stop", self)
        self.stopbtn.setShortcut("Ctrl+S")

        self.nextbtn = QAction(QIcon(self.icons["next"]), "Next", self)
        self.nextbtn.setShortcut("Ctrl+N")

        self.previousbtn = QAction(QIcon(self.icons["previous"]), "Previous", self)
        self.previousbtn.setShortcut("Ctrl+V")

        self.toolbar.addAction(self.playbtn)
        self.toolbar.addAction(self.pausebtn)
        self.toolbar.addAction(self.stopbtn)
        self.toolbar.addAction(self.previousbtn)
        self.toolbar.addAction(self.nextbtn)

        #setup the songs table view
        self.musicTable = QTableWidget(0, 5)
        self.musicTable.setHorizontalHeaderLabels(["Name", "Time", "Artist", "Albums", "Genre"])
        self.musicTable.horizontalHeader().setStretchLastSection(True)
        self.musicTable.setSelectionMode(QAbstractItemView.ContiguousSelection)
        self.musicTable.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.musicTable.setColumnWidth(0, 320)
        self.musicTable.setColumnWidth(1, 70)

        #setup lcdtimer
        pallete = QPalette()
        self.timeLcd = QLCDNumber()
        pallete.setBrush(QPalette.Light, Qt.darkGray)
        self.timeLcd.setPalette(pallete)
        self.timeLcd.display("00:00")

        #setup seeker
        self.seekSlider = Phonon.SeekSlider()
        self.seekSlider.setMediaObject(self.mediaObject)

        #setup volume slider
        self.volumeSlider = Phonon.VolumeSlider(self)
        self.volumeSlider.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        self.volumeSlider.setAudioOutput(self.audioOutput)

        #setup left pane
        self.playlist = QListWidget(self)

        #setup bottom control layout
        controlsLayout = QHBoxLayout()
        controlsLayout.addWidget(self.timeLcd)
        controlsLayout.addWidget(self.seekSlider)
        controlsLayout.addWidget(self.volumeSlider)

        #playlist controls
        self.addPlaylist = QPushButton(QIcon(self.icons["media_add"]), '', self)
        self.editPlaylist = QPushButton(QIcon(self.icons["media_edit"]), '', self)
        self.removePlaylist = QPushButton(QIcon(self.icons["media_remove"]), '', self)

        #playlist add/remove/edit
        playlistControlsLayout = QHBoxLayout()
        playlistControlsLayout.addWidget(self.addPlaylist)
        playlistControlsLayout.addWidget(self.editPlaylist)
        playlistControlsLayout.addWidget(self.removePlaylist)

        #playlist splitter
        playlistVertical = QVBoxLayout()
        playlistVertical.addWidget(self.playlist)
        playlistVertical.addLayout(playlistControlsLayout)

        leftPane = QWidget()
        leftPane.setLayout(playlistVertical)

        #setup splitter panes
        self.splitter = QSplitter(self)
        self.splitter.addWidget(leftPane)
        self.splitter.addWidget(self.musicTable)
        self.splitter.setSizes([50, 800])

        #setup main layout
        layout = QVBoxLayout()
        layout.addWidget(self.splitter)
        layout.addLayout(controlsLayout)

        #setup central widget
        self.central = QWidget()
        self.central.setLayout(layout)

        #setup content
        self.setCentralWidget(self.central)

    def addPlaylistAction(self):
        playlistName, response = QInputDialog.getText(self, 'Pysawndz', 'Playlist name:')

        if response:
            sql = "SELECT * FROM playlists WHERE name = '%s'" % (playlistName)
            query = Db.execute(sql)
            if query.size() == 0:
                Db.insert("playlists", {"name": playlistName})
                self.loadAllPlaylists()
                self.playlist.setCurrentRow(self.playlist.count() - 1)
                self.loadContextMenu()
            else:
                QMessageBox.warning(self, "Pysawndz", "Another playlist with the same name already exist.", QMessageBox.Ok);

    def removePlaylistAction(self):

        if self.playlist.currentRow() == 0:
            return

        self.mediaObject.stop()
        self.mediaObject.clearQueue()

        currentItem = self.playlist.currentItem()
        currentData = currentItem.data(Qt.UserRole).toInt()[0]

        Db.delete("playlists", {"id": currentData})
        Db.delete("playlist_songs", {"playlist_id": currentData})
        self.loadAllPlaylists()
        self.loadContextMenu()

    def editPlaylistAction(self):
        targetRow = self.playlist.currentRow()
        if targetRow == 0:
            return

        currentItem = self.playlist.currentItem()
        currentData = currentItem.data(Qt.UserRole).toInt()[0]

        playlistName, response = QInputDialog.getText(self, 'Pysawndz', 'New playlist name:')

        if response:
            Db.update("playlists", {"name": playlistName}, {"id": currentData})
            self.loadAllPlaylists()
            self.playlist.setCurrentRow(targetRow)
            self.loadContextMenu()

    def setupSignals(self):
        self.connect(self.importm, SIGNAL("triggered()"), self.showOpenDialog)
        # self.connect(self.exportm, SIGNAL("triggered()"), self.exportSongs)
        # self.connect(self.restorem, SIGNAL("triggered()"), self.restorePlaylist)
        #self.connect(self.musicTable.horizontalHeader(), SIGNAL("sectionClicked(int)"), self.sortColumn);

        self.connect(self.exit, SIGNAL("triggered()"), self, SLOT("close()"))
        self.connect(self.playbtn, SIGNAL("triggered()"), self.mediaObject, SLOT("play()"))
        self.connect(self.stopbtn, SIGNAL("triggered()"), self.mediaObject, SLOT("stop()"))
        self.connect(self.pausebtn, SIGNAL("triggered()"), self.mediaObject, SLOT("pause()"))

        self.connect(self.previousbtn, SIGNAL("triggered()"), self.movePrevious)
        self.connect(self.nextbtn, SIGNAL("triggered()"), self.moveNext)

        self.connect(self.playlist, SIGNAL("currentRowChanged(int)"), self.playListChanged)
        self.connect(self.addPlaylist, SIGNAL("clicked()"), self.addPlaylistAction)
        self.connect(self.removePlaylist, SIGNAL("clicked()"), self.removePlaylistAction)
        self.connect(self.editPlaylist, SIGNAL("clicked()"), self.editPlaylistAction)

        self.connect(self.musicTable, SIGNAL("cellDoubleClicked(int, int)"), self.cellDoubleClicked)
        #self.connect(self.addToPlaylist, SIGNAL("triggered()"), self.addToPlaylistAction)

        self.connect(self.mediaObject, SIGNAL("tick(qint64)"), self.tick)
        self.connect(self.mediaObject, SIGNAL("stateChanged(Phonon::State, Phonon::State)"), self.stateChanged)
        self.connect(self.mediaObject, SIGNAL("aboutToFinish()"), self.aboutToFinish)
        self.connect(self.mediaObject, SIGNAL("currentSourceChanged(const Phonon::MediaSource &)"), self.sourceChanged);

    # def sortColumn(self, colnum):
    #     self.musicTable.sortItems(colnum, Qt.AscendingOrder)

    def clearMusicTable(self):
        self.musicTable.clearContents()
        rowCount = self.musicTable.rowCount() - 1
        while (rowCount >= 0):
            self.musicTable.removeRow(rowCount)
            rowCount -= 1

    def playListChanged(self, row):

        currentRow = self.playlist.item(row)

        if not row == 0 and not currentRow == None:

            currentPlaylist = currentRow.data(Qt.UserRole).toInt()[0]

            sql = "SELECT s.id, s.title, s.path, s.duration, a.name as artist, al.name as album, g.name as genre FROM songs as s \
                    INNER JOIN artists as a ON a.id = s.artist_id \
                    INNER JOIN albums as al ON al.id = s.album_id \
                    INNER JOIN genres as g ON g.id = s.genre_id \
                    INNER JOIN playlist_songs as ps ON ps.song_id = s.id \
                    WHERE ps.playlist_id = %d \
                    ORDER BY s.title ASC" % (currentPlaylist)

            query = Db.execute(sql)
            if query and query.size() > 0:
                self.sources.clear()
                while query.next():
                    #song_id = query.value(0).toInt()[0]
                    song = Song(id=query.value(0).toInt()[0],
                            title=query.value(1).toString(),
                            path=query.value(2).toString(),
                            duration=query.value(3).toInt()[0],
                            artist=query.value(4).toString(),
                            album=query.value(5).toString(),
                            genre=query.value(6).toString())

                    self.sources.addSong(song)
                self.clearMusicTable()
                self.displayAllSongs()
            else:
                self.clearMusicTable()

        else:
            #all songs
            self.loadAllSongs()
            self.displayAllSongs()

    def movePrevious(self):
        current_index = self.sources.getSongIndex(self.sources.getSong(self.__current_sid))
        previous_song = self.sources.getByIndex(current_index - 1)
        if not previous_song == False:
            self.setCurrentSong(previous_song)
            self.musicTable.setCurrentCell(current_index - 1, 0)
            self.mediaObject.play()

    def moveNext(self):
        current_index = self.sources.getSongIndex(self.sources.getSong(self.__current_sid))
        next_song = self.sources.getByIndex(current_index + 1)
        if not next_song == False:
            self.setCurrentSong(next_song)
            self.musicTable.setCurrentCell(current_index + 1, 0)
            self.mediaObject.play()

    def exportSongs(self):
        targetRow = self.playlist.currentRow()
        if targetRow == 0:
            return

        currentItem = self.playlist.currentItem()
        filename = "%s/%s.songs" % (QDesktopServices.storageLocation(QDesktopServices.DesktopLocation), currentItem.text())

        handle = open(filename, "wb")
        pickle.dump(self.sources, handle, -1)

        QMessageBox.information(self, "Pysawndz",
                                   "Backup %s.songs has successfully been written." % (currentItem.text()),
                                   QMessageBox.Ok)

    def restorePlaylist(self):
        filename = QFileDialog.getOpenFileName(self,
            "Select playlist to restore",
            QDesktopServices.storageLocation(QDesktopServices.DesktopLocation),
            "*.songs")
        handle = open(filename, "rb")
        self.sources = pickle.load(handle)

        playlistName = self.phelper.getFileName(filename)
        sql = "SELECT * FROM playlists WHERE name = '%s'" % (playlistName)
        query = Db.execute(sql)
        if query.size() == 0:
            Db.insert("playlists", {"name": playlistName})

            #TODO: I forgot :)

            self.loadAllPlaylists()
            self.playlist.setCurrentRow(self.playlist.count() - 1)
            self.loadContextMenu()
        else:
            QMessageBox.warning(self, "Pysawndz", "Another playlist with the same name already exist.", QMessageBox.Ok);

    def showOpenDialog(self):
        filenames = QStringList()
        filenames = QFileDialog.getOpenFileNames(self,
            "Select music to import",
            QDesktopServices.storageLocation(QDesktopServices.MusicLocation),
            "*.mp3")

        if filenames.isEmpty():
            return

        self.tempMediaObject.clearQueue()
        if len(filenames) > 0:
            for f in filenames:

                source = Phonon.MediaSource(f)

                self.tempMediaObject.setCurrentSource(source)
                metaData = self.tempMediaObject.metaData()
                metaData = self.phelper.cmapToPyDict(metaData)

                if metaData["TITLE"] == "":
                    metaData["TITLE"] = self.phelper.getFileName(f)

                newSong = Song(title=metaData["TITLE"], artist=metaData["ARTIST"],
                               album=metaData["ALBUM"], genre=metaData["GENRE"], path=f,
                               duration=self.tempMediaObject.totalTime())

                if filenames.indexOf(f) == 0 and not self.mediaObject.state() == Phonon.PlayingState:
                    self.setCurrentSong(newSong)

                self.sources.addSong(newSong)

            self.displayAllSongs()

    def stateChanged(self, newState, oldState):

        if newState == Phonon.ErrorState:
            #QMessageBox.critical(self, "Application Error",
            #                     "An unrecoverable error occured, Pysawndz will now exit.",
            #                     QMessageBox.Ok, QMessageBox.Ok)
            return

        if newState != Phonon.StoppedState and newState != Phonon.PausedState:
            return

        if self.mediaObject.currentSource().type() == Phonon.MediaSource.Invalid:
            return

        if newState == Phonon.PlayingState:
            fileName = self.mediaObject.currentSource().fileName()
            self.setWindowTitle(fileName.right(fileName.length() - fileName.lastIndexOf("/") - 1))

        #metaData = self.mediaObject.metaData()

    def tick(self, time):
        self.timeLcd.display(self.calculateSongTime(time))

    def calculateSongTime(self, time, playing = True, customTime=None):
        if playing:
            remaining = self.mediaObject.totalTime() - time
        else:
            if customTime == None:
                remaining = self.mediaObject.totalTime()
            else:
                remaining = customTime
        displayTime = QTime(0, (remaining / 60000) % 60, (remaining / 1000) % 60)
        return displayTime.toString("mm:ss")

    def setCurrentSong(self, song):
        source = Phonon.MediaSource(song.getPath())
        self.setWindowTitle(song.getTitle())
        self.mediaObject.setCurrentSource(source)

        self.__current_sid = song.getId()

    def displayAllSongs(self):

        #self.musicTable.clearContents()

        if len(self.sources) > 0:

            for song in self.sources:

                sansFont = QFont("Helvetica [Cronyx]", 12);

                titleItem = QTableWidgetItem(song.getTitle())
                titleItem.setData(Qt.UserRole, song.getId())
                titleItem.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
                titleItem.setFont(sansFont)

                timeItem = QTableWidgetItem(self.calculateSongTime(None, False, song.getDuration()))
                timeItem.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
                timeItem.setFont(sansFont)

                artistItem = QTableWidgetItem(song.getArtist())
                artistItem.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
                artistItem.setFont(sansFont)

                albumItem = QTableWidgetItem(song.getAlbum())
                albumItem.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
                albumItem.setFont(sansFont)

                genreItem = QTableWidgetItem(song.getGenre())
                genreItem.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
                genreItem.setFont(sansFont)

                if not self.sources.getSongIndex(song) < self.musicTable.rowCount():
                    currentRow = self.sources.getSongIndex(song)
                    self.musicTable.removeRow(currentRow)

                    self.musicTable.insertRow(currentRow)
                    self.musicTable.setItem(currentRow, 0, titleItem)
                    self.musicTable.setItem(currentRow, 1, timeItem)
                    self.musicTable.setItem(currentRow, 2, artistItem)
                    self.musicTable.setItem(currentRow, 3, albumItem)
                    self.musicTable.setItem(currentRow, 4, genreItem)

                    self.musicTable.setRowHeight(currentRow, 20)

            currentSong = self.sources.getByIndex(0)
            if currentSong and not self.mediaObject.state() == Phonon.PlayingState:
                self.setCurrentSong(currentSong)

    def aboutToFinish(self):
        current_song = self.sources.getSong(self.__current_sid)
        current_index = self.sources.getSongIndex(current_song)

        if (current_index + 1) < len(self.sources):

            next_song = self.sources.getByIndex(current_index + 1)
            self.__current_sid = next_song.getId()
            source = Phonon.MediaSource(next_song.getPath())
            self.mediaObject.enqueue(source)

    def sourceChanged(self, source):

        newSong = self.sources.getSongByPath(source.fileName())
        if newSong:
            self.setWindowTitle(newSong.getTitle())
            self.musicTable.selectRow(self.sources.getSongIndex(newSong))

        self.timeLcd.display("00:00")

    def cellDoubleClicked(self, row, column):
        self.mediaObject.stop()
        self.mediaObject.clearQueue()
        song = self.sources.getByIndex(row)
        if song:
            self.setCurrentSong(song)
            self.mediaObject.play()

#test suite for mainwindow
if __name__ == "__main__":
    app = QApplication(sys.argv)
    main = Mainwindow()
    main.show()
    sys.exit(app.exec_())


from markupsafe import Markup

from odoo import api, fields, models, _
from odoo.exceptions import UserError
from odoo.osv.expression import AND
from odoo.tools.float_utils import float_compare, float_is_zero, float_round

class StockPickingBatch(models.Model):
    _inherit = ['mail.thread', 'mail.activity.mixin']
    _name = "stock.picking.batch"
    _description = "Batch Transfer"
    _order = "name desc"

    name = fields.Char(
        string='Batch Transfer', default='New',
        copy=False, required=True, readonly=True)
    user_id = fields.Many2one(
        'res.users', string='Responsible', tracking=True, check_company=True)
    company_id = fields.Many2one(
        'res.company', string="Company", required=True, readonly=True,
        index=True, default=lambda self: self.env.company)
    picking_ids = fields.One2many(
        'stock.picking', 'batch_id', string='Transfers',
        domain="[('id', 'in', allowed_picking_ids)]", check_company=True,
        help='List of transfers associated to this batch')
    show_check_availability = fields.Boolean(
        compute='_compute_move_ids',
        string='Show Check Availability')
    show_allocation = fields.Boolean(
        compute='_compute_show_allocation',
        string='Show Allocation Button')
    allowed_picking_ids = fields.One2many('stock.picking', compute='_compute_allowed_picking_ids')
    move_ids = fields.One2many(
        'stock.move', string="Stock moves", compute='_compute_move_ids')
    move_line_ids = fields.One2many(
        'stock.move.line', string='Stock move lines',
        compute='_compute_move_ids', inverse='_set_move_line_ids')
    state = fields.Selection([
        ('draft', 'Draft'),
        ('in_progress', 'In progress'),
        ('done', 'Done'),
        ('cancel', 'Cancelled')], default='draft',
        store=True, compute='_compute_state',
        copy=False, tracking=True, required=True, readonly=True, index=True)
    picking_type_id = fields.Many2one(
        'stock.picking.type', 'Operation Type', check_company=True, copy=False,
        index=True)
    picking_type_code = fields.Selection(
        related='picking_type_id.code')
    scheduled_date = fields.Datetime(
        'Scheduled Date', copy=False, store=True, readonly=False, compute="_compute_scheduled_date",
        help="""Scheduled date for the transfers to be processed.
              - If manually set then scheduled date for all transfers in batch will automatically update to this date.
              - If not manually changed and transfers are added/removed/updated then this will be their earliest scheduled date
                but this scheduled date will not be set for all transfers in batch.""")
    is_wave = fields.Boolean('This batch is a wave')
    # To remove in master
    show_set_qty_button = fields.Boolean(compute='_compute_show_qty_button')
    show_clear_qty_button = fields.Boolean(compute='_compute_show_qty_button')
    show_lots_text = fields.Boolean(compute='_compute_show_lots_text')

    @api.depends()
    def _compute_show_qty_button(self):
        self.show_set_qty_button = False
        self.show_clear_qty_button = False

    @api.depends('picking_type_id')
    def _compute_show_lots_text(self):
        for batch in self:
            batch.show_lots_text = batch.picking_ids and batch.picking_ids[0].show_lots_text

    @api.depends('company_id', 'picking_type_id', 'state')
    def _compute_allowed_picking_ids(self):
        allowed_picking_states = ['waiting', 'confirmed', 'assigned']

        for batch in self:
            domain_states = list(allowed_picking_states)
            # Allows to add draft pickings only if batch is in draft as well.
            if batch.state == 'draft':
                domain_states.append('draft')
            domain = [
                ('company_id', '=', batch.company_id.id),
                ('state', 'in', domain_states),
            ]
            if batch.picking_type_id:
                domain += [('picking_type_id', '=', batch.picking_type_id.id)]
            batch.allowed_picking_ids = self.env['stock.picking'].search(domain)

    @api.depends('picking_ids', 'picking_ids.move_line_ids', 'picking_ids.move_ids', 'picking_ids.move_ids.state')
    def _compute_move_ids(self):
        for batch in self:
            batch.move_ids = batch.picking_ids.move_ids
            batch.move_line_ids = batch.picking_ids.move_line_ids
            batch.show_check_availability = any(m.state not in ['assigned', 'done'] for m in batch.move_ids)

    @api.depends('state', 'move_ids', 'picking_type_id')
    def _compute_show_allocation(self):
        self.show_allocation = False
        if not self.user_has_groups('stock.group_reception_report'):
            return
        for batch in self:
            batch.show_allocation = batch.picking_ids._get_show_allocation(batch.picking_type_id)

    @api.depends('picking_ids', 'picking_ids.state')
    def _compute_state(self):
        batchs = self.filtered(lambda batch: batch.state not in ['cancel', 'done'])
        for batch in batchs:
            if not batch.picking_ids:
                continue
            # Cancels automatically the batch picking if all its transfers are cancelled.
            if all(picking.state == 'cancel' for picking in batch.picking_ids):
                batch.state = 'cancel'
            # Batch picking is marked as done if all its not canceled transfers are done.
            elif all(picking.state in ['cancel', 'done'] for picking in batch.picking_ids):
                batch.state = 'done'

    @api.depends('picking_ids', 'picking_ids.scheduled_date')
    def _compute_scheduled_date(self):
        for rec in self:
            rec.scheduled_date = min(rec.picking_ids.filtered('scheduled_date').mapped('scheduled_date'), default=False)

    @api.onchange('scheduled_date')
    def onchange_scheduled_date(self):
        if self.scheduled_date:
            self.picking_ids.scheduled_date = self.scheduled_date

    def _set_move_line_ids(self):
        new_move_lines = self[0].move_line_ids
        for picking in self.picking_ids:
            old_move_lines = picking.move_line_ids
            picking.move_line_ids = new_move_lines.filtered(lambda ml: ml.picking_id.id == picking.id)
            move_lines_to_unlink = old_move_lines - new_move_lines
            if move_lines_to_unlink:
                move_lines_to_unlink.unlink()

    # -------------------------------------------------------------------------
    # CRUD
    # -------------------------------------------------------------------------
    @api.model_create_multi
    def create(self, vals_list):
        for vals in vals_list:
            if vals.get('name', '/') == '/':
                company_id = vals.get('company_id', self.env.company.id)
                if vals.get('is_wave'):
                    vals['name'] = self.env['ir.sequence'].with_company(company_id).next_by_code('picking.wave') or '/'
                else:
                    vals['name'] = self.env['ir.sequence'].with_company(company_id).next_by_code('picking.batch') or '/'
        return super().create(vals_list)

    def write(self, vals):
        res = super().write(vals)
        if not self.picking_ids:
            self.filtered(lambda b: b.state == 'in_progress').action_cancel()
        if vals.get('picking_type_id'):
            self._sanity_check()
        if vals.get('picking_ids'):
            batch_without_picking_type = self.filtered(lambda batch: not batch.picking_type_id)
            if batch_without_picking_type:
                picking = self.picking_ids and self.picking_ids[0]
                batch_without_picking_type.picking_type_id = picking.picking_type_id.id
        if vals.get('user_id'):
            self.picking_ids.assign_batch_user(vals['user_id'])
        return res

    @api.ondelete(at_uninstall=False)
    def _unlink_if_not_done(self):
        if any(batch.state == 'done' for batch in self):
            raise UserError(_("You cannot delete Done batch transfers."))

    # -------------------------------------------------------------------------
    # Action methods
    # -------------------------------------------------------------------------
    def action_confirm(self):
        """Sanity checks, confirm the pickings and mark the batch as confirmed."""
        self.ensure_one()
        if not self.picking_ids:
            raise UserError(_("You have to set some pickings to batch."))
        self.picking_ids.action_confirm()
        self._check_company()
        self.state = 'in_progress'
        return True

    def action_cancel(self):
        self.state = 'cancel'
        self.picking_ids = False
        return True

    def action_print(self):
        self.ensure_one()
        return self.env.ref('stock_picking_batch.action_report_picking_batch').report_action(self)

    def action_done(self):
        def has_no_quantity(picking):
            return all(not m.picked or float_is_zero(m.quantity, precision_rounding=m.product_uom.rounding) for m in picking.move_ids if m.state not in ('done', 'cancel'))

        self.ensure_one()
        self._check_company()
        # Empty 'waiting for another operation' pickings will be removed from the batch when it is validated.
        pickings = self.mapped('picking_ids').filtered(lambda picking: picking.state not in ('cancel', 'done'))
        empty_waiting_pickings = self.mapped('picking_ids').filtered(lambda p: p.state == 'waiting' and has_no_quantity(p))
        pickings = pickings - empty_waiting_pickings

        empty_pickings = set()
        for picking in pickings:
            if has_no_quantity(picking):
                empty_pickings.add(picking.id)
            picking.message_post(
                body=Markup("%s: %s %s") % (
                    _("Transferred by"),
                    _("Batch Transfer"),
                    picking.batch_id.id,
                    picking.batch_id.name))

        # Run sanity_check as a batch and ignore the one in button_validate() since it is done here.
        pickings._sanity_check(separate_pickings=False)
        # Skip sanity_check in pickings button_validate() & remove 'waiting' pickings from the batch
        context = {'skip_sanity_check': True, 'pickings_to_detach': empty_waiting_pickings.ids}
        if len(empty_pickings) == len(pickings):
            return pickings.with_context(**context).button_validate()
        else:
            # If some pickings are at least partially done, other pickings (empty & waiting) will be removed from batch without being cancelled in case of no backorder
            pickings = pickings - self.env['stock.picking'].browse(empty_pickings)
            context['pickings_to_detach'] = context['pickings_to_detach'] + list(empty_pickings)
            return pickings.with_context(skip_immediate=True, **context).button_validate()

    def action_assign(self):
        self.ensure_one()
        self.picking_ids.action_assign()

    def action_put_in_pack(self):
        """ Action to put move lines with 'Done' quantities into a new pack
        This method follows same logic to stock.picking.
        """
        self.ensure_one()
        if self.state not in ('done', 'cancel'):
            move_line_ids = self.picking_ids[0]._package_move_lines()
            if move_line_ids:
                res = move_line_ids.picking_id[0]._pre_put_in_pack_hook(move_line_ids)
                if res:
                    return res
                package = move_line_ids.picking_id._put_in_pack(move_line_ids)
                return move_line_ids.picking_id[0]._post_put_in_pack_hook(package)
            raise UserError(_("Please add 'Done' quantities to the batch picking to create a new pack."))

    def action_view_reception_report(self):
        action = self.picking_ids[0].action_view_reception_report()
        action['context'] = {'default_picking_ids': self.picking_ids.ids}
        return action

    def action_open_label_layout(self):
        if self.user_has_groups('stock.group_production_lot') and self.move_line_ids.lot_id:
            view = self.env.ref('stock.picking_label_type_form')
            return {
                'name': _('Choose Type of Labels To Print'),
                'type': 'ir.actions.act_window',
                'res_model': 'picking.label.type',
                'views': [(view.id, 'form')],
                'target': 'new',
                'context': {'default_picking_ids': self.picking_ids.ids},
            }
        view = self.env.ref('stock.product_label_layout_form_picking')
        return {
            'name': _('Choose Labels Layout'),
            'type': 'ir.actions.act_window',
            'view_mode': 'form',
            'res_model': 'product.label.layout',
            'views': [(view.id, 'form')],
            'view_id': view.id,
            'target': 'new',
            'context': {
                'default_product_ids': self.move_line_ids.product_id.ids,
                'default_move_ids': self.move_ids.ids,
                'default_move_quantity': 'move'},
        }

    # -------------------------------------------------------------------------
    # Miscellaneous
    # -------------------------------------------------------------------------
    def _sanity_check(self):
        for batch in self:
            if not batch.picking_ids <= batch.allowed_picking_ids:
                erroneous_pickings = batch.picking_ids - batch.allowed_picking_ids
                raise UserError(_(
                    "The following transfers cannot be added to batch transfer %s. "
                    "Please check their states and operation types.\n\n"
                    "Incompatibilities: %s", batch.name, ', '.join(erroneous_pickings.mapped('name'))))

    def _track_subtype(self, init_values):
        if 'state' in init_values:
            return self.env.ref('stock_picking_batch.mt_batch_state')
        return super()._track_subtype(init_values)

    def _is_picking_auto_mergeable(self, picking):
        """ Verifies if a picking can be safely inserted into the batch without violating auto_batch_constrains.
        """
        res = True
        if self.picking_type_id.batch_max_lines:
            res = res and (len(self.move_ids) + len(picking.move_ids) <= self.picking_type_id.batch_max_lines)
        if self.picking_type_id.batch_max_pickings:
            res = res and (len(self.picking_ids) + 1 <= self.picking_type_id.batch_max_pickings)
        return res


"""
Date: 2021-11/22
Authors: Manuel Yahir Hernandez Mendez
         Mauricio Isaias Bolaños Vázquez
File:     T3E3_arithmetic.py
Brief:   Operaciones de numeros flotantes
Score:
Version: 0.0.1
Fixes:
"""
def suma(a, b):
    res = a + b
    return res

def resta(a, b):
    res = a - b
    return res

def multiplicacion(a, b):
    res = a * b
    return res

def division(a, b):
    res = a / b
    return res

if __name__ == '__main__':
    NUM1 = 1
    NUM2 = 5
    NUM4 = 7
    NUM5 = 9
    # para el PRIMER ejemplo

    resultado1 = suma(NUM1, NUM5)
    print("Para la suma ", resultado1)
    resultado1 = resta(NUM1, NUM5)
    print("Para la resta ", resultado1)
    resultado1 = multiplicacion(NUM1, NUM5)
    print("Para la multiplicacion ", resultado1)
    resultado1 = division(NUM1, NUM5)
    print("Para la division ", resultado1)

    # Para el segundo ejemplo

    print("-----------------------------")
    print("Ejemplo 2")
    print("-----------------------------")
    resultado2 = suma(NUM4, NUM5)

    print("Para la suma ", resultado2)
    resultado2 = resta(NUM4, NUM5)
    print("Para la resta ", resultado2)
    resultado2 = multiplicacion(NUM4, NUM5)
    print("Para la multiplicacion ", resultado2)
    resultado2 = division(NUM4, NUM5)
    print("Para la division ", resultado2)


# Licensed under a 3-clause BSD style license - see LICENSE.rst

import glob
import os

from sofia_redux.instruments.hawc.datafits import DataFits
from sofia_redux.instruments.hawc.steps.stepscanmap import StepScanMap
from sofia_redux.instruments.hawc.steps.stepdemodulate import StepDemodulate
from sofia_redux.instruments.hawc.steps.stepprepare import StepPrepare
from sofia_redux.instruments.hawc.steps.stepskydip import StepSkydip
from sofia_redux.instruments.hawc.tests.resources \
    import DRPTestCase, scan_raw_data

class TestSkyDip(DRPTestCase):
    def make_data(self, tmpdir, run_scanmap=False, suffix=''):
        hdul = scan_raw_data()
        hdul[0].header['INSTCFG'] = 'TOTAL_INTENSITY'
        hdul[0].header['CALMODE'] = 'SKY_DIP'
        hdul[0].header['OBSMODE'] = 'SkyDip'
        ffile = str(tmpdir.join(f'test{suffix}.fits'))
        hdul.writeto(ffile, overwrite=True)
        inp = DataFits(ffile)
        if run_scanmap:
            StepScanMap()([inp], options='-rounds=1')
        prep = StepPrepare()(inp)
        dmd = StepDemodulate()(prep)
        return dmd

    def test_mimo(self, tmpdir):
        with tmpdir.as_cwd():
            dmd = self.make_data(tmpdir)

            step = StepSkydip()
            out = step([dmd])
            assert isinstance(out, list)
            assert isinstance(out[0], DataFits)
            assert os.path.isfile('test.DMD_skydiplot.png')

    def test_scanmap_plots(self, tmpdir, mocker):
        with tmpdir.as_cwd():
            dmd = self.make_data(tmpdir, run_scanmap=True)
            dmd.filename = os.path.basename(dmd.filename)

            # mock os remove for an OSError -- should still complete
            tmp = os.remove

            def mock_remove(*args, **kwargs):
                raise OSError('test error')
            mocker.patch(
                'sofia_redux.instruments.hawc.steps.stepskydip.os.remove',
                mock_remove)

            step = StepSkydip()
            step([dmd])
            assert os.path.isfile('test.DMD_skydiplot.png')
            assert os.path.isfile('test.DMD_skymodel.png')

            # temporary dat files are not removed
            assert len(glob.glob('*.dat')) > 0

            # unmock
            mocker.patch(
                'sofia_redux.instruments.hawc.steps.stepskydip.os.remove', tmp)
            step = StepSkydip()
            step([dmd])

            # temporary dat files are now removed
            assert len(glob.glob('*.dat')) == 0

    def test_threadsafe(self, tmpdir, capsys):
        with tmpdir.as_cwd():

            dmd1 = self.make_data(tmpdir, suffix='1')
            dmd2 = self.make_data(tmpdir, suffix='2')
            inp = [dmd1, dmd2]

            def _try_plot(i):
                dmd = inp[i]
                step = StepSkydip()
                step([dmd])

            # this will crash with a fatal Python error
            # if plots are not thread safe

            from threading import Thread
            t1 = Thread(target=_try_plot, args=(0,))
            t1.setDaemon(True)
            t1.start()
            t2 = Thread(target=_try_plot, args=(1,))
            t2.setDaemon(True)
            t2.start()

            # let both finish
            t1.join()
            t2.join()

            # check for output from both threads
            fname = ['test1.DMD_skydiplot.png',
                     'test2.DMD_skydiplot.png']
            for fn in fname:
                assert os.path.exists(fn)


import pandas as pd
import re

# pd.set_option('display.max_columns', None)
df = pd.read_csv('pras.csv')
# print(df)

name_list = []
for index, row in df.iterrows():
    contains_digit = False
    wrong_email = False

    #     print(row['CANDIDATE NAME'])
    #For Candidate Name
    for character in row['CANDIDATE NAME']:
        if character.isdigit():
            contains_digit = True
            # print(row[['CANDIDATE NAME','EMAIL','ROLL NUMBER','CONTACT NUMBER','BRANCH']])
            name_list.append(
                {'CANDIDATE NAME': row['CANDIDATE NAME'], 'EMAIL': row['EMAIL'], 'ROLL NUMBER': row['ROLL NUMBER'],
                 'CONTACT NUMBER': row['CONTACT NUMBER'], 'BRANCH': row['BRANCH'], 'Error': 'wrong Name'})
            break

    # For Candidate Email
    if contains_digit == False:
        regex = '^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}$'
        if (re.search(regex, str(row['EMAIL']))):
            pass
        else:
            wrong_email = True
            name_list.append(
                {'CANDIDATE NAME': row['CANDIDATE NAME'], 'EMAIL': row['EMAIL'], 'ROLL NUMBER': row['ROLL NUMBER'],
                 'CONTACT NUMBER': row['CONTACT NUMBER'], 'BRANCH': row['BRANCH'], 'Error': 'wrong Email'})

    # For Candidate Contact Number
    if wrong_email == False or contains_digit == False:
        for character in str(row['CONTACT NUMBER']):
            if character.isalpha():
                contains_digit = True
                # print(row[['CANDIDATE NAME','EMAIL','ROLL NUMBER','CONTACT NUMBER','BRANCH']])
                name_list.append(
                    {'CANDIDATE NAME': row['CANDIDATE NAME'], 'EMAIL': row['EMAIL'], 'ROLL NUMBER': row['ROLL NUMBER'],
                     'CONTACT NUMBER': row['CONTACT NUMBER'], 'BRANCH': row['BRANCH'], 'Error': 'wrong Contact NO.'})
                break

#For normal printing

# print(len(name_list))
# for i in range(len(name_list)):
#     print('CANDIDATE NAME : ', name_list[i]['CANDIDATE NAME'])
#     print('ROLL NUMBER : ', name_list[i]['ROLL NUMBER'])
#     print('CONTACT NUMBER : ', name_list[i]['CONTACT NUMBER'])
#     print('BRANCH : ', name_list[i]['BRANCH'])
#     print('EMAIL : ', name_list[i]['EMAIL'])
#     print('__________________________________')

#Creating a new DataFrame and Printing

new_df = pd.DataFrame(name_list)
print('Change the values of faulted data')
print(new_df)


from xml.dom.minidom import Document
from django.shortcuts import redirect, render
from .models import Usuario

# Create your views here.
def index(request):
    return render(request,'usuarios/index.html')

def usuarios(request):

    #Salvar usuarios
    novo_usuario = Usuario()
    novo_usuario.nome = request.POST.get('tNome')
    novo_usuario.telefone = request.POST.get('tCel')
    novo_usuario.email = request.POST.get('tEmail')
    novo_usuario.save()
    #Exibir usuarios
    usuarios = {
        'usuarios': Usuario.objects.all()
    }
    #Retornar os usuarios
    return render(request, 'usuarios/usuarios.html', usuarios)

def lista_usuarios(request):
    #Exibir usuarios
    usuarios = {
        'usuarios': Usuario.objects.all()
    }
    #Retornar os usuarios
    return render(request, 'usuarios/usuarios.html', usuarios)

def editar(request, id):
    usuario = Usuario.objects.get(id=id)
    return render(request, 'usuarios/editar.html', {"usuario": usuario})

def update_usuarios(request, id):
    # Aqui é o que vem da tela
    nome = request.POST.get("tNome")
    telefone = request.POST.get("tCel")
    email = request.POST.get("tEmail")
    # aqui é o que é carregado do banco
    usuario = Usuario.objects.get(id=id)
    usuario.nome = nome
    usuario.telefone = telefone
    usuario.email = email
    usuario.save()
    return redirect(lista_usuarios)

def deletar_usuarios(request, id):
    usuario = Usuario.objects.get(id=id)
    usuario.delete()
    return redirect(lista_usuarios)


import os
from flask import Flask, request, jsonify, abort
from sqlalchemy import exc
import json
from flask_cors import CORS
import sys

from .database.models import db_drop_and_create_all, setup_db, Drink
from .auth.auth import AuthError, requires_auth

app = Flask(__name__)
setup_db(app)
CORS(app)

@app.after_request
def after_request(response):
    response.headers.add(
        "Access-Control-Allow-Headers", "Content-Type, Authorization"
    )
    response.headers.add(
        "Access-Control-Allow-Methods", "GET, POST, PATCH, DELETE"
    )
    return response

db_drop_and_create_all()

# ROUTES
@app.route('/drinks', methods=['GET'])
def get_drinks():
    all_drinks = Drink.query.order_by(Drink.id).all()

    if len(all_drinks) == 0:
        abort(404)

    drinks_data = [Drink.short(d) for d in all_drinks]

    return jsonify(
        {
            "success": True,
            "drinks": drinks_data
        }
    ), 200

@app.route('/drinks-detail', methods=['GET'])
@requires_auth('get:drinks-detail')
def get_drinks_detail(jwt):
    all_drinks = Drink.query.order_by(Drink.id).all()

    if len(all_drinks) == 0:
        abort(404)

    drinks_data = [d.long() for d in all_drinks]

    return jsonify(
        {
            "success": True,
            "drinks": drinks_data
        }
    ), 200

@app.route('/drinks', methods=['POST'])
@requires_auth('post:drinks')
def post_drink(jwt):
    body = request.get_json()
    n_title = body.get("title")
    n_recipe = body.get("recipe")
    n_recipe = json.dumps(n_recipe)

    try:
        drink = Drink(title=n_title, recipe=n_recipe)
        drink.insert()

        return jsonify(
            {
                "success": True,
                "drinks": drink.long()
            }
        ), 200
    except:
        print(sys.exc_info())
        abort(422)

@app.route("/drinks/<int:drinkid>", methods=["PATCH"])
@requires_auth('patch:drinks')
def patch_drink(jwt, drinkid):
    body = request.get_json()
    title = body.get("title")
    recipe = body.get("recipe")

    drink = Drink.query.filter(Drink.id == drinkid).one_or_none()

    if drink is None:
        abort(404)

    if title:
        drink.title = title
    if recipe:
        drink.recipe = json.dumps(recipe)

    drink.update()

    return jsonify(
        {
            "success": True,
            "drinks": drink.long()
        }
    ), 200

@app.route("/drinks/<int:drinkid>", methods=["DELETE"])
@requires_auth('delete:drinks')
def delete_drink(jwt, drinkid):
    drink = Drink.query.filter(Drink.id == drinkid).one_or_none()
    if drink is None:
        abort(404)

    drink.delete()

    return jsonify(
        {
            "success": True,
            "delete": drinkid
        }
    ), 200

# Error Handling
'''
Example error handling for unprocessable entity
'''

@app.errorhandler(422)
def unprocessable(error):
    return jsonify({
        "success": False,
        "error": 422,
        "message": "unprocessable"
    }), 422

@app.errorhandler(400)
def bad_request(error):
    return jsonify({
        "success": False,
        "error": 400,
        "message": "bad request"
    }), 400

@app.errorhandler(401)
def unauthorized(error):
    return jsonify({
        "success": False,
        "error": 401,
        "message": "unauthorized"
    }), 401

@app.errorhandler(403)
def forbidden(error):
    return jsonify({
        "success": False,
        "error": 403,
        "message": "forbidden"
    }), 403

@app.errorhandler(404)
def resource_not_found(error):
    return jsonify({
        "success": False,
        "error": 404,
        "message": "resource not found"
    }), 404

@app.errorhandler(AuthError)
def auth_error(ae):
    return jsonify({
        "success": False,
        "error": ae.status_code,
        "message": ae.error
    }), ae.status_code


class Solution:
    """my sol, time nlogn"""
    def merge(self, intervals: List[List[int]]) -> List[List[int]]:

        intervals = sorted(intervals)

        ans = []

        for i in intervals:

            if not ans:
                ans.append(i)
                continue

            if i[0] <= ans[-1][1]:
                last = ans.pop()
                ans.append([last[0], max(last[1], i[1])])
            else:
                ans.append(i)

        return ans


#!/usr/bin/env python3
import argparse
import logging.config
import os
import sys
import time

sys.path.append(os.path.abspath(os.path.join(__file__,'../../../')))

import odoo
from odoo.tools import config, topological_sort, unique
from odoo.netsvc import init_logger
from odoo.tests import standalone_tests
import odoo.tests.loader

_logger = logging.getLogger('odoo.tests.test_module_operations')

BLACKLIST = {
    'auth_ldap',
    'pos_blackbox_be',
}
IGNORE = ('hw_', 'theme_', 'l10n_', 'test_')

INSTALL_BLACKLIST = {
    'payment_alipay', 'payment_ogone', 'payment_payulatam', 'payment_payumoney',
}  # deprecated modules (cannot be installed manually through button_install anymore)

def install(db_name, module_id, module_name):
    with odoo.registry(db_name).cursor() as cr:
        env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
        module = env['ir.module.module'].browse(module_id)
        module.button_immediate_install()
    _logger.info('%s installed', module_name)

def uninstall(db_name, module_id, module_name):
    with odoo.registry(db_name).cursor() as cr:
        env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
        module = env['ir.module.module'].browse(module_id)
        module.button_immediate_uninstall()
    _logger.info('%s uninstalled', module_name)

def cycle(db_name, module_id, module_name):
    install(db_name, module_id, module_name)
    uninstall(db_name, module_id, module_name)
    install(db_name, module_id, module_name)

class CheckAddons(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        self.values = namespace
        config._check_addons_path(self, option_string, values, self)

def parse_args():
    parser = argparse.ArgumentParser(
        description="Script for testing the install / uninstall / reinstall"
                    " cycle of Odoo modules. Prefer the 'cycle' subcommand to"
                    " running this without anything specified (this is the"
                    " default behaviour).")
    parser.set_defaults(
        func=test_cycle,
        reinstall=True,
    )
    fake_commands = parser.add_mutually_exclusive_group()

    parser.add_argument("--database", "-d", type=str, required=True,
        help="The database to test (/ run the command on)")
    parser.add_argument("--data-dir", "-D", dest="data_dir", type=str,
        help="Directory where to store Odoo data"
    )
    parser.add_argument("--skip", "-s", type=str,
        help="Comma-separated list of modules to skip (they will only be installed)")
    parser.add_argument("--resume-at", "-r", type=str,
        help="Skip modules (only install) up to the specified one in topological order")
    parser.add_argument("--addons-path", "-p", type=str, action=CheckAddons,
        help="Comma-separated list of paths to directories containing extra Odoo modules")

    cmds = parser.add_subparsers(title="subcommands", metavar='')
    cycle = cmds.add_parser(
        'cycle', help="Full install/uninstall/reinstall cycle.",
        description="Installs, uninstalls, and reinstalls all modules which are"
                    " not skipped or blacklisted, the database should have"
                    " 'base' installed (only).")
    cycle.set_defaults(func=test_cycle)

    fake_commands.add_argument(
        "--uninstall", "-U", action=UninstallAction,
        help="Comma-separated list of modules to uninstall/reinstall. Prefer the 'uninstall' subcommand."
    )
    uninstall = cmds.add_parser(
        'uninstall', help="Uninstallation",
        description="Uninstalls then (by default) reinstalls every specified "
                    "module. Modules which are not installed before running "
                    "are ignored.")
    uninstall.set_defaults(func=test_uninstall)
    uninstall.add_argument('uninstall', help="comma-separated list of modules to uninstall/reinstall")
    uninstall.add_argument(
        '-n', '--no-reinstall', dest='reinstall', action='store_false',
        help="Skips reinstalling the module(s) after uninstalling."
    )

    fake_commands.add_argument("--standalone", action=StandaloneAction,
        help="Launch standalone scripts tagged with @standalone. Accepts a list of "
             "module names or tags separated by commas. 'all' will run all available scripts. Prefer the 'standalone' subcommand."
    )
    standalone = cmds.add_parser('standalone', help="Run scripts tagged with @standalone")
    standalone.set_defaults(func=test_standalone)
    standalone.add_argument('standalone', help="List of module names or tags separated by commas, 'all' will run all available scripts.")

    return parser.parse_args()

class UninstallAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        namespace.func = test_uninstall
        setattr(namespace, self.dest, values)

class StandaloneAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        namespace.func = test_standalone
        setattr(namespace, self.dest, values)

def test_cycle(args):
    """ Test full install/uninstall/reinstall cycle for all modules """
    with odoo.registry(args.database).cursor() as cr:
        env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})

        def valid(module):
            return not (
                module.name in BLACKLIST
                or module.name in INSTALL_BLACKLIST
                or module.name.startswith(IGNORE)
                or module.state in ('installed', 'uninstallable')
            )

        modules = env['ir.module.module'].search([]).filtered(valid)

        # order modules in topological order
        modules = modules.browse(topological_sort({
            module.id: module.dependencies_id.depend_id.ids
            for module in modules
        }))
        modules_todo = [(module.id, module.name) for module in modules]

    resume = args.resume_at
    skip = set(args.skip.split(',')) if args.skip else set()
    for module_id, module_name in modules_todo:
        if module_name == resume:
            resume = None

        if resume or module_name in skip:
            install(args.database, module_id, module_name)
        else:
            cycle(args.database, module_id, module_name)

def test_uninstall(args):
    """ Tries to uninstall/reinstall one ore more modules"""
    for module_name in args.uninstall.split(','):
        with odoo.registry(args.database).cursor() as cr:
            env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
            module = env['ir.module.module'].search([('name', '=', module_name)])
            module_id, module_state = module.id, module.state

        if module_state == 'installed':
            uninstall(args.database, module_id, module_name)
            if args.reinstall and module_name not in INSTALL_BLACKLIST:
                install(args.database, module_id, module_name)
        elif module_state:
            _logger.warning("Module %r is not installed", module_name)
        else:
            _logger.warning("Module %r does not exist", module_name)

def test_standalone(args):
    """ Tries to launch standalone scripts tagged with @post_testing """
    # load the registry once for script discovery
    registry = odoo.registry(args.database)
    for module_name in registry._init_modules:
        # import tests for loaded modules
        odoo.tests.loader.get_test_modules(module_name)

    # fetch and filter scripts to test
    funcs = list(unique(
        func
        for tag in args.standalone.split(',')
        for func in standalone_tests[tag]
    ))

    start_time = time.time()
    for index, func in enumerate(funcs, start=1):
        with odoo.registry(args.database).cursor() as cr:
            env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
            _logger.info("Executing standalone script: %s (%d / %d)",
                         func.__name__, index, len(funcs))
            try:
                func(env)
            except Exception:
                _logger.error("Standalone script %s failed", func.__name__, exc_info=True)

    _logger.info("%d standalone scripts executed in %.2fs" % (len(funcs), time.time() - start_time))

if __name__ == '__main__':
    args = parse_args()

    # handle paths option
    if args.addons_path:
        odoo.tools.config['addons_path'] = ','.join([args.addons_path, odoo.tools.config['addons_path']])
        if args.data_dir:
            odoo.tools.config['data_dir'] = args.data_dir
        odoo.modules.module.initialize_sys_path()

    init_logger()
    logging.config.dictConfig({
        'version': 1,
        'incremental': True,
        'disable_existing_loggers': False,
        'loggers': {
            'odoo.modules.loading': {'level': 'CRITICAL'},
            'odoo.sql_db': {'level': 'CRITICAL'},
            'odoo.models.unlink': {'level': 'WARNING'},
            'odoo.addons.base.models.ir_model': {'level': "WARNING"},
        }
    })

    try:
        args.func(args)
    except Exception:
        _logger.error("%s tests failed", args.func.__name__[5:])
        raise


from typing import Optional

import torch
from torch import nn
from torch.autograd import Function

from pointdet import _C

from .ball_query import ball_query

class QueryAndGroup(nn.Module):
    """Groups points with a ball query of radius.
    Args:
        radius (float): The maximum radius of the balls.
        num_neighbors (int): Maximum number of features to gather in the ball.
        return_grouped_xyz (bool): Whether to return grouped xyz. Default: False.
        normalize_xyz (bool): Whether to normalize xyz. Default: False.
        uniform_sample (bool): Whether to sample uniformly. Default: False
        return_grouped_idx (bool): Whether to return grouped idx. Default: False.
    """

    def __init__(
        self,
        num_neighbors: int,
        radius: float,
        relative_xyz: bool = True,
        normalize_xyz: bool = False,
    ):
        super().__init__()
        self.num_neighbors = num_neighbors
        self.radius = radius
        self.relative_xyz = relative_xyz
        self.normalize_xyz = normalize_xyz

    def forward(
        self,
        points: torch.Tensor,
        centroids: torch.Tensor,
        features: Optional[torch.Tensor] = None,
    ) -> tuple[torch.Tensor, Optional[torch.Tensor]]:
        """
        Args:
            points (torch.Tensor): (B, N, D) coordinates of the points.
            centroids (torch.Tensor): (B, K, D) coordinates of the centriods.
            features (torch.Tensor): (B, C, N) The features of grouped points.
        Returns:
            grouped_xyz: (B, D, K, num_neighbors)
            grouped_features: (B, C, K, num_neighbors)
        """
        # (B, K, num_neighbors)
        indices = ball_query(centroids, points, self.num_neighbors, self.radius)
        # Transpose since last dim of points is its features
        # (B, 3, K, num_neighbors)
        grouped_xyz = grouping_ops(points.transpose(1, 2), indices)
        # Relative offsets
        if self.relative_xyz:
            grouped_xyz -= centroids.transpose(1, 2).unsqueeze(-1)
        if self.normalize_xyz:
            grouped_xyz /= self.radius

        if features is not None:
            grouped_features = grouping_ops(features, indices)
            return grouped_xyz, grouped_features
        return grouped_xyz, None

    def extra_repr(self):
        return ", ".join(
            [
                f"num_neighbors={self.num_neighbors}",
                f"radius={self.radius}",
                f"relative_xyz={self.relative_xyz}",
                f"normalize_xyz={self.normalize_xyz}",
            ]
        )

class GroupingOperation(Function):
    """Group feature with given index."""

    @staticmethod
    def forward(ctx, features: torch.Tensor, indices: torch.Tensor) -> torch.Tensor:
        """
        Args:
            features (Tensor): (B, C, N) tensor of features to group.
            indices (Tensor): (B, K, num_neighbors) the indices of features to group with.
        Returns:
            (B, C, K, num_neighbors) Grouped features.
        """
        # B5, C 128, N 32
        # K16, num_neight 8
        num_feats = features.size(2)
        ctx.for_backwards = (indices, num_feats)
        return _C.group_points(features, indices)

    @staticmethod
    def backward(ctx, grad_grouped: torch.Tensor):
        """
        Args:
            grad_out (Tensor): (B, C, K, num_neighbors)
            tensor of the gradients of the output from forward.
        Returns:
            (B, C, N) gradient of the features.
        """
        indices, num_feats = ctx.for_backwards
        grad_feats: torch.Tensor = _C.group_points_backward(grad_grouped.data, indices, num_feats)
        grad_feats.requires_grad_(True)
        return grad_feats, None

grouping_ops = GroupingOperation.apply


from setuptools import setup, find_packages

version = '0.1'

setup(
	name='ckanext-agls',
	version=version,
	description='Extension for customising CKAN for data.gov.au',
	long_description='',
	classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
	keywords='',
	author='Alex Sadleir',
	author_email='alex.sadleir@linkdigital.com.au',
	url='',
	license='',
	packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
	namespace_packages=['ckanext'],
	include_package_data=True,
	zip_safe=False,
	install_requires=[],
	entry_points=\
	"""
        [ckan.plugins]
	agls=ckanext.agls.plugin:AGLSDatasetPlugin

	[paste.paster_command]
        initdb = ckanext.agls.command:InitDB
        [ckan.click_command]
        agls = ckanext.agls.cli:agls
	""",
)


from app import mongo
from app.config import DOCKER_CLIENT
from app.lib.utils.tools import get_uuid
from app.lib.core import formatnum
from app.lib.handler.decorator import threaded
from app.lib.thirdparty.wafcheck import waf_check

import time
import queue
import datetime
import threading

THREADS = 10

class ControllerPocs():
    # 控制并发线程数
    threads_queue = queue.Queue(maxsize=THREADS)
    for i in range(THREADS):
        threads_queue.put_nowait(" ")

    # 存放目标线程数
    target_queue = queue.Queue()

    list_queue = queue.Queue()

    def __init__(self, task_name, project, pid):

        self.task_name = task_name
        self.project = project
        self.pid = pid

    # waf检查函数
    def _waf_check(self):

        ports = mongo.db.ports.find({"parent_name": self.task_name})
        domains = mongo.db.subdomains.find({"parent_name": self.task_name})

        print(ports.count(), domains.count())

        for j in ports:
            self.target_queue.put_nowait(j)

        for k in domains:
            self.target_queue.put_nowait(k)

        while True:

            target_list = list()

            if self.target_queue.qsize() == 0:
                break

            if self.target_queue.qsize() >= THREADS:

                # 使用攻击对象attactObject的线程数来控制是否要启动新的线程
                for index in range(0, THREADS):
                    self.threads_queue.get()
                    param = self.target_queue.get()
                    attacker = threading.Thread(target=waf_check, args=(param, self.list_queue))
                    attacker.start()
                    target_list.append(attacker)

            else:
                for index in range(0, self.target_queue.qsize()):
                    self.threads_queue.get()
                    param = self.target_queue.get()
                    attacker = threading.Thread(target=waf_check, args=(param, self.list_queue))
                    attacker.start()
                    target_list.append(attacker)

            for t in target_list:
                t.join(3)

                self.threads_queue.put(" ")

        return list(self.list_queue.queue)

    # cms指纹识别函数
    def _cms_finger(self, target_list):
        return target_list

    def create_attack_task(self, target_list):
        """
        该函数用来进行POC扫描
        :param target_list:
        :return:
        """

        attack_list_xunfeng = []
        attack_list_s1riu5 = []
        attack_list_kunpeng = []
        attack_list_bugscan = []

        pocs = mongo.db.pocs.find({})

        pocs_list = list()

        for i in pocs:
            pocs_list.append(i)

        for m in pocs_list:
            for n in target_list:

                if m["flag"] == "xunfeng":

                    if n["service"] == m["vul_service"]:
                        new_dict = {}
                        new_dict["ip"] = n["address"]
                        new_dict["port"] = n["port"]
                        new_dict["poc"] = m["poc_name"]
                        new_dict["keyword"] = m["vul_service"]
                        new_dict["type_file"] = m["file_type"]
                        new_dict["project_name"] = self.project
                        attack_list_xunfeng.append(new_dict)

                    if "tag" in n:
                        if n["tag"] == m["vul_service"]:
                            new_dict = {}
                            new_dict["ip"] = n["address"]
                            new_dict["port"] = n["port"]
                            new_dict["poc"] = m["poc_name"]
                            new_dict["keyword"] = m["vul_service"]
                            new_dict["type_file"] = m["file_type"]
                            new_dict["project_name"] = self.project
                            attack_list_xunfeng.append(new_dict)

                elif m["flag"] == "kunpeng":

                    if "subdomain_name" in n:
                        attack_dict = {'type': 'web', 'target': "web", 'netloc': n["http_address"],
                                       "parent_name": self.project}
                        if attack_dict not in attack_list_kunpeng:
                            attack_list_kunpeng.append(attack_dict)
                    else:

                        if n["service"] in ["http", "ssl", "https"]:
                            if 'http' in n["service"]:
                                scheme = 'http'
                                if n["service"] in ['https', 'ssl'] or n["port"] == 443:
                                    scheme = 'https'
                                ip_url = '{}://{}:{}'.format(scheme, n["address"], n["port"])
                                attack_dict = {'type': 'web', 'target': "web", 'netloc': ip_url,
                                               "parent_name": self.project}
                                if attack_dict not in attack_list_kunpeng:
                                    attack_list_kunpeng.append(attack_dict)

                        else:

                            attack_dict = {'type': 'service', 'target': n["service"],
                                           'netloc': n["address"] + ':' + str(n["port"]), "parent_name": self.project}

                            if attack_dict not in attack_list_kunpeng:
                                attack_list_kunpeng.append(attack_dict)
                        #
                        # if n["service"] in ["http", "ssl", "https"]:
                        #     attack_dict = {'type': 'web', 'target': "web", 'netloc': n["http_address"],
                        #                    "parent_name": self.project}
                        #     if attack_dict not in attack_list_kunpeng:
                        #         attack_list_kunpeng.append(attack_dict)
                        #
                        # else:
                        #
                        #     attack_dict = {'type': 'service', 'target': n["service"],
                        #                    'netloc': n["http_address"], "parent_name": self.project}
                        #
                        #     if attack_dict not in attack_list_kunpeng:
                        #         attack_list_kunpeng.append(attack_dict)

                elif m["flag"] == "bugscan":

                    """
                    m: {'_id': ObjectId('5e2858f3a5c1fe4f0152e6c3'), 'cretae_date': datetime.datetime(2020, 1, 22, 22, 15, 15, 693000), 'vul_type': 'Null', 'file_type': 'py', 'vul_service': 'php168', 'flag': 'bugscan', 'id': '2acda09e-0964-4c52-b06f-c4188f5eeaf5', 'vul_name': 'Null', 'vul_info': 'Null', 'poc_name': 'exp_1170.py', 'vul_level': 'Null'}
                    n: {'_id': ObjectId('5e28ef328cd7cf0e4b791990'), 'id': '12adf194-e1ef-46ee-b552-645733f31e16', 'address': '127.0.0.1', 'mac': 'Null', 'vendor': 'Null', 'port': 8080, 'hostname': 'Null', 'create_date': datetime.datetime(2020, 1, 23, 8, 56, 18, 322000), 'end_time': datetime.datetime(2020, 1, 23, 8, 56, 18, 322000), 'parent_name': ' 测试项目', 'pid': '15ddb1f9-7792-4471-a084-2e6bfd3cc821', 'http_address': 'http://127.0.0.1', 'fofa': 'phpmyadmin,jquery,jquery-ui', 'category': 'phpmyadmin', 'service': 'http'}

                    """

                    if m["vul_service"] in n["service"]:

                        attack_dict = {'netloc': n["http_address"], "poc": m["poc_name"], "keyword": n["service"],
                                       "parent_name": self.project}
                        if attack_dict not in attack_list_bugscan:
                            attack_list_bugscan.append(attack_dict)

                    if m["vul_service"] in n["category"]:

                        attack_dict = {'netloc': n["http_address"], "poc": m["poc_name"], "keyword": n["category"],
                                       "parent_name": self.project}
                        if attack_dict not in attack_list_bugscan:
                            attack_list_bugscan.append(attack_dict)

        poc_num = attack_list_xunfeng + attack_list_kunpeng

        sess = mongo.db.tasks.find_one({"id": self.pid})

        # 项目被删除的时候
        if sess == None:
            return True

        if len(poc_num) == 0:
            mongo.db.tasks.update_one(
                {"id": self.pid},
                {'$set': {
                    'progress': "100.00%",
                    'status': 'Finished',
                    'end_time': datetime.datetime.now(),
                    'total_host': 0,

                }
                }
            )

            return True

        target_dict = {}
        target_dict["xunfeng"] = attack_list_xunfeng
        target_dict["kunpeng"] = attack_list_kunpeng
        # target_dict["bugscan"] = attack_list_bugscan

        for i in target_dict.items():

            if len(i[1]) != 0:
                vul_id = get_uuid()
                vul = {"id": vul_id, "parent_name": self.project, "progress": "0.00%", "total_num": len(i[1]),
                       "create_date": datetime.datetime.now(), "end_time": "Null",
                       "status": "Running",
                       "target": str(i[1]), "flag": i[0], "pid": self.pid}

                mongo.db.vuldocker.insert_one(vul)

                contain = DOCKER_CLIENT.containers.run(f"ap0llo/poc:{i[0]}", ["attack", vul_id], detach=True,
                                                       network="host", auto_remove=True)

                mongo.db.vuldocker.update_one(
                    {"id": self.pid},
                    {'$set': {
                        "contain_id": contain.id
                    }
                    }
                )

        while True:
            count = mongo.db.vuldocker.find({"pid": self.pid}).count()

            now_progress = 0

            for i in mongo.db.vuldocker.find({"pid": self.pid}):
                progress_ = formatnum(i["progress"])
                now_progress = now_progress + progress_

            progress = now_progress / count

            progress = '%.2f' % (progress)
            percent = f"{progress}%"

            if percent == "100.00%":

                mongo.db.tasks.update_one(
                    {"id": self.pid},
                    {'$set': {
                        'progress': "100.00%",
                        'status': 'Finished',
                        'end_time': datetime.datetime.now(),
                        'total_host': mongo.db.vuls.find({'pid': self.pid}).count(),

                    }
                    }
                )

                return True
            else:
                mongo.db.tasks.update_one(
                    {"id": self.pid},
                    {'$set': {
                        'progress': percent,
                        "total_host": mongo.db.vuls.find({'pid': self.pid}).count(),

                    }
                    }
                )

            time.sleep(3)

    @classmethod
    @threaded
    def thread_start(cls, task_name, project, pid):
        app = cls(task_name=task_name, project=project, pid=pid)
        # 类http标签进行waf检查
        info = app._waf_check()

        # 类http标签进行cms识别
        last_tag = app._cms_finger(info)

        # 正式开始运行
        app.create_attack_task(last_tag)

    @classmethod
    def start(cls, task_name, project, pid):
        app = cls(task_name, project=project, pid=pid)
        # 类http标签进行waf检查
        info = app._waf_check()

        # 类http标签进行cms识别
        last_tag = app._cms_finger(info)

        # 正式开始运行
        app.create_attack_task(last_tag)


def minSwaps(arr):
    n = len(arr)
    arrpos = [*enumerate(arr)]
    print(arrpos)
    arrpos.sort(key = lambda it:it[1])
    print(arrpos)
    vis = {k:False for k in range(n)}
    ans = 0
    for i in range(n):
        if vis[i] or arrpos[i][0] == i:
            continue
        cycle_size = 0
        j = i
        while not vis[j]:
            vis[j] = True
            j = arrpos[j][0]
            cycle_size += 1
        if cycle_size > 0:
            ans += (cycle_size - 1)
    return ans

arr = [3,4,2,5,1]
print(minSwaps(arr))

# This code is contributed
# by Dharan Aditya


import re
import random

class DnD_Dice:

    def __init__(self, dnd_dice_text:str):
        self.dice_text = dnd_dice_text
        self.num_dice = 0
        self.num_dice_sides = 0
        self.bonus = 0

        self.parse_dice_text(self.dice_text)

    def __str__(self):
        return self.dice_text

    @staticmethod
    def roll_dice_from_text(dice_text)->int:

        return DnD_Dice(dice_text).roll()

    def parse_dice_text(self, dice_text):

        # Define regex for parsing the text
        number_of_dice = re.compile(r'^\d+(?=d)')
        dice_sides = re.compile(r'(?<=\dd)\d+')
        extra_bonus = re.compile(r'(?<=\d\+)\d+$')

        # Use regex to extract the dice info from the text
        r = number_of_dice.search(dice_text)
        assert r is not None, "Can't find number of dice"
        self.num_dice = int(r[0])
        r = dice_sides.search(dice_text)
        assert r is not None, "Can't find number of dice sides"
        self.num_dice_sides = int(r[0])

        # Bonus is optional
        r = extra_bonus.search(dice_text)
        if r is not None:
            self.bonus = int(r[0])
        else:
            self.bonus = 0

    def roll(self):

        # Now time to roll the dice!
        result = 0

        for i in range(self.num_dice):
            result += random.randint(1, self.num_dice_sides)

        result += self.bonus

        return result

def run_tests():

    dice_rolls = ["1d6", "1d4+1", "1d20"]

    for dice in dice_rolls:

        d1 = DnD_Dice(dice)
        r = d1.roll()
        print(f'Rolling {d1} dice....result = {r}')

    for dice in dice_rolls:
        r=DnD_Dice.roll_dice_from_text(dice)
        print(f'Rolling {dice} dice....result = {r}')

if __name__ == "__main__":
    run_tests()


import argparse
from environment import Env
import strategies
def _parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument(
        '--strategy',
        help='Name of a strategy in the strategies directory',
        required=True
    )
    parser.add_argument(
        '--usdc_start',
        help='Initial USDC',
        required=True
    )
    parser.add_argument(
        '--eth_start',
        help='Initial ETH',
        required=True
    )
    # parser.add_argument(
    #     '--data',
    #     help='Path to data',
    #     required=True
    # )
    # parser.add_argument(
    #     '--look_back',
    #     help='How far you want to look at the past',
    #     required=True
    # )
    return parser.parse_args()

def main():
    args = _parse_args()
    environ = Env(float(args.usdc_start), float(args.eth_start))
    environ.define_strategy(getattr(strategies, args.strategy))
    environ.backtest()
    environ.get_plot()

if __name__ == '__main__':
    main()


import random

def display_board(board):
    print('\n'*100)

    print('   |   |')
    print(' ' + board[7] + ' | ' + board[8] + ' | ' + board[9])
    print('   |   |')
    print('-----------')
    print('   |   |')
    print(' ' + board[4] + ' | ' + board[5] + ' | ' + board[6])
    print('   |   |')
    print('-----------')
    print('   |   |')
    print(' ' + board[1] + ' | ' + board[2] + ' | ' + board[3])
    print('   |   |')

def player_input():

    choice = 'wrong'

    #we want to take input from user about which marker to choose, need to fail and ask again
    # if they enter anything else apart from X or O
    # also send a message if they give a wrong answer
    # if player1 chooses X, then player2 becomes O and vice versa

    while choice != 'X' and choice != 'O':
        choice = input("enter a marker X or O: ")

        if choice != 'X' and choice != 'O':
            print('\n'*100)
            print("Sorry, only X or O to be choosen")

        if choice == 'X':
            player1_marker = 'X'
            player2_marker = 'O'
        elif choice == 'O':
            player1_marker = 'O'
            player2_marker = 'X'

    return player1_marker,player2_marker

def place_marker(board, marker, position):
    # this func should open the board and take a marker which is X or O
    # and then take a index position from user and assign the marker to the position

    board[position] = marker

    return board

def win_check(board, mark):

    # need a func that checks the board and marker(X or O ) to see if the marker has won

     return ((board[7] == mark and board[8] == mark and board[9] == mark) or # across the top
    (board[4] == mark and board[5] == mark and board[6] == mark) or # across the middle
    (board[1] == mark and board[2] == mark and board[3] == mark) or # across the bottom
    (board[7] == mark and board[4] == mark and board[1] == mark) or # down the middle
    (board[8] == mark and board[5] == mark and board[2] == mark) or # down the middle
    (board[9] == mark and board[6] == mark and board[3] == mark) or # down the right side
    (board[7] == mark and board[5] == mark and board[3] == mark) or # diagonal
    (board[9] == mark and board[5] == mark and board[1] == mark)) # diagonal

def choose_first():
    # this function should let us know which one should go first
    # if the random int prints 0, player 1 should go, else player 2
    if random.randint(0,1) == 0:
        return 'Player1'
    else:
        return 'Player2'

def space_check(board, position):
    # this func should checks whether the position on the board is free
    return board[position] == ' '

def full_board_check(board):
    # need to check each position or index is full in the board
    for i in range(1,10):
        if space_check(board, i):
            return False
    return True

def player_choice(board):

    # should ask player next index pos b/w 1,9
    # use space check if the position is free
    # if free then assign the marker to free pos

    position = 0

    while position not in range(1,10) or not space_check(board, position):
        position = int(input("your next move? : "))

        if position not in range(1,10):
            print('\n'*100)
            print("your move out of range, try again")

    return position

def replay():

    return input("Do you wanna have another go? yes or no? ").lower().startswith('y')

while True:

    theboard = [' '] * 10
#     display_board(theboard)

    player1_marker,player2_marker = player_input()

    turn = choose_first()
    print(turn + " will go first")

    play_game = input("Lets start, yes or no?")

    if play_game.lower()[0] == 'y':
        game_on = True
    else:
        game_on = False

    while game_on:

        if turn == 'Player 1':
            display_board(theboard)
            position = player_choice(theboard)
            place_marker(theboard, player1_marker, position)

            if win_check(theboard, player1_marker):
                display_board(theboard)
                print("congrats mate P1!")
                game_on = False
            else:
                if full_board_check(theboard):
                    display_board(theboard)
                    print("Game's a draw bud !")
                    break
                else:
                    turn = 'Player 2'
                    display_board(theboard)

        else:
            #player2 turn
            display_board(theboard)
            position = player_choice(theboard)
            place_marker(theboard, player2_marker, position)

            if win_check(theboard, player2_marker):
                display_board(theboard)
                print("congrats mate player2 !")
                game_on = False
            else:
                if full_board_check(theboard):
                    display_board(theboard)
                    print("Game's a draw bud !")
                    break
                else:
                    turn = 'Player 1'

    if not replay():
        break


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Jan 25 15:36:39 2018

@author: fubao
"""

#   283. Move Zeroes

'''
Given an array nums, write a function to move all 0's to the end of it while maintaining the relative order of the non-zero elements.

For example, given nums = [0, 1, 0, 3, 12], after calling your function, nums should be [1, 3, 12, 0, 0].

Note:
You must do this in-place without making a copy of the array.
Minimize the total number of operations.

'''

# [0, 1, 0, 3, 12]
# i, j
#
class Solution(object):
    def moveZeroes(self, nums):
        """
        :type nums: List[int]
        :rtype: void Do not return anything, modify nums in-place instead.
        """
        if len(nums) == 0 or len(nums) == 1:
            return
        i = 0
        j = 1
        while ( j < len(nums)):
            if nums[i] != 0:
                #increase
                i += 1
                j += 1
            elif (nums[i] == 0) and (nums[j] !=0):
            #exchange
                nums[i], nums[j] = nums[j], nums[i]
                i += 1
                j += 1
            else:
                j += 1


#!/usr/bin/python
import traceback
import curses
import creature
import world

class Menu(object):
    def __init__(self):
        menuItems=[]

    def menuItem(self):
        pass

def mainMenu():
    pass

def printmenu():
    text='Welcome'
    return text

def printtext():
    text='asdf\nasfd\nasfd'
    return text

def main(mainScreen):
    ###lets instance a world
    w=world.World()
    #menuscr.addstr(2,3,printmenu())
    #menuScr.hline(3,3,'*',10)
    #statusscr=curses.newwin(15,15,5,20)
    #curses.textpad.rectangle(menuScr,4,4,15,15)

    mainScreen.refresh()

    exportScreen=curses.newwin(6,80,17,0)
    #exportScreen.border(' ',' ',0,0,' ',' ',' ',' ')
    exportScreen.refresh()

    mainmenuScreen=curses.newwin(10,10,0,69)
    mainmenuScreen.border(' ',' ',' ',' ',' ','?',' ',' ')
    mainmenuScreen.refresh()

    roomScreen=curses.newwin(15,40,2,2,)
    roomScreen.box()
    roomScreen.refresh()

    ###loading Files
    status=w.loadFiles(w.filenames)
    #mainScreen.addstr(status)

    while True:
        key=mainScreen.getch()

        if key==ord('q'):
            break
        elif key==ord('a'):
            mainScreen.addstr(3,12,'asdf')
        elif key==ord('?'):
            mainmenuScreen.addstr(2,0,'(?)elp\n(q)uit\n(t)ext\n(c)reate\n(l)ist')
        elif key==ord('t'):
            exportScreen.addstr(1,0,printtext())
        elif key==ord('c'):
            h=creature.Human()
            exportScreen.addstr(1,0,h.export())
        elif key==ord('l'):
            for h in world.World.creatures:
                mainScreen.addstr(1,0,world.World.creatures[h].export())
                tmp=mainScreen.getch()
        mainScreen.refresh()
        mainmenuScreen.refresh()
        exportScreen.refresh()

if __name__=='__main__':
    try:
        mainscr=curses.initscr()
        curses.noecho()
        curses.cbreak()
        curses.curs_set(0)
        ############
        main(mainscr)
        ############
        curses.echo()
        curses.nocbreak()
        curses.endwin()
    except:
        curses.echo()
        curses.nocbreak()
        curses.endwin()
        traceback.print_exc()
    finally:    #durchlesen und checken
        pass


__author__ = 'Mitenev'
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
import sys

def initGL(width, height):
    glClearColor(0.0, 0.0, 0.0, 0.0)
    glClearDepth(1.0)
    glEnable(GL_DEPTH_TEST)
    glViewport(0, 0, width, height)

    glMatrixMode(GL_PROJECTION)
    viewAngle = 30.0
    aspect = float(width) / float(height)
    gluPerspective(viewAngle, aspect, 0.1, 10)
    #glOrtho(-1.0, 1.0, -1.0, 1.0, -1, 10)
    glMatrixMode(GL_MODELVIEW)

def drawGLScene():

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    glLoadIdentity()
    glTranslatef(0.0, 0.0, -4.0)

    glBegin(GL_QUADS)

    glColor3f(0.0, 1.0, 0.0)
    glVertex3f(0.5, 0.5, -0.5)
    glVertex3f(-0.5, 0.5, -0.5)
    glVertex3f(-0.5, 0.5, 0.5)
    glVertex3f(0.5, 0.5, 0.5)

    glColor3f(1.0, 0.5, 0.0)
    glVertex3f(0.5, -0.5, 0.5)
    glVertex3f(-0.5, -0.5, 0.5)
    glVertex3f(-0.5, -0.5, -0.5)
    glVertex3f(0.5, -0.5, -0.5)

    glColor3f(1.0, 1.0, 0.0)
    glVertex3f(0.5, -0.5, -0.5)
    glVertex3f(-0.5, -0.5, -0.5)
    glVertex3f(-0.5, 0.5, -0.5)
    glVertex3f(0.5, 0.5, -0.5)

    glColor3f(0.0, 0.0, 1.0)
    glVertex3f(-0.5, 0.5, 0.5)
    glVertex3f(-0.5, 0.5, -0.5)
    glVertex3f(-0.5, -0.5, -0.5)
    glVertex3f(-0.5, -0.5, 0.5)

    glColor3f(1.0, 0.0, 1.0)
    glVertex3f(0.5, 0.5, -0.5)
    glVertex3f(0.5, 0.5, 0.5)
    glVertex3f(0.5, -0.5, 0.5)
    glVertex3f(0.5, -0.5, -0.5)

    glEnd()
    glutSwapBuffers()

def main():
    global window
    glutInit(sys.argv)
    width = 600
    height = 600

    glutInitWindowSize(width, height)
    window = glutCreateWindow("example")
    glutIdleFunc(drawGLScene)

    # Initialize our window.
    initGL(width, height)
    glutMainLoop()

main()


from unittest import TestCase
from datetime import datetime

from mock import Mock, patch

from plugins.admin_messenger.admin_messenger import AdminMessenger
from plugins.core.player_manager_plugin import UserLevels

class AdminMessengerTestCase(TestCase):
    def test_activate(self):
        plugin = AdminMessenger()
        plugin.config = Mock(chat_prefix='test prefix')

        with self.assertRaises(AttributeError):
            self.plugin.prefix

        plugin.activate()
        self.assertEqual(plugin.prefix, 'test prefix')

    @patch.object(AdminMessenger, 'message_admins')
    @patch.object(AdminMessenger, 'broadcast_message')
    @patch('plugins.admin_messenger.admin_messenger.packets')
    def test_on_chat_sent_broadcast(
        self, mock_packets, mock_broadcast, mock_admins
    ):
        mock_parse = Mock()
        message = Mock(message='###broadcast message')
        mock_parse.parse.return_value = message
        mock_packets.chat_sent.return_value = mock_parse
        mock_data = Mock(data='test data')
        plugin = AdminMessenger()
        plugin.config = Mock()
        plugin.activate()
        plugin.prefix = '#'

        self.assertFalse(plugin.on_chat_sent(mock_data))
        mock_parse.parse.assert_called_with('test data')
        mock_broadcast.assert_called_with(message)

    @patch.object(AdminMessenger, 'message_admins')
    @patch.object(AdminMessenger, 'broadcast_message')
    @patch('plugins.admin_messenger.admin_messenger.packets')
    def test_on_chat_sent_message_admins(
        self, mock_packets, mock_broadcast, mock_admins
    ):
        plugin = AdminMessenger()
        plugin.config = Mock()
        plugin.activate()
        plugin.prefix = '#'
        mock_parse = Mock()
        mock_data = Mock(data='test data')
        message = Mock(message='##admin message')
        mock_parse.parse.return_value = message
        mock_packets.chat_sent.return_value = mock_parse

        self.assertFalse(plugin.on_chat_sent(mock_data))
        mock_admins.assert_called_with(message)

    @patch.object(AdminMessenger, 'message_admins')
    @patch.object(AdminMessenger, 'broadcast_message')
    @patch('plugins.admin_messenger.admin_messenger.packets')
    def test_on_chat_sent_normal_message(
        self, mock_packets, mock_broadcast, mock_admins
    ):
        mock_parse = Mock()
        mock_data = Mock(data='test data')
        plugin = AdminMessenger()
        plugin.config = Mock()
        plugin.activate()
        plugin.prefix = '#'
        message = Mock(message='test message')
        mock_parse.parse.return_value = message

        self.assertTrue(plugin.on_chat_sent(mock_data))
        self.assertFalse(mock_admins.called)
        self.assertFalse(mock_broadcast.called)

    @patch('plugins.admin_messenger.admin_messenger.datetime')
    def test_add_timestamp(self, mock_datetime):
        current_datetime = datetime.now()
        mock_datetime.now.return_value = current_datetime
        plugin = AdminMessenger()
        plugin.config = Mock()

        result = plugin.add_timestamp()
        self.assertEqual(
            result,
            '^red;<{}> '.format(current_datetime.strftime('%H:%M'))
        )

        result = plugin.add_timestamp(True)
        self.assertEqual(
            result,
            '^red;<{}> ^yellow;'.format(current_datetime.strftime('%H:%M'))
        )

        plugin.config.chattimestamps = False
        result = plugin.add_timestamp()
        self.assertEqual(result, '')

    @patch.object(AdminMessenger, 'add_timestamp')
    def test_message_admins(self, mock_add_timestamp):
        mock_logger = Mock()
        mock_config = Mock()
        mock_config.colors = {'moderator': 'moderator colors'}
        mock_message = Mock()
        mock_message.message = '##test'
        mock_add_timestamp.return_value = 'with add_normalizer'
        mock_just_player = Mock()
        mock_just_player.player.access_level = UserLevels.GUEST
        mock_player_moderator = Mock()
        mock_player_moderator.player.access_level = UserLevels.MODERATOR
        mock_factory = Mock()
        mock_factory.protocols = {
            'normal player': mock_just_player,
            'moderator': mock_player_moderator
        }
        mock_protocol = Mock()
        mock_protocol.player.colored_name.return_value = 'player colors'
        plugin = AdminMessenger()
        plugin.factory = mock_factory
        plugin.config = mock_config
        plugin.logger = mock_logger
        plugin.protocol = mock_protocol

        plugin.message_admins(mock_message)
        mock_player_moderator.send_chat_message.assert_called_with(
            '{}{}ADMIN: ^yellow;<{}^yellow;> {}{}'.format(
                'with add_normalizer',
                'moderator colors',
                'player colors',
                'moderator colors',
                'test'
            )
        )
        mock_logger.info.assert_called_with(
            'Received an admin message from %s. Message: %s',
            mock_protocol.player.name, 'test'
        )
        self.assertFalse(mock_just_player.send_chat_message.called)
        mock_add_timestamp.assert_called_with(add_normalizer=True)

    @patch.object(AdminMessenger, 'add_timestamp')
    def test_broadcast_message(self, mock_add_timestamp):
        mock_logger = Mock()
        mock_config = Mock()
        mock_config.colors = {
            'admin': 'admin colors',
            'default': 'default colors'
        }
        mock_message = Mock()
        mock_message.message = '###test'
        mock_add_timestamp.return_value = 'without add_normalizer'
        mock_just_player = Mock()
        mock_player_moderator = Mock()
        mock_factory = Mock()
        mock_factory.protocols = {
            'normal player': mock_just_player,
            'moderator': mock_player_moderator
        }
        mock_protocol = Mock()
        mock_protocol.player.access_level = UserLevels.ADMIN
        plugin = AdminMessenger()
        plugin.factory = mock_factory
        plugin.config = mock_config
        plugin.logger = mock_logger
        plugin.protocol = mock_protocol
        expected_message = '{}{}BROADCAST: ^red;{}{}'.format(
            'without add_normalizer', 'admin colors', 'TEST',
            'default colors'
        )

        plugin.broadcast_message(mock_message)
        mock_player_moderator.send_chat_message.assert_called_with(
            expected_message
        )
        mock_just_player.send_chat_message.assert_called_with(expected_message)
        mock_logger.info.assert_called_with(
            'Broadcast from %s. Message: %s',
            mock_protocol.player.name, 'TEST'
        )
        self.assertFalse(mock_protocol.send_chat_message.called)

    def test_broadcast_message_not_admin(self):
        mock_protocol = Mock()
        mock_protocol.player.access_level = UserLevels.GUEST
        plugin = AdminMessenger()
        plugin.protocol = mock_protocol

        result = plugin.broadcast_message('test')
        self.assertFalse(result)
        mock_protocol.send_chat_message.assert_called_with(
            'You are not authorized to do this.'
        )


"""py.test testing fixtures"""

import pytest

# Websauna
from websauna.blog.models import Post
from websauna.utils.time import now

@pytest.fixture
def unpublished_post(dbsession):
    post = Post()
    post.title = "Hello world"
    post.body = "All roads lead to Toholampi"
    post.tags = "mytag,mytag2"
    post.ensure_slug(dbsession)
    dbsession.add(post)
    dbsession.flush()
    return post

@pytest.fixture
def published_post(unpublished_post):
    unpublished_post.published_at = now()
    return unpublished_post