<commit_before>import discord
from discord.ext import commands

import time
import datetime
import socket
import os
import psutil

class Basic:
    def __init__(self, bot):
        self.bot = bot
        self.process = psutil.Process(os.getpid())

    @commands.command(aliases=['about'])
    async def info(self, ctx):
        """Returns bot's info."""
        local_time = str(datetime.datetime.now()).split('.')[0]
        total_guild_count = len(self.bot.guilds)
        total_user_count = len(list(self.bot.get_all_members()))
        total_unique_user_count = len(list(set(self.bot.get_all_members())))
        owner = str(self.bot.bot_info.owner)

        mem_bytes = self.process.memory_full_info().rss
        mem_mb = round(mem_bytes / 1024 / 1024, 2)
        cpu_usage = round(self.process.cpu_percent() / psutil.cpu_count(), 2)

        uptime = self.bot.get_relative_timestamp(
            time_from=datetime.datetime.utcfromtimestamp(self.bot.start_time))

        em = discord.Embed(color=0xDAB420)

        em.add_field(name="Git Hash",
                     value=self.bot.get_git_revision_short_hash())
        em.add_field(name="Last git message",
                     value=self.bot.get_git_commit_text())
        em.add_field(name="Hostname", value=socket.gethostname())
        em.add_field(name="Guild count", value=total_guild_count)
        em.add_field(name="Unique users", value=total_unique_user_count)
        em.add_field(name="Local Time", value=local_time)
        em.add_field(name="RAM Usage", value=f"{mem_mb}MiB")
        em.add_field(name="CPU Percentage", value=f"{cpu_usage}%")
        em.add_field(name="Uptime", value=uptime)
        em.add_field(name="Owner", value=owner)
        em.add_field(name="Invite", value="https://bot.ave.zone/add")

        em.set_author(name='AveBot v3', icon_url='https://s.ave.zone/c7d.png')
        await ctx.send(embed=em)

    @commands.command(aliases=['addavebot'])
    async def invite(self, ctx):
        """Gives a link that can be used to add AveBot."""
        inviteurl = discord.utils.oauth_url(self.bot.user.id)
        await ctx.send(f"You can use the following link to add AveBot to your server:\n<{inviteurl}>")

    @commands.command()
    async def hello(self, ctx):
        """Says hello. Duh."""
        await ctx.send(f"Hello {ctx.message.author.mention}!")

    @commands.command()
    async def ginvite(self, ctx, discordid: int):
        """Generates a discord invite link."""
        inviteurl = discord.utils.oauth_url(discordid)
        await ctx.send(f"<{inviteurl}>")

    @commands.command()
    async def servercount(self, ctx):
        """Returns the amount of servers AveBot is in."""
        total_guild_count = len(self.bot.guilds)
        total_user_count = len(list(self.bot.get_all_members()))
        total_unique_user_count = len(list(set(self.bot.get_all_members())))
        await ctx.send(f"AveBot is in {total_guild_count} servers with {total_user_count} total users ({total_unique_user_count} unique).")

    @commands.command(aliases=['p'])
    async def ping(self, ctx):
        """Shows ping values to discord."""
        before = time.monotonic()
        tmp = await ctx.send('Calculating ping...')
        after = time.monotonic()
        rtt_ms = (after - before) * 1000
        gw_ms = self.bot.latency * 1000

        message_text = f":ping_pong: rtt: `{rtt_ms:.1f}ms`, `gw: {gw_ms:.1f}ms`"
        self.bot.log.info(message_text)
        await tmp.edit(content=message_text)

    @commands.guild_only()
    @commands.command(aliases=['serverinfo'])
    async def sinfo(self, ctx):
        """Shows info about the current server."""
        current_guild = ctx.guild
        em = discord.Embed(title=f"Server info of {current_guild.name} ({current_guild.id})")

        region_replace = {"us-west": ":flag_us: US West", "us-east": ":flag_us: US East",
                          "us-south": ":flag_us: US South", "us-central": ":flag_us: US Central",
                          "eu-west": ":flag_eu: EU West", "eu-central": ":flag_eu: EU Central",
                          "singapore": ":flag_si: Singapore", "london": ":flag_uk: London, UK",
                          "sydney": ":flag_au: Sydney, AU", "amsterdam": ":flag_nl: Amsterdam, NL",
                          "frankfurt": ":flag_de: Frankfurt, DE", "brazil": "<:lunadab:406845118105124864> Brazil",
                          "hongkong": ":flag_hk: Hong Kong", "russia": ":flag_ru: Russia",
                          "vip-us-east": ":flag_us: VIP US East", "vip-us-west": ":flag_us: VIP US West",
                          "vip-amsterdam": ":flag_nl: VIP Amsterdam, NL"}  # All this effort for :lunahahayes:

        region_text = str(current_guild.region)
        region_text = region_replace[region_text] if region_text in region_replace else region_text

        em.add_field(name="User Count", value=current_guild.member_count)
        em.add_field(name="Region", value=region_text)
        em.add_field(name="Owner", value=current_guild.owner)
        em.add_field(name="Verification Level",
                     value=current_guild.verification_level)
        humanized_created = self.bot.get_relative_timestamp(
            time_from=current_guild.created_at, humanized=True, include_from=True)
        em.add_field(name="Created at", value=humanized_created)

        em.set_thumbnail(url=current_guild.icon_url)
        await ctx.send(embed=em)

    @commands.command(aliases=['contact'])
    async def feedback(self, ctx, *, contact_text: str):
        """Contacts developers with a message."""
        em = discord.Embed(description=contact_text)

        author_name = f"{ctx.message.author} ({ctx.message.author.id}) "
        author_name += f"on \"{ctx.channel.name}\" at \"{ctx.guild.name}\"" if ctx.guild else "through DMs"

        em.set_author(name=author_name, icon_url=ctx.message.author.avatar_url)

        await self.bot.support_channel.send(embed=em)

        em = discord.Embed(title='Feedback sent!',
                           description='Your message has been delivered to the developers.')
        await ctx.send(embed=em)

    @commands.command(aliases=['userinfo', 'whoami', 'profile'])
    async def uinfo(self, ctx, *, user: discord.User = None):
        """Shows info about the user.

        info: returns info about the user who ran the command
        uinfo <mention/name>: returns info about the mentioned user"""

        if user is None:
            user = ctx.author

        if ctx.guild:
            maybe_member = ctx.guild.get_member(user.id)
            if maybe_member:
                user = maybe_member

        embed = discord.Embed(title=f"User Info of {str(user)}")

        if (user.avatar != ""):
            embed.set_thumbnail(url=user.avatar_url)
        embed.set_footer(text=f"UserID: {user.id}")

        humanized_discord = self.bot.get_relative_timestamp(
            time_from=user.created_at, humanized=True, include_from=True)
        embed.add_field(name="Joined Discord", value=humanized_discord)
        if ctx.guild and maybe_member:
            humanized_guild = self.bot.get_relative_timestamp(
                time_from=user.joined_at, humanized=True, include_from=True)
            embed.add_field(name="Joined Guild", value=humanized_guild)
            embed.add_field(name="Status", value=str(user.status))
        if user.game:
            embed.add_field(name="Game", value=user.game.name)
        is_bot_display = ":white_check_mark:" if user.bot else ":x:"
        embed.add_field(name="Is bot", value=is_bot_display)

        await ctx.send(embed=embed)

    @commands.command(aliases=['getavatar'])
    async def avatar(self, ctx, *, user: discord.User = None):
        """Gets your or a user's avatar.

        avatar <mention/name>: returns avatar of the mentioned user"""

        if user is None:
            user = ctx.author

        if ctx.guild:
            maybe_member = ctx.guild.get_member(user.id)
            if maybe_member:
                user = maybe_member

        if user.avatar:
            await ctx.send(f"{ctx.author.mention}: {user.avatar_url}")
        else:
            await ctx.send(f"{ctx.author.mention}: No user or avatar")

def setup(bot):
    bot.add_cog(Basic(bot))
<commit_msg>sinfo: update brazil flag<commit_after>import discord
from discord.ext import commands

import time
import datetime
import socket
import os
import psutil

class Basic:
    def __init__(self, bot):
        self.bot = bot
        self.process = psutil.Process(os.getpid())

    @commands.command(aliases=['about'])
    async def info(self, ctx):
        """Returns bot's info."""
        local_time = str(datetime.datetime.now()).split('.')[0]
        total_guild_count = len(self.bot.guilds)
        total_user_count = len(list(self.bot.get_all_members()))
        total_unique_user_count = len(list(set(self.bot.get_all_members())))
        owner = str(self.bot.bot_info.owner)

        mem_bytes = self.process.memory_full_info().rss
        mem_mb = round(mem_bytes / 1024 / 1024, 2)
        cpu_usage = round(self.process.cpu_percent() / psutil.cpu_count(), 2)

        uptime = self.bot.get_relative_timestamp(
            time_from=datetime.datetime.utcfromtimestamp(self.bot.start_time))

        em = discord.Embed(color=0xDAB420)

        em.add_field(name="Git Hash",
                     value=self.bot.get_git_revision_short_hash())
        em.add_field(name="Last git message",
                     value=self.bot.get_git_commit_text())
        em.add_field(name="Hostname", value=socket.gethostname())
        em.add_field(name="Guild count", value=total_guild_count)
        em.add_field(name="Unique users", value=total_unique_user_count)
        em.add_field(name="Local Time", value=local_time)
        em.add_field(name="RAM Usage", value=f"{mem_mb}MiB")
        em.add_field(name="CPU Percentage", value=f"{cpu_usage}%")
        em.add_field(name="Uptime", value=uptime)
        em.add_field(name="Owner", value=owner)
        em.add_field(name="Invite", value="https://bot.ave.zone/add")

        em.set_author(name='AveBot v3', icon_url='https://s.ave.zone/c7d.png')
        await ctx.send(embed=em)

    @commands.command(aliases=['addavebot'])
    async def invite(self, ctx):
        """Gives a link that can be used to add AveBot."""
        inviteurl = discord.utils.oauth_url(self.bot.user.id)
        await ctx.send(f"You can use the following link to add AveBot to your server:\n<{inviteurl}>")

    @commands.command()
    async def hello(self, ctx):
        """Says hello. Duh."""
        await ctx.send(f"Hello {ctx.message.author.mention}!")

    @commands.command()
    async def ginvite(self, ctx, discordid: int):
        """Generates a discord invite link."""
        inviteurl = discord.utils.oauth_url(discordid)
        await ctx.send(f"<{inviteurl}>")

    @commands.command()
    async def servercount(self, ctx):
        """Returns the amount of servers AveBot is in."""
        total_guild_count = len(self.bot.guilds)
        total_user_count = len(list(self.bot.get_all_members()))
        total_unique_user_count = len(list(set(self.bot.get_all_members())))
        await ctx.send(f"AveBot is in {total_guild_count} servers with {total_user_count} total users ({total_unique_user_count} unique).")

    @commands.command(aliases=['p'])
    async def ping(self, ctx):
        """Shows ping values to discord."""
        before = time.monotonic()
        tmp = await ctx.send('Calculating ping...')
        after = time.monotonic()
        rtt_ms = (after - before) * 1000
        gw_ms = self.bot.latency * 1000

        message_text = f":ping_pong: rtt: `{rtt_ms:.1f}ms`, `gw: {gw_ms:.1f}ms`"
        self.bot.log.info(message_text)
        await tmp.edit(content=message_text)

    @commands.guild_only()
    @commands.command(aliases=['serverinfo'])
    async def sinfo(self, ctx):
        """Shows info about the current server."""
        current_guild = ctx.guild
        em = discord.Embed(title=f"Server info of {current_guild.name} ({current_guild.id})")

        region_replace = {"us-west": ":flag_us: US West", "us-east": ":flag_us: US East",
                          "us-south": ":flag_us: US South", "us-central": ":flag_us: US Central",
                          "eu-west": ":flag_eu: EU West", "eu-central": ":flag_eu: EU Central",
                          "singapore": ":flag_si: Singapore", "london": ":flag_uk: London, UK",
                          "sydney": ":flag_au: Sydney, AU", "amsterdam": ":flag_nl: Amsterdam, NL",
                          "frankfurt": ":flag_de: Frankfurt, DE", "brazil": "<:lunacollardab:415413502023303169> Brazil",
                          "hongkong": ":flag_hk: Hong Kong", "russia": ":flag_ru: Russia",
                          "vip-us-east": ":flag_us: VIP US East", "vip-us-west": ":flag_us: VIP US West",
                          "vip-amsterdam": ":flag_nl: VIP Amsterdam, NL"}  # All this effort for luna memes

        region_text = str(current_guild.region)
        region_text = region_replace[region_text] if region_text in region_replace else region_text

        em.add_field(name="User Count", value=current_guild.member_count)
        em.add_field(name="Region", value=region_text)
        em.add_field(name="Owner", value=current_guild.owner)
        em.add_field(name="Verification Level",
                     value=current_guild.verification_level)
        humanized_created = self.bot.get_relative_timestamp(
            time_from=current_guild.created_at, humanized=True, include_from=True)
        em.add_field(name="Created at", value=humanized_created)

        em.set_thumbnail(url=current_guild.icon_url)
        await ctx.send(embed=em)

    @commands.command(aliases=['contact'])
    async def feedback(self, ctx, *, contact_text: str):
        """Contacts developers with a message."""
        em = discord.Embed(description=contact_text)

        author_name = f"{ctx.message.author} ({ctx.message.author.id}) "
        author_name += f"on \"{ctx.channel.name}\" at \"{ctx.guild.name}\"" if ctx.guild else "through DMs"

        em.set_author(name=author_name, icon_url=ctx.message.author.avatar_url)

        await self.bot.support_channel.send(embed=em)

        em = discord.Embed(title='Feedback sent!',
                           description='Your message has been delivered to the developers.')
        await ctx.send(embed=em)

    @commands.command(aliases=['userinfo', 'whoami', 'profile'])
    async def uinfo(self, ctx, *, user: discord.User = None):
        """Shows info about the user.

        info: returns info about the user who ran the command
        uinfo <mention/name>: returns info about the mentioned user"""

        if user is None:
            user = ctx.author

        if ctx.guild:
            maybe_member = ctx.guild.get_member(user.id)
            if maybe_member:
                user = maybe_member

        embed = discord.Embed(title=f"User Info of {str(user)}")

        if (user.avatar != ""):
            embed.set_thumbnail(url=user.avatar_url)
        embed.set_footer(text=f"UserID: {user.id}")

        humanized_discord = self.bot.get_relative_timestamp(
            time_from=user.created_at, humanized=True, include_from=True)
        embed.add_field(name="Joined Discord", value=humanized_discord)
        if ctx.guild and maybe_member:
            humanized_guild = self.bot.get_relative_timestamp(
                time_from=user.joined_at, humanized=True, include_from=True)
            embed.add_field(name="Joined Guild", value=humanized_guild)
            embed.add_field(name="Status", value=str(user.status))
        if user.game:
            embed.add_field(name="Game", value=user.game.name)
        is_bot_display = ":white_check_mark:" if user.bot else ":x:"
        embed.add_field(name="Is bot", value=is_bot_display)

        await ctx.send(embed=embed)

    @commands.command(aliases=['getavatar'])
    async def avatar(self, ctx, *, user: discord.User = None):
        """Gets your or a user's avatar.

        avatar <mention/name>: returns avatar of the mentioned user"""

        if user is None:
            user = ctx.author

        if ctx.guild:
            maybe_member = ctx.guild.get_member(user.id)
            if maybe_member:
                user = maybe_member

        if user.avatar:
            await ctx.send(f"{ctx.author.mention}: {user.avatar_url}")
        else:
            await ctx.send(f"{ctx.author.mention}: No user or avatar")

def setup(bot):
    bot.add_cog(Basic(bot))
<|endoftext|>


<commit_before>import numpy as np
import astropy.io.fits as pyfits

def poisson_randomization(rate, dt=1., bkg=0., seed=None):
    """
    Poisson randomization of the rate array.

    Args:
        rate:   input array of count rates (in cts/s).

    Kwargs:
        dt:     time resolution of the lightcurve to be simulated.

        bkg:    Mean count rate of the simulated lightcurve (default: 0.0).

        seed:   Seed for the random number generator.

    Returns:
        newrate: Array of Poisson randomized count rates of length n.

    History:
        v0.1:   Riccardo Campana, 2014.
        Initial python implementation.
    """

    # Set the seed for the random generator
    if seed:
        np.random.seed(seed)

    n = len(rate)
    # Arrays of total counts per bin
    # If l is less than 0 insert only background...
    l = (np.clip(rate, 0., np.max(rate)) + bkg)*dt
    newrate = np.zeros(n)

    for i in xrange(n):
    	newrate[i] = np.random.poisson(l[i])/float(dt)

    return newrate

def psd(time, rate, norm='leahy'):
    """
    Returns power spectral density from a (real) time series
    with Leahy normalization.

    Args:
        time:   array of times (evenly binned).

        rate:   array of rate in counts/s.

    Kwargs:
        norm:   Normalization (only Leahy for now).

    Returns:
        f:      array of frequencies.

        p:      power spectrum.

    History:
        v0.1:   Riccardo Campana, 2014.
        Initial python implementation.
    """

    # Sanity checks
    assert len(time) == len(rate), 'ERROR: Time and rate arrays with different dimensions'
    # Check that time array is evenly spaced (also taking into account rounding errors)
    assert np.std(np.diff(time)) <= 1e-12, 'ERROR: Time array is not evenly spaced'

    dt = time[1]-time[0]

    # Total number of photons
    counts = rate*dt
    n_phot = np.sum(counts)
    print "Total number of photons:", n_phot

    # Number of points
    n = len(counts)

    # Fourier transform
    f = np.fft.rfftfreq(n, d=dt)
    a = np.fft.rfft(counts)

    if norm == 'leahy':
        psd = 2./n_phot * np.abs(a)**2

    return f, psd

def rebin(x, y, nbins, mode='rate'):
    """
    Linearly rebins the (x, y) 1-D arrays using #nbins new bins,
    taking for each new element the mean of the corresponding x elements,
    and the sum (if mode=='counts') or the mean (if mode=='rate') of the corresponding y elements.

    Args:
        x:   x array (same length as y)

        y:   y array (same length as x)

        nbins:   Number of new bins. Should be a factor of len(x) == len(y).

    Kwargs:
        mode: 'counts' or 'rate'; returns sum or mean of y-array elements

    Returns:
        xreb:   rebinned x array

        yreb:   rebinned y array

    History:
        v0.1:   Riccardo Campana, 2014.
        Initial python implementation.
    """
    # Sanity checks
    assert len(x) == len(y), 'ERROR: x and y must have the same length!'
    assert len(x) % nbins == 0,  'ERROR: nbins should be a factor of len(x) = len(y)'
    assert (mode == 'counts' or mode == 'rate'), 'ERROR: keyword mode should be counts or rate'

    factor = len(x)/nbins

    xreb = x.reshape((nbins, factor)).mean(axis=1)

    if mode == 'counts':
        yreb = y.reshape((nbins, factor)).sum(axis=1)
    elif mode == 'rate':
        yreb = y.reshape((nbins, factor)).mean(axis=1)

    return xreb, yreb

def logrebin(x, y, nbins, mode='rate'):
    """
    Logarithmically rebins the (x, y) 1-D arrays using #nbins new bins,
    taking for each new element the logarithmic mean of the corresponding x elements,
    and the sum (if mode=='counts') or the mean (if mode=='rate') of the corresponding y elements.

    Args:
        x:   x array (same length as y)

        y:   y array (same length as x)

        nbins:   Number of new bins.

    Kwargs:
        mode: 'counts' or 'rate'; returns sum or mean of y-array elements

    Returns:
        xreb:   rebinned x array

        yreb:   rebinned y array

    History:
        v0.1:   Riccardo Campana, 2014.
        Initial python implementation.
    """
    # Sanity checks
    assert len(x) == len(y), 'ERROR: x and y must have the same length!'
    #assert len(x) % nbins == 0,  'ERROR: nbins should be a factor of len(x) = len(y)'
    assert (mode == 'counts' or mode == 'rate'), 'ERROR: keyword mode should be counts or rate'

    newbins = np.logspace(np.log10(np.min(x)+1e-12), np.log10(np.max(x)), nbins)

    xreb = newbins[:-1] + np.diff(newbins)/2

    digitized = np.digitize(x, newbins)

    if mode == 'counts':
        yreb = [y[digitized == i].sum() for i in xrange(1, len(newbins))]
    elif mode == 'rate':
        yreb = [y[digitized == i].mean() for i in xrange(1, len(newbins))]

    return np.asarray(xreb), np.asarray(yreb)

def saveFITSLC(outfilename, time, rate, clobber=True):
    """
    Produce an output FITS file containing a lightcurve.

    Args:
        outfilename: Name of the output FITS file

        time: Array of times

        rate: Array of count rates

    Kwargs:
        clobber: if True, overwrites existing files with same name

    Returns:
        none

    History:
        v0.1:   Riccardo Campana, 2014
        Initial python implementation.
    """
    # Sanity check
    assert len(time) == len(rate), 'ERROR: Time and rate should have the same length!'

    col1 = pyfits.Column(name='Time', unit='s', format='E', array=time)
    col2 = pyfits.Column(name='Rate', unit='counts/s', format='E', array=rate)

    cols = pyfits.ColDefs([col1, col2])
    tbhdu = pyfits.BinTableHDU.from_columns(cols)
    tbhdu.header['EXTNAME'] = ('LC', 'Name of this binary table extension')
    prihdu = pyfits.PrimaryHDU()
    thdulist = pyfits.HDUList([prihdu, tbhdu])
    thdulist.writeto(outfilename, clobber=clobber)

def saveFITSPSD(outfilename, freq, psd, clobber=True):
    """
    Produce an output FITS file containing a power spectrum.

    Args:
        outfilename: Name of the output FITS file

        freq: Array of frequencies

        psd: Array of power spectrum

    Kwargs:
        clobber: if True, overwrites existing files with same name

    Returns:
        none

    History:
        v0.1:   Riccardo Campana, 2014
        Initial python implementation.
    """
    # Sanity check
    assert len(freq) == len(psd), 'ERROR: Frequencies and PSD should have the same length!'

    col1 = pyfits.Column(name='Frequency', unit='Hz', format='E', array=freq)
    col2 = pyfits.Column(name='PSD', format='E', array=psd)

    cols = pyfits.ColDefs([col1, col2])
    tbhdu = pyfits.BinTableHDU.from_columns(cols)
    tbhdu.header['EXTNAME'] = ('PSD', 'Name of this binary table extension')
    prihdu = pyfits.PrimaryHDU()
    thdulist = pyfits.HDUList([prihdu, tbhdu])
    thdulist.writeto(outfilename, clobber=clobber)
<commit_msg>Updated FITS LC output: OGIP compliance<commit_after>import numpy as np
import datetime
import astropy.io.fits as pyfits

def poisson_randomization(rate, dt=1., bkg=0., seed=None):
    """
    Poisson randomization of the rate array.

    Args:
        rate:   input array of count rates (in cts/s).

    Kwargs:
        dt:     time resolution of the lightcurve to be simulated.

        bkg:    Mean count rate of the simulated lightcurve (default: 0.0).

        seed:   Seed for the random number generator.

    Returns:
        newrate: Array of Poisson randomized count rates of length n.

    History:
        v0.1:   Riccardo Campana, 2014.
        Initial python implementation.
    """

    # Set the seed for the random generator
    if seed:
        np.random.seed(seed)

    n = len(rate)
    # Arrays of total counts per bin
    # If l is less than 0 insert only background...
    l = (np.clip(rate, 0., np.max(rate)) + bkg)*dt
    newrate = np.zeros(n)

    for i in xrange(n):
    	newrate[i] = np.random.poisson(l[i])/float(dt)

    return newrate

def psd(time, rate, norm='leahy'):
    """
    Returns power spectral density from a (real) time series
    with Leahy normalization.

    Args:
        time:   array of times (evenly binned).

        rate:   array of rate in counts/s.

    Kwargs:
        norm:   Normalization (only Leahy for now).

    Returns:
        f:      array of frequencies.

        p:      power spectrum.

    History:
        v0.1:   Riccardo Campana, 2014.
        Initial python implementation.
    """

    # Sanity checks
    assert len(time) == len(rate), 'ERROR: Time and rate arrays with different dimensions'
    # Check that time array is evenly spaced (also taking into account rounding errors)
    assert np.std(np.diff(time)) <= 1e-12, 'ERROR: Time array is not evenly spaced'

    dt = time[1]-time[0]

    # Total number of photons
    counts = rate*dt
    n_phot = np.sum(counts)
    print "Total number of photons:", n_phot

    # Number of points
    n = len(counts)

    # Fourier transform
    f = np.fft.rfftfreq(n, d=dt)
    a = np.fft.rfft(counts)

    if norm == 'leahy':
        psd = 2./n_phot * np.abs(a)**2

    return f, psd

def rebin(x, y, nbins, mode='rate'):
    """
    Linearly rebins the (x, y) 1-D arrays using #nbins new bins,
    taking for each new element the mean of the corresponding x elements,
    and the sum (if mode=='counts') or the mean (if mode=='rate') of the corresponding y elements.

    Args:
        x:   x array (same length as y)

        y:   y array (same length as x)

        nbins:   Number of new bins. Should be a factor of len(x) == len(y).

    Kwargs:
        mode: 'counts' or 'rate'; returns sum or mean of y-array elements

    Returns:
        xreb:   rebinned x array

        yreb:   rebinned y array

    History:
        v0.1:   Riccardo Campana, 2014.
        Initial python implementation.
    """
    # Sanity checks
    assert len(x) == len(y), 'ERROR: x and y must have the same length!'
    assert len(x) % nbins == 0,  'ERROR: nbins should be a factor of len(x) = len(y)'
    assert (mode == 'counts' or mode == 'rate'), 'ERROR: keyword mode should be counts or rate'

    factor = len(x)/nbins

    xreb = x.reshape((nbins, factor)).mean(axis=1)

    if mode == 'counts':
        yreb = y.reshape((nbins, factor)).sum(axis=1)
    elif mode == 'rate':
        yreb = y.reshape((nbins, factor)).mean(axis=1)

    return xreb, yreb

def logrebin(x, y, nbins, mode='rate'):
    """
    Logarithmically rebins the (x, y) 1-D arrays using #nbins new bins,
    taking for each new element the logarithmic mean of the corresponding x elements,
    and the sum (if mode=='counts') or the mean (if mode=='rate') of the corresponding y elements.

    Args:
        x:   x array (same length as y)

        y:   y array (same length as x)

        nbins:   Number of new bins.

    Kwargs:
        mode: 'counts' or 'rate'; returns sum or mean of y-array elements

    Returns:
        xreb:   rebinned x array

        yreb:   rebinned y array

    History:
        v0.1:   Riccardo Campana, 2014.
        Initial python implementation.
    """
    # Sanity checks
    assert len(x) == len(y), 'ERROR: x and y must have the same length!'
    #assert len(x) % nbins == 0,  'ERROR: nbins should be a factor of len(x) = len(y)'
    assert (mode == 'counts' or mode == 'rate'), 'ERROR: keyword mode should be counts or rate'

    newbins = np.logspace(np.log10(np.min(x)+1e-12), np.log10(np.max(x)), nbins)

    xreb = newbins[:-1] + np.diff(newbins)/2

    digitized = np.digitize(x, newbins)

    if mode == 'counts':
        yreb = [y[digitized == i].sum() for i in xrange(1, len(newbins))]
    elif mode == 'rate':
        yreb = [y[digitized == i].mean() for i in xrange(1, len(newbins))]

    return np.asarray(xreb), np.asarray(yreb)

def saveFITSLC(outfilename, time, rate, clobber=True):
    """
    Produce an output FITS file containing a lightcurve.

    Args:
        outfilename: Name of the output FITS file

        time: Array of times

        rate: Array of count rates

    Kwargs:
        clobber: if True, overwrites existing files with same name

    Returns:
        none

    History:
        v2:   OGIP-compliance (OGIP 93-003). Riccardo Campana, 2014
        v1:   Initial python implementation. Riccardo Campana, 2014
    """
    # Sanity check
    assert len(time) == len(rate), 'ERROR: Time and rate should have the same length!'

    timedelta = time[1]-time[0]

    # Dummy start date for observation
    start_date = datetime.datetime(2015, 1, 1)
    stop_date  = start_date + datetime.timedelta(seconds=time[-1])

    col1 = pyfits.Column(name='TIME', unit='s', format='D', array=time)
    col2 = pyfits.Column(name='RATE', unit='count/s', format='D', array=rate)

    cols = pyfits.ColDefs([col1, col2])
    tbhdu = pyfits.BinTableHDU.from_columns(cols)

    tbhdu.header['EXTNAME']    = ('RATE', 'Name of this binary table extension')
    tbhdu.header['TELESCOP']   = ('PYLCSIM', 'Mission or telescope name')
    tbhdu.header['INSTRUME']   = ('PYLCSIM', 'Instrument name')
    tbhdu.header['ORIGIN']     = ('PYLCSIM', 'Who produced this file')
    tbhdu.header['TIMVERSN']   = ('OGIP/93-003', 'OGIP memo describing the convention used')
    tbhdu.header['AUTHOR']     = ('PYLCSIM', 'Name of the program that produced this file')

    tbhdu.header['RA']         = (0, 'Source right ascension in degrees')
    tbhdu.header['DEC']        = (0, 'Source declination in degrees')

    tbhdu.header['DATE-OBS']   = (start_date.strftime("%d/%m/%y"), 'Date of observation start')
    tbhdu.header['TIME-OBS']   = (start_date.strftime("%H:%M:%S.%f"), 'Time of observation start')
    tbhdu.header['DATE-END']   = (stop_date.strftime("%d/%m/%y"), 'Date of observation end')
    tbhdu.header['TIME-END']   = (stop_date.strftime("%H:%M:%S.%f"), 'Time of observation end')

    tbhdu.header['TSTART']     = (0., 'Start time')
    tbhdu.header['TSTOP']      = (time[-1], 'Stop time')
    tbhdu.header['TIMEZERO']   = (0., 'Zero time used to calculate the n-th event')
    tbhdu.header['TIMESYS']    = ('2015.0', 'System used to define time')
    tbhdu.header['TIMEUNIT']   = ('s', 'Unit for TSTART, TSTOP, TIMEZERO')
    tbhdu.header['CLOCKCOR']   = ('YES', 'If time corrected to UT')
    tbhdu.header['MJDREF']     = (57023.0, 'MJD for reference time')

    tbhdu.header['TIMEDEL']    = (timedelta, 'Source declination in degrees')

    prihdu = pyfits.PrimaryHDU()
    thdulist = pyfits.HDUList([prihdu, tbhdu])
    thdulist.writeto(outfilename, clobber=clobber)

def saveFITSPSD(outfilename, freq, psd, clobber=True):
    """
    Produce an output FITS file containing a power spectrum.

    Args:
        outfilename: Name of the output FITS file

        freq: Array of frequencies

        psd: Array of power spectrum

    Kwargs:
        clobber: if True, overwrites existing files with same name

    Returns:
        none

    History:
        v1:   Initial python implementation. Riccardo Campana, 2014
    """
    # Sanity check
    assert len(freq) == len(psd), 'ERROR: Frequencies and PSD should have the same length!'

    col1 = pyfits.Column(name='Frequency', unit='Hz', format='E', array=freq)
    col2 = pyfits.Column(name='PSD', format='E', array=psd)

    cols = pyfits.ColDefs([col1, col2])
    tbhdu = pyfits.BinTableHDU.from_columns(cols)
    tbhdu.header['EXTNAME'] = ('PSD', 'Name of this binary table extension')
    prihdu = pyfits.PrimaryHDU()
    thdulist = pyfits.HDUList([prihdu, tbhdu])
    thdulist.writeto(outfilename, clobber=clobber)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""
Display NVIDIA properties currently exhibiting in the NVIDIA GPUs.

nvidia-smi, short for NVIDIA System Management Interface program, is a cross
platform tool that supports all standard NVIDIA driver-supported Linux distros.

Configuration parameters:
    cache_timeout: refresh interval for this module (default 10)
    format: display format for this module (default '{format_gpu}')
    format_gpu: display format for NVIDIA GPUs
        *(default '{gpu_name} [\?color=temperature.gpu {temperature.gpu}°] '
        '[\?color=memory.used_percent {memory.used} MiB]')*
    format_gpu_separator: show separator if more than one (default ' ')
    thresholds: specify color thresholds to use
        (default [(0, 'good'), (65, 'degraded'), (75, 'orange'), (85, 'bad')])

Format placeholders:
    {format_gpu} format for NVIDIA GPUs

format_gpu placeholders:
    {index}               Zero based index of the GPU.
    {count}               The number of NVIDIA GPUs in the system
    {driver_version}      The version of the installed NVIDIA display driver
    {gpu_name}            The official product name of the GPU
    {gpu_uuid}            Globally unique immutable identifier of the GPU
    {memory.free}         Total free memory
    {memory.total}        Total installed GPU memory
    {memory.used}         Total memory allocated by active contexts
    {memory.used_percent} Total memory allocated by active contexts percentage
    {temperature.gpu}     Core GPU temperature in degrees C

    Use `python /path/to/nvidia_smi.py --list-properties` for a full list of
    supported NVIDIA properties to use. Not all of supported NVIDIA properties
    will be usable. See `nvidia-smi --help-query-gpu` for more information.

Color thresholds:
    format_gpu:
        `xxx`: print a color based on the value of NVIDIA `xxx` property

Requires:
    nvidia-smi: command line interface to query NVIDIA devices

Examples:
```
# add awesome {memory.used_percent} too
nvidia_smi {
    format_gpu = '{gpu_name} [\?color=temperature.gpu {temperature.gpu}°] '
    format_gpu += '[\?color=memory.used_percent {memory.used} MiB'
    format_gpu += '[\?color=darkgray&show \|]{memory.used_percent:.1f}%]'
}
```

@author lasers

SAMPLE OUTPUT
[
    {'full_text': 'GeForce GTX 1060 '},
    {'color': '#00ff00', 'full_text': '51°C '},
]

memory
[
    {'full_text': 'GeForce GTX 1060 '},
    {'color': '#ffff00', 'full_text': '65°C '},
    {'color': '#00ff00', 'full_text': '188 MiB (3.12%)},
]

custom
[
    {'color': '#a9a9a9', 'full_text': 'temperature.gpu '},
    {'color': '#00ff00', 'full_text': '54°C '},
    {'color': '#a9a9a9', 'full_text': 'memory.used '},
    {'color': '#ffff00', 'full_text': '135 MiB'}
]
"""

STRING_NOT_INSTALLED = 'not installed'

class Py3status:
    """
    """
    # available configuration parameters
    cache_timeout = 10
    format = '{format_gpu}'
    format_gpu = (u'{gpu_name} [\?color=temperature.gpu {temperature.gpu}°] '
                  '[\?color=memory.used_percent {memory.used} MiB]')
    format_gpu_separator = ' '
    thresholds = [(0, 'good'), (65, 'degraded'), (75, 'orange'), (85, 'bad')]

    def post_config_hook(self):
        command = 'nvidia-smi --format=csv,noheader,nounits --query-gpu='
        if not self.py3.check_commands(command.split()[0]):
            raise Exception(STRING_NOT_INSTALLED)
        self.properties = self.py3.get_placeholders_list(self.format_gpu)

        format_gpu = {x: ':.1f' for x in self.properties if 'used_percent' in x}
        self.format_gpu = self.py3.update_placeholder_formats(
            self.format_gpu, format_gpu
        )

        for name in ['memory.used_percent']:
            if name in self.properties:
                self.properties.remove(name)
        for name in ['memory.used', 'memory.total']:
            if name not in self.properties:
                self.properties.append(name)
        self.nvidia_command = command + ','.join(self.properties)

        self.thresholds_init = self.py3.get_color_names_list(self.format_gpu)

    def _get_nvidia_data(self):
        data = self.py3.command_output(self.nvidia_command)
        if '[Not Supported]' in data:
            data = data.replace('[Not Supported]', 'None')
        return data

    def nvidia_smi(self):
        nvidia_data = self._get_nvidia_data()
        new_gpu = []

        for line in nvidia_data.splitlines():
            gpu = dict(zip(self.properties, line.split(', ')))
            gpu['memory.used_percent'] = (
                float(gpu['memory.used']) / float(gpu['memory.total']) * 100.0
            )
            for x in self.thresholds_init:
                if x in gpu:
                    self.py3.threshold_get_color(gpu[x], x)

            new_gpu.append(self.py3.safe_format(self.format_gpu, gpu))

        format_gpu_separator = self.py3.safe_format(self.format_gpu_separator)
        format_gpu = self.py3.composite_join(format_gpu_separator, new_gpu)

        return {
            'cached_until': self.py3.time_in(self.cache_timeout),
            'full_text': self.py3.safe_format(
                self.format, {'format_gpu': format_gpu}
            )
        }

if __name__ == "__main__":
    from sys import argv
    if '--list-properties' in argv:
        from sys import exit
        from json import dumps
        from subprocess import check_output

        help_cmd = 'nvidia-smi --help-query-gpu'
        help_data = check_output(help_cmd.split()).decode()

        new_properties = []
        e = ['Default', 'Exclusive_Thread', 'Exclusive_Process', 'Prohibited']
        for line in help_data.splitlines():
            if line.startswith('"'):
                properties = line.split('"')[1::2]
                for name in properties:
                    if name not in e:
                        new_properties.append(name)

        properties = ','.join(new_properties)
        gpu_cmd = 'nvidia-smi --format=csv,noheader,nounits --query-gpu='
        gpu_data = check_output((gpu_cmd + properties).split()).decode()

        new_gpus = []
        msg = 'This GPU contains {} supported properties.'
        for line in gpu_data.splitlines():
            gpu = dict(zip(new_properties, line.split(', ')))
            gpu = {k: v for k, v in gpu.items() if '[Not Supported]' not in v}
            gpu['= ' + msg.format(len(gpu))] = ''
            gpu['=' * (len(msg) + 2)] = ''
            new_gpus.append(gpu)

        print(dumps(new_gpus, sort_keys=True, indent=4))
        exit()
    """
    Run module in test mode.
    """
    from py3status.module_test import module_test
    module_test(Py3status)
<commit_msg>nvidia_smi: fix SAMPLE_DATA_ERROR<commit_after># -*- coding: utf-8 -*-
"""
Display NVIDIA properties currently exhibiting in the NVIDIA GPUs.

nvidia-smi, short for NVIDIA System Management Interface program, is a cross
platform tool that supports all standard NVIDIA driver-supported Linux distros.

Configuration parameters:
    cache_timeout: refresh interval for this module (default 10)
    format: display format for this module (default '{format_gpu}')
    format_gpu: display format for NVIDIA GPUs
        *(default '{gpu_name} [\?color=temperature.gpu {temperature.gpu}°] '
        '[\?color=memory.used_percent {memory.used} MiB]')*
    format_gpu_separator: show separator if more than one (default ' ')
    thresholds: specify color thresholds to use
        (default [(0, 'good'), (65, 'degraded'), (75, 'orange'), (85, 'bad')])

Format placeholders:
    {format_gpu} format for NVIDIA GPUs

format_gpu placeholders:
    {index}               Zero based index of the GPU.
    {count}               The number of NVIDIA GPUs in the system
    {driver_version}      The version of the installed NVIDIA display driver
    {gpu_name}            The official product name of the GPU
    {gpu_uuid}            Globally unique immutable identifier of the GPU
    {memory.free}         Total free memory
    {memory.total}        Total installed GPU memory
    {memory.used}         Total memory allocated by active contexts
    {memory.used_percent} Total memory allocated by active contexts percentage
    {temperature.gpu}     Core GPU temperature in degrees C

    Use `python /path/to/nvidia_smi.py --list-properties` for a full list of
    supported NVIDIA properties to use. Not all of supported NVIDIA properties
    will be usable. See `nvidia-smi --help-query-gpu` for more information.

Color thresholds:
    format_gpu:
        `xxx`: print a color based on the value of NVIDIA `xxx` property

Requires:
    nvidia-smi: command line interface to query NVIDIA devices

Examples:
```
# add awesome {memory.used_percent} too
nvidia_smi {
    format_gpu = '{gpu_name} [\?color=temperature.gpu {temperature.gpu}°] '
    format_gpu += '[\?color=memory.used_percent {memory.used} MiB'
    format_gpu += '[\?color=darkgray&show \|]{memory.used_percent:.1f}%]'
}
```

@author lasers

SAMPLE OUTPUT
[
    {'full_text': 'GeForce GTX 1060 '},
    {'color': '#00ff00', 'full_text': '51°C '},
]

memory
[
    {'full_text': 'GeForce GTX 1060 '},
    {'color': '#ffff00', 'full_text': '65°C '},
    {'color': '#00ff00', 'full_text': '188 MiB'},
    {'color': '#a9a9a9', 'full_text': '|'},
    {'color': '#00ff00', 'full_text': '3.12%'},
]

custom
[
    {'color': '#a9a9a9', 'full_text': 'temperature.gpu '},
    {'color': '#00ff00', 'full_text': '54°C '},
    {'color': '#a9a9a9', 'full_text': 'memory.used '},
    {'color': '#ffff00', 'full_text': '135 MiB'}
]
"""

STRING_NOT_INSTALLED = 'not installed'

class Py3status:
    """
    """
    # available configuration parameters
    cache_timeout = 10
    format = '{format_gpu}'
    format_gpu = (u'{gpu_name} [\?color=temperature.gpu {temperature.gpu}°] '
                  '[\?color=memory.used_percent {memory.used} MiB]')
    format_gpu_separator = ' '
    thresholds = [(0, 'good'), (65, 'degraded'), (75, 'orange'), (85, 'bad')]

    def post_config_hook(self):
        command = 'nvidia-smi --format=csv,noheader,nounits --query-gpu='
        if not self.py3.check_commands(command.split()[0]):
            raise Exception(STRING_NOT_INSTALLED)
        self.properties = self.py3.get_placeholders_list(self.format_gpu)

        format_gpu = {x: ':.1f' for x in self.properties if 'used_percent' in x}
        self.format_gpu = self.py3.update_placeholder_formats(
            self.format_gpu, format_gpu
        )

        for name in ['memory.used_percent']:
            if name in self.properties:
                self.properties.remove(name)
        for name in ['memory.used', 'memory.total']:
            if name not in self.properties:
                self.properties.append(name)
        self.nvidia_command = command + ','.join(self.properties)

        self.thresholds_init = self.py3.get_color_names_list(self.format_gpu)

    def _get_nvidia_data(self):
        data = self.py3.command_output(self.nvidia_command)
        if '[Not Supported]' in data:
            data = data.replace('[Not Supported]', 'None')
        return data

    def nvidia_smi(self):
        nvidia_data = self._get_nvidia_data()
        new_gpu = []

        for line in nvidia_data.splitlines():
            gpu = dict(zip(self.properties, line.split(', ')))
            gpu['memory.used_percent'] = (
                float(gpu['memory.used']) / float(gpu['memory.total']) * 100.0
            )
            for x in self.thresholds_init:
                if x in gpu:
                    self.py3.threshold_get_color(gpu[x], x)

            new_gpu.append(self.py3.safe_format(self.format_gpu, gpu))

        format_gpu_separator = self.py3.safe_format(self.format_gpu_separator)
        format_gpu = self.py3.composite_join(format_gpu_separator, new_gpu)

        return {
            'cached_until': self.py3.time_in(self.cache_timeout),
            'full_text': self.py3.safe_format(
                self.format, {'format_gpu': format_gpu}
            )
        }

if __name__ == "__main__":
    from sys import argv
    if '--list-properties' in argv:
        from sys import exit
        from json import dumps
        from subprocess import check_output

        help_cmd = 'nvidia-smi --help-query-gpu'
        help_data = check_output(help_cmd.split()).decode()

        new_properties = []
        e = ['Default', 'Exclusive_Thread', 'Exclusive_Process', 'Prohibited']
        for line in help_data.splitlines():
            if line.startswith('"'):
                properties = line.split('"')[1::2]
                for name in properties:
                    if name not in e:
                        new_properties.append(name)

        properties = ','.join(new_properties)
        gpu_cmd = 'nvidia-smi --format=csv,noheader,nounits --query-gpu='
        gpu_data = check_output((gpu_cmd + properties).split()).decode()

        new_gpus = []
        msg = 'This GPU contains {} supported properties.'
        for line in gpu_data.splitlines():
            gpu = dict(zip(new_properties, line.split(', ')))
            gpu = {k: v for k, v in gpu.items() if '[Not Supported]' not in v}
            gpu['= ' + msg.format(len(gpu))] = ''
            gpu['=' * (len(msg) + 2)] = ''
            new_gpus.append(gpu)

        print(dumps(new_gpus, sort_keys=True, indent=4))
        exit()
    """
    Run module in test mode.
    """
    from py3status.module_test import module_test
    module_test(Py3status)
<|endoftext|>


<commit_before>from .utils import config, checks, formats
import discord
from discord.ext import commands
import discord.utils
import random, json, asyncio
from urllib.parse import unquote
import os

class Radio:
    """The radio-bot related commands."""

    def __init__(self, bot):
        self.bot = bot
        if not discord.opus.is_loaded():
            discord.opus.load_opus('/usr/local/lib/libopus.so') #FreeBSD path

        self.player = None
        #self.stopped = True
        self.q = asyncio.Queue()
        self.play_next_song = asyncio.Event()
        self.stopped = asyncio.Event()
        self.current_song = None
        self.songs_dir = 'radio/'
        self.songs = []
        self.update_song_list()

    @property
    def is_playing(self):
        return self.player is not None and self.player.is_playing() and not self.stopped.is_set()

    def toggle_next_song(self):
        self.bot.loop.call_soon_threadsafe(self.bot.change_status(None))
        if not self.stopped.is_set():
            self.bot.loop.call_soon_threadsafe(self.play_next_song.set)

    def update_song_list(self):
        self.songs = self.bot.pycopy.list_files(self.songs_dir)

    @commands.command(pass_context=True)
    async def join(self, ctx, *, channel_name : str):
        """Зайти на указанный голосовой канал."""
        if self.bot.is_voice_connected():
            await ctx.invoke(self.leave)

        check = lambda c: c.name == channel_name and c.type == discord.ChannelType.voice
        channel = discord.utils.find(check, ctx.message.server.channels)
        if channel is None:
            await self.bot.say('Нет такого голосового канала.')
        await self.bot.join_voice_channel(channel)

    @commands.command(pass_context=True)
    async def leave(self, ctx):
        """Покинуть текущий голосовой каналю"""
        await ctx.invoke(self.stop)
        await self.bot.voice.disconnect()

    @commands.command()
    async def pause(self):
        """Приостановить воспроизведение."""
        if self.player is not None:
            self.player.pause()

    @commands.command()
    async def resume(self):
        """Продолжить воспроизведение."""
        if self.player is not None and not self.is_playing:
            self.player.resume()

    @commands.command()
    async def skip(self):
        """Перейти к следующей песне в очереди."""
        if self.player is not None and self.is_playing:
            self.player.stop()
            self.toggle_next_song()

    @commands.command()
    async def stop(self):
        """Остановить воспроизведение."""
        if self.is_playing:
            self.stopped.set()
            self.player.stop()

    @commands.command(pass_context=True)
    async def play(self, ctx):
        """Начать воспроизведение песен из очереди."""
        self.stopped.clear()
        if self.player is not None:# and not self.stopped.is_set():
            if not self.is_playing:
                await ctx.invoke(self.resume)
                return
            else:
                await self.bot.say('Уже играю песенку.')
                return

        while True:
            if not self.bot.is_voice_connected():
                author_channel = ctx.message.author.voice_channel
                if author_channel is not None:
                    await ctx.invoke(self.join, channel_name=author_channel.name)
                else:
                    await self.bot.say('Не выбран голосовой канал.')
                    return

            if self.stopped.is_set():
                break
            if self.q.empty():
                await self.q.put(random.choice(self.songs))
            self.play_next_song.clear()
            self.current = await self.q.get()
            self.player = self.bot.voice.create_ffmpeg_player(
                self.bot.pycopy.direct_link(self.songs_dir + self.current),
                after=self.toggle_next_song,
                #options="-loglevel debug -report",
                headers = dict(self.bot.pycopy.session.headers))
            #self.stopped.clear()
            self.player.start()
            song_name = unquote(self.current.split('/')[-1])
            await self.bot.change_status(discord.Game(name=song_name))

            await self.play_next_song.wait()

    @commands.command(aliases=['c'])
    async def current(self):
        """Что там играет?"""
        if self.is_playing:
            song_name = unquote(self.current.split('/')[-1])
            await self.bot.say(song_name)

    @commands.command()
    async def update(self):
        """Обновить список песен."""
        self.update_song_list()
        await self.bot.say("Найдено {} песенок".format(len(self.songs)))

    @commands.command()
    async def list(self):
        """Вывести список всех доступных песен."""
        song_list = ""
        id = 1
        for song in self.songs:
            song_list += "{}. {}\n".format(id, song)
            id += 1
            if len(song_list) > 1800:
                await self.bot.say(song_list)
                song_list = ''
        await self.bot.say(song_list)

    @commands.command()
    async def add(self, song_num : int):
        """Добавить в конец очереди песню с данным номером."""
        await self.q.put(self.songs[song_num-1])
        await self.bot.say("{} будет следующей песенкой".format(self.songs[song_num-1]))

def setup(bot):
    bot.add_cog(Radio(bot))
<commit_msg>Update radio.py<commit_after>from .utils import config, checks, formats
import discord
from discord.ext import commands
import discord.utils
import random, json, asyncio
from urllib.parse import unquote
import os

class Radio:
    """The radio-bot related commands."""

    def __init__(self, bot):
        self.bot = bot
        if not discord.opus.is_loaded():
            discord.opus.load_opus('/usr/local/lib/libopus.so') #FreeBSD path

        self.player = None
        #self.stopped = True
        self.q = asyncio.Queue()
        self.play_next_song = asyncio.Event()
        self.stopped = asyncio.Event()
        self.current_song = None
        self.songs_dir = 'radio/'
        self.songs = []
        self.update_song_list()

    @property
    def is_playing(self):
        return self.player is not None and self.player.is_playing() and not self.stopped.is_set()

    def toggle_next_song(self):
        self.bot.loop.call_soon_threadsafe(self.bot.change_status(None))
        if not self.stopped.is_set():
            self.bot.loop.call_soon_threadsafe(self.play_next_song.set)

    def update_song_list(self):
        self.songs = self.bot.pycopy.list_files(self.songs_dir)

    @commands.command(pass_context=True)
    async def join(self, ctx, *, channel_name : str):
        """Зайти на указанный голосовой канал."""
        if self.bot.is_voice_connected():
            await ctx.invoke(self.leave)

        check = lambda c: c.name == channel_name and c.type == discord.ChannelType.voice
        channel = discord.utils.find(check, ctx.message.server.channels)
        if channel is None:
            await self.bot.say('Нет такого голосового канала.')
        await self.bot.join_voice_channel(channel)

    @commands.command(pass_context=True)
    async def leave(self, ctx):
        """Покинуть текущий голосовой каналю"""
        await ctx.invoke(self.stop)
        await self.bot.voice.disconnect()

    @commands.command()
    async def pause(self):
        """Приостановить воспроизведение."""
        if self.player is not None:
            self.player.pause()

    @commands.command()
    async def resume(self):
        """Продолжить воспроизведение."""
        if self.player is not None and not self.is_playing:
            self.player.resume()

    @commands.command()
    async def skip(self):
        """Перейти к следующей песне в очереди."""
        if self.player is not None and self.is_playing:
            self.player.stop()
            self.toggle_next_song()

    @commands.command()
    async def stop(self):
        """Остановить воспроизведение."""
        if self.is_playing:
            self.stopped.set()
            self.player.stop()
            self.player = None

    @commands.command(pass_context=True)
    async def play(self, ctx):
        """Начать воспроизведение песен из очереди."""
        self.stopped.clear()
        if self.player is not None:# and not self.stopped.is_set():
            if not self.is_playing:
                await ctx.invoke(self.resume)
                return
            else:
                await self.bot.say('Уже играю песенку.')
                return

        while True:
            if not self.bot.is_voice_connected():
                author_channel = ctx.message.author.voice_channel
                if author_channel is not None:
                    await ctx.invoke(self.join, channel_name=author_channel.name)
                else:
                    await self.bot.say('Не выбран голосовой канал.')
                    return

            if self.stopped.is_set():
                break
            if self.q.empty():
                await self.q.put(random.choice(self.songs))
            self.play_next_song.clear()
            self.current = await self.q.get()
            self.player = self.bot.voice.create_ffmpeg_player(
                self.bot.pycopy.direct_link(self.songs_dir + self.current),
                after=self.toggle_next_song,
                #options="-loglevel debug -report",
                headers = dict(self.bot.pycopy.session.headers))
            #self.stopped.clear()
            self.player.start()
            song_name = unquote(self.current.split('/')[-1])
            await self.bot.change_status(discord.Game(name=song_name))

            await self.play_next_song.wait()

    @commands.command(aliases=['c'])
    async def current(self):
        """Что там играет?"""
        if self.is_playing:
            song_name = unquote(self.current.split('/')[-1])
            await self.bot.say(song_name)

    @commands.command()
    async def update(self):
        """Обновить список песен."""
        self.update_song_list()
        await self.bot.say("Найдено {} песенок".format(len(self.songs)))

    @commands.command()
    async def list(self):
        """Вывести список всех доступных песен."""
        song_list = ""
        id = 1
        for song in self.songs:
            song_list += "{}. {}\n".format(id, song)
            id += 1
            if len(song_list) > 1800:
                await self.bot.say(song_list)
                song_list = ''
        await self.bot.say(song_list)

    @commands.command()
    async def add(self, song_num : int):
        """Добавить в конец очереди песню с данным номером."""
        await self.q.put(self.songs[song_num-1])
        await self.bot.say("{} будет следующей песенкой".format(self.songs[song_num-1]))

def setup(bot):
    bot.add_cog(Radio(bot))
<|endoftext|>


<commit_before>commands = {}
perms = {}

def add_cmd(name, alias=None, owner=False, admin=False):
    def real_command(func):
        global commands
        global perms
        commands[name] = func
        perms[name] = [admin, owner]
        if alias:
            commands[alias] = func

    return real_command

def call_command(bot, event, irc):
    command = ' '.join(event.arguments).split(' ')
    args = ' '.join(command[1:]) if len(command) > 1 else None
    name = command[0][1:]
    try:
        if checkPerms(event.source.host, owner=perms[name][0], admin=perms[name][0]):
            commands[name](bot, event, irc, args)

    except KeyError:
        irc.reply(event, 'Invalid command {}'.format(name))
    except Exception:
        irc.reply(event, 'Oops, an unknown error occured')
    else:
        privmsg = event.target == bot.config['nickname']
        target = "a private message" if privmsg else event.target
        print("{} called {} in {}".format(event.source, name, target))

def checkPerms(host, owner=False, admin=False):
    owner_list = ['botters/wolfy1339']
    admin_list = []
    if owner and host in owner_list:
        return True
    elif admin and host in admin_list or admin and host in owner_list:
        return True
    elif not owner and not admin:
        return True
    else:
        return False

<commit_msg>Remove trailing whitespace<commit_after>commands = {}
perms = {}

def add_cmd(name, alias=None, owner=False, admin=False):
    def real_command(func):
        global commands
        global perms
        commands[name] = func
        perms[name] = [admin, owner]
        if alias:
            commands[alias] = func

    return real_command

def call_command(bot, event, irc):
    command = ' '.join(event.arguments).split(' ')
    args = ' '.join(command[1:]) if len(command) > 1 else None
    name = command[0][1:]
    try:
        if checkPerms(event.source.host, owner=perms[name][0], admin=perms[name][0]):
            commands[name](bot, event, irc, args)
    except KeyError:
        irc.reply(event, 'Invalid command {}'.format(name))
    except Exception:
        irc.reply(event, 'Oops, an unknown error occured')
    else:
        privmsg = event.target == bot.config['nickname']
        target = "a private message" if privmsg else event.target
        print("{} called {} in {}".format(event.source, name, target))

def checkPerms(host, owner=False, admin=False):
    owner_list = ['botters/wolfy1339']
    admin_list = []
    if owner and host in owner_list:
        return True
    elif admin and host in admin_list or admin and host in owner_list:
        return True
    elif not owner and not admin:
        return True
    else:
        return False

<|endoftext|>


<commit_before># Copyright (c) 2010 by Ladislav Lhotka, CESNET <lhotka@cesnet.cz>
#
# Python class representing a node in a RELAX NG schema.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

from xml.sax.saxutils import escape

class SchemaNode(object):

    """This class represents a node in a RELAX NG schema.

    The details are tailored to the specific features of the hybrid
    DSDL schema generated from YANG modules, but the class may be
    reasonably used for representing any other RELAX NG schema.

    Specific types of nodes are created using class methods below.

    Instance variables:

    * `self.attr` - dictionary of XML attributes. Keys are attribute
      names and values attribute values.

    * `self.children` - list of child nodes.

    * `self.default` - default value (only for "element" nodes)

    * `self.interleave` - boolean flag determining the interleave
      status. If True, the children of `self` will end up inside
      <interleave>.

    * `self.keys` - list of QNames of YANG list keys (only for "_list_"
      nodes having children).

    * `self.keymap` - dictionary of key nodes (only for "_list_" nodes
      having children). The keys of the dictionary are the QNames of
      YANG list keys.

    * `self.minEl` - minimum number of items (only for "_list_" nodes).

    * `self.maxEl` - maximum number of items (only for "_list_" nodes).

    * `self.name` - name of the schema node (XML element name).

    * `self.occur` - specifies the occurrence status using interger
      values: 0=optional, 1=implicit, 2=mandatory, 3=presence.

    * `self.parent` - parent node.

    * `self.text` - text content.
    """
    def element(cls, name, parent=None, interleave=None, occur=0):
        """Create an element node."""
        node = cls("element", parent, interleave=interleave)
        node.attr["name"] = name
        node.occur = occur
        return node
    element = classmethod(element)

    def leaf_list(cls, name, parent=None, interleave=None):
        """Create _list_ node for a leaf-list."""
        node = cls("_list_", parent, interleave=interleave)
        node.attr["name"] = name
        node.keys = None
        node.minEl = "0"
        node.maxEl = None
        return node
    leaf_list = classmethod(leaf_list)

    def list(cls, name, parent=None, interleave=None):
        """Create _list_ node for a list."""
        node = cls.leaf_list(name, parent, interleave=interleave)
        node.keys = []
        node.keymap = {}
        node.occur = 3
        return node
    list = classmethod(list)

    def choice(cls, parent=None, occur=0):
        """Create choice node."""
        node = cls("choice", parent)
        node.occur = occur
        node.default_case = None
        return node
    choice = classmethod(choice)

    def case(cls, parent=None):
        """Create case node."""
        node = cls("case", parent)
        node.occur = 0
        return node
    case = classmethod(case)

    def define(cls, name, parent=None, interleave=False):
        """Create define node."""
        node = cls("define", parent, interleave=interleave)
        node.occur = 0
        node.attr["name"] = name
        return node
    define = classmethod(define)

    def __init__(self, name, parent=None, text="", interleave=None):
        """Initialize the object under `parent`.
        """
        self.name = name
        self.parent = parent
        if parent is not None: parent.children.append(self)
        self.text = text
        self.adjust_interleave(interleave)
        self.children = []
        self.attr = {}

    def adjust_interleave(self, interleave):
        """Inherit interleave status from parent if undefined."""
        if interleave == None and self.parent:
            self.interleave = self.parent.interleave
        else:
            self.interleave = interleave

    def subnode(self, node):
        """Make `node` receiver's child."""
        self.children.append(node)
        node.parent = self
        node.adjust_interleave(None)

    def set_attr(self, key, value):
        """Set attribute `key` to `value` and return the receiver."""
        self.attr[key] = value
        return self

    def data_nodes_count(self):
        """Return the number of receiver's data subnodes."""
        return len([ch for ch in self.children if ch.name in
                    ("element", "choice", "_list_","ref", "grammar")])

    def start_tag(self, alt=None, empty=False):
        """Return XML start tag for the receiver."""
        if alt:
            name = alt
        else:
            name = self.name
        result = "<" + name
        for it in self.attr:
            result += ' %s="%s"' % (it, escape(self.attr[it]))
        if empty:
            return result + "/>"
        else:
            return result + ">"

    def end_tag(self, alt=None):
        """Return XML end tag for the receiver."""
        if alt:
            name = alt
        else:
            name = self.name
        return "</" + name + ">"

    def serialize(self, occur=None):
        """Return RELAX NG representation of the receiver and subtree.
        """
        return (self.ser_format.get(self.name, SchemaNode._default_format)
                (self, occur) % (escape(self.text) + ''.join
                                 ([ch.serialize() for ch in self.children])))

    def _default_format(self, occur):
        """Return the default serialization format."""
        if self.text or self.children:
            return self.start_tag() + "%s" + self.end_tag()
        else:
            return self.start_tag(empty=True) + "%s"

    def _define_format(self, occur):
        """Return the serialization format for a define node."""
        if hasattr(self, "default"):
            self.attr["nma:default"] = self.default
        return self.start_tag() + self._chorder() + self.end_tag()

    def _element_format(self, occur):
        """Return the serialization format for an element node."""
        if occur:
            occ = occur
        else:
            occ = self.occur
        if occ == 1:
            if hasattr(self, "default"):
                self.attr["nma:default"] = self.default
            else:
                self.attr["nma:implicit"] = "true"
        fmt = self.start_tag() + self._chorder() + self.end_tag()
        if (occ == 2 or self.parent.name == "choice"
            or self.parent.name == "case" and self.data_nodes_count() == 1):
            return fmt
        else:
            return "<optional>" + fmt + "</optional>"

    def _chorder(self):
        """Add <interleave> if child order is arbitrary."""
        if (self.interleave and self.data_nodes_count() > 1):
            return "<interleave>%s</interleave>"
        return "%s"

    def _list_format(self, occur):
        """Return the serialization format for a _list_ node."""
        if self.keys:
            self.attr["nma:key"] = " ".join(self.keys)
            keys = ''.join([self.keymap[k].serialize(occur=2)
                            for k in self.keys])
        else:
            keys = ""
        if self.maxEl:
            self.attr["nma:max-elements"] = self.maxEl
        if int(self.minEl) == 0:
            ord_ = "zeroOrMore"
        else:
            ord_ = "oneOrMore"
            if int(self.minEl) > 1:
                self.attr["nma:min-elements"] = self.minEl
        return ("<" + ord_ + ">" + self.start_tag("element") + keys +
                self._chorder() + self.end_tag("element") + "</" + ord_ + ">")

    def _choice_format(self, occur):
        """Return the serialization format for a choice node."""
        fmt = self.start_tag() + "%s" + self.end_tag()
        if self.occur < 2:
            return "<optional>" + fmt + "</optional>"
        else:
            return fmt

    def _case_format(self, occur):
        """Return the serialization format for a case node."""
        if self.occur == 1:
            self.attr["nma:implicit"] = "true"
        if len(self.children) == 1 or not self.interleave:
            return self.start_tag("group") + "%s" + self.end_tag("group")
        else:
            return (self.start_tag("interleave") + "%s" +
                    self.end_tag("interleave"))

    ser_format = { "element": _element_format,
                   "_list_": _list_format,
                   "choice": _choice_format,
                   "case": _case_format,
                   "define": _define_format,
                   }
    """Class variable - dictionary of methods returning string
    serialization formats. Keys are node names."""
<commit_msg>Interleave for elements other that rng:element.<commit_after># Copyright (c) 2010 by Ladislav Lhotka, CESNET <lhotka@cesnet.cz>
#
# Python class representing a node in a RELAX NG schema.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

from xml.sax.saxutils import escape

class SchemaNode(object):

    """This class represents a node in a RELAX NG schema.

    The details are tailored to the specific features of the hybrid
    DSDL schema generated from YANG modules, but the class may be
    reasonably used for representing any other RELAX NG schema.

    Specific types of nodes are created using class methods below.

    Instance variables:

    * `self.attr` - dictionary of XML attributes. Keys are attribute
      names and values attribute values.

    * `self.children` - list of child nodes.

    * `self.default` - default value (only for "element" nodes)

    * `self.interleave` - boolean flag determining the interleave
      status. If True, the children of `self` will end up inside
      <interleave>.

    * `self.keys` - list of QNames of YANG list keys (only for "_list_"
      nodes having children).

    * `self.keymap` - dictionary of key nodes (only for "_list_" nodes
      having children). The keys of the dictionary are the QNames of
      YANG list keys.

    * `self.minEl` - minimum number of items (only for "_list_" nodes).

    * `self.maxEl` - maximum number of items (only for "_list_" nodes).

    * `self.name` - name of the schema node (XML element name).

    * `self.occur` - specifies the occurrence status using interger
      values: 0=optional, 1=implicit, 2=mandatory, 3=presence.

    * `self.parent` - parent node.

    * `self.text` - text content.
    """
    def element(cls, name, parent=None, interleave=None, occur=0):
        """Create an element node."""
        node = cls("element", parent, interleave=interleave)
        node.attr["name"] = name
        node.occur = occur
        return node
    element = classmethod(element)

    def leaf_list(cls, name, parent=None, interleave=None):
        """Create _list_ node for a leaf-list."""
        node = cls("_list_", parent, interleave=interleave)
        node.attr["name"] = name
        node.keys = None
        node.minEl = "0"
        node.maxEl = None
        return node
    leaf_list = classmethod(leaf_list)

    def list(cls, name, parent=None, interleave=None):
        """Create _list_ node for a list."""
        node = cls.leaf_list(name, parent, interleave=interleave)
        node.keys = []
        node.keymap = {}
        node.occur = 3
        return node
    list = classmethod(list)

    def choice(cls, parent=None, occur=0):
        """Create choice node."""
        node = cls("choice", parent)
        node.occur = occur
        node.default_case = None
        return node
    choice = classmethod(choice)

    def case(cls, parent=None):
        """Create case node."""
        node = cls("case", parent)
        node.occur = 0
        return node
    case = classmethod(case)

    def define(cls, name, parent=None, interleave=False):
        """Create define node."""
        node = cls("define", parent, interleave=interleave)
        node.occur = 0
        node.attr["name"] = name
        return node
    define = classmethod(define)

    def __init__(self, name, parent=None, text="", interleave=None):
        """Initialize the object under `parent`.
        """
        self.name = name
        self.parent = parent
        if parent is not None: parent.children.append(self)
        self.text = text
        self.adjust_interleave(interleave)
        self.children = []
        self.attr = {}

    def adjust_interleave(self, interleave):
        """Inherit interleave status from parent if undefined."""
        if interleave == None and self.parent:
            self.interleave = self.parent.interleave
        else:
            self.interleave = interleave

    def subnode(self, node):
        """Make `node` receiver's child."""
        self.children.append(node)
        node.parent = self
        node.adjust_interleave(None)

    def set_attr(self, key, value):
        """Set attribute `key` to `value` and return the receiver."""
        self.attr[key] = value
        return self

    def data_nodes_count(self):
        """Return the number of receiver's data subnodes."""
        return len([ch for ch in self.children if ch.name in
                    ("element", "choice", "_list_","ref", "grammar")])

    def start_tag(self, alt=None, empty=False):
        """Return XML start tag for the receiver."""
        if alt:
            name = alt
        else:
            name = self.name
        result = "<" + name
        for it in self.attr:
            result += ' %s="%s"' % (it, escape(self.attr[it]))
        if empty:
            return result + "/>"
        else:
            return result + ">"

    def end_tag(self, alt=None):
        """Return XML end tag for the receiver."""
        if alt:
            name = alt
        else:
            name = self.name
        return "</" + name + ">"

    def serialize(self, occur=None):
        """Return RELAX NG representation of the receiver and subtree.
        """
        return (self.ser_format.get(self.name, SchemaNode._default_format)
                (self, occur) % (escape(self.text) + ''.join
                                 ([ch.serialize() for ch in self.children])))

    def _default_format(self, occur):
        """Return the default serialization format."""
        if self.text or self.children:
            return self.start_tag() + self._chorder() + self.end_tag()
        else:
            return self.start_tag(empty=True) + "%s"

    def _define_format(self, occur):
        """Return the serialization format for a define node."""
        if hasattr(self, "default"):
            self.attr["nma:default"] = self.default
        return self.start_tag() + self._chorder() + self.end_tag()

    def _element_format(self, occur):
        """Return the serialization format for an element node."""
        if occur:
            occ = occur
        else:
            occ = self.occur
        if occ == 1:
            if hasattr(self, "default"):
                self.attr["nma:default"] = self.default
            else:
                self.attr["nma:implicit"] = "true"
        fmt = self.start_tag() + self._chorder() + self.end_tag()
        if (occ == 2 or self.parent.name == "choice"
            or self.parent.name == "case" and self.data_nodes_count() == 1):
            return fmt
        else:
            return "<optional>" + fmt + "</optional>"

    def _chorder(self):
        """Add <interleave> if child order is arbitrary."""
        if (self.interleave and self.data_nodes_count() > 1):
            return "<interleave>%s</interleave>"
        return "%s"

    def _list_format(self, occur):
        """Return the serialization format for a _list_ node."""
        if self.keys:
            self.attr["nma:key"] = " ".join(self.keys)
            keys = ''.join([self.keymap[k].serialize(occur=2)
                            for k in self.keys])
        else:
            keys = ""
        if self.maxEl:
            self.attr["nma:max-elements"] = self.maxEl
        if int(self.minEl) == 0:
            ord_ = "zeroOrMore"
        else:
            ord_ = "oneOrMore"
            if int(self.minEl) > 1:
                self.attr["nma:min-elements"] = self.minEl
        return ("<" + ord_ + ">" + self.start_tag("element") + keys +
                self._chorder() + self.end_tag("element") + "</" + ord_ + ">")

    def _choice_format(self, occur):
        """Return the serialization format for a choice node."""
        fmt = self.start_tag() + "%s" + self.end_tag()
        if self.occur < 2:
            return "<optional>" + fmt + "</optional>"
        else:
            return fmt

    def _case_format(self, occur):
        """Return the serialization format for a case node."""
        if self.occur == 1:
            self.attr["nma:implicit"] = "true"
        if len(self.children) == 1 or not self.interleave:
            return self.start_tag("group") + "%s" + self.end_tag("group")
        else:
            return (self.start_tag("interleave") + "%s" +
                    self.end_tag("interleave"))

    ser_format = { "element": _element_format,
                   "_list_": _list_format,
                   "choice": _choice_format,
                   "case": _case_format,
                   "define": _define_format,
                   }
    """Class variable - dictionary of methods returning string
    serialization formats. Keys are node names."""
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
import os
import sys
import argparse
import datetime
import time
import xlsxwriter
from get_solr_json import get_solr_json, create_facet_dict

facet_query = { 'q': '*:*',
        'rows' : 0,
        'wt' : 'json',
        'facet': 'true',
        }

def get_facet_query(solr_url, field, **kwargs):
    '''Return a facet data dict to muck with based on "field")
    '''
    query = facet_query.copy()
    query.update({'facet.field':field})
    solr_json = get_solr_json(solr_url=solr_url, query=query, **kwargs)
    return create_facet_dict(solr_json, field)

def create_report_workbook(outdir):
    today = datetime.date.today()
    fileout = os.path.join(outdir, '{}-{}.xlsx'.format(today,
                                            'duplicates'))
    runtime = '{}'.format(time.ctime())

    # open the workbook
    workbook = xlsxwriter.Workbook(fileout)

    # formats
    header_format = workbook.add_format({'bold': True, })
    number_format = workbook.add_format()
    number_format.set_num_format('#,##0')
    return workbook, header_format, number_format

def main(solr_url='https://52.10.100.133/solr/dc-collection/query',
        outdir=None,
        api_key=None, digest_user=None, digest_pswd=None):
    field = 'reference_image_md5'
    #print "======FIELD:{} {} {}".format(field, digest_user, digest_pswd)
    #print "======FIELD:{} {} {}".format(field, api_key, solr_url)
    dup_md5 = get_facet_query(solr_url, field, api_key=api_key,
            digest_user=digest_user, digest_pswd=digest_pswd)
    #now for each md5, get the collection_url that it is in
    for md5, count in dup_md5.items():
        query = { 'q': md5,
            'rows' : 0,
            'wt' : 'json',
            'facet': 'true',
            'facet.field': 'collection_url'
            }
        collection_urls = create_facet_dict(get_solr_json(solr_url,
                query=query, api_key=api_key,
                digest_user=digest_user, digest_pswd=digest_pswd),
                'collection_url')
        dup_md5[md5] = (count, collection_urls)
    workbook, header_format, number_format = create_report_workbook(outdir)
    page = workbook.add_worksheet(field)
    # headers
    page.write(0, 0, field, header_format)
    page.write(0, 1, 'Number Dups', header_format)
    page.write(0, 2, 'Collections', header_format)
    # width
    page.set_column(0, 0, 50, )
    page.set_column(1, 1, 10, )
    page.set_column(2, 10, 50, )
    row = 1
    for md5, data in dup_md5.items():
        page.write(row, 0, md5)
        page.write(row, 1, data[0])
        column = 2
        for c_url, num in data[1].items():
            coll_data = ' - '.join((c_url, str(num)))
            page.write(row, column, coll_data)
            column += 1
        row += 1
    #end md5 page
    #missing type_ss
    query = { 'q': '-type_ss:[* TO *]',
            'rows' : 0,
            'wt' : 'json',
            'facet': 'true',
            'facet.field': 'collection_url'
            }
    collection_urls = create_facet_dict(get_solr_json(solr_url,
                query=query, api_key=api_key,
                digest_user=digest_user, digest_pswd=digest_pswd),
                'collection_url')
    field = 'missing type_ss'
    page = workbook.add_worksheet(field)
    # headers
    page.write(0, 0, field, header_format)
    page.write(0, 1, 'Number Missing', header_format)
    # width
    page.set_column(0, 0, 50, )
    page.set_column(1, 1, 10, )
    row = 1
    for collection_url, count in collection_urls.items():
        page.write(row, 0, collection_url)
        page.write(row, 1, count)
        row += 1

if __name__=='__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--solr_url', type=str)
    parser.add_argument('--api_key', type=str)
    parser.add_argument('--digest_user', type=str)
    parser.add_argument('--digest_pswd', type=str)
    parser.add_argument('outdir', nargs=1, type=str)

    args = parser.parse_args()

    print "ARGS OUTDIR:{}".format(args.outdir)
    solr_url = args.solr_url if args.solr_url else 'https://52.10.100.133/solr/dc-collection/query'
    if not args.api_key and not args.digest_user:
        parser.print_help()
        sys.exit(7)
    sys.exit(main(solr_url=solr_url, outdir=args.outdir[0],
        api_key=args.api_key,
        digest_user=args.digest_user, digest_pswd=args.digest_pswd))

# Copyright © 2016, Regents of the University of California
# All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# - Redistributions of source code must retain the above copyright notice,
#   this list of conditions and the following disclaimer.
# - Redistributions in binary form must reproduce the above copyright notice,
#   this list of conditions and the following disclaimer in the documentation
#   and/or other materials provided with the distribution.
# - Neither the name of the University of California nor the names of its
#   contributors may be used to endorse or promote products derived from this
#   software without specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

<commit_msg>make name duplicates_and_missing_fields<commit_after># -*- coding: utf-8 -*-
import os
import sys
import argparse
import datetime
import time
import ConfigParser
import xlsxwriter
from get_solr_json import get_solr_json, create_facet_dict

facet_query = { 'q': '*:*',
        'rows' : 0,
        'wt' : 'json',
        'facet': 'true',
        }
FNAME = 'duplicates_and_missing_fields'

def get_facet_query(solr_url, field, **kwargs):
    '''Return a facet data dict to muck with based on "field")
    '''
    query = facet_query.copy()
    query.update({'facet.field':field})
    solr_json = get_solr_json(solr_url=solr_url, query=query, **kwargs)
    return create_facet_dict(solr_json, field)

def create_report_workbook(outdir):
    today = datetime.date.today()
    fileout = os.path.join(outdir, '{}-{}.xlsx'.format(today,
                                            FNAME))
    runtime = '{}'.format(time.ctime())

    # open the workbook
    workbook = xlsxwriter.Workbook(fileout)

    # formats
    header_format = workbook.add_format({'bold': True, })
    number_format = workbook.add_format()
    number_format.set_num_format('#,##0')
    return workbook, header_format, number_format

def main(solr_url='https://52.10.100.133/solr/dc-collection/query',
        outdir=None,
        api_key=None, digest_user=None, digest_pswd=None):
    print "USING SOLR:{}".format(solr_url)
    field = 'reference_image_md5'
    #print "======FIELD:{} {} {}".format(field, digest_user, digest_pswd)
    #print "======FIELD:{} {} {}".format(field, api_key, solr_url)
    dup_md5 = get_facet_query(solr_url, field, api_key=api_key,
            digest_user=digest_user, digest_pswd=digest_pswd)
    #now for each md5, get the collection_url that it is in
    for md5, count in dup_md5.items():
        query = { 'q': md5,
            'rows' : 0,
            'wt' : 'json',
            'facet': 'true',
            'facet.field': 'collection_url'
            }
        collection_urls = create_facet_dict(get_solr_json(solr_url,
                query=query, api_key=api_key,
                digest_user=digest_user, digest_pswd=digest_pswd),
                'collection_url')
        dup_md5[md5] = (count, collection_urls)
    workbook, header_format, number_format = create_report_workbook(outdir)
    page = workbook.add_worksheet(field)
    # headers
    page.write(0, 0, field, header_format)
    page.write(0, 1, 'Number Dups', header_format)
    page.write(0, 2, 'Collections', header_format)
    # width
    page.set_column(0, 0, 50, )
    page.set_column(1, 1, 10, )
    page.set_column(2, 10, 50, )
    row = 1
    for md5, data in dup_md5.items():
        page.write(row, 0, md5)
        page.write(row, 1, data[0])
        column = 2
        for c_url, num in data[1].items():
            coll_data = ' - '.join((c_url, str(num)))
            page.write(row, column, coll_data)
            column += 1
        row += 1
    #end md5 page
    #missing type_ss
    query = { 'q': '-type_ss:[* TO *]',
            'rows' : 0,
            'wt' : 'json',
            'facet': 'true',
            'facet.field': 'collection_url'
            }
    collection_urls = create_facet_dict(get_solr_json(solr_url,
                query=query, api_key=api_key,
                digest_user=digest_user, digest_pswd=digest_pswd),
                'collection_url')
    field = 'missing type_ss'
    page = workbook.add_worksheet(field)
    # headers
    page.write(0, 0, field, header_format)
    page.write(0, 1, 'Number Missing', header_format)
    # width
    page.set_column(0, 0, 50, )
    page.set_column(1, 1, 10, )
    row = 1
    for collection_url, count in collection_urls.items():
        page.write(row, 0, collection_url)
        page.write(row, 1, count)
        row += 1

if __name__=='__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--solr_url', type=str)
    parser.add_argument('--api_key', type=str)
    parser.add_argument('--digest_user', type=str)
    parser.add_argument('--digest_pswd', type=str)
    parser.add_argument('outdir', nargs=1, type=str)

    args = parser.parse_args()

    solr_url = args.solr_url if args.solr_url else 'https://52.10.100.133/solr/dc-collection/query'
    digest_user = digest_pswd = None
    if not args.api_key and not args.digest_user:
        #use config file for qa_counts
        config = ConfigParser.SafeConfigParser()
        config.read('report.ini')
        solr_url = config.get('new-index-api', 'solrUrl')
        api_key = config.get('new-index-api', 'solrAuth')
    else:
        api_key = args.api_key
        digest_user = args.digest_user
        digest_pswd = args.digest_pswd
    sys.exit(main(solr_url=solr_url, outdir=args.outdir[0],
        api_key=api_key,
        digest_user=digest_user, digest_pswd=digest_pswd))

# Copyright © 2016, Regents of the University of California
# All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# - Redistributions of source code must retain the above copyright notice,
#   this list of conditions and the following disclaimer.
# - Redistributions in binary form must reproduce the above copyright notice,
#   this list of conditions and the following disclaimer in the documentation
#   and/or other materials provided with the distribution.
# - Neither the name of the University of California nor the names of its
#   contributors may be used to endorse or promote products derived from this
#   software without specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

<|endoftext|>