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

import collections
import itertools
import os

import jsonschema
import six

# An object to represent an "unset" value
unset = object()

def canonicalize_path(cwd, path):
    """
    Canonicalizes a path relative to a given working directory.  That
    is, the path, if not absolute, is interpreted relative to the
    working directory, then converted to absolute form.

    :param cwd: The working directory.
    :param path: The path to canonicalize.

    :returns: The absolute path.
    """

    if not os.path.isabs(path):
        path = os.path.join(cwd, path)

    return os.path.abspath(path)

class SensitiveDict(collections.MutableMapping):
    """
    A dictionary containing some keys which contain sensitive data.
    """

    # The mask to use
    masking = '<masked {key}>'

    def __init__(self, data=None, sensitive=None):
        """
        Initialize a new ``SensitiveDict`` instance.

        :param data: An optional dictionary containing the data.
        :param sensitive: An optional set of "sensitive" keys, keys
                          whose values should be considered sensitive.
        """

        # Save the data and the sensitive set
        self._data = data or {}
        self._sensitive = sensitive or set()

        # Initialize the demand-allocated 'masked' property
        self._masked = None

    def __str__(self):
        """
        Obtain a string form of a ``SensitiveDict`` instance.

        :returns: The string form of the ``SensitiveDict``.
        """

        return six.text_type(self._data)

    def __len__(self):
        """
        Obtain the length of a ``SensitiveDict`` instance.

        :returns: The number of keys in the dictionary.
        """

        return len(self._data)

    def __getitem__(self, key):
        """
        Retrieve the value of a key.

        :param key: The key to retrieve the value of.

        :returns: The value of the key.
        """

        return self._data[key]

    def __setitem__(self, key, value):
        """
        Set the value of a key.

        :param key: The key to set the value of.
        :param value: The value to set the key to.
        """

        self._data[key] = value

    def __delitem__(self, key):
        """
        Delete the value of a key.

        :param key: The key to delete.
        """

        del self._data[key]

    def __iter__(self):
        """
        Iterate over the dictionary.

        :returns: An iterator over the keys in the dictionary.
        """

        return iter(self._data)

    def copy(self):
        """
        Retrieve a copy of the sensitive dictionary.  Note that this is a
        shallow copy.
        """

        return self.__class__(self._data.copy(), self._sensitive.copy())

    def declare_sensitive(self, key):
        """
        Declare a key as a "sensitive" key, a key for which the data
        should be treated as sensitive.  The key need not be set to be
        declared as sensitive.

        :param key: The key to mark as sensitive.
        """

        self._sensitive.add(key)

    @property
    def sensitive(self):
        """
        Retrieve a set of the "sensitive" keys, keys for which the data
        should be treated as sensitive.  This will be a copy;
        modifications will not affect the set.
        """

        return frozenset(self._sensitive)

    @property
    def masked(self):
        """
        Retrieve a read-only subordinate mapping.  All values are
        stringified, and sensitive values are masked.  The subordinate
        mapping implements the context manager protocol for
        convenience.
        """

        if self._masked is None:
            self._masked = MaskedDict(self)

        return self._masked

class MaskedDict(collections.Mapping):
    """
    A read-only proxy for ``SensitiveDict`` which applies appropriate
    masking.  Implements the context manager protocol for convenience.
    """

    def __init__(self, parent):
        """
        Initialize a new ``MaskedDict`` instance.

        :param parent: The ``SensitiveDict`` instance to be wrapped.
        """

        self._parent = parent

    def __enter__(self):
        """
        Called upon entry to a context manager.

        :returns: The ``MaskedDict`` instance.
        """

        return self

    def __exit__(self, exc_type, exc_value, traceback):
        """
        Called upon exit from a context manager.

        :param exc_type: The type of any exception that occurred
                         within the context manager.
        :param exc_value: The actual value of any exception that
                          occurred within the context manager.
        :param traceback: The traceback of any exception that occurred
                          within the context manager.

        :returns: A ``None`` value to indicate that exceptions were
                  not handled.
        """

        pass

    def __str__(self):
        """
        Obtain a string form of a ``MaskedDict`` instance.

        :returns: The string form of the ``MaskedDict`` instance.
        """

        return six.text_type(dict(self))

    def __len__(self):
        """
        Obtain the length of a ``MaskedDict`` instance.

        :returns: The number of keys in the dictionary.
        """

        return len(self._parent)

    def __getitem__(self, key):
        """
        Retrieve the value of a key.  All values are returned as simple
        strings, and sensitive values are masked--that is, their value
        is reported as the string "<masked VAR>", where "VAR" will be
        the key.

        :param key: The name of the key to retrieve.

        :returns: The value of the designated key, with appropriate
                  masking applied.
        """

        # Well, if it doesn't even exist, raise KeyError immediately
        if key not in self._parent:
            raise KeyError(key)

        # Apply masking
        if key in self._parent.sensitive:
            return self._parent.masking.format(key=key)

        # OK, just stringify the value
        return self._parent[key]

    def __iter__(self):
        """
        Iterate over the dictionary.

        :returns: An iterator over the keys in the dictionary.
        """

        return iter(self._parent)

    @property
    def sensitive(self):
        """
        Retrieve a set of the "sensitive" keys, keys for which the data
        should be treated as sensitive.  This will be a copy;
        modifications will not affect the set.
        """

        return self._parent.sensitive

    @property
    def masked(self):
        """
        Retrieve a read-only subordinate mapping.  All values are
        stringified, and sensitive values are masked.  The subordinate
        mapping implements the context manager protocol for
        convenience.
        """

        return self

def schema_validate(instance, schema, exc_class, *prefix, **kwargs):
    """
    Schema validation helper.  Performs JSONSchema validation.  If a
    schema validation error is encountered, an exception of the
    designated class is raised with the validation error message
    appropriately simplified and passed as the sole positional
    argument.

    :param instance: The object to schema validate.
    :param schema: The schema to use for validation.
    :param exc_class: The exception class to raise instead of the
                      ``jsonschema.ValidationError`` exception.
    :param prefix: Positional arguments are interpreted as a list of
                   keys to prefix to the path contained in the
                   validation error.
    :param kwargs: Keyword arguments to pass to the exception
                   constructor.
    """

    try:
        # Do the validation
        jsonschema.validate(instance, schema)
    except jsonschema.ValidationError as exc:
        # Assemble the path
        path = '/'.join((a if isinstance(a, six.string_types) else '[%d]' % a)
                        for a in itertools.chain(prefix, exc.path))

        # Construct the message
        message = 'Failed to validate "%s": %s' % (path, exc.message)

        # Raise the target exception
        raise exc_class(message, **kwargs)

def iter_prio_dict(prio_dict):
    """
    Iterate over a priority dictionary.  A priority dictionary is a
    dictionary keyed by integer priority, with the values being lists
    of objects.  This generator will iterate over the dictionary in
    priority order (from lowest integer value to highest integer
    value), yielding each object in the lists in turn.

    :param prio_dict: A priority dictionary, as described above.

    :returns: An iterator that yields each object in the correct
              order, based on priority and ordering within the
              priority values.
    """

    for _prio, objs in sorted(prio_dict.items(), key=lambda x: x[0]):
        for obj in objs:
            yield obj


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

"""setup for IOT Message package"""

import os
from setuptools import setup, find_packages

def read(*paths):
    """Build a file path from *paths* and return the contents."""
    with open(os.path.join(*paths), 'r') as file_handler:
        return file_handler.read()

setup(
    name='iot_message',
    version='0.1.0',
    description='Custom iot:1 protocol',
    keywords=['iot:1'],
    long_description=(read('readme.md')),
    url='https://github.com/bkosciow/python_iot-1',
    license='MIT',
    author='Bartosz Kościów',
    author_email='kosci1@gmail.com',
    py_modules=['iot_message'],
    include_package_data=True,
    classifiers=[
        'Development Status :: 4 - Beta',
        'Environment :: Console',
        'Intended Audience :: Developers',
        'Natural Language :: English',
        'License :: OSI Approved :: MIT License',
        'Operating System :: OS Independent',
        'Programming Language :: Python',
        'Programming Language :: Python :: 3',
        'Topic :: Software Development :: Libraries :: Python Modules',
        'Topic :: Home Automation'
    ],
    packages=find_packages(exclude=['tests*']),
)


"""Locations where we look for configs, install stuff, etc"""

import sys
import site
import os
import tempfile
from pip.backwardcompat import get_python_lib

def running_under_virtualenv():
    """
    Return True if we're running inside a virtualenv, False otherwise.

    """
    return hasattr(sys, 'real_prefix')

def virtualenv_no_global():
    """
    Return True if in a venv and no system site packages.
    """
    #this mirrors the logic in virtualenv.py for locating the no-global-site-packages.txt file
    site_mod_dir = os.path.dirname(os.path.abspath(site.__file__))
    no_global_file = os.path.join(site_mod_dir, 'no-global-site-packages.txt')
    if running_under_virtualenv() and os.path.isfile(no_global_file):
        return True

if running_under_virtualenv():
    build_prefix = os.path.join(sys.prefix, 'build')
    src_prefix = os.path.join(sys.prefix, 'src')
else:
    # Use tempfile to create a temporary folder for build
    # Note: we are NOT using mkdtemp so we can have a consistent build dir
    build_prefix = os.path.join(tempfile.gettempdir(), 'pip-build')

    ## FIXME: keep src in cwd for now (it is not a temporary folder)
    try:
        src_prefix = os.path.join(os.getcwd(), 'src')
    except OSError:
        # In case the current working directory has been renamed or deleted
        sys.exit("The folder you are executing pip from can no longer be found.")

# under Mac OS X + virtualenv sys.prefix is not properly resolved
# it is something like /path/to/python/bin/..
build_prefix = os.path.abspath(build_prefix)
src_prefix = os.path.abspath(src_prefix)

# FIXME doesn't account for venv linked to global site-packages

site_packages = get_python_lib()
user_dir = os.path.expanduser('~')
if sys.platform == 'win32':
    bin_py = os.path.join(sys.prefix, 'Scripts')
    # buildout uses 'bin' on Windows too?
    if not os.path.exists(bin_py):
        bin_py = os.path.join(sys.prefix, 'bin')
    default_storage_dir = os.path.join(user_dir, 'pip')
    default_config_file = os.path.join(default_storage_dir, 'pip.ini')
    default_log_file = os.path.join(default_storage_dir, 'pip.log')
else:
    bin_py = os.path.join(sys.prefix, 'bin')
    default_storage_dir = os.path.join(user_dir, '.pip')
    default_config_file = os.path.join(default_storage_dir, 'pip.conf')
    default_log_file = os.path.join(default_storage_dir, 'pip.log')
    # Forcing to use /usr/local/bin for standard Mac OS X framework installs
    # Also log to ~/Library/Logs/ for use with the Console.app log viewer
    if sys.platform[:6] == 'darwin' and sys.prefix[:16] == '/System/Library/':
        bin_py = '/usr/local/bin'
        default_log_file = os.path.join(user_dir, 'Library/Logs/pip.log')


#!/usr/bin/env python
"""Parallel word frequency counter.

This only works for a local cluster, because the filenames are local paths.
"""

import os
import time
import urllib

from itertools import repeat

from wordfreq import print_wordfreq, wordfreq

from IPython.parallel import Client, Reference

davinci_url = "http://www.gutenberg.org/cache/epub/5000/pg5000.txt"

def pwordfreq(view, fnames):
    """Parallel word frequency counter.

    view - An IPython DirectView
    fnames - The filenames containing the split data.
    """
    assert len(fnames) == len(view.targets)
    view.scatter('fname', fnames, flatten=True)
    ar = view.apply(wordfreq, Reference('fname'))
    freqs_list = ar.get()
    word_set = set()
    for f in freqs_list:
        word_set.update(f.keys())
    freqs = dict(zip(word_set, repeat(0)))
    for f in freqs_list:
        for word, count in f.iteritems():
            freqs[word] += count
    return freqs

if __name__ == '__main__':
    # Create a Client and View
    rc = Client()

    view = rc[:]

    if not os.path.exists('davinci.txt'):
        # download from project gutenberg
        print("Downloading Da Vinci's notebooks from Project Gutenberg")
        urllib.urlretrieve(davinci_url, 'davinci.txt')

    # Run the serial version
    print("Serial word frequency count:")
    text = open('davinci.txt').read()
    tic = time.time()
    freqs = wordfreq(text)
    toc = time.time()
    print_wordfreq(freqs, 10)
    print("Took %.3f s to calcluate"%(toc-tic))

    # The parallel version
    print("\nParallel word frequency count:")
    # split the davinci.txt into one file per engine:
    lines = text.splitlines()
    nlines = len(lines)
    n = len(rc)
    block = nlines/n
    for i in range(n):
        chunk = lines[i*block:i*(block+1)]
        with open('davinci%i.txt'%i, 'w') as f:
            f.write('\n'.join(chunk))

    cwd = os.path.abspath(os.getcwdu())
    fnames = [ os.path.join(cwd, 'davinci%i.txt'%i) for i in range(n)]
    tic = time.time()
    pfreqs = pwordfreq(view,fnames)
    toc = time.time()
    print_wordfreq(freqs)
    print("Took %.3f s to calcluate on %i engines"%(toc-tic, len(view.targets)))
    # cleanup split files
    map(os.remove, fnames)


from django.utils.decorators import method_decorator

def view_decorator(function_decorator):
	"""Convert a function based decorator into a class based decorator usable
	on class based Views.

	Can't subclass the `View` as it breaks inheritance (super in particular),
	so we monkey-patch instead.

	Based on http://stackoverflow.com/a/8429311
	"""

	def simple_decorator(View):
		View.dispatch = method_decorator(function_decorator)(View.dispatch)
		return View

	return simple_decorator

# Simplified version from https://github.com/mitsuhiko/werkzeug/blob/master/werkzeug/_internal.py
class _Missing(object):
	pass
_missing = _Missing()

# From https://github.com/mitsuhiko/werkzeug/blob/master/werkzeug/utils.py
class cached_property(object):
	"""A decorator that converts a function into a lazy property.  The
	function wrapped is called the first time to retrieve the result
	and then that calculated result is used the next time you access
	the value::

		class Foo(object):

			@cached_property
			def foo(self):
				# calculate something important here
				return 42

	The class has to have a `__dict__` in order for this property to
	work.
	"""

	# implementation detail: this property is implemented as non-data
	# descriptor.  non-data descriptors are only invoked if there is
	# no entry with the same name in the instance's __dict__.
	# this allows us to completely get rid of the access function call
	# overhead.  If one choses to invoke __get__ by hand the property
	# will still work as expected because the lookup logic is replicated
	# in __get__ for manual invocation.

	def __init__(self, func, name=None, doc=None):
		self.__name__ = name or func.__name__
		self.__module__ = func.__module__
		self.__doc__ = doc or func.__doc__
		self.func = func

	def __get__(self, obj, type=None):
		if obj is None:
			return self
		value = obj.__dict__.get(self.__name__, _missing)
		if value is _missing:
			value = self.func(obj)
			obj.__dict__[self.__name__] = value
		return value


# encoding: utf-8
"""
System command aliases.

Authors:

* Fernando Perez
* Brian Granger
"""

#-----------------------------------------------------------------------------
#  Copyright (C) 2008-2011  The IPython Development Team
#
#  Distributed under the terms of the BSD License.
#
#  The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------

#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------

import __builtin__
import keyword
import os
import re
import sys

from IPython.config.configurable import Configurable
from IPython.core.splitinput import split_user_input

from IPython.utils.traitlets import List, Instance
from IPython.utils.autoattr import auto_attr
from IPython.utils.warn import warn, error

#-----------------------------------------------------------------------------
# Utilities
#-----------------------------------------------------------------------------

# This is used as the pattern for calls to split_user_input.
shell_line_split = re.compile(r'^(\s*)()(\S+)(.*$)')

def default_aliases():
    """Return list of shell aliases to auto-define.
    """
    # Note: the aliases defined here should be safe to use on a kernel
    # regardless of what frontend it is attached to.  Frontends that use a
    # kernel in-process can define additional aliases that will only work in
    # their case.  For example, things like 'less' or 'clear' that manipulate
    # the terminal should NOT be declared here, as they will only work if the
    # kernel is running inside a true terminal, and not over the network.

    if os.name == 'posix':
        default_aliases = [('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
                           ('mv', 'mv -i'), ('rm', 'rm -i'), ('cp', 'cp -i'),
                           ('cat', 'cat'),
                           ]
        # Useful set of ls aliases.  The GNU and BSD options are a little
        # different, so we make aliases that provide as similar as possible
        # behavior in ipython, by passing the right flags for each platform
        if sys.platform.startswith('linux'):
            ls_aliases = [('ls', 'ls -F --color'),
                          # long ls
                          ('ll', 'ls -F -o --color'),
                          # ls normal files only
                          ('lf', 'ls -F -o --color %l | grep ^-'),
                          # ls symbolic links
                          ('lk', 'ls -F -o --color %l | grep ^l'),
                          # directories or links to directories,
                          ('ldir', 'ls -F -o --color %l | grep /$'),
                          # things which are executable
                          ('lx', 'ls -F -o --color %l | grep ^-..x'),
                          ]
        else:
            # BSD, OSX, etc.
            ls_aliases = [('ls', 'ls -F'),
                          # long ls
                          ('ll', 'ls -F -l'),
                          # ls normal files only
                          ('lf', 'ls -F -l %l | grep ^-'),
                          # ls symbolic links
                          ('lk', 'ls -F -l %l | grep ^l'),
                          # directories or links to directories,
                          ('ldir', 'ls -F -l %l | grep /$'),
                          # things which are executable
                          ('lx', 'ls -F -l %l | grep ^-..x'),
                          ]
        default_aliases = default_aliases + ls_aliases
    elif os.name in ['nt', 'dos']:
        default_aliases = [('ls', 'dir /on'),
                           ('ddir', 'dir /ad /on'), ('ldir', 'dir /ad /on'),
                           ('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
                           ('echo', 'echo'), ('ren', 'ren'), ('copy', 'copy'),
                           ]
    else:
        default_aliases = []

    return default_aliases

class AliasError(Exception):
    pass

class InvalidAliasError(AliasError):
    pass

#-----------------------------------------------------------------------------
# Main AliasManager class
#-----------------------------------------------------------------------------

class AliasManager(Configurable):

    default_aliases = List(default_aliases(), config=True)
    user_aliases = List(default_value=[], config=True)
    shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')

    def __init__(self, shell=None, config=None):
        super(AliasManager, self).__init__(shell=shell, config=config)
        self.alias_table = {}
        self.exclude_aliases()
        self.init_aliases()

    def __contains__(self, name):
        return name in self.alias_table

    @property
    def aliases(self):
        return [(item[0], item[1][1]) for item in self.alias_table.iteritems()]

    def exclude_aliases(self):
        # set of things NOT to alias (keywords, builtins and some magics)
        no_alias = set(['cd','popd','pushd','dhist','alias','unalias'])
        no_alias.update(set(keyword.kwlist))
        no_alias.update(set(__builtin__.__dict__.keys()))
        self.no_alias = no_alias

    def init_aliases(self):
        # Load default aliases
        for name, cmd in self.default_aliases:
            self.soft_define_alias(name, cmd)

        # Load user aliases
        for name, cmd in self.user_aliases:
            self.soft_define_alias(name, cmd)

    def clear_aliases(self):
        self.alias_table.clear()

    def soft_define_alias(self, name, cmd):
        """Define an alias, but don't raise on an AliasError."""
        try:
            self.define_alias(name, cmd)
        except AliasError, e:
            error("Invalid alias: %s" % e)

    def define_alias(self, name, cmd):
        """Define a new alias after validating it.

        This will raise an :exc:`AliasError` if there are validation
        problems.
        """
        nargs = self.validate_alias(name, cmd)
        self.alias_table[name] = (nargs, cmd)

    def undefine_alias(self, name):
        if self.alias_table.has_key(name):
            del self.alias_table[name]

    def validate_alias(self, name, cmd):
        """Validate an alias and return the its number of arguments."""
        if name in self.no_alias:
            raise InvalidAliasError("The name %s can't be aliased "
                                    "because it is a keyword or builtin." % name)
        if not (isinstance(cmd, basestring)):
            raise InvalidAliasError("An alias command must be a string, "
                                    "got: %r" % cmd)
        nargs = cmd.count('%s')
        if nargs>0 and cmd.find('%l')>=0:
            raise InvalidAliasError('The %s and %l specifiers are mutually '
                                    'exclusive in alias definitions.')
        return nargs

    def call_alias(self, alias, rest=''):
        """Call an alias given its name and the rest of the line."""
        cmd = self.transform_alias(alias, rest)
        try:
            self.shell.system(cmd)
        except:
            self.shell.showtraceback()

    def transform_alias(self, alias,rest=''):
        """Transform alias to system command string."""
        nargs, cmd = self.alias_table[alias]

        if ' ' in cmd and os.path.isfile(cmd):
            cmd = '"%s"' % cmd

        # Expand the %l special to be the user's input line
        if cmd.find('%l') >= 0:
            cmd = cmd.replace('%l', rest)
            rest = ''
        if nargs==0:
            # Simple, argument-less aliases
            cmd = '%s %s' % (cmd, rest)
        else:
            # Handle aliases with positional arguments
            args = rest.split(None, nargs)
            if len(args) < nargs:
                raise AliasError('Alias <%s> requires %s arguments, %s given.' %
                      (alias, nargs, len(args)))
            cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
        return cmd

    def expand_alias(self, line):
        """ Expand an alias in the command line

        Returns the provided command line, possibly with the first word
        (command) translated according to alias expansion rules.

        [ipython]|16> _ip.expand_aliases("np myfile.txt")
                 <16> 'q:/opt/np/notepad++.exe myfile.txt'
        """

        pre,_,fn,rest = split_user_input(line)
        res = pre + self.expand_aliases(fn, rest)
        return res

    def expand_aliases(self, fn, rest):
        """Expand multiple levels of aliases:

        if:

        alias foo bar /tmp
        alias baz foo

        then:

        baz huhhahhei -> bar /tmp huhhahhei
        """
        line = fn + " " + rest

        done = set()
        while 1:
            pre,_,fn,rest = split_user_input(line, shell_line_split)
            if fn in self.alias_table:
                if fn in done:
                    warn("Cyclic alias definition, repeated '%s'" % fn)
                    return ""
                done.add(fn)

                l2 = self.transform_alias(fn, rest)
                if l2 == line:
                    break
                # ls -> ls -F should not recurse forever
                if l2.split(None,1)[0] == line.split(None,1)[0]:
                    line = l2
                    break
                line=l2
            else:
                break

        return line


import distutils, os
from setuptools import Command
from distutils.util import convert_path
from distutils import log
from distutils.errors import *
from setuptools.command.setopt import edit_config, option_base, config_file

def shquote(arg):
    """Quote an argument for later parsing by shlex.split()"""
    for c in '"', "'", "\\", "#":
        if c in arg: return repr(arg)
    if arg.split()<>[arg]:
        return repr(arg)
    return arg

class alias(option_base):
    """Define a shortcut that invokes one or more commands"""

    description = "define a shortcut to invoke one or more commands"
    command_consumes_arguments = True

    user_options = [
        ('remove',   'r', 'remove (unset) the alias'),
    ] + option_base.user_options

    boolean_options = option_base.boolean_options + ['remove']

    def initialize_options(self):
        option_base.initialize_options(self)
        self.args = None
        self.remove = None

    def finalize_options(self):
        option_base.finalize_options(self)
        if self.remove and len(self.args)<>1:
            raise DistutilsOptionError(
                "Must specify exactly one argument (the alias name) when "
                "using --remove"
            )

    def run(self):
        aliases = self.distribution.get_option_dict('aliases')

        if not self.args:
            print "Command Aliases"
            print "---------------"
            for alias in aliases:
                print "setup.py alias", format_alias(alias, aliases)
            return

        elif len(self.args)==1:
            alias, = self.args
            if self.remove:
                command = None
            elif alias in aliases:
                print "setup.py alias", format_alias(alias, aliases)
                return
            else:
                print "No alias definition found for %r" % alias
                return
        else:
            alias = self.args[0]
            command = ' '.join(map(shquote,self.args[1:]))

        edit_config(self.filename, {'aliases': {alias:command}}, self.dry_run)

def format_alias(name, aliases):
    source, command = aliases[name]
    if source == config_file('global'):
        source = '--global-config '
    elif source == config_file('user'):
        source = '--user-config '
    elif source == config_file('local'):
        source = ''
    else:
        source = '--filename=%r' % source
    return source+name+' '+command


"""
Adds a sphinx directive that can be used to automatically document a plugin.

this::

 .. autoplugin :: nose.plugins.foo
    :plugin: Pluggy

produces::

  .. automodule :: nose.plugins.foo

  Options
  -------

  .. cmdoption :: --foo=BAR, --fooble=BAR

    Do the foo thing to the new thing.

  Plugin
  ------

  .. autoclass :: nose.plugins.foo.Pluggy
     :members:

  Source
  ------

  .. include :: path/to/nose/plugins/foo.py
     :literal:

"""
import os
try:
    from docutils import nodes
    from docutils.statemachine import ViewList
    from docutils.parsers.rst import directives
except ImportError:
    pass # won't run anyway

from nose.util import resolve_name
from nose.plugins.base import Plugin
from nose.plugins.manager import BuiltinPluginManager
from nose.config import Config
from nose.core import TestProgram
from inspect import isclass

def autoplugin_directive(dirname, arguments, options, content, lineno,
                         content_offset, block_text, state, state_machine):
    mod_name = arguments[0]
    mod = resolve_name(mod_name)
    plug_name = options.get('plugin', None)
    if plug_name:
        obj = getattr(mod, plug_name)
    else:
        for entry in dir(mod):
            obj = getattr(mod, entry)
            if isclass(obj) and issubclass(obj, Plugin) and obj is not Plugin:
                plug_name = '%s.%s' % (mod_name, entry)
                break

    # mod docstring
    rst = ViewList()
    rst.append('.. automodule :: %s\n' % mod_name, '<autodoc>')
    rst.append('', '<autodoc>')

    # options
    rst.append('Options', '<autodoc>')
    rst.append('-------', '<autodoc>')
    rst.append('', '<autodoc>')

    plug = obj()
    opts = OptBucket()
    plug.options(opts, {})
    for opt in opts:
        rst.append(opt.options(), '<autodoc>')
        rst.append('   \n', '<autodoc>')
        rst.append('   ' + opt.help + '\n', '<autodoc>')
        rst.append('\n', '<autodoc>')

    # plugin class
    rst.append('Plugin', '<autodoc>')
    rst.append('------', '<autodoc>')
    rst.append('', '<autodoc>')

    rst.append('.. autoclass :: %s\n' % plug_name, '<autodoc>')
    rst.append('   :members:\n', '<autodoc>')
    rst.append('   :show-inheritance:\n', '<autodoc>')
    rst.append('', '<autodoc>')

    # source
    rst.append('Source', '<autodoc>')
    rst.append('------', '<autodoc>')
    rst.append('.. include :: %s\n' % os.path.relpath(
            mod.__file__.replace('.pyc', '.py'), os.getcwd()),
               '<autodoc>')
    rst.append('   :literal:\n', '<autodoc>')
    rst.append('', '<autodoc>')

    node = nodes.section()
    node.document = state.document
    surrounding_title_styles = state.memo.title_styles
    surrounding_section_level = state.memo.section_level
    state.memo.title_styles = []
    state.memo.section_level = 0
    state.nested_parse(rst, 0, node, match_titles=1)
    state.memo.title_styles = surrounding_title_styles
    state.memo.section_level = surrounding_section_level

    return node.children

def autohelp_directive(dirname, arguments, options, content, lineno,
                       content_offset, block_text, state, state_machine):
    """produces rst from nose help"""
    config = Config(parserClass=OptBucket,
                    plugins=BuiltinPluginManager())
    parser = config.getParser(TestProgram.usage())
    rst = ViewList()
    for line in parser.format_help().split('\n'):
        rst.append(line, '<autodoc>')

    rst.append('Options', '<autodoc>')
    rst.append('-------', '<autodoc>')
    rst.append('', '<autodoc>')
    for opt in parser:
        rst.append(opt.options(), '<autodoc>')
        rst.append('   \n', '<autodoc>')
        rst.append('   ' + opt.help + '\n', '<autodoc>')
        rst.append('\n', '<autodoc>')
    node = nodes.section()
    node.document = state.document
    surrounding_title_styles = state.memo.title_styles
    surrounding_section_level = state.memo.section_level
    state.memo.title_styles = []
    state.memo.section_level = 0
    state.nested_parse(rst, 0, node, match_titles=1)
    state.memo.title_styles = surrounding_title_styles
    state.memo.section_level = surrounding_section_level

    return node.children

class OptBucket(object):
    def __init__(self, doc=None, prog='nosetests'):
        self.opts = []
        self.doc = doc
        self.prog = prog

    def __iter__(self):
        return iter(self.opts)

    def format_help(self):
        return self.doc.replace('%prog', self.prog).replace(':\n', '::\n')

    def add_option(self, *arg, **kw):
        self.opts.append(Opt(*arg, **kw))

class Opt(object):
    def __init__(self, *arg, **kw):
        self.opts = arg
        self.action = kw.pop('action', None)
        self.default = kw.pop('default', None)
        self.metavar = kw.pop('metavar', None)
        self.help = kw.pop('help', None)

    def options(self):
        buf = []
        for optstring in self.opts:
            desc = optstring
            if self.action not in ('store_true', 'store_false'):
                desc += '=%s' % self.meta(optstring)
            buf.append(desc)
        return '.. cmdoption :: ' + ', '.join(buf)

    def meta(self, optstring):
        # FIXME optparser default metavar?
        return self.metavar or 'DEFAULT'

def setup(app):
    app.add_directive('autoplugin',
                      autoplugin_directive, 1, (1, 0, 1),
                      plugin=directives.unchanged)
    app.add_directive('autohelp', autohelp_directive, 0, (0, 0, 1))


""" Utilities for processing ANSI escape codes and special ASCII characters.
"""
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------

# Standard library imports
from collections import namedtuple
import re

# System library imports
from IPython.external.qt import QtCore, QtGui

#-----------------------------------------------------------------------------
# Constants and datatypes
#-----------------------------------------------------------------------------

# An action for erase requests (ED and EL commands).
EraseAction = namedtuple('EraseAction', ['action', 'area', 'erase_to'])

# An action for cursor move requests (CUU, CUD, CUF, CUB, CNL, CPL, CHA, CUP,
# and HVP commands).
# FIXME: Not implemented in AnsiCodeProcessor.
MoveAction = namedtuple('MoveAction', ['action', 'dir', 'unit', 'count'])

# An action for scroll requests (SU and ST) and form feeds.
ScrollAction = namedtuple('ScrollAction', ['action', 'dir', 'unit', 'count'])

# An action for the carriage return character
CarriageReturnAction = namedtuple('CarriageReturnAction', ['action'])

# An action for the \n character
NewLineAction = namedtuple('NewLineAction', ['action'])

# An action for the beep character
BeepAction = namedtuple('BeepAction', ['action'])

# An action for backspace
BackSpaceAction = namedtuple('BackSpaceAction', ['action'])

# Regular expressions.
CSI_COMMANDS = 'ABCDEFGHJKSTfmnsu'
CSI_SUBPATTERN = '\[(.*?)([%s])' % CSI_COMMANDS
OSC_SUBPATTERN = '\](.*?)[\x07\x1b]'
ANSI_PATTERN = ('\x01?\x1b(%s|%s)\x02?' % \
                (CSI_SUBPATTERN, OSC_SUBPATTERN))
ANSI_OR_SPECIAL_PATTERN = re.compile('(\a|\b|\r(?!\n)|\r?\n)|(?:%s)' % ANSI_PATTERN)
SPECIAL_PATTERN = re.compile('([\f])')

#-----------------------------------------------------------------------------
# Classes
#-----------------------------------------------------------------------------

class AnsiCodeProcessor(object):
    """ Translates special ASCII characters and ANSI escape codes into readable
        attributes. It also supports a few non-standard, xterm-specific codes.
    """

    # Whether to increase intensity or set boldness for SGR code 1.
    # (Different terminals handle this in different ways.)
    bold_text_enabled = False

    # We provide an empty default color map because subclasses will likely want
    # to use a custom color format.
    default_color_map = {}

    #---------------------------------------------------------------------------
    # AnsiCodeProcessor interface
    #---------------------------------------------------------------------------

    def __init__(self):
        self.actions = []
        self.color_map = self.default_color_map.copy()
        self.reset_sgr()

    def reset_sgr(self):
        """ Reset graphics attributs to their default values.
        """
        self.intensity = 0
        self.italic = False
        self.bold = False
        self.underline = False
        self.foreground_color = None
        self.background_color = None

    def split_string(self, string):
        """ Yields substrings for which the same escape code applies.
        """
        self.actions = []
        start = 0

        # strings ending with \r are assumed to be ending in \r\n since
        # \n is appended to output strings automatically.  Accounting
        # for that, here.
        last_char = '\n' if len(string) > 0 and string[-1] == '\n' else None
        string = string[:-1] if last_char is not None else string

        for match in ANSI_OR_SPECIAL_PATTERN.finditer(string):
            raw = string[start:match.start()]
            substring = SPECIAL_PATTERN.sub(self._replace_special, raw)
            if substring or self.actions:
                yield substring
                self.actions = []
            start = match.end()

            groups = filter(lambda x: x is not None, match.groups())
            g0 = groups[0]
            if g0 == '\a':
                self.actions.append(BeepAction('beep'))
                yield None
                self.actions = []
            elif g0 == '\r':
                self.actions.append(CarriageReturnAction('carriage-return'))
                yield None
                self.actions = []
            elif g0 == '\b':
                self.actions.append(BackSpaceAction('backspace'))
                yield None
                self.actions = []
            elif g0 == '\n' or g0 == '\r\n':
                self.actions.append(NewLineAction('newline'))
                yield g0
                self.actions = []
            else:
                params = [ param for param in groups[1].split(';') if param ]
                if g0.startswith('['):
                    # Case 1: CSI code.
                    try:
                        params = map(int, params)
                    except ValueError:
                        # Silently discard badly formed codes.
                        pass
                    else:
                        self.set_csi_code(groups[2], params)

                elif g0.startswith(']'):
                    # Case 2: OSC code.
                    self.set_osc_code(params)

        raw = string[start:]
        substring = SPECIAL_PATTERN.sub(self._replace_special, raw)
        if substring or self.actions:
            yield substring

        if last_char is not None:
            self.actions.append(NewLineAction('newline'))
            yield last_char

    def set_csi_code(self, command, params=[]):
        """ Set attributes based on CSI (Control Sequence Introducer) code.

        Parameters
        ----------
        command : str
            The code identifier, i.e. the final character in the sequence.

        params : sequence of integers, optional
            The parameter codes for the command.
        """
        if command == 'm':   # SGR - Select Graphic Rendition
            if params:
                self.set_sgr_code(params)
            else:
                self.set_sgr_code([0])

        elif (command == 'J' or # ED - Erase Data
              command == 'K'):  # EL - Erase in Line
            code = params[0] if params else 0
            if 0 <= code <= 2:
                area = 'screen' if command == 'J' else 'line'
                if code == 0:
                    erase_to = 'end'
                elif code == 1:
                    erase_to = 'start'
                elif code == 2:
                    erase_to = 'all'
                self.actions.append(EraseAction('erase', area, erase_to))

        elif (command == 'S' or # SU - Scroll Up
              command == 'T'):  # SD - Scroll Down
            dir = 'up' if command == 'S' else 'down'
            count = params[0] if params else 1
            self.actions.append(ScrollAction('scroll', dir, 'line', count))

    def set_osc_code(self, params):
        """ Set attributes based on OSC (Operating System Command) parameters.

        Parameters
        ----------
        params : sequence of str
            The parameters for the command.
        """
        try:
            command = int(params.pop(0))
        except (IndexError, ValueError):
            return

        if command == 4:
            # xterm-specific: set color number to color spec.
            try:
                color = int(params.pop(0))
                spec = params.pop(0)
                self.color_map[color] = self._parse_xterm_color_spec(spec)
            except (IndexError, ValueError):
                pass

    def set_sgr_code(self, params):
        """ Set attributes based on SGR (Select Graphic Rendition) codes.

        Parameters
        ----------
        params : sequence of ints
            A list of SGR codes for one or more SGR commands. Usually this
            sequence will have one element per command, although certain
            xterm-specific commands requires multiple elements.
        """
        # Always consume the first parameter.
        if not params:
            return
        code = params.pop(0)

        if code == 0:
            self.reset_sgr()
        elif code == 1:
            if self.bold_text_enabled:
                self.bold = True
            else:
                self.intensity = 1
        elif code == 2:
            self.intensity = 0
        elif code == 3:
            self.italic = True
        elif code == 4:
            self.underline = True
        elif code == 22:
            self.intensity = 0
            self.bold = False
        elif code == 23:
            self.italic = False
        elif code == 24:
            self.underline = False
        elif code >= 30 and code <= 37:
            self.foreground_color = code - 30
        elif code == 38 and params and params.pop(0) == 5:
            # xterm-specific: 256 color support.
            if params:
                self.foreground_color = params.pop(0)
        elif code == 39:
            self.foreground_color = None
        elif code >= 40 and code <= 47:
            self.background_color = code - 40
        elif code == 48 and params and params.pop(0) == 5:
            # xterm-specific: 256 color support.
            if params:
                self.background_color = params.pop(0)
        elif code == 49:
            self.background_color = None

        # Recurse with unconsumed parameters.
        self.set_sgr_code(params)

    #---------------------------------------------------------------------------
    # Protected interface
    #---------------------------------------------------------------------------

    def _parse_xterm_color_spec(self, spec):
        if spec.startswith('rgb:'):
            return tuple(map(lambda x: int(x, 16), spec[4:].split('/')))
        elif spec.startswith('rgbi:'):
            return tuple(map(lambda x: int(float(x) * 255),
                             spec[5:].split('/')))
        elif spec == '?':
            raise ValueError('Unsupported xterm color spec')
        return spec

    def _replace_special(self, match):
        special = match.group(1)
        if special == '\f':
            self.actions.append(ScrollAction('scroll', 'down', 'page', 1))
        return ''

class QtAnsiCodeProcessor(AnsiCodeProcessor):
    """ Translates ANSI escape codes into QTextCharFormats.
    """

    # A map from ANSI color codes to SVG color names or RGB(A) tuples.
    darkbg_color_map = {
        0  : 'black',       # black
        1  : 'darkred',     # red
        2  : 'darkgreen',   # green
        3  : 'brown',       # yellow
        4  : 'darkblue',    # blue
        5  : 'darkviolet',  # magenta
        6  : 'steelblue',   # cyan
        7  : 'grey',        # white
        8  : 'grey',        # black (bright)
        9  : 'red',         # red (bright)
        10 : 'lime',        # green (bright)
        11 : 'yellow',      # yellow (bright)
        12 : 'deepskyblue', # blue (bright)
        13 : 'magenta',     # magenta (bright)
        14 : 'cyan',        # cyan (bright)
        15 : 'white' }      # white (bright)

    # Set the default color map for super class.
    default_color_map = darkbg_color_map.copy()

    def get_color(self, color, intensity=0):
        """ Returns a QColor for a given color code, or None if one cannot be
            constructed.
        """
        if color is None:
            return None

        # Adjust for intensity, if possible.
        if color < 8 and intensity > 0:
            color += 8

        constructor = self.color_map.get(color, None)
        if isinstance(constructor, basestring):
            # If this is an X11 color name, we just hope there is a close SVG
            # color name. We could use QColor's static method
            # 'setAllowX11ColorNames()', but this is global and only available
            # on X11. It seems cleaner to aim for uniformity of behavior.
            return QtGui.QColor(constructor)

        elif isinstance(constructor, (tuple, list)):
            return QtGui.QColor(*constructor)

        return None

    def get_format(self):
        """ Returns a QTextCharFormat that encodes the current style attributes.
        """
        format = QtGui.QTextCharFormat()

        # Set foreground color
        qcolor = self.get_color(self.foreground_color, self.intensity)
        if qcolor is not None:
            format.setForeground(qcolor)

        # Set background color
        qcolor = self.get_color(self.background_color, self.intensity)
        if qcolor is not None:
            format.setBackground(qcolor)

        # Set font weight/style options
        if self.bold:
            format.setFontWeight(QtGui.QFont.Bold)
        else:
            format.setFontWeight(QtGui.QFont.Normal)
        format.setFontItalic(self.italic)
        format.setFontUnderline(self.underline)

        return format

    def set_background_color(self, color):
        """ Given a background color (a QColor), attempt to set a color map
            that will be aesthetically pleasing.
        """
        # Set a new default color map.
        self.default_color_map = self.darkbg_color_map.copy()

        if color.value() >= 127:
            # Colors appropriate for a terminal with a light background. For
            # now, only use non-bright colors...
            for i in xrange(8):
                self.default_color_map[i + 8] = self.default_color_map[i]

            # ...and replace white with black.
            self.default_color_map[7] = self.default_color_map[15] = 'black'

        # Update the current color map with the new defaults.
        self.color_map.update(self.default_color_map)


# vim:set et ts=4 sw=4 ai ft=python:
# pylint: disable=superfluous-parens

"""
One Time JWT

Simple mechanism for cross service authorization.  Usage:

Client side:

    import onetimejwt

    jwt = onetimejwt.generate('shared secret', 60) # shared secret, 60 second age

    headers = {
        "Authorization": "Bearer " + onetimejwt.generate('shared secret', 60)
    }

Server side, create a single instance of Manager and use it for all threads:

    import onetimejwt

    # at startup, creates a cleanup thread
    # note: you can include any number of secrets
    JTM = onetimejwt.Manager('shared secret', maxage=60)

    # during processing -- throws JwtFailed exception if not authorized
    JTM.valid(headers.get('Authorization'))

Manager will keep a list of recognized JWTS, and uses logging of a warning level
to report problems.

You can store the secret in base64 format for full binary spectrum of random
data.  If you do this, begin the secret with 'base64:...' and Manager init will
properly handler it.  generate, however, does not pay attention to this--
for performance purposes it assumes you give it the final form of the secret.

To pre-process the secret for generate, call:

    decoded_secret = threading.decode_secret("base64:bm90IHJlYWxseSBiaW5hcnk=")
    jwt = onetimejwt.generate(decoded_secret, 60)

------------------------------------------------------------------

Copyright 2016 Brandon Gillespie

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero 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 Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

"""

import threading
import base64
import uuid
import time
import jwt
import timeinterval # look elsewhere for this module
#import logging

__version__ = 1.0

def decode_secret(secret):
    """Allow for base64 encoding of binary secret data--greater entropy"""
    if secret[:6] == "base64":
        return base64.b64decode(secret[7:])
    else:
        return secret

def generate(secret, age, **payload):
    """Generate a one-time jwt with an age in seconds"""
    jti = str(uuid.uuid1()) # random id
    if not payload:
        payload = {}
    payload['exp'] = int(time.time() + age)
    payload['jti'] = jti
    return jwt.encode(payload, decode_secret(secret))

def mutex(func):
    """use a thread lock on current method, if self.lock is defined"""
    def wrapper(*args, **kwargs):
        """Decorator Wrapper"""
        lock = args[0].lock
        lock.acquire(True)
        try:
            return func(*args, **kwargs)
        except:
            raise
        finally:
            lock.release()

    return wrapper

class JwtFailed(Exception):
    """Exception"""
    pass

class Manager(object):
    """
    Threadsafe mechanism to have one-time jwts.
    """

    secrets = []
    jwts = {}
    age = 60
    lock = threading.Lock()

    def __init__(self, *secrets, **kwargs):
        self.age = kwargs.get('age', 60)
        for secret in secrets:
            self.secrets.append(decode_secret(secret))
        timeinterval.start(self.age * 1000, self._clean)

    @mutex
    def _clean(self):
        """Run by housekeeper thread"""
        now = time.time()
        for jwt in self.jwts.keys():
            if (now - self.jwts[jwt]) > (self.age * 2):
                del self.jwts[jwt]

    @mutex
    def already_used(self, tok):
        """has this jwt been used?"""
        if tok in self.jwts:
            return True
        self.jwts[tok] = time.time()
        return False

    def valid(self, token):
        """is this token valid?"""
        now = time.time()

        if 'Bearer ' in token:
            token = token[7:]

        data = None
        for secret in self.secrets:
            try:
                data = jwt.decode(token, secret)
                break
            except jwt.DecodeError:
                continue
            except jwt.ExpiredSignatureError:
                raise JwtFailed("Jwt expired")

        if not data:
            raise JwtFailed("Jwt cannot be decoded")

        exp = data.get('exp')
        if not exp:
            raise JwtFailed("Jwt missing expiration (exp)")

        if now - exp > self.age:
            raise JwtFailed("Jwt bad expiration - greater than I want to accept")

        jti = data.get('jti')
        if not jti:
            raise JwtFailed("Jwt missing one-time id (jti)")

        if self.already_used(jti):
            raise JwtFailed("Jwt re-use disallowed (jti={})".format(jti))

        return data


"""Base classes and utilities for readers and writers.

Authors:

* Brian Granger
"""

#-----------------------------------------------------------------------------
#  Copyright (C) 2008-2011  The IPython Development Team
#
#  Distributed under the terms of the BSD License.  The full license is in
#  the file COPYING, distributed as part of this software.
#-----------------------------------------------------------------------------

#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------

from base64 import encodestring, decodestring
import pprint

from IPython.utils.py3compat import str_to_bytes

#-----------------------------------------------------------------------------
# Code
#-----------------------------------------------------------------------------

def restore_bytes(nb):
    """Restore bytes of image data from unicode-only formats.

    Base64 encoding is handled elsewhere.  Bytes objects in the notebook are
    always b64-encoded. We DO NOT encode/decode around file formats.
    """
    for ws in nb.worksheets:
        for cell in ws.cells:
            if cell.cell_type == 'code':
                for output in cell.outputs:
                    if 'png' in output:
                        output.png = str_to_bytes(output.png, 'ascii')
                    if 'jpeg' in output:
                        output.jpeg = str_to_bytes(output.jpeg, 'ascii')
    return nb

# output keys that are likely to have multiline values
_multiline_outputs = ['text', 'html', 'svg', 'latex', 'javascript', 'json']

def rejoin_lines(nb):
    """rejoin multiline text into strings

    For reversing effects of ``split_lines(nb)``.

    This only rejoins lines that have been split, so if text objects were not split
    they will pass through unchanged.

    Used when reading JSON files that may have been passed through split_lines.
    """
    for ws in nb.worksheets:
        for cell in ws.cells:
            if cell.cell_type == 'code':
                if 'input' in cell and isinstance(cell.input, list):
                    cell.input = u'\n'.join(cell.input)
                for output in cell.outputs:
                    for key in _multiline_outputs:
                        item = output.get(key, None)
                        if isinstance(item, list):
                            output[key] = u'\n'.join(item)
            else: # text cell
                for key in ['source', 'rendered']:
                    item = cell.get(key, None)
                    if isinstance(item, list):
                        cell[key] = u'\n'.join(item)
    return nb

def split_lines(nb):
    """split likely multiline text into lists of strings

    For file output more friendly to line-based VCS. ``rejoin_lines(nb)`` will
    reverse the effects of ``split_lines(nb)``.

    Used when writing JSON files.
    """
    for ws in nb.worksheets:
        for cell in ws.cells:
            if cell.cell_type == 'code':
                if 'input' in cell and isinstance(cell.input, basestring):
                    cell.input = cell.input.splitlines()
                for output in cell.outputs:
                    for key in _multiline_outputs:
                        item = output.get(key, None)
                        if isinstance(item, basestring):
                            output[key] = item.splitlines()
            else: # text cell
                for key in ['source', 'rendered']:
                    item = cell.get(key, None)
                    if isinstance(item, basestring):
                        cell[key] = item.splitlines()
    return nb

# b64 encode/decode are never actually used, because all bytes objects in
# the notebook are already b64-encoded, and we don't need/want to double-encode

def base64_decode(nb):
    """Restore all bytes objects in the notebook from base64-encoded strings.

    Note: This is never used
    """
    for ws in nb.worksheets:
        for cell in ws.cells:
            if cell.cell_type == 'code':
                for output in cell.outputs:
                    if 'png' in output:
                        if isinstance(output.png, unicode):
                            output.png = output.png.encode('ascii')
                        output.png = decodestring(output.png)
                    if 'jpeg' in output:
                        if isinstance(output.jpeg, unicode):
                            output.jpeg = output.jpeg.encode('ascii')
                        output.jpeg = decodestring(output.jpeg)
    return nb

def base64_encode(nb):
    """Base64 encode all bytes objects in the notebook.

    These will be b64-encoded unicode strings

    Note: This is never used
    """
    for ws in nb.worksheets:
        for cell in ws.cells:
            if cell.cell_type == 'code':
                for output in cell.outputs:
                    if 'png' in output:
                        output.png = encodestring(output.png).decode('ascii')
                    if 'jpeg' in output:
                        output.jpeg = encodestring(output.jpeg).decode('ascii')
    return nb

class NotebookReader(object):
    """A class for reading notebooks."""

    def reads(self, s, **kwargs):
        """Read a notebook from a string."""
        raise NotImplementedError("loads must be implemented in a subclass")

    def read(self, fp, **kwargs):
        """Read a notebook from a file like object"""
        return self.read(fp.read(), **kwargs)

class NotebookWriter(object):
    """A class for writing notebooks."""

    def writes(self, nb, **kwargs):
        """Write a notebook to a string."""
        raise NotImplementedError("loads must be implemented in a subclass")

    def write(self, nb, fp, **kwargs):
        """Write a notebook to a file like object"""
        return fp.write(self.writes(nb,**kwargs))


# coding: utf-8
"""
GLUT Inputhook support functions
"""

#-----------------------------------------------------------------------------
#  Copyright (C) 2008-2011  The IPython Development Team
#
#  Distributed under the terms of the BSD License.  The full license is in
#  the file COPYING, distributed as part of this software.
#-----------------------------------------------------------------------------

# GLUT is quite an old library and it is difficult to ensure proper
# integration within IPython since original GLUT does not allow to handle
# events one by one. Instead, it requires for the mainloop to be entered
# and never returned (there is not even a function to exit he
# mainloop). Fortunately, there are alternatives such as freeglut
# (available for linux and windows) and the OSX implementation gives
# access to a glutCheckLoop() function that blocks itself until a new
# event is received. This means we have to setup the idle callback to
# ensure we got at least one event that will unblock the function.
#
# Furthermore, it is not possible to install these handlers without a window
# being first created. We choose to make this window invisible. This means that
# display mode options are set at this level and user won't be able to change
# them later without modifying the code. This should probably be made available
# via IPython options system.

#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
import os
import sys
import time
import signal
import OpenGL
import OpenGL.GLUT as glut
import OpenGL.platform as platform
from timeit import default_timer as clock

#-----------------------------------------------------------------------------
# Constants
#-----------------------------------------------------------------------------

# Frame per second : 60
# Should probably be an IPython option
glut_fps = 60

# Display mode : double buffeed + rgba + depth
# Should probably be an IPython option
glut_display_mode = (glut.GLUT_DOUBLE |
                     glut.GLUT_RGBA   |
                     glut.GLUT_DEPTH)

glutMainLoopEvent = None
if sys.platform == 'darwin':
    try:
        glutCheckLoop = platform.createBaseFunction(
            'glutCheckLoop', dll=platform.GLUT, resultType=None,
            argTypes=[],
            doc='glutCheckLoop(  ) -> None',
            argNames=(),
            )
    except AttributeError:
        raise RuntimeError(
            '''Your glut implementation does not allow interactive sessions'''
            '''Consider installing freeglut.''')
    glutMainLoopEvent = glutCheckLoop
elif glut.HAVE_FREEGLUT:
    glutMainLoopEvent = glut.glutMainLoopEvent
else:
    raise RuntimeError(
        '''Your glut implementation does not allow interactive sessions. '''
        '''Consider installing freeglut.''')

#-----------------------------------------------------------------------------
# Platform-dependent imports and functions
#-----------------------------------------------------------------------------

if os.name == 'posix':
    import select

    def stdin_ready():
        infds, outfds, erfds = select.select([sys.stdin],[],[],0)
        if infds:
            return True
        else:
            return False

elif sys.platform == 'win32':
    import msvcrt

    def stdin_ready():
        return msvcrt.kbhit()

#-----------------------------------------------------------------------------
# Callback functions
#-----------------------------------------------------------------------------

def glut_display():
    # Dummy display function
    pass

def glut_idle():
    # Dummy idle function
    pass

def glut_close():
    # Close function only hides the current window
    glut.glutHideWindow()
    glutMainLoopEvent()

def glut_int_handler(signum, frame):
    # Catch sigint and print the defautl message
    signal.signal(signal.SIGINT, signal.default_int_handler)
    print '\nKeyboardInterrupt'
    # Need to reprint the prompt at this stage

#-----------------------------------------------------------------------------
# Code
#-----------------------------------------------------------------------------
def inputhook_glut():
    """Run the pyglet event loop by processing pending events only.

    This keeps processing pending events until stdin is ready.  After
    processing all pending events, a call to time.sleep is inserted.  This is
    needed, otherwise, CPU usage is at 100%.  This sleep time should be tuned
    though for best performance.
    """
    # We need to protect against a user pressing Control-C when IPython is
    # idle and this is running. We trap KeyboardInterrupt and pass.

    signal.signal(signal.SIGINT, glut_int_handler)

    try:
        t = clock()

        # Make sure the default window is set after a window has been closed
        if glut.glutGetWindow() == 0:
            glut.glutSetWindow( 1 )
            glutMainLoopEvent()
            return 0

        while not stdin_ready():
            glutMainLoopEvent()
            # We need to sleep at this point to keep the idle CPU load
            # low.  However, if sleep to long, GUI response is poor.  As
            # a compromise, we watch how often GUI events are being processed
            # and switch between a short and long sleep time.  Here are some
            # stats useful in helping to tune this.
            # time    CPU load
            # 0.001   13%
            # 0.005   3%
            # 0.01    1.5%
            # 0.05    0.5%
            used_time = clock() - t
            if used_time > 5*60.0:
                # print 'Sleep for 5 s'  # dbg
                time.sleep(5.0)
            elif used_time > 10.0:
                # print 'Sleep for 1 s'  # dbg
                time.sleep(1.0)
            elif used_time > 0.1:
                # Few GUI events coming in, so we can sleep longer
                # print 'Sleep for 0.05 s'  # dbg
                time.sleep(0.05)
            else:
                # Many GUI events coming in, so sleep only very little
                time.sleep(0.001)
    except KeyboardInterrupt:
        pass
    return 0