#!/usr/bin/env python
#
#-----------------------------------------------------------------------
# A test suite for the table interface built on bsddb.db
#-----------------------------------------------------------------------
#
# Copyright (C) 2000, 2001 by Autonomous Zone Industries
# Copyright (C) 2002 Gregory P. Smith
#
# March 20, 2000
#
# License:      This is free software.  You may use this software for any
#               purpose including modification/redistribution, so long as
#               this header remains intact and that you do not claim any
#               rights of ownership or authorship of this software.  This
#               software has been tested, but no warranty is expressed or
#               implied.
#
#   --  Gregory P. Smith <greg@electricrain.com>
#
# $Id: test_dbtables.py 35267 2004-02-12 17:35:32Z doerwalter $

import sys, os, re
try:
    import cPickle
    pickle = cPickle
except ImportError:
    import pickle

import unittest
from test_all import verbose

try:
    # For Pythons w/distutils pybsddb
    from bsddb3 import db, dbtables
except ImportError:
    # For Python 2.3
    from bsddb import db, dbtables

#----------------------------------------------------------------------

class TableDBTestCase(unittest.TestCase):
    db_home = 'db_home'
    db_name = 'test-table.db'

    def setUp(self):
        homeDir = os.path.join(os.path.dirname(sys.argv[0]), 'db_home')
        self.homeDir = homeDir
        try: os.mkdir(homeDir)
        except os.error: pass
        self.tdb = dbtables.bsdTableDB(
            filename='tabletest.db', dbhome=homeDir, create=1)

    def tearDown(self):
        self.tdb.close()
        import glob
        files = glob.glob(os.path.join(self.homeDir, '*'))
        for file in files:
            os.remove(file)

    def test01(self):
        tabname = "test01"
        colname = 'cool numbers'
        try:
            self.tdb.Drop(tabname)
        except dbtables.TableDBError:
            pass
        self.tdb.CreateTable(tabname, [colname])
        self.tdb.Insert(tabname, {colname: pickle.dumps(3.14159, 1)})

        if verbose:
            self.tdb._db_print()

        values = self.tdb.Select(
            tabname, [colname], conditions={colname: None})

        colval = pickle.loads(values[0][colname])
        assert(colval > 3.141 and colval < 3.142)

    def test02(self):
        tabname = "test02"
        col0 = 'coolness factor'
        col1 = 'but can it fly?'
        col2 = 'Species'
        testinfo = [
            {col0: pickle.dumps(8, 1), col1: 'no', col2: 'Penguin'},
            {col0: pickle.dumps(-1, 1), col1: 'no', col2: 'Turkey'},
            {col0: pickle.dumps(9, 1), col1: 'yes', col2: 'SR-71A Blackbird'}
        ]

        try:
            self.tdb.Drop(tabname)
        except dbtables.TableDBError:
            pass
        self.tdb.CreateTable(tabname, [col0, col1, col2])
        for row in testinfo :
            self.tdb.Insert(tabname, row)

        values = self.tdb.Select(tabname, [col2],
            conditions={col0: lambda x: pickle.loads(x) >= 8})

        assert len(values) == 2
        if values[0]['Species'] == 'Penguin' :
            assert values[1]['Species'] == 'SR-71A Blackbird'
        elif values[0]['Species'] == 'SR-71A Blackbird' :
            assert values[1]['Species'] == 'Penguin'
        else :
            if verbose:
                print "values= %r" % (values,)
            raise "Wrong values returned!"

    def test03(self):
        tabname = "test03"
        try:
            self.tdb.Drop(tabname)
        except dbtables.TableDBError:
            pass
        if verbose:
            print '...before CreateTable...'
            self.tdb._db_print()
        self.tdb.CreateTable(tabname, ['a', 'b', 'c', 'd', 'e'])
        if verbose:
            print '...after CreateTable...'
            self.tdb._db_print()
        self.tdb.Drop(tabname)
        if verbose:
            print '...after Drop...'
            self.tdb._db_print()
        self.tdb.CreateTable(tabname, ['a', 'b', 'c', 'd', 'e'])

        try:
            self.tdb.Insert(tabname,
                            {'a': "",
                             'e': pickle.dumps([{4:5, 6:7}, 'foo'], 1),
                             'f': "Zero"})
            assert 0
        except dbtables.TableDBError:
            pass

        try:
            self.tdb.Select(tabname, [], conditions={'foo': '123'})
            assert 0
        except dbtables.TableDBError:
            pass

        self.tdb.Insert(tabname,
                        {'a': '42',
                         'b': "bad",
                         'c': "meep",
                         'e': 'Fuzzy wuzzy was a bear'})
        self.tdb.Insert(tabname,
                        {'a': '581750',
                         'b': "good",
                         'd': "bla",
                         'c': "black",
                         'e': 'fuzzy was here'})
        self.tdb.Insert(tabname,
                        {'a': '800000',
                         'b': "good",
                         'd': "bla",
                         'c': "black",
                         'e': 'Fuzzy wuzzy is a bear'})

        if verbose:
            self.tdb._db_print()

        # this should return two rows
        values = self.tdb.Select(tabname, ['b', 'a', 'd'],
            conditions={'e': re.compile('wuzzy').search,
                        'a': re.compile('^[0-9]+$').match})
        assert len(values) == 2

        # now lets delete one of them and try again
        self.tdb.Delete(tabname, conditions={'b': dbtables.ExactCond('good')})
        values = self.tdb.Select(
            tabname, ['a', 'd', 'b'],
            conditions={'e': dbtables.PrefixCond('Fuzzy')})
        assert len(values) == 1
        assert values[0]['d'] == None

        values = self.tdb.Select(tabname, ['b'],
            conditions={'c': lambda c: c == 'meep'})
        assert len(values) == 1
        assert values[0]['b'] == "bad"

    def test04_MultiCondSelect(self):
        tabname = "test04_MultiCondSelect"
        try:
            self.tdb.Drop(tabname)
        except dbtables.TableDBError:
            pass
        self.tdb.CreateTable(tabname, ['a', 'b', 'c', 'd', 'e'])

        try:
            self.tdb.Insert(tabname,
                            {'a': "",
                             'e': pickle.dumps([{4:5, 6:7}, 'foo'], 1),
                             'f': "Zero"})
            assert 0
        except dbtables.TableDBError:
            pass

        self.tdb.Insert(tabname, {'a': "A", 'b': "B", 'c': "C", 'd': "D",
                                  'e': "E"})
        self.tdb.Insert(tabname, {'a': "-A", 'b': "-B", 'c': "-C", 'd': "-D",
                                  'e': "-E"})
        self.tdb.Insert(tabname, {'a': "A-", 'b': "B-", 'c': "C-", 'd': "D-",
                                  'e': "E-"})

        if verbose:
            self.tdb._db_print()

        # This select should return 0 rows.  it is designed to test
        # the bug identified and fixed in sourceforge bug # 590449
        # (Big Thanks to "Rob Tillotson (n9mtb)" for tracking this down
        # and supplying a fix!!  This one caused many headaches to say
        # the least...)
        values = self.tdb.Select(tabname, ['b', 'a', 'd'],
            conditions={'e': dbtables.ExactCond('E'),
                        'a': dbtables.ExactCond('A'),
                        'd': dbtables.PrefixCond('-')
                       } )
        assert len(values) == 0, values

    def test_CreateOrExtend(self):
        tabname = "test_CreateOrExtend"

        self.tdb.CreateOrExtendTable(
            tabname, ['name', 'taste', 'filling', 'alcohol content', 'price'])
        try:
            self.tdb.Insert(tabname,
                            {'taste': 'crap',
                             'filling': 'no',
                             'is it Guinness?': 'no'})
            assert 0, "Insert should've failed due to bad column name"
        except:
            pass
        self.tdb.CreateOrExtendTable(tabname,
                                     ['name', 'taste', 'is it Guinness?'])

        # these should both succeed as the table should contain the union of both sets of columns.
        self.tdb.Insert(tabname, {'taste': 'crap', 'filling': 'no',
                                  'is it Guinness?': 'no'})
        self.tdb.Insert(tabname, {'taste': 'great', 'filling': 'yes',
                                  'is it Guinness?': 'yes',
                                  'name': 'Guinness'})

    def test_CondObjs(self):
        tabname = "test_CondObjs"

        self.tdb.CreateTable(tabname, ['a', 'b', 'c', 'd', 'e', 'p'])

        self.tdb.Insert(tabname, {'a': "the letter A",
                                  'b': "the letter B",
                                  'c': "is for cookie"})
        self.tdb.Insert(tabname, {'a': "is for aardvark",
                                  'e': "the letter E",
                                  'c': "is for cookie",
                                  'd': "is for dog"})
        self.tdb.Insert(tabname, {'a': "the letter A",
                                  'e': "the letter E",
                                  'c': "is for cookie",
                                  'p': "is for Python"})

        values = self.tdb.Select(
            tabname, ['p', 'e'],
            conditions={'e': dbtables.PrefixCond('the l')})
        assert len(values) == 2, values
        assert values[0]['e'] == values[1]['e'], values
        assert values[0]['p'] != values[1]['p'], values

        values = self.tdb.Select(
            tabname, ['d', 'a'],
            conditions={'a': dbtables.LikeCond('%aardvark%')})
        assert len(values) == 1, values
        assert values[0]['d'] == "is for dog", values
        assert values[0]['a'] == "is for aardvark", values

        values = self.tdb.Select(tabname, None,
                                 {'b': dbtables.Cond(),
                                  'e':dbtables.LikeCond('%letter%'),
                                  'a':dbtables.PrefixCond('is'),
                                  'd':dbtables.ExactCond('is for dog'),
                                  'c':dbtables.PrefixCond('is for'),
                                  'p':lambda s: not s})
        assert len(values) == 1, values
        assert values[0]['d'] == "is for dog", values


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

import datetime
import logging

import bleach

from django import http
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404, redirect, render
from django.utils import timezone

from .forms import AnnouncementForm, AnnouncementRequestForm
from .models import Announcement, AnnouncementRequest
from .notifications import (admin_request_announcement_email, announcement_approved_email, announcement_posted_email, announcement_posted_twitter,
                            request_announcement_email)
from ..auth.decorators import announcements_admin_required
from ..dashboard.views import dashboard_view
from ..groups.models import Group

logger = logging.getLogger(__name__)

@login_required
def view_announcements(request):
    """Show the dashboard with only announcements."""
    return dashboard_view(request, show_widgets=False, ignore_dashboard_types=["event"])

@login_required
def view_announcements_archive(request):
    """Show the dashboard with only announcements, showing expired posts."""
    return dashboard_view(request, show_widgets=False, show_expired=True, ignore_dashboard_types=["event"])

def announcement_posted_hook(request, obj):
    """Runs whenever a new announcement is created, or a request is approved and posted.

    obj: The Announcement object

    """
    logger.debug("Announcement posted")

    if obj.notify_post:
        logger.debug("Announcement notify on")
        announcement_posted_twitter(request, obj)
        try:
            notify_all = obj.notify_email_all
        except AttributeError:
            notify_all = False

        try:
            if notify_all:
                announcement_posted_email(request, obj, True)
            else:
                announcement_posted_email(request, obj)
        except Exception as e:
            logger.error("Exception when emailing announcement: {}".format(e))
            messages.error("Exception when emailing announcement: {}".format(e))
            raise e
    else:
        logger.debug("Announcement notify off")

def announcement_approved_hook(request, obj, req):
    """Runs whenever an administrator approves an announcement request.

    obj: the Announcement object
    req: the AnnouncementRequest object

    """
    announcement_approved_email(request, obj, req)

@login_required
def request_announcement_view(request):
    """The request announcement page."""
    if request.method == "POST":
        form = AnnouncementRequestForm(request.POST)
        logger.debug(form)
        logger.debug(form.data)

        if form.is_valid():
            teacher_objs = form.cleaned_data["teachers_requested"]
            logger.debug("teacher objs:")
            logger.debug(teacher_objs)

            if len(teacher_objs) > 2:
                messages.error(request, "Please select a maximum of 2 teachers to approve this post.")
            else:
                obj = form.save(commit=True)
                obj.user = request.user
                # SAFE HTML
                obj.content = bleach.linkify(obj.content)

                obj.save()

                ann = AnnouncementRequest.objects.get(id=obj.id)
                logger.debug(teacher_objs)
                approve_self = False
                for teacher in teacher_objs:
                    ann.teachers_requested.add(teacher)
                    if teacher == request.user:
                        approve_self = True
                ann.save()

                if approve_self:
                    ann.teachers_approved.add(teacher)
                    ann.save()
                    admin_request_announcement_email(request, form, ann)
                    ann.admin_email_sent = True
                    ann.save()

                    messages.success(request, "Successfully added approved announcement request. An Intranet administrator "
                                     "will review and post the announcement shortly. (Notification sent.)")
                else:
                    request_announcement_email(request, form, obj)
                    messages.success(request, "Successfully added announcement request.")
                return redirect("index")
        else:
            messages.error(request, "Error adding announcement request")
    else:
        form = AnnouncementRequestForm()
    return render(request, "announcements/request.html", {"form": form, "action": "add"})

@login_required
def approve_announcement_view(request, req_id):
    """The approve announcement page. Teachers will be linked to this page from an email.

    req_id: The ID of the AnnouncementRequest

    """
    req = get_object_or_404(AnnouncementRequest, id=req_id)

    requested_teachers = req.teachers_requested.all()
    logger.debug(requested_teachers)
    if request.user not in requested_teachers:
        messages.error(request, "You do not have permission to approve this announcement.")
        return redirect("index")

    if request.method == "POST":
        form = AnnouncementRequestForm(request.POST, instance=req)
        if form.is_valid():
            obj = form.save(commit=True)
            # SAFE HTML
            obj.content = bleach.linkify(obj.content)
            obj.save()
            if "approve" in request.POST:
                obj.teachers_approved.add(request.user)
                obj.save()
                if not obj.admin_email_sent:
                    admin_request_announcement_email(request, form, obj)
                    obj.admin_email_sent = True
                    obj.save()

                    messages.success(request, "Successfully approved announcement request. An Intranet administrator "
                                     "will review and post the announcement shortly. (Notification sent.)")
                else:
                    messages.success(request, "Successfully approved announcement request. An Intranet administrator "
                                     "will review and post the announcement shortly.")
            else:
                obj.save()
                messages.success(request, "You did not approve this request.")
                return redirect("index")

    form = AnnouncementRequestForm(instance=req)
    context = {"form": form, "req": req, "admin_approve": False}
    return render(request, "announcements/approve.html", context)

@announcements_admin_required
def admin_approve_announcement_view(request, req_id):
    """The administrator approval announcement request page. Admins will view this page through the
    UI.

    req_id: The ID of the AnnouncementRequest

    """
    req = get_object_or_404(AnnouncementRequest, id=req_id)

    requested_teachers = req.teachers_requested.all()
    logger.debug(requested_teachers)

    if request.method == "POST":
        form = AnnouncementRequestForm(request.POST, instance=req)
        if form.is_valid():
            req = form.save(commit=True)
            # SAFE HTML
            req.content = bleach.linkify(req.content)
            if "approve" in request.POST:
                groups = []
                if "groups" in request.POST:
                    group_ids = request.POST.getlist("groups")
                    groups = Group.objects.filter(id__in=group_ids)
                logger.debug(groups)
                announcement = Announcement.objects.create(title=req.title, content=req.content, author=req.author, user=req.user,
                                                           expiration_date=req.expiration_date)
                for g in groups:
                    announcement.groups.add(g)
                announcement.save()

                req.posted = announcement
                req.posted_by = request.user
                req.save()

                announcement_approved_hook(request, announcement, req)
                announcement_posted_hook(request, announcement)

                messages.success(request, "Successfully approved announcement request. It has been posted.")
            else:
                req.rejected = True
                req.rejected_by = request.user
                req.save()
                messages.success(request, "You did not approve this request. It will be hidden.")
            return redirect("index")

    form = AnnouncementRequestForm(instance=req)
    all_groups = Group.objects.all()
    context = {"form": form, "req": req, "admin_approve": True, "all_groups": all_groups}
    return render(request, "announcements/approve.html", context)

@announcements_admin_required
def admin_request_status_view(request):
    all_waiting = AnnouncementRequest.objects.filter(posted=None, rejected=False)
    awaiting_teacher = all_waiting.filter(teachers_approved__isnull=True)
    awaiting_approval = all_waiting.filter(teachers_approved__isnull=False)
    approved = AnnouncementRequest.objects.exclude(posted=None)
    rejected = AnnouncementRequest.objects.filter(rejected=True)

    context = {"awaiting_teacher": awaiting_teacher, "awaiting_approval": awaiting_approval, "approved": approved, "rejected": rejected}

    return render(request, "announcements/request_status.html", context)

@announcements_admin_required
def add_announcement_view(request):
    """Add an announcement."""
    if request.method == "POST":
        form = AnnouncementForm(request.POST)
        logger.debug(form)
        if form.is_valid():
            obj = form.save()
            obj.user = request.user
            # SAFE HTML
            obj.content = bleach.linkify(obj.content)
            obj.save()
            announcement_posted_hook(request, obj)
            messages.success(request, "Successfully added announcement.")
            return redirect("index")
        else:
            messages.error(request, "Error adding announcement")
    else:
        form = AnnouncementForm()
    return render(request, "announcements/add_modify.html", {"form": form, "action": "add"})

@login_required
def view_announcement_view(request, id):
    """View an announcement.

    id: announcement id

    """
    announcement = get_object_or_404(Announcement, id=id)

    return render(request, "announcements/view.html", {"announcement": announcement})

@announcements_admin_required
def modify_announcement_view(request, id=None):
    """Modify an announcement.

    id: announcement id

    """
    if request.method == "POST":
        announcement = Announcement.objects.get(id=id)
        form = AnnouncementForm(request.POST, instance=announcement)
        if form.is_valid():
            obj = form.save()
            logger.debug(form.cleaned_data)
            if "update_added_date" in form.cleaned_data and form.cleaned_data["update_added_date"]:
                logger.debug("Update added date")


#!/usr/bin/env python
""" Fast algorithm for spectral analysis of unevenly sampled data

The Lomb-Scargle method performs spectral analysis on unevenly sampled
data and is known to be a powerful way to find, and test the
significance of, weak periodic signals. The method has previously been
thought to be 'slow', requiring of order 10(2)N(2) operations to analyze
N data points. We show that Fast Fourier Transforms (FFTs) can be used
in a novel way to make the computation of order 10(2)N log N. Despite
its use of the FFT, the algorithm is in no way equivalent to
conventional FFT periodogram analysis.

Keywords:
  DATA SAMPLING, FAST FOURIER TRANSFORMATIONS,
  SPECTRUM ANALYSIS, SIGNAL  PROCESSING

Example:
  > import numpy as np
  > import lomb
  > x = np.arange(10)
  > y = np.sin(x)
  > fx,fy, nout, jmax, prob = lomb.fasper(x,y, 6., 6.)

Reference:
  Press, W. H. & Rybicki, G. B. 1989
  ApJ vol. 338, p. 277-280.
  Fast algorithm for spectral analysis of unevenly sampled data
  bib code: 1989ApJ...338..277P

"""
from np import *
from np.fft import *

def __spread__(y, yy, n, x, m):
    """
    Given an array yy(0:n-1), extirpolate (spread) a value y into
    m actual array elements that best approximate the "fictional"
    (i.e., possible noninteger) array element number x. The weights
    used are coefficients of the Lagrange interpolating polynomial
    Arguments:
      y :
      yy :
      n :
      x :
      m :
    Returns:

    """
    nfac = [0, 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880]
    if m > 10.:
        print 'factorial table too small in spread'
        return

    ix = long(x)
    if x == float(ix):
        yy[ix] = yy[ix] + y
    else:
        ilo = long(x - 0.5 * float(m) + 1.0)
        ilo = min(max(ilo, 1), n - m + 1)
        ihi = ilo + m - 1
        nden = nfac[m]
        fac = x - ilo
        for j in range(ilo + 1, ihi + 1): fac = fac * (x - j)
        yy[ihi] = yy[ihi] + y * fac / (nden * (x - ihi))
        for j in range(ihi - 1, ilo - 1, -1):
            nden = (nden / (j + 1 - ilo)) * (j - ihi)
            yy[j] = yy[j] + y * fac / (nden * (x - j))

def fasper(x, y, ofac, hifac, MACC=4):
    """ function fasper
      Given abscissas x (which need not be equally spaced) and ordinates
      y, and given a desired oversampling factor ofac (a typical value
      being 4 or larger). this routine creates an array wk1 with a
      sequence of nout increasing frequencies (not angular frequencies)
      up to hifac times the "average" Nyquist frequency, and creates
      an array wk2 with the values of the Lomb normalized periodogram at
      those frequencies. The arrays x and y are not altered. This
      routine also returns jmax such that wk2(jmax) is the maximum
      element in wk2, and prob, an estimate of the significance of that
      maximum against the hypothesis of random noise. A small value of prob
      indicates that a significant periodic signal is present.

    Reference:
      Press, W. H. & Rybicki, G. B. 1989
      ApJ vol. 338, p. 277-280.
      Fast algorithm for spectral analysis of unevenly sampled data
      (1989ApJ...338..277P)

    Arguments:
        X   : Abscissas array, (e.g. an array of times).
        Y   : Ordinates array, (e.g. corresponding counts).
        Ofac : Oversampling factor.
        Hifac : Hifac * "average" Nyquist frequency = highest frequency
             for which values of the Lomb normalized periodogram will
             be calculated.

     Returns:
        Wk1 : An array of Lomb periodogram frequencies.
        Wk2 : An array of corresponding values of the Lomb periodogram.
        Nout : Wk1 & Wk2 dimensions (number of calculated frequencies)
        Jmax : The array index corresponding to the MAX( Wk2 ).
        Prob : False Alarm Probability of the largest Periodogram value
        MACC : Number of interpolation points per 1/4 cycle
              of highest frequency

    History:
      02/23/2009, v1.0, MF
        Translation of IDL code (orig. Numerical recipies)
    """
    # Check dimensions of input arrays
    n = long(len(x))
    if n != len(y):
        print 'Incompatible arrays.'
        return

    nout = 0.5 * ofac * hifac * n
    nfreqt = long(ofac * hifac * n * MACC)  #Size the FFT as next power
    nfreq = 64L  # of 2 above nfreqt.

    while nfreq < nfreqt:
        nfreq = 2 * nfreq

    ndim = long(2 * nfreq)

    #Compute the mean, variance
    ave = y.mean()
    ##sample variance because the divisor is N-1
    var = ((y - y.mean()) ** 2).sum() / (len(y) - 1)
    # and range of the data.
    xmin = x.min()
    xmax = x.max()
    xdif = xmax - xmin

    #extirpolate the data into the workspaces
    wk1 = zeros(ndim, dtype='complex')
    wk2 = zeros(ndim, dtype='complex')

    fac = ndim / (xdif * ofac)
    fndim = ndim
    ck = ((x - xmin) * fac) % fndim
    ckk = (2.0 * ck) % fndim

    for j in range(0L, n):
        __spread__(y[j] - ave, wk1, ndim, ck[j], MACC)
        __spread__(1.0, wk2, ndim, ckk[j], MACC)

    #Take the Fast Fourier Transforms
    wk1 = ifft(wk1) * len(wk1)
    wk2 = ifft(wk2) * len(wk1)

    wk1 = wk1[1:nout + 1]
    wk2 = wk2[1:nout + 1]
    rwk1 = wk1.real
    iwk1 = wk1.imag
    rwk2 = wk2.real
    iwk2 = wk2.imag

    df = 1.0 / (xdif * ofac)

    #Compute the Lomb value for each frequency
    hypo2 = 2.0 * abs(wk2)
    hc2wt = rwk2 / hypo2
    hs2wt = iwk2 / hypo2

    cwt = sqrt(0.5 + hc2wt)
    swt = sign(hs2wt) * (sqrt(0.5 - hc2wt))
    den = 0.5 * n + hc2wt * rwk2 + hs2wt * iwk2
    cterm = (cwt * rwk1 + swt * iwk1) ** 2. / den
    sterm = (cwt * iwk1 - swt * rwk1) ** 2. / (n - den)

    wk1 = df * (arange(nout, dtype='float') + 1.)
    wk2 = (cterm + sterm) / (2.0 * var)
    pmax = wk2.max()
    jmax = wk2.argmax()

    #Significance estimation
    #expy = exp(-wk2)
    #effm = 2.0*(nout)/ofac
    #sig = effm*expy
    #ind = (sig > 0.01).nonzero()
    #sig[ind] = 1.0-(1.0-expy[ind])**effm

    #Estimate significance of largest peak value
    expy = exp(-pmax)
    effm = 2.0 * (nout) / ofac
    prob = effm * expy

    if prob > 0.01:
        prob = 1.0 - (1.0 - expy) ** effm

    return wk1, wk2, nout, jmax, prob

def getSignificance(wk1, wk2, nout, ofac):
    """ returns the peak false alarm probabilities
    Hence the lower is the probability and the more significant is the peak
    """
    expy = exp(-wk2)
    effm = 2.0 * (nout) / ofac
    sig = effm * expy
    ind = (sig > 0.01).nonzero()
    sig[ind] = 1.0 - (1.0 - expy[ind]) ** effm
    return sig

if __name__ == "__main__":
    import FitsUtils
    import pylab
    import numpy as np

    ordernum = 7
    orders = FitsUtils.MakeXYpoints("output-8.fits")


#!/usr/bin/env python
#
# Copyright 2010-2012 Michael Ossmann, Jared Boone, Dominic Spill
# Copyright 2010 TheSeven
#
# This file is part of Project Ubertooth.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING.  If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.

# http://pyusb.sourceforge.net/docs/1.0/tutorial.html

import struct
import sys
import time

class Enumeration(object):
    def __init__(self, id, name):
        self._id = id
        self._name = name
        setattr(self.__class__, name, self)
        self.map[id] = self

    def __int__(self):
        return self.id

    def __repr__(self):
        return self.name

    @property
    def id(self):
        return self._id

    @property
    def name(self):
        return self._name

    @classmethod
    def create_from_map(cls):
        for id, name in cls.map.iteritems():
            cls(id, name)

class Request(Enumeration):
    map = {
        0: 'DETACH',
        1: 'DNLOAD',
        2: 'UPLOAD',
        3: 'GETSTATUS',
        4: 'CLRSTATUS',
        5: 'GETSTATE',
        6: 'ABORT',
    }

Request.create_from_map()

class State(Enumeration):
    map = {
         0: 'appIDLE',
         1: 'appDETACH',
         2: 'dfuIDLE',
         3: 'dfuDNLOAD_SYNC',
         4: 'dfuDNBUSY',
         5: 'dfuDNLOAD_IDLE',
         6: 'dfuMANIFEST_SYNC',
         7: 'dfuMANIFEST',
         8: 'dfuMANIFEST_WAIT_RESET',
         9: 'dfuUPLOAD_IDLE',
        10: 'dfuERROR',
    }

State.create_from_map()

class Status(Enumeration):
    map = {
        0x00: 'OK',
        0x01: 'errTARGET',
        0x02: 'errFILE',
        0x03: 'errWRITE',
        0x04: 'errERASE',
        0x05: 'errCHECK_ERASED',
        0x06: 'errPROG',
        0x07: 'errVERIFY',
        0x08: 'errADDRESS',
        0x09: 'errNOTDONE',
        0x0A: 'errFIRMWARE',
        0x0B: 'errVENDOR',
        0x0C: 'errUSBR',
        0x0D: 'errPOR',
        0x0E: 'errUNKNOWN',
        0x0F: 'errSTALLEDPKT',
    }

Status.create_from_map()

class DFU(object):
    def __init__(self, device):
        self._device = device

    def detach(self):
        try:
            self._device.ctrl_transfer(0x21, Request.DETACH, 0, 0, None)
        except Exception, e:
            # Expected disconnect
            msg = getattr(e, 'message')
            if msg and not msg.startswith('No such device'):
                raise

    def download(self, block_number, data):
        self._device.ctrl_transfer(0x21, Request.DNLOAD, block_number, 0, data)

    def upload(self, block_number, length):
        data = self._device.ctrl_transfer(0xA1, Request.UPLOAD, block_number, 0, length)
        return data

    def get_status(self):
        status_packed = self._device.ctrl_transfer(0xA1, Request.GETSTATUS, 0, 0, 6)
        status = struct.unpack('<BBBBBB', status_packed)
        return (Status.map[status[0]], (((status[1] << 8) | status[2]) << 8) | status[3],
                State.map[status[4]], status[5])

    def clear_status(self):
        self._device.ctrl_transfer(0x21, Request.CLRSTATUS, 0, 0, None)

    def get_state(self):
        state_packed = self._device.ctrl_transfer(0xA1, Request.GETSTATE, 0, 0, 1)
        return State.map[struct.unpack('<B', state_packed)[0]]

    def abort(self):
        self._device.ctrl_transfer(0x21, Request.ABORT, 0, 0, None)

    def enter_dfu_mode(self):
        action_map = {
            State.dfuDNLOAD_SYNC: self.abort,
            State.dfuDNLOAD_IDLE: self.abort,
            State.dfuMANIFEST_SYNC: self.abort,
            State.dfuUPLOAD_IDLE: self.abort,
            State.dfuERROR: self.clear_status,
            State.appIDLE: self.detach,
            State.appDETACH: self._wait,
            State.dfuDNBUSY: self._wait,
            State.dfuMANIFEST: self.abort,
            State.dfuMANIFEST_WAIT_RESET: self._wait,
            State.dfuIDLE: self._wait
        }

        while True:
            state = self.get_state()
            if state == State.dfuIDLE:
                break
            action = action_map[state]
            action()

    def _wait(self):
        time.sleep(0.1)

def download(dfu, data, flash_address):
    block_size = 1 << 8
    sector_size = 1 << 12
    if flash_address & (sector_size - 1) != 0:
        raise Exception('Download must start at flash sector boundary')

    block_number = flash_address / block_size
    assert block_number * block_size == flash_address

    try:
        while len(data) > 0:
            packet, data = data[:block_size], data[block_size:]
            if len(packet) < block_size:
                packet += '\xFF' * (block_size - len(packet))
            dfu.download(block_number, packet)
            status, timeout, state, discarded = dfu.get_status()
            sys.stdout.write('.')
            sys.stdout.flush()
            block_number += 1
    finally:
        print

def upload(dfu, flash_address, length, path):
    block_size = 1 << 8
    if flash_address & (block_size - 1) != 0:
        raise Exception('Upload must start at block boundary')

    block_number = flash_address / block_size
    assert block_number * block_size == flash_address

    f = open(path, 'wb')

    try:
        while length > 0:
            data = dfu.upload(block_number, block_size)
            status, timeout, state, discarded = dfu.get_status()
            sys.stdout.write('.')
            sys.stdout.flush()
            if len(data) == block_size:
                f.write(data)
            else:
                raise Exception('Upload failed to read full block')
            block_number += 1
            length -= len(data)
    finally:
        f.close()
        print

def detach(dfu):
    if dfu.get_state() == State.dfuIDLE:
        dfu.detach()
        print('Detached')
    else:
        print 'In unexpected state: %s' % dfu.get_state()

def init_dfu(idVendor, idProduct):
    import usb.core
    dev = usb.core.find(idVendor=idVendor, idProduct=idProduct)
    if dev is None:
        raise RuntimeError('Device not found')

    dfu = DFU(dev)
    dev.default_timeout = 3000

    try:
        dfu.enter_dfu_mode()
    except usb.core.USBError, e:
        if len(e.args) > 0 and 'Pipe error' in e.args:
            raise RuntimeError('Failed to enter DFU mode. Is bootloader running?')
        else:
            raise e

    return dfu

class DfuSuffix(object):
    '''
    A class for adding and checking DFU file suffixes
    '''

    def __init__(self):
        # From freemyipod.org
        self.crc_table = []
        for i in range(256):
            t = i;
            for j in range(8):
                if t & 1:
                    t = (t >> 1) ^ 0xedb88320
                else:
                    t = t >> 1
            self.crc_table.append(t)

    def crc32(self, data):
        crc = 0xffffffff
        for byte in data:
            crc = (crc >> 8) ^ self.crc_table[(crc ^ ord(byte)) & 0xff]
        return crc

    def check_suffix(self, firmware):
        '''
        Check the dfu suffix
        @param firmware - binary of firmware file, including suffix
        '''
        print('Checking firmware signature')

        data   = firmware[:-4]
        length = ord(firmware[-5])
        suffix = firmware[-length:]

        # Will always have these fields
        dwCRC     = struct.unpack('<L', suffix[12:])[0]
        bLength   = struct.unpack('<B', suffix[11])[0]
        ucDfuSig  = struct.unpack('<3s', suffix[8:11])[0]
        bcdDFU    = struct.unpack('<H', suffix[6:8])[0]
        #bcdDFU, ucDfuSig, bLength, dwCRC = unpack('<H3sBL', suffix[6:])

        if bLength != 16:
            raise Exception("Unknown DFU suffix length: %s" % type(bLength))

        # We only know about dfu version 1.0/1.1
        # This needs to be smarter to support other versions if/when they exist
        if bcdDFU != 0x0100:
            raise Exception("Unknown DFU version: %d" % bcdDFU)

        # Suffix bytes are reversed
        if ucDfuSig != 'UFD':
            raise Exception("DFU Signature mismatch: not a DFU file")

        crc = self.crc32(data)
        if crc != dwCRC:
            raise Exception("CRC mismatch: calculated: 0x%x, found: 0x%x" % (crc, dwCRC))

        # Extract additional fields now that we know the suffix contains them


from amoco.system.structs import struct, Consts, StructFormatter, StructDefine
from amoco.arch.arm import cpu_armv7
from amoco.system.core import DataIO
from amoco.system.raw import RawExec

with Consts("tag"):
    HAB_TAG_IVT = 0xD1
    HAB_TAG_DCD = 0xD2
    HAB_TAG_CSF = 0xD4
    HAB_TAG_CRT = 0xD7
    HAB_TAG_SIG = 0xD8
    HAB_TAG_EVT = 0xDB
    HAB_TAG_RVT = 0xDD
    HAB_TAG_WRP = 0x81
    HAB_TAG_MAC = 0xAC

with Consts("cmd"):
    HAB_CMD_SET = 0xB1
    HAB_CMD_INS_KEY = 0xBE
    HAB_CMD_AUT_DAT = 0xCA
    HAB_CMD_WRT_DAT = 0xCC
    HAB_CMD_CHK_DAT = 0xCF
    HAB_CMD_NOP = 0xC0
    HAB_CMD_INIT = 0xB4
    HAB_CMD_UNLK = 0xB2

with Consts("flg"):
    HAB_CMD_INS_KEY_CLR = 0
    HAB_CMD_INS_KEY_ABS = 1
    HAB_CMD_INS_KEY_CSF = 2
    HAB_CMD_INS_KEY_DAT = 4
    HAB_CMD_INS_KEY_CFG = 8
    HAB_CMD_INS_KEY_FID = 16
    HAB_CMD_INS_KEY_MID = 32
    HAB_CMD_INS_KEY_CID = 64
    HAB_CMD_INS_KEY_HSH = 128

with Consts("pcl"):
    HAB_PCL_SRK = 0x03
    HAB_PCL_X509 = 0x09
    HAB_PCL_CMS = 0xC5
    HAB_PCL_BLOB = 0xBB
    HAB_PCL_AEAD = 0xA3

with Consts("alg"):
    HAB_ALG_ANY = 0x00
    HAB_ALG_HASH = 0x01
    HAB_ALG_SIG = 0x02
    HAB_ALG_F = 0x03
    HAB_ALG_EC = 0x04
    HAB_ALG_CIPHER = 0x05
    HAB_ALG_MODE = 0x06
    HAB_ALG_WRAP = 0x07
    HAB_ALG_SHA1 = 0x11
    HAB_ALG_SHA256 = 0x17
    HAB_ALG_SHA512 = 0x1B
    HAB_ALG_PKCS1 = 0x21
    HAB_ALG_AES = 0x55
    HAB_MODE_CCM = 0x66
    HAB_ALG_BLOB = 0x71

with Consts("key_type"):
    HAB_KEY_PUBLIC = 0xE1
    HAB_KEY_HASH = 0xEE
    HAB_KEY_X509 = 0x30

with Consts("eng"):
    HAB_ENG_ANY = 0x00
    HAB_ENG_SCC = 0x03
    HAB_ENG_RTIC = 0x05
    HAB_ENG_SAHARA = 0x06
    HAB_ENG_CSU = 0x0A
    HAB_ENG_SRTC = 0x0C
    HAB_ENG_DCP = 0x1B
    HAB_ENG_CAAM = 0x1D
    HAB_ENG_SNVS = 0x1E
    HAB_ENG_OCOTP = 0x21
    HAB_ENG_DTCP = 0x22
    HAB_ENG_ROM = 0x36
    HAB_ENG_HDCP = 0x24
    HAB_ENG_SW = 0xFF

# ------------------------------------------------------------------------------

@StructDefine(
    """
B :  tag
H :> length
B :  version
""",
    packed=True,
)
class HAB_Header(StructFormatter):
    order = "<"

    def __init__(self, data="", offset=0):
        self.name_formatter("tag")
        self.func_formatter(version=self.token_ver_format)
        if data:
            self.unpack(data, offset)

    @staticmethod
    def token_ver_format(k, x, cls=None):
        return highlight([(Token.Literal, "%d.%d" % (x >> 4, x & 0xF))])

# ------------------------------------------------------------------------------

@StructDefine(
    """
HAB_Header : header
I          : entry
I          : reserved1
I          : dcd
I          : boot_data
I          : self
I          : csf
I          : reserved2
""",
    packed=True,
)
class IVT(StructFormatter):
    order = "<"

    def __init__(self, data="", offset=0):
        self.address_formatter("entry")
        self.address_formatter("dcd")
        self.address_formatter("boot_data")
        self.address_formatter("self")
        self.address_formatter("csf")
        if data:
            self.unpack(data, offset)

# ------------------------------------------------------------------------------

@StructDefine(
    """
I          : start
I          : size
I          : plugin
""",
    packed=True,
)
class BootData(StructFormatter):
    order = "<"

    def __init__(self, data="", offset=0):
        self.address_formatter("start")
        self.address_formatter("size")
        self.flag_formatter("plugin")
        if data:
            self.unpack(data, offset)

# ------------------------------------------------------------------------------

@StructDefine(
    """
B          :  key_type
H          :> len
B          :  unk
I          :  unk_flags
H          :> nlen
H          :> elen
""",
    packed=True,
)
class PublicKey(StructFormatter):
    order = "<"

    def __init__(self, data="", offset=0):
        self.name_formatter("key_type")
        if data:
            self.unpack(data, offset)

    def unpack(self, data, offset=0):
        StructFormatter.unpack(self, data, offset)
        offset += 12
        self.modulus = data[offset : offset + self.nlen]
        offset += self.nlen
        self.exponent = data[offset : offset + self.elen]
        return self

    def size(self):
        return 12 + self.nlen + self.elen

# ------------------------------------------------------------------------------

@StructDefine(
    """
HAB_Header : header
""",
    packed=True,
)
class CRT(StructFormatter):
    def __init__(self, data="", offset=0):
        self.keys = []
        if data:
            self.unpack(data, offset)

    def unpack(self, data, offset=0):
        StructFormatter.unpack(self, data, offset)
        assert self.header.tag == HAB_TAG_CRT
        crtend = offset + self.header.length
        offset += self.size()
        crt = data[offset:crtend]
        if crt[0] == HAB_KEY_PUBLIC:
            while offset < csfend:
                k = PublicKey(data, offset)
                self.keys.append(k)
                offset += k.size()
        else:
            self.data = crt
        return self

    def size(self):
        S = struct.calcsize(self.order + self.format())
        S += sum((len(c) for c in self.keys), 0)
        return S

# ------------------------------------------------------------------------------

@StructDefine(
    """
HAB_Header : header
""",
    packed=True,
)
class CSF(StructFormatter):
    def __init__(self, data="", offset=0):
        self.cmds = []
        if data:
            self.unpack(data, offset)

    def unpack(self, data, offset=0):
        StructFormatter.unpack(self, data, offset)
        assert self.header.tag == HAB_TAG_CSF
        csfend = offset + self.header.length
        offset += self.size()
        self.cmds = []
        while offset < csfend:
            k = self.CMD(data, offset)
            self.cmds.append(k)
            offset += k.size()
        return self

    def size(self):
        S = struct.calcsize(self.format())
        S += sum((len(c) for c in self.cmds), 0)
        return S

    @staticmethod
    def CMD(data, offset):
        tag = ord(data[offset : offset + 1])
        if tag == HAB_CMD_CHK_DAT:
            return CheckData(data, offset)
        if tag == HAB_CMD_NOP:
            return NOP(data, offset)
        if tag == HAB_CMD_INS_KEY:
            return InstallKey(data, offset)
        if tag == HAB_CMD_AUT_DAT:
            return Authenticate(data, offset)
        if tag == HAB_CMD_UNLK:
            return Unlock(data, offset)
        else:
            return HAB_Header(data, offset)

# ------------------------------------------------------------------------------

@StructDefine(
    """
B        :  cmd
H        :> len
B        :  par
I        :  address
I        :  mask
""",
    packed=True,
)
class CheckData(StructFormatter):
    order = "<"

    def __init__(self, data="", offset=0):
        self.name_formatter("cmd")
        self.address_formatter("address")
        self.flag_formatter("mask")
        if data:
            self.unpack(data, offset)

    def unpack(self, data, offset=0):
        StructFormatter.unpack(self, data, offset)
        assert self.cmd == HAB_CMD_CHK_DAT
        self.flags = self.par >> 3
        self.bytes = self.par & 0x7
        if self.len > 8:
            cnt = RawField("I", fname="count")
            offset += self.size()
            self.count = cnt.unpack(data, offset)
        return self

    def size(self):
        S = struct.calcsize(self.format())
        if hasattr(self, "count"):
            S += 4
        return S

# ------------------------------------------------------------------------------

@StructDefine(
    """
B        :  cmd
H        :> len
B        :  und
""",
    packed=True,
)
class NOP(StructFormatter):
    order = "<"

    def __init__(self, data="", offset=0):
        self.name_formatter("cmd")
        if data:
            self.unpack(data, offset)

# ------------------------------------------------------------------------------

@StructDefine(
    """
B        :  cmd
H        :> len
B        :  eng
""",
    packed=True,
)
class Unlock(StructFormatter):
    order = "<"

    def __init__(self, data="", offset=0):
        self.name_formatter("cmd")
        if data:
            self.unpack(data, offset)

    def unpack(self, data, offset=0):
        StructFormatter.unpack(self, data, offset)
        assert self.cmd == HAB_CMD_UNLK
        if self.len > self.size():
            nb = (self.len - self.size()) // 4
            val = RawField("I", nb, fname="val", forder=">")
            offset += self.size()
            self.val = val.unpack(data, offset)
        return self

    def size(self):
        S = struct.calcsize(self.format())
        if hasattr(self, "val"):


# -*- coding: utf-8 -*-
"""
Models for Credit Eligibility for courses.

Credit courses allow students to receive university credit for
successful completion of a course on EdX
"""

import datetime
import logging
from collections import defaultdict

import pytz
from config_models.models import ConfigurationModel
from django.conf import settings
from django.core.cache import cache
from django.core.validators import RegexValidator
from django.db import IntegrityError, models, transaction
from django.dispatch import receiver
from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_lazy
from jsonfield.fields import JSONField
from model_utils.models import TimeStampedModel
from opaque_keys.edx.django.models import CourseKeyField

from openedx.core.djangoapps.request_cache.middleware import RequestCache, ns_request_cached

CREDIT_PROVIDER_ID_REGEX = r"[a-z,A-Z,0-9,\-]+"
log = logging.getLogger(__name__)

class CreditProvider(TimeStampedModel):
    """
    This model represents an institution that can grant credit for a course.

    Each provider is identified by unique ID (e.g., 'ASU'). CreditProvider also
    includes a `url` where the student will be sent when he/she will try to
    get credit for course. Eligibility duration will be use to set duration
    for which credit eligible message appears on dashboard.
    """
    provider_id = models.CharField(
        max_length=255,
        unique=True,
        validators=[
            RegexValidator(
                regex=CREDIT_PROVIDER_ID_REGEX,
                message="Only alphanumeric characters and hyphens (-) are allowed",
                code="invalid_provider_id",
            )
        ],
        help_text=ugettext_lazy(
            "Unique identifier for this credit provider. "
            "Only alphanumeric characters and hyphens (-) are allowed. "
            "The identifier is case-sensitive."
        )
    )

    active = models.BooleanField(
        default=True,
        help_text=ugettext_lazy("Whether the credit provider is currently enabled.")
    )

    display_name = models.CharField(
        max_length=255,
        help_text=ugettext_lazy("Name of the credit provider displayed to users")
    )

    enable_integration = models.BooleanField(
        default=False,
        help_text=ugettext_lazy(
            "When true, automatically notify the credit provider "
            "when a user requests credit. "
            "In order for this to work, a shared secret key MUST be configured "
            "for the credit provider in secure auth settings."
        )
    )

    provider_url = models.URLField(
        default="",
        help_text=ugettext_lazy(
            "URL of the credit provider.  If automatic integration is "
            "enabled, this will the the end-point that we POST to "
            "to notify the provider of a credit request.  Otherwise, the "
            "user will be shown a link to this URL, so the user can "
            "request credit from the provider directly."
        )
    )

    provider_status_url = models.URLField(
        default="",
        help_text=ugettext_lazy(
            "URL from the credit provider where the user can check the status "
            "of his or her request for credit.  This is displayed to students "
            "*after* they have requested credit."
        )
    )

    provider_description = models.TextField(
        default="",
        help_text=ugettext_lazy(
            "Description for the credit provider displayed to users."
        )
    )

    fulfillment_instructions = models.TextField(
        null=True,
        blank=True,
        help_text=ugettext_lazy(
            "Plain text or html content for displaying further steps on "
            "receipt page *after* paying for the credit to get credit for a "
            "credit course against a credit provider."
        )
    )

    eligibility_email_message = models.TextField(
        default="",
        help_text=ugettext_lazy(
            "Plain text or html content for displaying custom message inside "
            "credit eligibility email content which is sent when user has met "
            "all credit eligibility requirements."
        )
    )

    receipt_email_message = models.TextField(
        default="",
        help_text=ugettext_lazy(
            "Plain text or html content for displaying custom message inside "
            "credit receipt email content which is sent *after* paying to get "
            "credit for a credit course."
        )
    )

    thumbnail_url = models.URLField(
        default="",
        max_length=255,
        help_text=ugettext_lazy(
            "Thumbnail image url of the credit provider."
        )
    )

    CREDIT_PROVIDERS_CACHE_KEY = "credit.providers.list"

    @classmethod
    def get_credit_providers(cls, providers_list=None):
        """
        Retrieve a list of all credit providers or filter on providers_list, represented
        as dictionaries.

        Arguments:
            provider_list (list of strings or None): contains list of ids if required results
            to be filtered, None for all providers.

        Returns:
            list of providers represented as dictionaries.

        """
        # Attempt to retrieve the credit provider list from the cache if provider_list is None
        # The cache key is invalidated when the provider list is updated
        # (a post-save signal handler on the CreditProvider model)
        # This doesn't happen very often, so we would expect a *very* high
        # cache hit rate.

        credit_providers = cache.get(cls.CREDIT_PROVIDERS_CACHE_KEY)
        if credit_providers is None:
            # Cache miss: construct the provider list and save it in the cache

            credit_providers = CreditProvider.objects.filter(active=True)

            credit_providers = [
                {
                    "id": provider.provider_id,
                    "display_name": provider.display_name,
                    "url": provider.provider_url,
                    "status_url": provider.provider_status_url,
                    "description": provider.provider_description,
                    "enable_integration": provider.enable_integration,
                    "fulfillment_instructions": provider.fulfillment_instructions,
                    "thumbnail_url": provider.thumbnail_url,
                }
                for provider in credit_providers
            ]

            cache.set(cls.CREDIT_PROVIDERS_CACHE_KEY, credit_providers)

        if providers_list:
            credit_providers = [provider for provider in credit_providers if provider['id'] in providers_list]

        return credit_providers

    @classmethod
    def get_credit_provider(cls, provider_id):
        """
        Retrieve a credit provider with provided 'provider_id'.
        """
        try:
            return CreditProvider.objects.get(active=True, provider_id=provider_id)
        except cls.DoesNotExist:
            return None

    def __unicode__(self):
        """Unicode representation of the credit provider. """
        return self.provider_id

@receiver(models.signals.post_save, sender=CreditProvider)
@receiver(models.signals.post_delete, sender=CreditProvider)
def invalidate_provider_cache(sender, **kwargs):  # pylint: disable=unused-argument
    """Invalidate the cache of credit providers. """
    cache.delete(CreditProvider.CREDIT_PROVIDERS_CACHE_KEY)

class CreditCourse(models.Model):
    """
    Model for tracking a credit course.
    """

    course_key = CourseKeyField(max_length=255, db_index=True, unique=True)
    enabled = models.BooleanField(default=False)

    CREDIT_COURSES_CACHE_KEY = "credit.courses.set"

    @classmethod
    def is_credit_course(cls, course_key):
        """
        Check whether the course has been configured for credit.

        Args:
            course_key (CourseKey): Identifier of the course.

        Returns:
            bool: True iff this is a credit course.

        """
        credit_courses = cache.get(cls.CREDIT_COURSES_CACHE_KEY)
        if credit_courses is None:
            credit_courses = set(
                unicode(course.course_key)
                for course in cls.objects.filter(enabled=True)
            )
            cache.set(cls.CREDIT_COURSES_CACHE_KEY, credit_courses)

        return unicode(course_key) in credit_courses

    @classmethod
    def get_credit_course(cls, course_key):
        """
        Get the credit course if exists for the given 'course_key'.

        Args:
            course_key(CourseKey): The course identifier

        Raises:
            DoesNotExist if no CreditCourse exists for the given course key.

        Returns:
            CreditCourse if one exists for the given course key.
        """
        return cls.objects.get(course_key=course_key, enabled=True)

    def __unicode__(self):
        """Unicode representation of the credit course. """
        return unicode(self.course_key)

@receiver(models.signals.post_save, sender=CreditCourse)
@receiver(models.signals.post_delete, sender=CreditCourse)
def invalidate_credit_courses_cache(sender, **kwargs):   # pylint: disable=unused-argument
    """Invalidate the cache of credit courses. """
    cache.delete(CreditCourse.CREDIT_COURSES_CACHE_KEY)

class CreditRequirement(TimeStampedModel):
    """
    This model represents a credit requirement.

    Each requirement is uniquely identified by its 'namespace' and
    'name' fields.
    The 'name' field stores the unique name or location (in case of XBlock)
    for a requirement, which serves as the unique identifier for that
    requirement.
    The 'display_name' field stores the display name of the requirement.
    The 'criteria' field dictionary provides additional information, clients
    may need to determine whether a user has satisfied the requirement.
    """

    course = models.ForeignKey(CreditCourse, related_name="credit_requirements")
    namespace = models.CharField(max_length=255)
    name = models.CharField(max_length=255)
    display_name = models.CharField(max_length=255, default="")
    order = models.PositiveIntegerField(default=0)
    criteria = JSONField()
    active = models.BooleanField(default=True)

    CACHE_NAMESPACE = u"credit.CreditRequirement.cache."

    class Meta(object):
        unique_together = ('namespace', 'name', 'course')
        ordering = ["order"]

    def __unicode__(self):
        return '{course_id} - {name}'.format(course_id=self.course.course_key, name=self.display_name)

    @classmethod
    def add_or_update_course_requirement(cls, credit_course, requirement, order):
        """
        Add requirement to a given course.

        Args:
            credit_course(CreditCourse): The identifier for credit course
            requirement(dict): Requirement dict to be added

        Returns:
            (CreditRequirement, created) tuple
        """

        credit_requirement, created = cls.objects.get_or_create(
            course=credit_course,
            namespace=requirement["namespace"],
            name=requirement["name"],
            defaults={
                "display_name": requirement["display_name"],
                "criteria": requirement["criteria"],
                "order": order,
                "active": True
            }
        )
        if not created:
            credit_requirement.criteria = requirement["criteria"]
            credit_requirement.active = True
            credit_requirement.order = order
            credit_requirement.display_name = requirement["display_name"]
            credit_requirement.save()

        return credit_requirement, created

    @classmethod
    @ns_request_cached(CACHE_NAMESPACE)
    def get_course_requirements(cls, course_key, namespace=None, name=None):
        """
        Get credit requirements of a given course.

        Args:
            course_key (CourseKey): The identifier for a course

        Keyword Arguments
            namespace (str): Optionally filter credit requirements by namespace.
            name (str): Optionally filter credit requirements by name.

        Returns:
            QuerySet of CreditRequirement model

        """
        # order credit requirements according to their appearance in courseware
        requirements = CreditRequirement.objects.filter(course__course_key=course_key, active=True)

        if namespace is not None:
            requirements = requirements.filter(namespace=namespace)

        if name is not None:
            requirements = requirements.filter(name=name)

        return requirements

    @classmethod
    def disable_credit_requirements(cls, requirement_ids):
        """
        Mark the given requirements inactive.

        Args:
            requirement_ids(list): List of ids

        Returns:
            None
        """
        cls.objects.filter(id__in=requirement_ids).update(active=False)

    @classmethod
    def get_course_requirement(cls, course_key, namespace, name):
        """
        Get credit requirement of a given course.

        Args:
            course_key(CourseKey): The identifier for a course


#!/usr/bin/env python
#
# Python-bindings volume type test script
#
# Copyright (C) 2009-2022, Joachim Metz <joachim.metz@gmail.com>
#
# Refer to AUTHORS for acknowledgements.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

import argparse
import os
import sys
import unittest

import pyfshfs

class DataRangeFileObject(object):
  """File-like object that maps an in-file data range."""

  def __init__(self, path, range_offset, range_size):
    """Initializes a file-like object.

    Args:
      path (str): path of the file that contains the data range.
      range_offset (int): offset where the data range starts.
      range_size (int): size of the data range starts, or None to indicate
          the range should continue to the end of the parent file-like object.
    """
    super(DataRangeFileObject, self).__init__()
    self._current_offset = 0
    self._file_object = open(path, "rb")
    self._range_offset = range_offset
    self._range_size = range_size

  def __enter__(self):
    """Enters a with statement."""
    return self

  def __exit__(self, unused_type, unused_value, unused_traceback):
    """Exits a with statement."""
    return

  def close(self):
    """Closes the file-like object."""
    if self._file_object:
      self._file_object.close()
      self._file_object = None

  def get_offset(self):
    """Retrieves the current offset into the file-like object.

    Returns:
      int: current offset in the data range.
    """
    return self._current_offset

  def get_size(self):
    """Retrieves the size of the file-like object.

    Returns:
      int: size of the data range.
    """
    return self._range_size

  def read(self, size=None):
    """Reads a byte string from the file-like object at the current offset.

    The function will read a byte string of the specified size or
    all of the remaining data if no size was specified.

    Args:
      size (Optional[int]): number of bytes to read, where None is all
          remaining data.

    Returns:
      bytes: data read.

    Raises:
      IOError: if the read failed.
    """
    if (self._range_offset < 0 or
        (self._range_size is not None and self._range_size < 0)):
      raise IOError("Invalid data range.")

    if self._current_offset < 0:
      raise IOError(
          "Invalid current offset: {0:d} value less than zero.".format(
              self._current_offset))

    if (self._range_size is not None and
        self._current_offset >= self._range_size):
      return b""

    if size is None:
      size = self._range_size
    if self._range_size is not None and self._current_offset + size > self._range_size:
      size = self._range_size - self._current_offset

    self._file_object.seek(
        self._range_offset + self._current_offset, os.SEEK_SET)

    data = self._file_object.read(size)

    self._current_offset += len(data)

    return data

  def seek(self, offset, whence=os.SEEK_SET):
    """Seeks to an offset within the file-like object.

    Args:
      offset (int): offset to seek to.
      whence (Optional(int)): value that indicates whether offset is an absolute
          or relative position within the file.

    Raises:
      IOError: if the seek failed.
    """
    if self._current_offset < 0:
      raise IOError(
          "Invalid current offset: {0:d} value less than zero.".format(
              self._current_offset))

    if whence == os.SEEK_CUR:
      offset += self._current_offset
    elif whence == os.SEEK_END:
      offset += self._range_size
    elif whence != os.SEEK_SET:
      raise IOError("Unsupported whence.")
    if offset < 0:
      raise IOError("Invalid offset value less than zero.")

    self._current_offset = offset

class VolumeTypeTests(unittest.TestCase):
  """Tests the volume type."""

  def test_signal_abort(self):
    """Tests the signal_abort function."""
    fshfs_volume = pyfshfs.volume()

    fshfs_volume.signal_abort()

  def test_open(self):
    """Tests the open function."""
    test_source = unittest.source
    if not test_source:
      raise unittest.SkipTest("missing source")

    if unittest.offset:
      raise unittest.SkipTest("source defines offset")

    fshfs_volume = pyfshfs.volume()

    fshfs_volume.open(test_source)

    with self.assertRaises(IOError):
      fshfs_volume.open(test_source)

    fshfs_volume.close()

    with self.assertRaises(TypeError):
      fshfs_volume.open(None)

    with self.assertRaises(ValueError):
      fshfs_volume.open(test_source, mode="w")

  def test_open_file_object(self):
    """Tests the open_file_object function."""
    test_source = unittest.source
    if not test_source:
      raise unittest.SkipTest("missing source")

    if not os.path.isfile(test_source):
      raise unittest.SkipTest("source not a regular file")

    with DataRangeFileObject(
        test_source, unittest.offset or 0, None) as file_object:

      fshfs_volume = pyfshfs.volume()
      fshfs_volume.open_file_object(file_object)

      with self.assertRaises(IOError):
        fshfs_volume.open_file_object(file_object)

      fshfs_volume.close()

      with self.assertRaises(TypeError):
        fshfs_volume.open_file_object(None)

      with self.assertRaises(ValueError):
        fshfs_volume.open_file_object(file_object, mode="w")

  def test_close(self):
    """Tests the close function."""
    test_source = unittest.source
    if not test_source:
      raise unittest.SkipTest("missing source")

    fshfs_volume = pyfshfs.volume()

    with self.assertRaises(IOError):
      fshfs_volume.close()

  def test_open_close(self):
    """Tests the open and close functions."""
    test_source = unittest.source
    if not test_source:
      return

    if unittest.offset:
      raise unittest.SkipTest("source defines offset")

    fshfs_volume = pyfshfs.volume()

    # Test open and close.
    fshfs_volume.open(test_source)
    fshfs_volume.close()

    # Test open and close a second time to validate clean up on close.
    fshfs_volume.open(test_source)
    fshfs_volume.close()

    if os.path.isfile(test_source):
      with open(test_source, "rb") as file_object:

        # Test open_file_object and close.
        fshfs_volume.open_file_object(file_object)
        fshfs_volume.close()

        # Test open_file_object and close a second time to validate clean up on close.
        fshfs_volume.open_file_object(file_object)
        fshfs_volume.close()

        # Test open_file_object and close and dereferencing file_object.
        fshfs_volume.open_file_object(file_object)
        del file_object
        fshfs_volume.close()

  def test_get_name(self):
    """Tests the get_name function and name property."""
    test_source = unittest.source
    if not test_source:
      raise unittest.SkipTest("missing source")

    with DataRangeFileObject(
        test_source, unittest.offset or 0, None) as file_object:

      fshfs_volume = pyfshfs.volume()
      fshfs_volume.open_file_object(file_object)

      name = fshfs_volume.get_name()
      self.assertIsNotNone(name)

      self.assertIsNotNone(fshfs_volume.name)

      fshfs_volume.close()

  def test_get_root_directory(self):
    """Tests the get_root_directory function."""
    test_source = unittest.source
    if not test_source:
      raise unittest.SkipTest("missing source")

    with DataRangeFileObject(
        test_source, unittest.offset or 0, None) as file_object:


# Copyright (c) 2010 Red Hat, Inc.
#
# Authors: Jeff Ortel <jortel@redhat.com>
#
# This software is licensed to you under the GNU General Public License,
# version 2 (GPLv2). There is NO WARRANTY for this software, express or
# implied, including the implied warranties of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
# along with this software; if not, see
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
#
# Red Hat trademarks are not licensed under GPLv2. No permission is
# granted to use or replicate Red Hat trademarks that are incorporated
# in this software or its documentation.
#
import logging
import os

from rhsm.certificate import Key, create_from_file
from rhsm.config import get_config_parser
from subscription_manager.injection import require, ENT_DIR

from rhsmlib.services import config
from rhsm.certificate2 import CONTENT_ACCESS_CERT_TYPE

log = logging.getLogger(__name__)

conf = config.Config(get_config_parser())

DEFAULT_PRODUCT_CERT_DIR = "/etc/pki/product-default"

class Directory(object):

    def __init__(self, path):
        self.path = Path.abs(path)

    def list_all(self):
        all_items = []
        if not os.path.exists(self.path):
            return all_items

        for fn in os.listdir(self.path):
            p = (self.path, fn)
            all_items.append(p)
        return all_items

    def list(self):
        files = []
        for p, fn in self.list_all():
            path = self.abspath(fn)
            if Path.isdir(path):
                continue
            else:
                files.append((p, fn))
        return files

    def listdirs(self):
        dirs = []
        for _p, fn in self.list_all():
            path = self.abspath(fn)
            if Path.isdir(path):
                dirs.append(Directory(path))
        return dirs

    def create(self):
        if not os.path.exists(self.path):
            os.makedirs(self.path)

    def delete(self):
        self.clean()
        os.rmdir(self.path)

    def clean(self):
        if not os.path.exists(self.path):
            return

        for x in os.listdir(self.path):
            path = self.abspath(x)
            if Path.isdir(path):
                d = Directory(path)
                d.delete()
            else:
                os.unlink(path)

    def abspath(self, filename):
        """
        Return path for a filename relative to this directory.
        """
        # NOTE: self.path is already aware of the Path.ROOT setting, so we
        # can just join normally.
        return os.path.join(self.path, filename)

    def __str__(self):
        return self.path

class CertificateDirectory(Directory):

    KEY = 'key.pem'

    def __init__(self, path):
        super(CertificateDirectory, self).__init__(path)
        self.create()
        self._listing = None

    def refresh(self):
        # simply clear the cache. the next list() will reload.
        self._listing = None

    def list(self):
        if self._listing is not None:
            return self._listing
        listing = []
        for _p, fn in Directory.list(self):
            if not fn.endswith('.pem') or fn.endswith(self.KEY):
                continue
            path = self.abspath(fn)
            listing.append(create_from_file(path))
        self._listing = listing
        return listing

    def list_valid(self):
        valid = []
        for c in self.list():
            if c.is_valid():
                valid.append(c)
        return valid

    def list_expired(self):
        expired = []
        for c in self.list():
            if c.is_expired():
                expired.append(c)
        return expired

    def find(self, sn):
        # TODO: could optimize to just load SERIAL.pem? Maybe not in all cases.
        for c in self.list():
            if c.serial == sn:
                return c
        return None

    def find_all_by_product(self, p_hash):
        certs = set()
        providing_stack_ids = set()
        stack_id_map = {}

        # Note this will override a product cert for id '71' with
        # a different product cert for id '71' if it is later in self.list
        for c in self.list():
            for p in c.products:
                if p.id == p_hash:
                    certs.add(c)
                    # Keep track of stacks that provide our product
                    if c.order and c.order.stacking_id:
                        providing_stack_ids.add(c.order.stacking_id)

            # Keep track of stack ids in case we need them later.  avoids another loop
            if c.order and c.order.stacking_id:
                if c.order.stacking_id not in stack_id_map:
                    stack_id_map[c.order.stacking_id] = set()
                stack_id_map[c.order.stacking_id].add(c)

        # Complete
        for stack_id in providing_stack_ids:
            certs |= stack_id_map[stack_id]

        return list(certs)

    def find_by_product(self, p_hash):
        for c in self.list():
            for p in c.products:
                if p.id == p_hash:
                    return c
        return None

    # Set up an alias for backwards compatibility
    findByProduct = find_by_product

class ProductCertificateDirectory(CertificateDirectory):

    def get_provided_tags(self):
        """
        Iterates all product certificates in the directory and extracts a set
        of all tags they provide.
        """
        tags = set()
        for prod_cert in self.list_valid():
            for product in prod_cert.products:
                for tag in product.provided_tags:
                    tags.add(tag)
        return tags

    # This method will lose multiple product certs for
    # the same product, with the last read winning.

    # This needs to pick the correct cert if multiple
    # product certs provide the same product id.
    #
    # If we put the defaults at the begining of .list()
    # results, we will override them with the instaled products
    # certs.
    #
    # Instead of always overriding, something like
    # productid.ComparableProductCert may be useful
    def get_installed_products(self):
        prod_certs = self.list()
        installed_products = {}
        for product_cert in prod_certs:
            product = product_cert.products[0]
            installed_products[product.id] = product_cert
        log.debug("Installed product IDs: %s" % list(installed_products.keys()))
        return installed_products

class ProductDirectory(ProductCertificateDirectory):
    def __init__(self, path=None, default_path=None):
        installed_prod_path = path or conf['rhsm']['productCertDir']
        default_prod_path = default_path or DEFAULT_PRODUCT_CERT_DIR
        self.installed_prod_dir = ProductCertificateDirectory(path=installed_prod_path)
        self.default_prod_dir = ProductCertificateDirectory(path=default_prod_path)

    def list(self):
        installed_prod_list = self.installed_prod_dir.list()
        default_prod_list = self.default_prod_dir.list()

        # Product IDs in installed_prod dir.
        pids = set([cert.products[0].id for cert in installed_prod_list])
        # Everything from /etc/pki/product, only use product-default for pids that don't already exist
        return installed_prod_list + [
            cert
            for cert
            in default_prod_list
            if cert.products[0].id not in pids
        ]

    def refresh(self):
        self.installed_prod_dir.refresh()
        self.default_prod_dir.refresh()

    # In productid.py, ProductDirectory.path is used as path to write new certs
    # to. Souse  the installed_prod_dir (/etc/pki/product) as that is
    # meant to be writable
    #
    # FIXME: a ProductDirectory should probably be responsible for deciding
    # where to write out the certs. For container cases, this could be passing
    # the product cert back to the host in some manner. Or better, let a plugin
    # decide.
    @property
    def path(self):
        return self.installed_prod_dir.path

class EntitlementDirectory(CertificateDirectory):

    PATH = conf['rhsm']['entitlementCertDir']
    PRODUCT = 'product'

    @classmethod
    def productpath(cls):
        return cls.PATH

    def __init__(self):
        super(EntitlementDirectory, self).__init__(self.productpath())

    def _check_key(self, cert):
        """
        If the new key file (SERIAL-key.pem) does not exist, check for
        the old style (key.pem), and if found write it out as the new style.

        Return false if neither is found, indicating we have no key for this
        certificate.

        See bz #711133.
        """
        key_path = cert.key_path()
        if not os.access(key_path, os.R_OK):
            # read key from old key path
            old_key_path = "%s/key.pem" % self.path

            # if we don't have a new style or old style key, consider the
            # cert invalid
            if not os.access(old_key_path, os.R_OK):
                return False

            # write the key/cert out again in new style format
            key = Key.read(old_key_path)
            cert_writer = Writer(self)
            cert_writer.write(key, cert)
        return True

    def list_valid(self):
        return [x for x in self.list() if self._check_key(x) and x.is_valid()]

    def list_valid_with_content_access(self):
        return [x for x in self.list_with_content_access() if self._check_key(x) and x.is_valid()]

    def list(self):
        """
        List entitlement certificates that do not have SCA type
        :return: list of entitlement certs
        """
        certs = super(EntitlementDirectory, self).list()
        return [cert for cert in certs if cert.entitlement_type != CONTENT_ACCESS_CERT_TYPE]

    def list_with_content_access(self):
        """
        List all entitlement certificates
        :return: list of entitlement certs
        """
        return super(EntitlementDirectory, self).list()

    def list_with_sca_mode(self):
        """
        List only entitlement certificates that do have SCA type
        :return:
        """
        certs = super(EntitlementDirectory, self).list()
        return [cert for cert in certs if cert.entitlement_type == CONTENT_ACCESS_CERT_TYPE]

    def list_for_product(self, product_id):
        """
        Returns all entitlement certificates providing access to the given
        product ID.
        """
        entitlements = []
        for cert in self.list():
            for cert_product in cert.products:
                if product_id == cert_product.id:
                    entitlements.append(cert)
        return entitlements

    def list_for_pool_id(self, pool_id):
        """
        Returns all entitlement certificates provided by the given
        pool ID.
        """
        entitlements = [entitlement for entitlement in self.list() if str(entitlement.pool.id) == str(pool_id)]
        return entitlements

    def list_serials_for_pool_ids(self, pool_ids):
        """
        Returns a dict of all entitlement certificate serials for each pool_id in the list provided
        """
        pool_id_to_serials = {}
        for pool_id in pool_ids:
            pool_id_to_serials[pool_id] = [str(cert.serial) for cert in self.list_for_pool_id(pool_id)]
        return pool_id_to_serials

class Path(object):

    # Used during Anaconda install by the yum pidplugin to ensure we operate
    # beneath /mnt/sysimage/ instead of /.
    ROOT = '/'

    @classmethod
    def join(cls, a, b):


#pylint: disable=no-init
from __future__ import (absolute_import, division, print_function)
import stresstesting
import re
import mantid
from mantid.simpleapi import *
from six.moves import range
from six import iteritems

MAX_ALG_LEN = 40 # TODO convention says 20 is the maximum

SPECIAL = ["InputWorkspace", "OutputWorkspace", "Workspace",
           "ReductionProperties"]
SPECIAL_UPPER = [specialname.upper for specialname in SPECIAL]

# TODO this list should be empty
ALG_BAD_PARAMS = {
    "CalculateUMatrix(v1)":("a", "b", "c", "alpha", "beta", "gamma"),
    "ConvertToMD(v1)":("dEAnalysisMode"),
    "ConvertToMDMinMaxLocal(v1)":("dEAnalysisMode"),
    "ConvertToMDMinMaxGlobal(v1)":("dEAnalysisMode"),
    "FindUBUsingLatticeParameters(v1)":("a", "b", "c", "alpha", "beta", "gamma"),
    "IndexSXPeaks(v1)":("a", "b", "c", "alpha", "beta", "gamma", "dTolerance"),
    "ModeratorTzero(v1)":("tolTOF"),
    "MuscatFunc(v1)":("dQ", "dW"),
    "OptimizeCrystalPlacement(v1)":("nPeaks", "nParams", "nIndexed"),
    "PDFFourierTransform(v1)":("rho0"),
    "PoldiAutoCorrelation(v5)":("wlenmin", "wlenmax"),
    "PoldiLoadChopperSlits(v1)":("nbLoadedSlits"),
    "PoldiLoadSpectra(v1)":("nbSpectraLoaded"),
    "PoldiProjectRun(v1)":("wlenmin", "wlenmax"),
    "PoldiRemoveDeadWires(v1)":("nbExcludedWires", "nbAuteDeadWires"),
    "SaveIsawQvector(v1)":("Qx_vector", "Qy_vector", "Qz_vector"),
    "SCDCalibratePanels(v1)":("a", "b", "c", "alpha", "beta", "gamma",
                              "useL0", "usetimeOffset", "usePanelWidth",
                              "usePanelHeight", "usePanelPosition",
                              "usePanelOrientation", "tolerance",
                              "MaxPositionChange_meters"),
    "SetSampleMaterial(v1)":("bAverage", "bSquaredAverage"),
    "SetUB(v1)":("a", "b", "c", "alpha", "beta", "gamma", "u", "v"),
    "ViewBOA(v1)":("CD-Distance"),
    "PoldiCreatePeaksFromCell(v1)":("a", "b", "c", "alpha", "beta", "gamma"),
    "CreateMD(v1)" : ("u", "v"),
    "AccumulateMD(v1)" : ("u", "v")
    }

# TODO this list should be empty
FUNC_BAD_NAME = ("Muon_ExpDecayOscTest")

# TODO this list should be empty
FUNC_BAD_PARAMS = {
    "Bk2BkExpConvPV":("TOF_h"),
    "CubicSpline":("y0", "y1", "y2"),
    "DiffRotDiscreteCircle":("f0.Height", "f0.Radius", "f0.Centre"),
    "DiffSphere":("f0.Height", "f0.Radius", "f0.Centre"),
    "IsoRotDiff":("f0.Height", "f0.Radius", "f0.Centre"),
    "LatticeErrors":("p0", "p1", "p2", "p3", "p4", "p5"),
    "Muon_ExpDecayOscTest":("lambda", "frequency", "phi"),
    "SCDPanelErrors":("f0_detWidthScale", "f0_detHeightScale",
                      "f0_Xoffset", "f0_Yoffset", "f0_Zoffset",
                      "f0_Xrot", "f0_Yrot", "f0_Zrot",
                      "l0", "t0"),
    "StretchedExpFT":("height", "tau", "beta"),
    "PawleyParameterFunction":("a","b","c"),
    "PawleyFunction":("f0.a","f0.b","f0.c", "f0.Alpha", "f0.Beta", "f0.Gamma", "f0.ZeroShift"),
    "LatticeFunction":("a","b","c"),
    "CrystalFieldSpectrum":("f0.Amplitude","f0.PeakCentre","f0.FWHM","f1.Amplitude","f1.PeakCentre","f1.FWHM",
                            "f2.Amplitude","f2.PeakCentre","f2.FWHM","f3.Amplitude","f3.PeakCentre","f3.FWHM",
                            "f4.Amplitude","f4.PeakCentre","f4.FWHM","f5.Amplitude","f5.PeakCentre","f5.FWHM"),
    "CrystalFieldMultiSpectrum":("f0.f0.A0","f0.f1.Amplitude","f0.f1.PeakCentre","f0.f1.FWHM",
                                 "f0.f2.Amplitude","f0.f2.PeakCentre","f0.f2.FWHM")
    }

class Algorithms(stresstesting.MantidStressTest):

    def __init__(self):
        super(Algorithms, self).__init__()
        self.__ranOk = 0
        self.algRegExp = re.compile(r'^[A-Z][a-zA-Z0-9]+$')
        self.paramRegExp = re.compile(r'^[A-Z][a-zA-Z0-9]*$')
        self.categoryRegExp = re.compile(r'^([A-Z][a-zA-Z]+\\?)+$')

    def verifyAlgName(self, name):
        if not self.algRegExp.match(name):
            print("Algorithm " + name + " has a name that violates conventions")
            return False

        if bool(len(name) > MAX_ALG_LEN):
            print("%s has a name that is longer than " % name,
                  "%d characters (%d > %d)" % (MAX_ALG_LEN, len(name), MAX_ALG_LEN))
            return False

        # passed all of the checks
        return True

    def verifyCategories(self, name, categories):
        if len(categories) <= 0:
            print(name + " has no categories")

        for category in categories:
            if not self.categoryRegExp.match(category):
                print(name + " has a bad category " + category)
                return False

        return True

    def checkAllowed(self, alg_descr, name):
        if alg_descr not in ALG_BAD_PARAMS.keys():
            return False

        return name in  ALG_BAD_PARAMS[alg_descr]

    def verifyProperty(self, alg_descr, name):
        upper = name.upper()
        if (upper in SPECIAL_UPPER) and (name not in SPECIAL):
            index = SPECIAL_UPPER.index(upper)
            print(alg_descr + " property (" + name + ") has special name "
                  + "with wrong case: " + name + " should be " + SPECIAL[index])
            return False

        if not self.paramRegExp.match(name):
            if not self.checkAllowed(alg_descr, name):
                print(alg_descr + " property (" + name +") violates conventions")
                return False

        # passed all of the checks
        return True

    def runTest(self):
        algs = AlgorithmFactory.getRegisteredAlgorithms(True)

        for (name, versions) in iteritems(algs):
            if not self.verifyAlgName(name):
                self.__ranOk += 1
                continue
            for version in versions:
                # get an instance
                alg = mantid.AlgorithmManager.create(name, version)
                alg_descr = "%s(v%d)" % (name, version)

                # verify the categories
                if not self.verifyCategories(alg_descr, alg.categories()):
                    self.__ranOk += 1

                # verify the properties
                props = alg.getProperties()
                for prop in props:
                    if not self.verifyProperty(alg_descr, prop.name):
                        self.__ranOk += 1

    def validate(self):
        if self.__ranOk > 0:
            print("Found %d errors. Coding conventions found at" % self.__ranOk,
                  "http://www.mantidproject.org/Mantid_Standards")
            return False

        return True

class FitFunctions(stresstesting.MantidStressTest):
    def __init__(self):
        super(FitFunctions, self).__init__()
        self.__ranOk = 0
        self.funcRegExp = re.compile(r'^[A-Z][a-zA-Z0-9]+$')
        self.paramRegExp = re.compile(r'^[A-Z][a-zA-Z0-9]*$')
        self.categoryRegExp = re.compile(r'^([A-Z][a-zA-Z]+\\?)+$')

    def verifyFuncName(self, name):
        if name in FUNC_BAD_NAME:
            return True

        if not self.funcRegExp.match(name):
            print("Function " + name + " has a name that violates conventions")
            return False

        if bool(len(name) > MAX_ALG_LEN):
            print("%s has a name that is longer than " % name,
                  "%d characters (%d > %d)" % (MAX_ALG_LEN, len(name), MAX_ALG_LEN))
            return False

        # passed all of the checks
        return True

    def verifyCategories(self, name, categories):
        if len(categories) <= 0:
            print(name + " has no categories")

        for category in categories:
            # TODO remove the special case
            if category == "C++ User Defined":
                return True

            if not self.categoryRegExp.match(category):
                print(name + " has a bad category " + category)
                return False

        return True

    def checkAllowed(self, func, name):
        if func not in FUNC_BAD_PARAMS.keys():
            return False

        return name in  FUNC_BAD_PARAMS[func]

    def verifyParameter(self, alg_descr, name):

        if not self.paramRegExp.match(name):
            if not self.checkAllowed(alg_descr, name):
                print(alg_descr + " property (" + name +") violates conventions")
                return False

        # passed all of the checks
        return True

    def runTest(self):


# Pretty-printers for libstdc++.

# Copyright (C) 2008-2015 Free Software Foundation, Inc.

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import gdb
import itertools
import re
import sys

### Python 2 + Python 3 compatibility code

# Resources about compatibility:
#
#  * <http://pythonhosted.org/six/>: Documentation of the "six" module

# FIXME: The handling of e.g. std::basic_string (at least on char)
# probably needs updating to work with Python 3's new string rules.
#
# In particular, Python 3 has a separate type (called byte) for
# bytestrings, and a special b"" syntax for the byte literals; the old
# str() type has been redefined to always store Unicode text.
#
# We probably can't do much about this until this GDB PR is addressed:
# <https://sourceware.org/bugzilla/show_bug.cgi?id=17138>

if sys.version_info[0] > 2:
    ### Python 3 stuff
    Iterator = object
    # Python 3 folds these into the normal functions.
    imap = map
    izip = zip
    # Also, int subsumes long
    long = int
else:
    ### Python 2 stuff
    class Iterator:
        """Compatibility mixin for iterators

        Instead of writing next() methods for iterators, write
        __next__() methods and use this mixin to make them work in
        Python 2 as well as Python 3.

        Idea stolen from the "six" documentation:
        <http://pythonhosted.org/six/#six.Iterator>
        """

        def next(self):
            return self.__next__()

    # In Python 2, we still need these from itertools
    from itertools import imap, izip

# Try to use the new-style pretty-printing if available.
_use_gdb_pp = True
try:
    import gdb.printing
except ImportError:
    _use_gdb_pp = False

# Try to install type-printers.
_use_type_printing = False
try:
    import gdb.types
    if hasattr(gdb.types, 'TypePrinter'):
        _use_type_printing = True
except ImportError:
    pass

# Starting with the type ORIG, search for the member type NAME.  This
# handles searching upward through superclasses.  This is needed to
# work around http://sourceware.org/bugzilla/show_bug.cgi?id=13615.
def find_type(orig, name):
    typ = orig.strip_typedefs()
    while True:
        search = str(typ) + '::' + name
        try:
            return gdb.lookup_type(search)
        except RuntimeError:
            pass
        # The type was not found, so try the superclass.  We only need
        # to check the first superclass, so we don't bother with
        # anything fancier here.
        field = typ.fields()[0]
        if not field.is_base_class:
            raise ValueError("Cannot find type %s::%s" % (str(orig), name))
        typ = field.type

class SharedPointerPrinter:
    "Print a shared_ptr or weak_ptr"

    def __init__ (self, typename, val):
        self.typename = typename
        self.val = val

    def to_string (self):
        state = 'empty'
        refcounts = self.val['_M_refcount']['_M_pi']
        if refcounts != 0:
            usecount = refcounts['_M_use_count']
            weakcount = refcounts['_M_weak_count']
            if usecount == 0:
                state = 'expired, weak %d' % weakcount
            else:
                state = 'count %d, weak %d' % (usecount, weakcount - 1)
        return '%s (%s) %s' % (self.typename, state, self.val['_M_ptr'])

class UniquePointerPrinter:
    "Print a unique_ptr"

    def __init__ (self, typename, val):
        self.val = val

    def to_string (self):
        v = self.val['_M_t']['_M_head_impl']
        return ('std::unique_ptr<%s> containing %s' % (str(v.type.target()),
                                                       str(v)))

class StdListPrinter:
    "Print a std::list"

    class _iterator(Iterator):
        def __init__(self, nodetype, head):
            self.nodetype = nodetype
            self.base = head['_M_next']
            self.head = head.address
            self.count = 0

        def __iter__(self):
            return self

        def __next__(self):
            if self.base == self.head:
                raise StopIteration
            elt = self.base.cast(self.nodetype).dereference()
            self.base = elt['_M_next']
            count = self.count
            self.count = self.count + 1
            return ('[%d]' % count, elt['_M_data'])

    def __init__(self, typename, val):
        self.typename = typename
        self.val = val

    def children(self):
        nodetype = find_type(self.val.type, '_Node')
        nodetype = nodetype.strip_typedefs().pointer()
        return self._iterator(nodetype, self.val['_M_impl']['_M_node'])

    def to_string(self):
        if self.val['_M_impl']['_M_node'].address == self.val['_M_impl']['_M_node']['_M_next']:
            return 'empty %s' % (self.typename)
        return '%s' % (self.typename)

class StdListIteratorPrinter:
    "Print std::list::iterator"

    def __init__(self, typename, val):
        self.val = val
        self.typename = typename

    def to_string(self):
        nodetype = find_type(self.val.type, '_Node')
        nodetype = nodetype.strip_typedefs().pointer()
        return self.val['_M_node'].cast(nodetype).dereference()['_M_data']

class StdSlistPrinter:
    "Print a __gnu_cxx::slist"

    class _iterator(Iterator):
        def __init__(self, nodetype, head):
            self.nodetype = nodetype
            self.base = head['_M_head']['_M_next']
            self.count = 0

        def __iter__(self):
            return self

        def __next__(self):
            if self.base == 0:
                raise StopIteration
            elt = self.base.cast(self.nodetype).dereference()
            self.base = elt['_M_next']
            count = self.count
            self.count = self.count + 1
            return ('[%d]' % count, elt['_M_data'])

    def __init__(self, typename, val):
        self.val = val

    def children(self):
        nodetype = find_type(self.val.type, '_Node')
        nodetype = nodetype.strip_typedefs().pointer()
        return self._iterator(nodetype, self.val)

    def to_string(self):
        if self.val['_M_head']['_M_next'] == 0:
            return 'empty __gnu_cxx::slist'
        return '__gnu_cxx::slist'

class StdSlistIteratorPrinter:
    "Print __gnu_cxx::slist::iterator"

    def __init__(self, typename, val):
        self.val = val

    def to_string(self):
        nodetype = find_type(self.val.type, '_Node')
        nodetype = nodetype.strip_typedefs().pointer()
        return self.val['_M_node'].cast(nodetype).dereference()['_M_data']

class StdVectorPrinter:
    "Print a std::vector"

    class _iterator(Iterator):
        def __init__ (self, start, finish, bitvec):
            self.bitvec = bitvec
            if bitvec:
                self.item   = start['_M_p']
                self.so     = start['_M_offset']
                self.finish = finish['_M_p']
                self.fo     = finish['_M_offset']
                itype = self.item.dereference().type
                self.isize = 8 * itype.sizeof
            else:
                self.item = start
                self.finish = finish
            self.count = 0

        def __iter__(self):
            return self

        def __next__(self):
            count = self.count
            self.count = self.count + 1
            if self.bitvec:
                if self.item == self.finish and self.so >= self.fo:
                    raise StopIteration
                elt = self.item.dereference()
                if elt & (1 << self.so):
                    obit = 1
                else:
                    obit = 0
                self.so = self.so + 1
                if self.so >= self.isize:
                    self.item = self.item + 1
                    self.so = 0
                return ('[%d]' % count, obit)
            else:
                if self.item == self.finish:
                    raise StopIteration
                elt = self.item.dereference()
                self.item = self.item + 1
                return ('[%d]' % count, elt)

    def __init__(self, typename, val):
        self.typename = typename
        self.val = val
        self.is_bool = val.type.template_argument(0).code  == gdb.TYPE_CODE_BOOL

    def children(self):
        return self._iterator(self.val['_M_impl']['_M_start'],
                              self.val['_M_impl']['_M_finish'],
                              self.is_bool)

    def to_string(self):
        start = self.val['_M_impl']['_M_start']
        finish = self.val['_M_impl']['_M_finish']
        end = self.val['_M_impl']['_M_end_of_storage']
        if self.is_bool:
            start = self.val['_M_impl']['_M_start']['_M_p']
            so    = self.val['_M_impl']['_M_start']['_M_offset']