<commit_before># -*- coding: utf-8 -*-

from pint import UnitRegistry

ureg = UnitRegistry()
ureg.define('bmi = kilogram / meter **2')

#Update schema
__url__ = "https://raw.githubusercontent.com/KittyHawkIrc/modules/production/" + __name__ + ".py"
__version__ = 2.0

# declare() sets the strings that trigger this module.
# declare: None -> Dict{Str: Str}
def declare():
    declares = ['bmi', 'weight', 'mass', 'height', 'setbmi', 'clear_bmi2']
    return {command: 'privmsg' for command in declares}

def callback(self):
    channel = self.channel
    command = self.command.lower()
    user = self.user.split('!')[0]
    msg = self.msg
    isop = self.isop
    message = self.message.split(command, 1)[1].strip()
    words = message.split()

    if command == 'clear_bmi2':
        self.locker.bmi2 = None
        self.cache_save()   #persist cache post-restarts
        return msg(channel, 'All stored values cleared.')

    try:
        mass, height, bmi = parse_input(message)
    except AttributeError:
        pass

    if mass and height and bmi:
        if command == 'setbmi' and len(words) > 0:
            set_other = not message[0].isdigit() and isop
            set_self = bool(message[0].isdigit() and bmi.magnitude < 25)

            if set_other or set_self:
                if set_other:
                    user = words[0]
                try:
                    self.locker.bmi2[user.lower()] = (mass, height, bmi)
                except:
                    self.locker.bmi2 = {user.lower(): (mass, height, bmi)}

                self.cache_save()   #persist cache post-restarts

                output = 'BMI for user [{u}] set to {b:.4g~P} / {b_c}'
            elif set_self:
                output = 'BMI [{b:.4g~P}] out of range settable by [{u}]'
            else:
                output = 'BMI for user [{w[0]}] cannot be set by user [{u}]'
        else:
            output = '{m:.4g~P} / {h:.4g~P} / {b:.4g~P} / {b_c}'
    elif mass or height or bmi or command == 'setbmi':
        output = 'Insufficient input given for {c}'
    else:
        if len(words) > 0 and not message[0].isdigit():
            user = words[0]
        try:
            mass, height, bmi = self.locker.bmi2[user.lower()]
            if command == 'bmi':
                output = '{u} / {b:.4g~P} / {b_c}'
            elif command == 'height':
                output = '{u} / {h:.4g~P}'
            else:
                output = '{u} / {m:.4g~P}'
        except:
            if command == 'bmi':
                try:
                    bmi = self.locker.bmi[user.lower()]
                    if is_quantity(bmi):
                        bmi = bmi.magnitude
                    bmi = bmi * ureg.bmi
                    output = '{u} / {b:.4g~P} / {b_c}'
                except:
                    output = 'BMI not found for user [{u}]'
            else:
                output = '{c} for [{u}] has not been updated since bmi2 update.'

    if height and height.units == ureg.foot:
        output = output.replace('h:.4g~P', 'i_h')

    return msg(channel, output.format(w = words,   b = bmi,
                                      u = user,    m = mass,
                                      c = command, h = height,
                                      i_h = to_feet_inches(height),
                                      b_c = classify_bmi(bmi)))

# parse_input(message) takes string 'message' and attempts to extract and return
#   heights, masses, and BMIs from the string.
# parse_input: Str -> (Quantity None), (Quantity None), (Quantity None)
def parse_input(message):
    # replace ' and " with inch and feet before splitting message
    words = replace_foot_inch_symbol(message).split()

    # create variables
    heights = []
    masses = []
    bmi = 0

    for i, word in enumerate(words):
        # only allow numbers to be processed
        if not word[0].isdigit():
            continue

        # allow for spaces between magnitudes and units by concatenating word
        #   with following word
        if is_float(word) and (i+1 < len(words) and not is_float(words[i+1])):
            word = ' '.join((word, words.pop(i+1)))

        # check for bmi values included
        if len(word) > 3 and is_float(word[:-3]) and word[-3:].lower() == 'bmi':
            bmi = float(word[:-3]) * (ureg.bmi)
            continue

        # otherwise, check for quantities recognized by ureg
        quantity = ureg.Quantity(word)
        if is_quantity(quantity):
            if str(quantity.dimensionality) == '[length]':
                heights.append(quantity)
            elif str(quantity.dimensionality) == '[mass]':
                masses.append(quantity)

    # sum quantities recognized by ureg
    height = sum(heights)
    mass = sum(masses)

    # fill in missing quantity with maths
    if is_quantity(height) and is_quantity(mass):
        bmi = (mass / height ** 2).to(ureg.bmi)
    elif is_quantity(bmi) and is_quantity(height):
        mass = (bmi * height ** 2).to_base_units()
    elif is_quantity(bmi) and is_quantity(mass):
        height = ((mass / bmi) ** 0.5).to_base_units()

    # return tuple in order of mass, height (as mass/height^2=bmi)
    return mass, height, bmi

# classify_bmi(bmi) takes quantity 'bmi' and returns string for whether a bmi of
#   'bmi' is one of underweight, normal, obese, or overweight, with IRC control
#   codes to colour those results.
# classify_bmi: Quantity -> (Str None)
# requires: bmi.dimensionality == {'[length]': -2.0, '[mass]': 1.0}
def classify_bmi(bmi):
    try:
        if bmi.magnitude < 18.5:
            return '\002\00308underweight\017'
        if bmi.magnitude < 25.0:
            return '\002\00309normal\017'
        if bmi.magnitude < 30.0:
            return '\002\00307overweight\017'
        else:
            return '\002\00304obese\017'
    except:
        return None

# to_feet_inches(quantity) takes length 'quantity' and returns a tuple of the
#   length in feet and inches.
# to_feet_inches: Quantity -> (Str None)
# requires: quantity.dimensionality == {'[length]': 1.0}
def to_feet_inches(quantity):
    try:
        imperial_height_str = '{.magnitude:.0f}\'{.magnitude:.4g}"'
        feet = int(quantity.to(ureg.foot).magnitude) * ureg.foot
        inches = (quantity - feet).to(ureg.inch)
        return imperial_height_str.format(feet, inches)
    except:
        return None

# replace_foot_inch_symbol(string) takes string and replaces all instances of
#   quotation marks with their respective unit (foot or inch).
# replace_foot_inch_symbol: Str -> Str
def replace_foot_inch_symbol(string):
    foot_symbols = ["'", "‘", "’"]
    inch_symbols = ['"', '“', '”']

    for symbol in foot_symbols:
        string = string.replace(symbol, 'foot ')

    for symbol in inch_symbols:
        string = string.replace(symbol, 'inch ')

    return string

# is_imperial(quantity) returns whether 'quantity' is an imperial unit or not.
# is_imperial: Quantity -> Bool
def is_imperial(quantity):
    if (quantity.units in dir(ureg.sys.US) or
        quantity.units in dir(ureg.sys.imperial)):
        return True
    return False

# is_float(object_) takes any object 'object_' and returns a boolean for
#   whether it can be converted into a float
# is_float: Any -> Bool
def is_float(object_):
    try:
        float(object_)
        return True
    except:
        return False

# is_quantity(object_) takes any object 'object_' and returns a boolean for
#   whether it is of the type 'Quantity'
# is_quantity: Any -> Bool
def is_quantity(object_):
    return type(object_).__name__ == 'Quantity'

################################ START: Testing ################################
class api:
    def msg(self, channel, text):
        return "[%s] %s" % (channel, text)

class empty:
    pass

if __name__ == "__main__":
    def cache_save():
        print 'Cache saved'
    api = api()
    declares = declare().keys()
226
    declares = ['bmi', 'weight', 'mass', 'height', 'setbmi']
    setattr(api, 'cache_save', cache_save)
    setattr(api, 'type', 'privmsg')
    setattr(api, 'channel', "#channel")
    setattr(api, 'locker', empty)
    setattr(api, 'user', 'nick!ident@host')
    setattr(api, 'isop', False)
########################## START: Interactive Testing ##########################
'''
    while(True):
        _input = raw_input('Enter message here: ')
        input_split = _input.split()
        if input_split[0] == 'op':
            setattr(api, 'isop', True)
            print 'User opped'
            continue
        elif input_split[0] == 'deop':
            setattr(api, 'isop', False)
            print 'User deopped'
            continue
        elif input_split[0] == 'user' and len(input_split) > 1:
            setattr(api, 'user', input_split[1])
            print 'User changed to {}'.format(input_split[1])
            continue
        elif input_split[0] == 'quit':
            break
        elif len(_input) > 0 and input_split[0][1:] in declares:
            setattr(api, 'command', _input.split()[0][1:])
            setattr(api, 'message', _input)
            print callback(api)
            continue
'''
########################### END: Interactive Testing ###########################

################################# END: Testing #################################
<commit_msg>oops<commit_after># -*- coding: utf-8 -*-

from pint import UnitRegistry

ureg = UnitRegistry()
ureg.define('bmi = kilogram / meter **2')

#Update schema
__url__ = "https://raw.githubusercontent.com/KittyHawkIrc/modules/production/" + __name__ + ".py"
__version__ = 2.0

# declare() sets the strings that trigger this module.
# declare: None -> Dict{Str: Str}
def declare():
    declares = ['bmi', 'weight', 'mass', 'height', 'setbmi', 'clear_bmi2']
    return {command: 'privmsg' for command in declares}

def callback(self):
    channel = self.channel
    command = self.command.lower()
    user = self.user.split('!')[0]
    msg = self.msg
    isop = self.isop
    message = self.message.split(command, 1)[1].strip()
    words = message.split()

    if command == 'clear_bmi2':
        self.locker.bmi2 = None
        self.cache_save()   #persist cache post-restarts
        return msg(channel, 'All stored values cleared.')

    try:
        mass, height, bmi = parse_input(message)
    except AttributeError:
        pass

    if mass and height and bmi:
        if command == 'setbmi' and len(words) > 0:
            set_other = not message[0].isdigit() and isop
            set_self = bool(message[0].isdigit() and bmi.magnitude < 25)

            if set_other or set_self:
                if set_other:
                    user = words[0]
                try:
                    self.locker.bmi2[user.lower()] = (mass, height, bmi)
                except:
                    self.locker.bmi2 = {user.lower(): (mass, height, bmi)}

                self.cache_save()   #persist cache post-restarts

                output = 'BMI for user [{u}] set to {b:.4g~P} / {b_c}'
            elif set_self:
                output = 'BMI [{b:.4g~P}] out of range settable by [{u}]'
            else:
                output = 'BMI for user [{w[0]}] cannot be set by user [{u}]'
        else:
            output = '{m:.4g~P} / {h:.4g~P} / {b:.4g~P} / {b_c}'
    elif mass or height or bmi or command == 'setbmi':
        output = 'Insufficient input given for {c}'
    else:
        if len(words) > 0 and not message[0].isdigit():
            user = words[0]
        try:
            mass, height, bmi = self.locker.bmi2[user.lower()]
            if command == 'bmi':
                output = '{u} / {b:.4g~P} / {b_c}'
            elif command == 'height':
                output = '{u} / {h:.4g~P}'
            else:
                output = '{u} / {m:.4g~P}'
        except:
            if command == 'bmi':
                try:
                    bmi = self.locker.bmi[user.lower()]
                    if is_quantity(bmi):
                        bmi = bmi.magnitude
                    bmi = bmi * ureg.bmi
                    output = '{u} / {b:.4g~P} / {b_c}'
                except:
                    output = 'BMI not found for user [{u}]'
            else:
                output = '{c} for [{u}] has not been updated since bmi2 update.'

    if height and height.units == ureg.foot:
        output = output.replace('h:.4g~P', 'i_h')

    return msg(channel, output.format(w = words,   b = bmi,
                                      u = user,    m = mass,
                                      c = command, h = height,
                                      i_h = to_feet_inches(height),
                                      b_c = classify_bmi(bmi)))

# parse_input(message) takes string 'message' and attempts to extract and return
#   heights, masses, and BMIs from the string.
# parse_input: Str -> (Quantity None), (Quantity None), (Quantity None)
def parse_input(message):
    # replace ' and " with inch and feet before splitting message
    words = replace_foot_inch_symbol(message).split()

    # create variables
    heights = []
    masses = []
    bmi = 0

    for i, word in enumerate(words):
        # only allow numbers to be processed
        if not word[0].isdigit():
            continue

        # allow for spaces between magnitudes and units by concatenating word
        #   with following word
        if is_float(word) and (i+1 < len(words) and not is_float(words[i+1])):
            word = ' '.join((word, words.pop(i+1)))

        # check for bmi values included
        if len(word) > 3 and is_float(word[:-3]) and word[-3:].lower() == 'bmi':
            bmi = float(word[:-3]) * (ureg.bmi)
            continue

        # otherwise, check for quantities recognized by ureg
        quantity = ureg.Quantity(word)
        if is_quantity(quantity):
            if str(quantity.dimensionality) == '[length]':
                heights.append(quantity)
            elif str(quantity.dimensionality) == '[mass]':
                masses.append(quantity)

    # sum quantities recognized by ureg
    height = sum(heights)
    mass = sum(masses)

    # fill in missing quantity with maths
    if is_quantity(height) and is_quantity(mass):
        bmi = (mass / height ** 2).to(ureg.bmi)
    elif is_quantity(bmi) and is_quantity(height):
        mass = (bmi * height ** 2).to_base_units()
    elif is_quantity(bmi) and is_quantity(mass):
        height = ((mass / bmi) ** 0.5).to_base_units()

    # return tuple in order of mass, height (as mass/height^2=bmi)
    return mass, height, bmi

# classify_bmi(bmi) takes quantity 'bmi' and returns string for whether a bmi of
#   'bmi' is one of underweight, normal, obese, or overweight, with IRC control
#   codes to colour those results.
# classify_bmi: Quantity -> (Str None)
# requires: bmi.dimensionality == {'[length]': -2.0, '[mass]': 1.0}
def classify_bmi(bmi):
    try:
        if bmi.magnitude < 18.5:
            return '\002\00308underweight\017'
        if bmi.magnitude < 25.0:
            return '\002\00309normal\017'
        if bmi.magnitude < 30.0:
            return '\002\00307overweight\017'
        else:
            return '\002\00304obese\017'
    except:
        return None

# to_feet_inches(quantity) takes length 'quantity' and returns a tuple of the
#   length in feet and inches.
# to_feet_inches: Quantity -> (Str None)
# requires: quantity.dimensionality == {'[length]': 1.0}
def to_feet_inches(quantity):
    try:
        imperial_height_str = '{.magnitude:.0f}\'{.magnitude:.4g}"'
        feet = int(quantity.to(ureg.foot).magnitude) * ureg.foot
        inches = (quantity - feet).to(ureg.inch)
        return imperial_height_str.format(feet, inches)
    except:
        return None

# replace_foot_inch_symbol(string) takes string and replaces all instances of
#   quotation marks with their respective unit (foot or inch).
# replace_foot_inch_symbol: Str -> Str
def replace_foot_inch_symbol(string):
    foot_symbols = ["'", "‘", "’"]
    inch_symbols = ['"', '“', '”']

    for symbol in foot_symbols:
        string = string.replace(symbol, 'foot ')

    for symbol in inch_symbols:
        string = string.replace(symbol, 'inch ')

    return string

# is_imperial(quantity) returns whether 'quantity' is an imperial unit or not.
# is_imperial: Quantity -> Bool
def is_imperial(quantity):
    if (quantity.units in dir(ureg.sys.US) or
        quantity.units in dir(ureg.sys.imperial)):
        return True
    return False

# is_float(object_) takes any object 'object_' and returns a boolean for
#   whether it can be converted into a float
# is_float: Any -> Bool
def is_float(object_):
    try:
        float(object_)
        return True
    except:
        return False

# is_quantity(object_) takes any object 'object_' and returns a boolean for
#   whether it is of the type 'Quantity'
# is_quantity: Any -> Bool
def is_quantity(object_):
    return type(object_).__name__ == 'Quantity'

################################ START: Testing ################################
class api:
    def msg(self, channel, text):
        return "[%s] %s" % (channel, text)

class empty:
    pass

if __name__ == "__main__":
    def cache_save():
        print 'Cache saved'
    api = api()
    declares = declare().keys()
    setattr(api, 'cache_save', cache_save)
    setattr(api, 'type', 'privmsg')
    setattr(api, 'channel', "#channel")
    setattr(api, 'locker', empty)
    setattr(api, 'user', 'nick!ident@host')
    setattr(api, 'isop', False)
########################## START: Interactive Testing ##########################
'''
    while(True):
        _input = raw_input('Enter message here: ')
        input_split = _input.split()
        if input_split[0] == 'op':
            setattr(api, 'isop', True)
            print 'User opped'
            continue
        elif input_split[0] == 'deop':
            setattr(api, 'isop', False)
            print 'User deopped'
            continue
        elif input_split[0] == 'user' and len(input_split) > 1:
            setattr(api, 'user', input_split[1])
            print 'User changed to {}'.format(input_split[1])
            continue
        elif input_split[0] == 'quit':
            break
        elif len(_input) > 0 and input_split[0][1:] in declares:
            setattr(api, 'command', _input.split()[0][1:])
            setattr(api, 'message', _input)
            print callback(api)
            continue
'''
########################### END: Interactive Testing ###########################

################################# END: Testing #################################
<|endoftext|>


<commit_before>"""Compute driving functions for various systems"""

import numpy as np

def delay_3d_pw(k, x0, n0, npw=[0, 1, 0]):
    """Plane wave by simple delay of secondary sources."""
    x0 = np.asarray(x0)
    npw = np.squeeze(np.asarray(npw))
    return np.exp(-1j * k * np.inner(npw, x0))

def wfs_3d_pw(k, x0, n0, npw=[0, 1, 0]):
    """Plane wave by three dimensional WFS. Eq.(17) from [Spors et al, 2008]"""
    x0 = np.asarray(x0)
    n0 = np.asarray(n0)
    npw = np.squeeze(np.asarray(npw))
    return -2j * k * np.inner(npw, n0) * np.exp(-1j * k * np.inner(npw, x0))

def source_selection_pw(n0, npw):
    """Secondary source selection for a plane wave. Eq.(13) from [Spors et al, 2008]"""
    n0 = np.asarray(n0)
    npw = np.asarray(npw)
    return np.inner(npw, n0) >= 0
<commit_msg>Add WFS mono driving functions<commit_after>"""Compute driving functions for various systems"""

import numpy as np

def wfs_ps(k, x0, n0, xs):
    """Point source by two-dimensional WFS."""
    #                (x0-xs) n0
    # D(x0,k) = j k ------------- e^(-j k |x0-xs|)
    #               |x0-xs|^(3/2)
    x0 = np.asarray(x0)
    n0 = np.asarray(n0)
    xs = np.asarray(xs)
    r = x0-xs
    return 1j * k * np.inner(r, n0) / np.abs(r) ** (3 / 2) * \
        np.exp(-1j * k * np.abs(r))

def wfs_2d_ps(k, x0, n0, xs):
    """Point source by two-dimensional WFS."""
    return wfs_ps(k, x0, n0, xs)

def wfs_25d_ps(k, x0, n0, xs, xref=[0, 0, 0]):
    """Point source by 2.5-dimensional WFS."""
    #             ____________   (x0-xs) n0
    # D(x0,k) = \|j k |xref-x0| ------------- e^(-j k |x0-xs|)
    #                           |x0-xs|^(3/2)
    x0 = np.asarray(x0)
    n0 = np.asarray(n0)
    xs = np.asarray(xs)
    xref = np.asarray(xref)
    r = x0-xs
    return np.sqrt(1j * k * np.abs(xref - x0)) * np.inner(r, n0) / \
        np.abs(r) ** (3 / 2) * np.exp(-1j * k * np.abs(r))

def wfs_3d_ps(k, x0, nx0, xs):
    """Point source by three-dimensional WFS."""
    return wfs_ps(k, x0, nx0, xs)

def wfs_pw(k, x0, n0, n=[0, 1, 0]):
    """Plane wave by WFS."""
    # D(x0,k) =  j k n n0  e^(-j k n x0)
    x0 = np.asarray(x0)
    n0 = np.asarray(n0)
    n = np.squeeze(np.asarray(n))
    return 1j * k * np.inner(n, n0) * np.exp(-1j * k * np.inner(n, n0))

def wfs_2d_pw(k, x0, n0, n=[0, 1, 0]):
    """Plane wave by two-dimensional WFS."""
    return wfs_pw(k, x0, n0, n)

def wfs_25d_pw(k, x0, n0, n=[0, 1, 0], xref=[0, 0, 0]):
    """Plane wave by 2.5-dimensional WFS."""
    #                  ____________
    # D_2.5D(x0,w) = \|j k |xref-x0| n n0 e^(-j k n x0)
    x0 = np.asarray(x0)
    n0 = np.asarray(n0)
    n = np.squeeze(np.asarray(n))
    return np.sqrt(1j * k * np.abs(xref-x0)) * np.inner(n, n0) * \
        np.exp(-1j * k * np.inner(n, x0))

def wfs_3d_pw(k, x0, n0, n=[0, 1, 0]):
    """Plane wave by three-dimensional WFS.
       Eq.(17) from [Spors et al, 2008]"""
    return wfs_pw(k, x0, n0, n)

def delay_3d_pw(k, x0, n0, n=[0, 1, 0]):
    """Plane wave by simple delay of secondary sources."""
    x0 = np.asarray(x0)
    n = np.squeeze(np.asarray(n))
    return np.exp(-1j * k * np.inner(n, x0))

def source_selection_pw(n0, n):
    """Secondary source selection for a plane wave.
       Eq.(13) from [Spors et al, 2008]"""
    n0 = np.asarray(n0)
    n = np.asarray(n)
    return np.inner(n, n0) >= 0
<|endoftext|>


<commit_before>import os, sys

# We allow a two-level project structure where your root folder contains
# project-specific apps and the "common" subfolder contains common apps.
COMMON_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
PROJECT_DIR = os.path.dirname(COMMON_DIR)
if os.path.basename(COMMON_DIR) == 'common-apps':
    MAIN_DIRS = (PROJECT_DIR, COMMON_DIR)
else:
    PROJECT_DIR = COMMON_DIR
    MAIN_DIRS = (PROJECT_DIR,)

# Overrides for os.environ
env_ext = {}
if 'DJANGO_SETTINGS_MODULE' not in os.environ:
    env_ext['DJANGO_SETTINGS_MODULE'] = 'settings'

def setup_env():
    """Configures app engine environment for command-line apps."""
    # Try to import the appengine code from the system path.
    try:
        from google.appengine.api import apiproxy_stub_map
    except ImportError:
        for k in [k for k in sys.modules if k.startswith('google')]:
            del sys.modules[k]

        # Not on the system path. Build a list of alternative paths where it
        # may be. First look within the project for a local copy, then look for
        # where the Mac OS SDK installs it.
        paths = [os.path.join(PROJECT_DIR, '.google_appengine'),
                 os.path.join(COMMON_DIR, '.google_appengine'),
                 '/usr/local/google_appengine',
                 '/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine']
        for path in os.environ.get('PATH', '').replace(';', ':').split(':'):
            path = path.rstrip(os.sep)
            if path.endswith('google_appengine'):
                paths.append(path)
        if os.name in ('nt', 'dos'):
            prefix = '%(PROGRAMFILES)s' % os.environ
            paths.append(prefix + r'\Google\google_appengine')
        # Loop through all possible paths and look for the SDK dir.
        SDK_PATH = None
        for sdk_path in paths:
            sdk_path = os.path.realpath(sdk_path)
            if os.path.exists(sdk_path):
                SDK_PATH = sdk_path
                break
        if SDK_PATH is None:
            # The SDK could not be found in any known location.
            sys.stderr.write('The Google App Engine SDK could not be found!\n'
                             "Make sure it's accessible via your PATH "
                             "environment and called google_appengine.")
            sys.exit(1)
        # Add the SDK and the libraries within it to the system path.
        EXTRA_PATHS = [SDK_PATH]
        lib = os.path.join(SDK_PATH, 'lib')
        # Automatically add all packages in the SDK's lib folder:
        for dir in os.listdir(lib):
            path = os.path.join(lib, dir)
            # Package can be under 'lib/<pkg>/<pkg>/' or 'lib/<pkg>/lib/<pkg>/'
            detect = (os.path.join(path, dir), os.path.join(path, 'lib', dir))
            for path in detect:
                if os.path.isdir(path) and not dir == 'django':
                    EXTRA_PATHS.append(os.path.dirname(path))
                    break
        sys.path = EXTRA_PATHS + sys.path
        from google.appengine.api import apiproxy_stub_map

    setup_project()
    setup_logging()

def setup_threading():
    # XXX: GAE's threading.local doesn't work correctly with subclassing
    try:
        from django.utils._threading_local import local
        import threading
        threading.local = local
    except ImportError:
        pass

def setup_logging():
    import logging

    # Fix Python 2.6 logging module
    logging.logMultiprocessing = 0

    # Enable logging
    from django.conf import settings
    if settings.DEBUG:
        logging.getLogger().setLevel(logging.DEBUG)
    else:
        logging.getLogger().setLevel(logging.INFO)

def setup_project():
    from .utils import have_appserver
    if have_appserver:
        # This fixes a pwd import bug for os.path.expanduser()
        global env_ext
        env_ext['HOME'] = PROJECT_DIR

    os.environ.update(env_ext)

    EXTRA_PATHS = list(MAIN_DIRS)
    EXTRA_PATHS.append(os.path.dirname(PROJECT_DIR))
    EXTRA_PATHS.append(os.path.join(os.path.dirname(__file__), 'lib'))

    ZIP_PACKAGES_DIRS = tuple(os.path.join(dir, 'zip-packages')
                              for dir in MAIN_DIRS)

    # We support zipped packages in the common and project folders.
    for packages_dir in ZIP_PACKAGES_DIRS:
        if os.path.isdir(packages_dir):
            for zip_package in os.listdir(packages_dir):
                EXTRA_PATHS.append(os.path.join(packages_dir, zip_package))

    # App Engine causes main.py to be reloaded if an exception gets raised
    # on the first request of a main.py instance, so don't call setup_project()
    # multiple times. We ensure this indirectly by checking if we've already
    # modified sys.path.
    if len(sys.path) < len(EXTRA_PATHS) or \
            sys.path[:len(EXTRA_PATHS)] != EXTRA_PATHS:

        sys.path = EXTRA_PATHS + sys.path
<commit_msg>deprecated "common-apps" folder<commit_after>import os, sys

# We allow a two-level project structure where your root folder contains
# project-specific apps and the "common" subfolder contains common apps.
COMMON_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
PROJECT_DIR = os.path.dirname(COMMON_DIR)
if os.path.basename(COMMON_DIR) == 'common-apps':
    MAIN_DIRS = (PROJECT_DIR, COMMON_DIR)
    print >>sys.stderr, '!!!!!!!!!!!!!!!!!!!!!!!!!!\n' \
                        'Deprecation warning: the "common-apps" folder ' \
                        'is deprecated. Please move all modules from ' \
                        'there into the main project folder and remove ' \
                        'the "common-apps" folder.\n' \
                        '!!!!!!!!!!!!!!!!!!!!!!!!!!\n'
else:
    PROJECT_DIR = COMMON_DIR
    MAIN_DIRS = (PROJECT_DIR,)

# Overrides for os.environ
env_ext = {}
if 'DJANGO_SETTINGS_MODULE' not in os.environ:
    env_ext['DJANGO_SETTINGS_MODULE'] = 'settings'

def setup_env():
    """Configures app engine environment for command-line apps."""
    # Try to import the appengine code from the system path.
    try:
        from google.appengine.api import apiproxy_stub_map
    except ImportError:
        for k in [k for k in sys.modules if k.startswith('google')]:
            del sys.modules[k]

        # Not on the system path. Build a list of alternative paths where it
        # may be. First look within the project for a local copy, then look for
        # where the Mac OS SDK installs it.
        paths = [os.path.join(PROJECT_DIR, '.google_appengine'),
                 os.path.join(COMMON_DIR, '.google_appengine'),
                 '/usr/local/google_appengine',
                 '/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine']
        for path in os.environ.get('PATH', '').replace(';', ':').split(':'):
            path = path.rstrip(os.sep)
            if path.endswith('google_appengine'):
                paths.append(path)
        if os.name in ('nt', 'dos'):
            prefix = '%(PROGRAMFILES)s' % os.environ
            paths.append(prefix + r'\Google\google_appengine')
        # Loop through all possible paths and look for the SDK dir.
        SDK_PATH = None
        for sdk_path in paths:
            sdk_path = os.path.realpath(sdk_path)
            if os.path.exists(sdk_path):
                SDK_PATH = sdk_path
                break
        if SDK_PATH is None:
            # The SDK could not be found in any known location.
            sys.stderr.write('The Google App Engine SDK could not be found!\n'
                             "Make sure it's accessible via your PATH "
                             "environment and called google_appengine.")
            sys.exit(1)
        # Add the SDK and the libraries within it to the system path.
        EXTRA_PATHS = [SDK_PATH]
        lib = os.path.join(SDK_PATH, 'lib')
        # Automatically add all packages in the SDK's lib folder:
        for dir in os.listdir(lib):
            path = os.path.join(lib, dir)
            # Package can be under 'lib/<pkg>/<pkg>/' or 'lib/<pkg>/lib/<pkg>/'
            detect = (os.path.join(path, dir), os.path.join(path, 'lib', dir))
            for path in detect:
                if os.path.isdir(path) and not dir == 'django':
                    EXTRA_PATHS.append(os.path.dirname(path))
                    break
        sys.path = EXTRA_PATHS + sys.path
        from google.appengine.api import apiproxy_stub_map

    setup_project()
    setup_logging()

def setup_threading():
    # XXX: GAE's threading.local doesn't work correctly with subclassing
    try:
        from django.utils._threading_local import local
        import threading
        threading.local = local
    except ImportError:
        pass

def setup_logging():
    import logging

    # Fix Python 2.6 logging module
    logging.logMultiprocessing = 0

    # Enable logging
    from django.conf import settings
    if settings.DEBUG:
        logging.getLogger().setLevel(logging.DEBUG)
    else:
        logging.getLogger().setLevel(logging.INFO)

def setup_project():
    from .utils import have_appserver
    if have_appserver:
        # This fixes a pwd import bug for os.path.expanduser()
        global env_ext
        env_ext['HOME'] = PROJECT_DIR

    os.environ.update(env_ext)

    EXTRA_PATHS = list(MAIN_DIRS)
    EXTRA_PATHS.append(os.path.dirname(PROJECT_DIR))
    EXTRA_PATHS.append(os.path.join(os.path.dirname(__file__), 'lib'))

    ZIP_PACKAGES_DIRS = tuple(os.path.join(dir, 'zip-packages')
                              for dir in MAIN_DIRS)

    # We support zipped packages in the common and project folders.
    for packages_dir in ZIP_PACKAGES_DIRS:
        if os.path.isdir(packages_dir):
            for zip_package in os.listdir(packages_dir):
                EXTRA_PATHS.append(os.path.join(packages_dir, zip_package))

    # App Engine causes main.py to be reloaded if an exception gets raised
    # on the first request of a main.py instance, so don't call setup_project()
    # multiple times. We ensure this indirectly by checking if we've already
    # modified sys.path.
    if len(sys.path) < len(EXTRA_PATHS) or \
            sys.path[:len(EXTRA_PATHS)] != EXTRA_PATHS:

        sys.path = EXTRA_PATHS + sys.path
<|endoftext|>


<commit_before>import socket
import threading
import sys
import getopt
import time
import signal
import os

inputport = 0
remoteport = 0
remoteaddress = ""
kill = False

help = "Invalid arguments, usage:\nboxy.py -i <input port> -p <remote port> -a <remote address>"

def relay():
	sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
	sock.bind(("0.0.0.0", inputport))

	incomingsetup = False
	clientport = 0
	clientip = ""

	while True:
		data, fromaddr = sock.recvfrom(1024)

		if (kill == True):
			sock.close()
			return

		if (incomingsetup == False):
			clientport = fromaddr[1]
			clientip = fromaddr[0]
			incomingsetup = True

		if (fromaddr[0] == clientip):
			#forward from client to server
			sock.sendto(data, (remoteaddress, remoteport))
		else:
			#forward from server to client
			sock.sendto(data, (clientip, clientport))

def quit():
	global kill

	print "Quitting..."

	kill = True
	#send anything to the input port to trigger it to read, therefore allowing the thread to close
	quitsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
	quitsock.sendto("killing", ("127.0.0.1", inputport))
	quitsock.close()
	os._exit(0)

#process args
try:
	options, args = getopt.getopt(sys.argv[1:], "i:p:a:")
except getopt.Getopterror:
	print help
	sys.exit(2)

for option, arg in options:
	if (option == "-i"):
		inputport = int(arg)
	elif (option == "-p"):
		remoteport = int(arg)
	elif (option == "-a"):
		remoteaddress = arg

if ((0 < inputport <= 65535 and 0 < remoteport <= 65535 and remoteaddress != "") == False):
	print help
	sys.exit(2)

print "Relay starting on port " + str(inputport) + ", relaying UDP to", remoteaddress + ":" + str(remoteport)

#start relay
relaythread = threading.Thread(target=relay)
relaythread.start()

try:
	while raw_input() != "quit":
		continue
	quit()
except KeyboardInterrupt:
	quit()
except EOFError:
	#this exception is raised when ctrl-c is used to close the application on Windows, appears to be thrown twice?
	try:
		quit()
	except KeyboardInterrupt:
		os._exit(0)<commit_msg>Add error handling in parsing arguments<commit_after>import socket
import threading
import sys
import getopt
import time
import signal
import os

inputport = 0
remoteport = 0
remoteaddress = ""
kill = False

help = "Invalid arguments, usage:\nboxy.py -i <input port> -p <remote port> -a <remote address>"

def relay():
	sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
	sock.bind(("0.0.0.0", inputport))

	incomingsetup = False
	clientport = 0
	clientip = ""

	while True:
		data, fromaddr = sock.recvfrom(1024)

		if (kill == True):
			sock.close()
			return

		if (incomingsetup == False):
			clientport = fromaddr[1]
			clientip = fromaddr[0]
			incomingsetup = True

		if (fromaddr[0] == clientip):
			#forward from client to server
			sock.sendto(data, (remoteaddress, remoteport))
		else:
			#forward from server to client
			sock.sendto(data, (clientip, clientport))

def quit():
	global kill

	print "Quitting..."

	kill = True
	#send anything to the input port to trigger it to read, therefore allowing the thread to close
	quitsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
	quitsock.sendto("killing", ("127.0.0.1", inputport))
	quitsock.close()
	os._exit(0)

#process args
try:
	options, args = getopt.getopt(sys.argv[1:], "i:p:a:")
except getopt.Getopterror:
	print help
	sys.exit(2)

try:
	for option, arg in options:
		if (option == "-i"):
			inputport = int(arg)
		elif (option == "-p"):
			remoteport = int(arg)
		elif (option == "-a"):
			remoteaddress = arg
except ValueError:
	print help
	sys.exit(2)

if ((0 < inputport <= 65535 and 0 < remoteport <= 65535 and remoteaddress != "") == False):
	print help
	sys.exit(2)

print "Relay starting on port " + str(inputport) + ", relaying UDP to", remoteaddress + ":" + str(remoteport)

#start relay
relaythread = threading.Thread(target=relay)
relaythread.start()

try:
	while raw_input() != "quit":
		continue
	quit()
except KeyboardInterrupt:
	quit()
except EOFError:
	#this exception is raised when ctrl-c is used to close the application on Windows, appears to be thrown twice?
	try:
		quit()
	except KeyboardInterrupt:
		os._exit(0)<|endoftext|>


<commit_before>"""calc.py: A simple Python calculator."""
import sys

def add_all(nums):
    return sum (nums)

def multiply_all(nums):
    return reduce(lambda a, b: a * b, nums)

if __name__ == '__main__':
    command = sys.argv[1]
    nums = map(float, sys.argv[2:])
    if command == 'add':
        print (add_all(nums))
    elif command == 'multiply':
        print(multiply_all(nums))
<commit_msg>Add usage message<commit_after>"""calc.py: A simple Python calculator."""
import sys

def add_all(nums):
    return sum (nums)

def multiply_all(nums):
    return reduce(lambda a, b: a * b, nums)

if __name__ == '__main__':
    command = sys.argv[1]
    nums = map(float, sys.argv[2:])
    if command == 'add':
        print (add_all(nums))
    elif command == 'multiply':
        print(multiply_all(nums))
    else:
        usage = "calc.py [add|multiply] NUM1 [NUM2 [NUM3 [...]]]"
        print(usage)
<|endoftext|>


<commit_before># card.py
#
# Created by Thomas Nelson on 2014-04-12, tn90ca@gmail.com
#
# This class was developed for public use as part of the
# Cards package.

 # The Card class is used to represent a single playing card
 # from a deck of 52 or 54. The card has a suit and a rank.
class Card:
  self.card = ""
  self.suit = ''
  self.rank = ''

   # Class initializer method creates a new playing card with
   # a desired rank and suit provided through the creation
   # parameters.
   #
   # @param self  This is a default python class argument
   # @param suit  Card suit denoted by char (C,H,D,S)
   # @param rank  Card rank denoted by char (2,3,4,5,6,7,8,9,0,J,Q,K,A)
  def __init__(self,suit,rank):
    self.suit = suit
    self.rank = rank
    self.card = rank + auit
  # end def __init__

   # Method returns the class rank as a character
   # 2,3,4,5,6,7,8,9,0,J,Q,K,A
   #
   # @param self  This is a default python class argument
  def getRank(self):
    return self.rank
  # end def getRank

   # Method returns the class suit as a character
   # C,H,D,S
   #
   # @param self  This is a default python class argument
  def getSuit(self):
    return self.suit
  # end def getSuit

   # When print is called on a card this method will return
   # the card as a string representation of its suit and
   # rank. (i.e. 3C,AH,0D,KS)
   #
   # @param self  This is is a default python class argument
  def __str__(self):
    return self.card
  # end def __str__
# end class Card
<commit_msg>Update card.py (spelling fix)<commit_after># card.py
#
# Created by Thomas Nelson on 2014-04-12, tn90ca@gmail.com
#
# This class was developed for public use as part of the
# Cards package.

 # The Card class is used to represent a single playing card
 # from a deck of 52 or 54. The card has a suit and a rank.
class Card:
  self.card = ""
  self.suit = ''
  self.rank = ''

   # Class initializer method creates a new playing card with
   # a desired rank and suit provided through the creation
   # parameters.
   #
   # @param self  This is a default python class argument
   # @param suit  Card suit denoted by char (C,H,D,S)
   # @param rank  Card rank denoted by char (2,3,4,5,6,7,8,9,0,J,Q,K,A)
  def __init__(self,suit,rank):
    self.suit = suit
    self.rank = rank
    self.card = rank + suit
  # end def __init__

   # Method returns the class rank as a character
   # 2,3,4,5,6,7,8,9,0,J,Q,K,A
   #
   # @param self  This is a default python class argument
  def getRank(self):
    return self.rank
  # end def getRank

   # Method returns the class suit as a character
   # C,H,D,S
   #
   # @param self  This is a default python class argument
  def getSuit(self):
    return self.suit
  # end def getSuit

   # When print is called on a card this method will return
   # the card as a string representation of its suit and
   # rank. (i.e. 3C,AH,0D,KS)
   #
   # @param self  This is is a default python class argument
  def __str__(self):
    return self.card
  # end def __str__
# end class Card
<|endoftext|>


<commit_before>from metabotnik.models import Project, File, new_task
from dropbox.client import DropboxClient
import os
import sys
import subprocess
import traceback
import json
from django.utils import timezone
from django.core.mail import send_mail
from django.conf import settings
import planodo
from PIL import Image
from metabotnik.xmp import read_metadata
import random
import shutil
from natsort import natsorted

class RetryTaskException(Exception):
    'Raise this Exception in a task to have it retried later'
    pass

def execute_task(task):
    payload = task.get_payload()
    task_function = globals().get(task.action) # Consider doing a getattr(sys.modules[__name__], action) ?
    if task_function:

        # Bit of fun on local development machine
        if sys.platform == 'darwin':
            subprocess.call(['say', 'started task %s' % task.pk])

        task.status = 'wip'
        task.time_started = timezone.now()
        task.save()
        try:
            result = task_function(payload)
            if type(result) is dict:
                payload.update(result)
            # consider taking the return value from the task_function, if it is a dict
            # update the payload with the returned value
            task.status = 'done'
            task.time_ended = timezone.now()
            task.set_payload(payload)
            if sys.platform == 'darwin':
                subprocess.call(['say', 'task %s done' % task.pk])
        except RetryTaskException, e:
            payload['error'] = 'Retrying %s' % e
            task.status = 'new'
            task.set_payload(payload)
        except Exception:
            if sys.platform == 'darwin':
                subprocess.call(['say', 'error in task %s' % task.pk])

            payload['error'] = traceback.format_exc()
            task.status = 'error'
            task.set_payload(payload)
            # mail the error along
            send_mail('An error occurred in task %s ' % task.pk,
                      '%s\nIt can be viewed at https://metabotnik.com/admin/metabotnik/task/%s/' % (payload['error'],task.pk),
                      'info@metabotnik.com',
                      [address for name, address in settings.ADMINS],
                      fail_silently=True)

    else:
        task.status = 'error'
        payload['error'] = 'Task %s is unrecognised' % task.action
        task.set_payload(payload)

# Defined tasks follow here ############################################################

def layout(payload):
    project = Project.objects.get(pk=payload['project_id'])
    data = planodo.horzvert_layout(project)
    project.layout_data = json.dumps(data)
    project.save()

def makethumbnails(payload):
    project = Project.objects.get(pk=payload['project_id'])

    output_filepath = os.path.join(project.storage_path, 'thumbnails')
    if not os.path.exists(output_filepath):
        os.mkdir(output_filepath)
    output_filepath += '/%s.jpg'

    # this command does not run in a shell, so we need to supply the wildcard arguments
    input_files = [os.path.join(project.originals_path, x) for x in os.listdir(project.originals_path) if x.lower().endswith('.jpg')]
    # Due to a file limit bug in vipsthumbnail, do 300 at a time : https://github.com/jcupitt/libvips/issues/182
    while input_files:
        subprocess.call(['%svipsthumbnail'%settings.VIPSBIN_PATH, '-o', output_filepath]+input_files[:300])
        input_files = input_files[300:]

def makedeepzoom(payload):
    project = Project.objects.get(pk=payload['project_id'])
    project.set_status('dzgen')

    new_nonce = ''.join(random.choice('0123456789abcdef') for i in range(6))
    # Call VIPS to make the DZ
    input_filepath = os.path.join(project.storage_path, 'metabotnik.jpg')
    output_filepath = os.path.join(project.storage_path, new_nonce)
    subprocess.call(['%svips'%settings.VIPSBIN_PATH, 'dzsave', input_filepath, output_filepath, '--suffix', '.jpg'])

    try:
        # clean up the previous deepzoom folder and dzi file
        old_path = os.path.join(project.storage_path, project.metabotnik_nonce+'_files')
        shutil.rmtree(old_path, ignore_errors=True)
        os.remove(os.path.join(project.storage_path, project.metabotnik_nonce+'.dzi'))
    except (OSError, TypeError):
        # maybe the files were removed by some other process, just move right along
        pass
        # though really, we need to do some better logging and signalling

    project.metabotnik_nonce = new_nonce
    project.set_status('done')

def generate(payload):
    project = Project.objects.get(pk=payload['project_id'])
    # Check to see if the number of files retrieved from Dropbox is done yet.
    # If not, just reset this task to new and return
    if project.num_files_local < project.num_files_on_dropbox:
        raise RetryTaskException('Local files < Dropbox files')

    if payload.get('preview'):
        filename = os.path.join(project.storage_path, 'preview.jpg')
        # For Previews, an arbitrary size
        # We need to add setting preview size to layouter...
        project.set_status('previewing')
    else:
        filename = os.path.join(project.storage_path, 'metabotnik.jpg')
        project.set_status('generating')

    error_msgs = planodo.make_bitmap(project, filename)

    new_task(project.user, {
            'action': 'makedeepzoom',
            'project_id': project.pk
    })

    if payload.get('sendemail'):
        send_mail('Your generation task for project %s done' % project, 'It can be viewed at https://metabotnik.com/projects/%s/' % project.pk,
                      'info@metabotnik.com', [project.user.email], fail_silently=False)

    project.set_status('layout')

    if error_msgs:
        return {'error': error_msgs}

def download_dropboxfiles(payload):
    # Get the Project
    project = Project.objects.get(pk=payload['project_id'])
    project.set_status('downloading')

    # Check to see what files to download from Dropbox
    client = DropboxClient(project.user.dropboxinfo.access_token)
    folder_metadata = client.metadata(project.path)
    num_files = 0
    for x in folder_metadata['contents']:
        if x['path'].lower().endswith('.jpg') and x['bytes'] > 0:
            # Download the file from Dropbox to local disk
            local_filename = os.path.split(x['path'].lower())[-1]
            local_filepath = os.path.join(project.originals_path, local_filename)
            num_files += 1
            if os.path.exists(local_filepath): # and not payload.get('redownload') == True
                continue
            with client.get_file(x['path']) as f:
                open(local_filepath, 'wb').write(f.read())

    # Get the metadata as a separate task
    new_task(project.user, {
        'action': 'extract_metadata',
        'project_id': project.pk
    })

    # schedule a thumbnail task
    new_task(project.user, {
        'action': 'makethumbnails',
        'project_id': project.pk
    })

    # Downloading files can take a long time
    # In the meantime this Project could have been changed by other tasks
    # Reload it before setting the status
    project = Project.objects.get(pk=payload['project_id'])
    project.num_files_on_dropbox = num_files
    project.status = 'layout'
    project.save()
    return {'downloaded_files_count':num_files}

def extract_metadata(payload):
    project = Project.objects.get(pk=payload['project_id'])
    current_files = {}
    for image in project.files.all():
        current_files[image.filename] = image
    #  For every file, read the metadata
    order = 1
    for filename in natsorted(os.listdir(project.originals_path)):
        if not filename.endswith('.jpg'):
            continue
        filepath = os.path.join(project.originals_path, filename)
        image = current_files.get(filename,
                    File(project=project, filename=filename, order=order)
        )
        order += 1
        try:
            tmp = read_metadata(filepath)
            image.metadata = json.dumps(tmp)
        except:
            pass
        # check the filesize
        image.size = os.stat(filepath).st_size
        # check the image size
        image.width, image.height = Image.open(filepath).size
        image.save()

def makemetametabotnik(payload):
    'For all the public Projects with a metabotnik, make a thumbnail of them and combine into one giant metabotnik'
    metaproject = Project.objects.get(name='Metametabotnik')
    for p in Project.objects.filter(public=True):
        path = p.metabotnik_path()
        if not path: continue
        subprocess.call(['%svipsthumbnail'%settings.VIPSBIN_PATH, '-o', 'preview.jpg', '-s', '1000', path])
        preview_path = os.path.join(p.storage_path, 'preview.jpg')
        os.link(preview_path, os.path.join(metaproject.originals_path, 'project_%s.jpg' % p.pk))
    extract_metadata({'project_id':metaproject.pk})
<commit_msg>Also do a layout task when doing a generate<commit_after>from metabotnik.models import Project, File, new_task
from dropbox.client import DropboxClient
import os
import sys
import subprocess
import traceback
import json
from django.utils import timezone
from django.core.mail import send_mail
from django.conf import settings
import planodo
from PIL import Image
from metabotnik.xmp import read_metadata
import random
import shutil
from natsort import natsorted

class RetryTaskException(Exception):
    'Raise this Exception in a task to have it retried later'
    pass

def execute_task(task):
    payload = task.get_payload()
    task_function = globals().get(task.action) # Consider doing a getattr(sys.modules[__name__], action) ?
    if task_function:

        # Bit of fun on local development machine
        if sys.platform == 'darwin':
            subprocess.call(['say', 'started task %s' % task.pk])

        task.status = 'wip'
        task.time_started = timezone.now()
        task.save()
        try:
            result = task_function(payload)
            if type(result) is dict:
                payload.update(result)
            # consider taking the return value from the task_function, if it is a dict
            # update the payload with the returned value
            task.status = 'done'
            task.time_ended = timezone.now()
            task.set_payload(payload)
            if sys.platform == 'darwin':
                subprocess.call(['say', 'task %s done' % task.pk])
        except RetryTaskException, e:
            payload['error'] = 'Retrying %s' % e
            task.status = 'new'
            task.set_payload(payload)
        except Exception:
            if sys.platform == 'darwin':
                subprocess.call(['say', 'error in task %s' % task.pk])

            payload['error'] = traceback.format_exc()
            task.status = 'error'
            task.set_payload(payload)
            # mail the error along
            send_mail('An error occurred in task %s ' % task.pk,
                      '%s\nIt can be viewed at https://metabotnik.com/admin/metabotnik/task/%s/' % (payload['error'],task.pk),
                      'info@metabotnik.com',
                      [address for name, address in settings.ADMINS],
                      fail_silently=True)

    else:
        task.status = 'error'
        payload['error'] = 'Task %s is unrecognised' % task.action
        task.set_payload(payload)

# Defined tasks follow here ############################################################

def layout(payload):
    project = Project.objects.get(pk=payload['project_id'])
    data = planodo.horzvert_layout(project)
    project.layout_data = json.dumps(data)
    project.save()

def makethumbnails(payload):
    project = Project.objects.get(pk=payload['project_id'])

    output_filepath = os.path.join(project.storage_path, 'thumbnails')
    if not os.path.exists(output_filepath):
        os.mkdir(output_filepath)
    output_filepath += '/%s.jpg'

    # this command does not run in a shell, so we need to supply the wildcard arguments
    input_files = [os.path.join(project.originals_path, x) for x in os.listdir(project.originals_path) if x.lower().endswith('.jpg')]
    # Due to a file limit bug in vipsthumbnail, do 300 at a time : https://github.com/jcupitt/libvips/issues/182
    while input_files:
        subprocess.call(['%svipsthumbnail'%settings.VIPSBIN_PATH, '-o', output_filepath]+input_files[:300])
        input_files = input_files[300:]

def makedeepzoom(payload):
    project = Project.objects.get(pk=payload['project_id'])
    project.set_status('dzgen')

    new_nonce = ''.join(random.choice('0123456789abcdef') for i in range(6))
    # Call VIPS to make the DZ
    input_filepath = os.path.join(project.storage_path, 'metabotnik.jpg')
    output_filepath = os.path.join(project.storage_path, new_nonce)
    subprocess.call(['%svips'%settings.VIPSBIN_PATH, 'dzsave', input_filepath, output_filepath, '--suffix', '.jpg'])

    try:
        # clean up the previous deepzoom folder and dzi file
        old_path = os.path.join(project.storage_path, project.metabotnik_nonce+'_files')
        shutil.rmtree(old_path, ignore_errors=True)
        os.remove(os.path.join(project.storage_path, project.metabotnik_nonce+'.dzi'))
    except (OSError, TypeError):
        # maybe the files were removed by some other process, just move right along
        pass
        # though really, we need to do some better logging and signalling

    project.metabotnik_nonce = new_nonce
    project.set_status('done')

def generate(payload):
    project = Project.objects.get(pk=payload['project_id'])
    # Check to see if the number of files retrieved from Dropbox is done yet.
    # If not, just reset this task to new and return
    if project.num_files_local < project.num_files_on_dropbox:
        raise RetryTaskException('Local files < Dropbox files')

    # Always first do a layout for the project using the current settings before generation
    # Especially neded where users do not first do a 'preview' before hitting generate button
    layout(payload)

    if payload.get('preview'):
        filename = os.path.join(project.storage_path, 'preview.jpg')
        # For Previews, an arbitrary size
        # We need to add setting preview size to layouter...
        project.set_status('previewing')
    else:
        filename = os.path.join(project.storage_path, 'metabotnik.jpg')
        project.set_status('generating')

    error_msgs = planodo.make_bitmap(project, filename)

    new_task(project.user, {
            'action': 'makedeepzoom',
            'project_id': project.pk
    })

    if payload.get('sendemail'):
        send_mail('Your generation task for project %s done' % project, 'It can be viewed at https://metabotnik.com/projects/%s/' % project.pk,
                      'info@metabotnik.com', [project.user.email], fail_silently=False)

    project.set_status('layout')

    if error_msgs:
        return {'error': error_msgs}

def download_dropboxfiles(payload):
    # Get the Project
    project = Project.objects.get(pk=payload['project_id'])
    project.set_status('downloading')

    # Check to see what files to download from Dropbox
    client = DropboxClient(project.user.dropboxinfo.access_token)
    folder_metadata = client.metadata(project.path)
    num_files = 0
    for x in folder_metadata['contents']:
        if x['path'].lower().endswith('.jpg') and x['bytes'] > 0:
            # Download the file from Dropbox to local disk
            local_filename = os.path.split(x['path'].lower())[-1]
            local_filepath = os.path.join(project.originals_path, local_filename)
            num_files += 1
            if os.path.exists(local_filepath): # and not payload.get('redownload') == True
                continue
            with client.get_file(x['path']) as f:
                open(local_filepath, 'wb').write(f.read())

    # Get the metadata as a separate task
    new_task(project.user, {
        'action': 'extract_metadata',
        'project_id': project.pk
    })

    # schedule a thumbnail task
    new_task(project.user, {
        'action': 'makethumbnails',
        'project_id': project.pk
    })

    # Downloading files can take a long time
    # In the meantime this Project could have been changed by other tasks
    # Reload it before setting the status
    project = Project.objects.get(pk=payload['project_id'])
    project.num_files_on_dropbox = num_files
    project.status = 'layout'
    project.save()
    return {'downloaded_files_count':num_files}

def extract_metadata(payload):
    project = Project.objects.get(pk=payload['project_id'])
    current_files = {}
    for image in project.files.all():
        current_files[image.filename] = image
    #  For every file, read the metadata
    order = 1
    for filename in natsorted(os.listdir(project.originals_path)):
        if not filename.endswith('.jpg'):
            continue
        filepath = os.path.join(project.originals_path, filename)
        image = current_files.get(filename,
                    File(project=project, filename=filename, order=order)
        )
        order += 1
        try:
            tmp = read_metadata(filepath)
            image.metadata = json.dumps(tmp)
        except:
            pass
        # check the filesize
        image.size = os.stat(filepath).st_size
        # check the image size
        image.width, image.height = Image.open(filepath).size
        image.save()

def makemetametabotnik(payload):
    'For all the public Projects with a metabotnik, make a thumbnail of them and combine into one giant metabotnik'
    metaproject = Project.objects.get(name='Metametabotnik')
    for p in Project.objects.filter(public=True):
        path = p.metabotnik_path()
        if not path: continue
        subprocess.call(['%svipsthumbnail'%settings.VIPSBIN_PATH, '-o', 'preview.jpg', '-s', '1000', path])
        preview_path = os.path.join(p.storage_path, 'preview.jpg')
        os.link(preview_path, os.path.join(metaproject.originals_path, 'project_%s.jpg' % p.pk))
    extract_metadata({'project_id':metaproject.pk})
<|endoftext|>


<commit_before>
from tornado.gen import coroutine, Return

import profile

from request import RequestType, RequestError, NoSuchRequest

from common.internal import InternalError
from common.validate import validate
from common.database import DatabaseError

class ConnectionError(Exception):
    def __init__(self, code, message):
        self.code = code
        self.message = message

    def __str__(self):
        return str(self.code) + ": " + self.message

class ConnectionsModel(profile.ProfilesModel):

    APPROVAL_SCOPE = 'connection_approval'

    MESSAGE_CONNECTION_REQUEST = 'connection_request'
    MESSAGE_CONNECTION_CREATED = 'connection_created'
    MESSAGE_CONNECTION_DELETED = 'connection_deleted'
    MESSAGE_CONNECTION_APPROVED = 'connection_approved'
    MESSAGE_CONNECTION_REJECTED = 'connection_rejected'

    def __init__(self, db, cache, requests):
        super(ConnectionsModel, self).__init__(db, cache)

        self.requests = requests

    def get_setup_db(self):
        return self.db

    def get_setup_tables(self):
        return ["account_connections"]

    @coroutine
    @validate(account_id="int", target_account="int")
    def create(self, account_id, target_account):

        try:
            yield self.db.insert(
                """
                    INSERT INTO `account_connections`
                    (`account_id`, `account_connection`)
                    VALUES (%s, %s), (%s, %s);
                """, account_id, target_account, target_account, account_id)
        except DatabaseError as e:
            raise ConnectionError(500, "Failed to add a connection: " + e.args[1])

    @coroutine
    @validate(gamespace_id="int", account_id="int", approve_account_id="int", key="str", notify="json_dict")
    def approve_connection(self, gamespace_id, account_id, approve_account_id, key, notify=None):

        try:
            request = yield self.requests.acquire(
                gamespace_id, approve_account_id, key)
        except NoSuchRequest:
            raise ConnectionError(404, "No such request")
        except RequestError as e:
            raise ConnectionError(500, e.message)

        if request.type != RequestType.ACCOUNT:
            raise ConnectionError(400, "Bad request type")

        try:
            yield self.create(
                account_id, request.account)
        except ConnectionError as e:
            raise ConnectionError(500, e.message)

        if notify is not None:
            yield self.__send_message__(
                gamespace_id, "user", str(request.account), account_id,
                ConnectionsModel.MESSAGE_CONNECTION_APPROVED, notify, ["remove_delivered"],
                authoritative=True)

    @coroutine
    @validate(gamespace_id="int", account_id="int", reject_account_id="int", key="str", notify="json_dict")
    def reject_connection(self, gamespace_id, account_id, reject_account_id, key, notify=None):

        try:
            request = yield self.requests.acquire(
                gamespace_id, reject_account_id, key)
        except NoSuchRequest:
            raise ConnectionError(404, "No such request")
        except RequestError as e:
            raise ConnectionError(500, e.message)

        if request.type != RequestType.ACCOUNT:
            raise ConnectionError(400, "Bad request type")

        if notify is not None:
            yield self.__send_message__(
                gamespace_id, "user", str(request.object), reject_account_id,
                ConnectionsModel.MESSAGE_CONNECTION_REJECTED, notify, ["remove_delivered"],
                authoritative=True)

    @coroutine
    @validate(gamespace_id="int", account_id="int", target_account="int", approval="bool", notify="json_dict",
              payload="json_dict")
    def request_connection(self, gamespace_id, account_id, target_account, approval=True, notify=None,
                           payload=None):

        if approval:
            try:
                key = yield self.requests.create_request(
                    gamespace_id, account_id, RequestType.ACCOUNT, target_account, payload)
            except RequestError as e:
                raise ConnectionError(500, e.message)

            if notify is not None:
                notify.update({
                    "key": key
                })

                yield self.__send_message__(
                    gamespace_id, "user", str(target_account), account_id,
                    ConnectionsModel.MESSAGE_CONNECTION_REQUEST, notify, ["remove_delivered"],
                    authoritative=True)

            raise Return({
                "key": key
            })
        else:
            try:
                yield self.create(account_id, target_account)
            except ConnectionError as e:
                raise ConnectionError(500, e.message)

            if notify is not None:
                yield self.__send_message__(
                    gamespace_id, "user", str(target_account), account_id,
                    ConnectionsModel.MESSAGE_CONNECTION_CREATED, notify, ["remove_delivered"],
                    authoritative=True)

    @coroutine
    def __send_message__(self, gamespace_id, recipient_class, recipient_key,
                         account_id, message_type, payload, flags=None, authoritative=False):
        try:
            yield self.internal.rpc(
                "message", "send_message",
                gamespace=gamespace_id, sender=account_id,
                recipient_class=recipient_class, recipient_key=recipient_key,
                message_type=message_type, payload=payload, flags=flags or [],
                authoritative=authoritative)
        except InternalError:
            pass  # well

    @coroutine
    def cleanup(self, account_id):
        try:
            yield self.db.execute(
                """
                    DELETE FROM `account_connections`
                    WHERE `account_id`=%s OR `account_connection`=%s
                    LIMIT 2;
                """, account_id, account_id)
        except DatabaseError as e:
            raise ConnectionError(500, "Failed to delete a connection: " + e.args[1])

    @coroutine
    @validate(gamespace_id="int", account_id="int", target_account="int", notify="json_dict")
    def delete(self, gamespace_id, account_id, target_account, notify=None):

        try:
            yield self.db.execute(
                """
                    DELETE FROM `account_connections`
                    WHERE (`account_id`=%s AND `account_connection`=%s) OR
                          (`account_connection`=%s AND `account_id`=%s)
                    LIMIT 2;
                """, account_id, target_account, account_id, target_account)
        except DatabaseError as e:
            raise ConnectionError(500, "Failed to delete a connection: " + e.args[1])

        if notify is not None:
            yield self.__send_message__(
                gamespace_id, "user", str(target_account), account_id,
                ConnectionsModel.MESSAGE_CONNECTION_DELETED, notify, ["remove_delivered"],
                authoritative=True)

    @coroutine
    def get_connections_profiles(self, gamespace_id, account_id, profile_fields):
        connections = yield self.list_connections(account_id)

        try:
            connection_profiles = yield self.get_profiles(
                account_id,
                connections,
                profile_fields,
                gamespace_id)

        except profile.ProfileRequestError as e:
            raise ConnectionError(500, e.message)

        raise Return(connection_profiles)

    @coroutine
    def list_connections(self, account_id):
        try:
            connections = yield self.db.query(
                """
                    SELECT *
                    FROM `account_connections`
                    WHERE `account_id`=%s;
                """, account_id)
        except DatabaseError as e:
            raise ConnectionError(500, "Failed to get connections: " + e.args[1])

        raise Return([str(c["account_connection"]) for c in connections])
<commit_msg>Fixed ‘reject’ connection notify method<commit_after>
from tornado.gen import coroutine, Return

import profile

from request import RequestType, RequestError, NoSuchRequest

from common.internal import InternalError
from common.validate import validate
from common.database import DatabaseError

class ConnectionError(Exception):
    def __init__(self, code, message):
        self.code = code
        self.message = message

    def __str__(self):
        return str(self.code) + ": " + self.message

class ConnectionsModel(profile.ProfilesModel):

    APPROVAL_SCOPE = 'connection_approval'

    MESSAGE_CONNECTION_REQUEST = 'connection_request'
    MESSAGE_CONNECTION_CREATED = 'connection_created'
    MESSAGE_CONNECTION_DELETED = 'connection_deleted'
    MESSAGE_CONNECTION_APPROVED = 'connection_approved'
    MESSAGE_CONNECTION_REJECTED = 'connection_rejected'

    def __init__(self, db, cache, requests):
        super(ConnectionsModel, self).__init__(db, cache)

        self.requests = requests

    def get_setup_db(self):
        return self.db

    def get_setup_tables(self):
        return ["account_connections"]

    @coroutine
    @validate(account_id="int", target_account="int")
    def create(self, account_id, target_account):

        try:
            yield self.db.insert(
                """
                    INSERT INTO `account_connections`
                    (`account_id`, `account_connection`)
                    VALUES (%s, %s), (%s, %s);
                """, account_id, target_account, target_account, account_id)
        except DatabaseError as e:
            raise ConnectionError(500, "Failed to add a connection: " + e.args[1])

    @coroutine
    @validate(gamespace_id="int", account_id="int", approve_account_id="int", key="str", notify="json_dict")
    def approve_connection(self, gamespace_id, account_id, approve_account_id, key, notify=None):

        try:
            request = yield self.requests.acquire(
                gamespace_id, approve_account_id, key)
        except NoSuchRequest:
            raise ConnectionError(404, "No such request")
        except RequestError as e:
            raise ConnectionError(500, e.message)

        if request.type != RequestType.ACCOUNT:
            raise ConnectionError(400, "Bad request type")

        try:
            yield self.create(
                account_id, request.account)
        except ConnectionError as e:
            raise ConnectionError(500, e.message)

        if notify is not None:
            yield self.__send_message__(
                gamespace_id, "user", str(request.account), account_id,
                ConnectionsModel.MESSAGE_CONNECTION_APPROVED, notify, ["remove_delivered"],
                authoritative=True)

    @coroutine
    @validate(gamespace_id="int", account_id="int", reject_account_id="int", key="str", notify="json_dict")
    def reject_connection(self, gamespace_id, account_id, reject_account_id, key, notify=None):

        try:
            request = yield self.requests.acquire(
                gamespace_id, reject_account_id, key)
        except NoSuchRequest:
            raise ConnectionError(404, "No such request")
        except RequestError as e:
            raise ConnectionError(500, e.message)

        if request.type != RequestType.ACCOUNT:
            raise ConnectionError(400, "Bad request type")

        if notify is not None:
            yield self.__send_message__(
                gamespace_id, "user", str(request.account), account_id,
                ConnectionsModel.MESSAGE_CONNECTION_REJECTED, notify, ["remove_delivered"],
                authoritative=True)

    @coroutine
    @validate(gamespace_id="int", account_id="int", target_account="int", approval="bool", notify="json_dict",
              payload="json_dict")
    def request_connection(self, gamespace_id, account_id, target_account, approval=True, notify=None,
                           payload=None):

        if approval:
            try:
                key = yield self.requests.create_request(
                    gamespace_id, account_id, RequestType.ACCOUNT, target_account, payload)
            except RequestError as e:
                raise ConnectionError(500, e.message)

            if notify is not None:
                notify.update({
                    "key": key
                })

                yield self.__send_message__(
                    gamespace_id, "user", str(target_account), account_id,
                    ConnectionsModel.MESSAGE_CONNECTION_REQUEST, notify, ["remove_delivered"],
                    authoritative=True)

            raise Return({
                "key": key
            })
        else:
            try:
                yield self.create(account_id, target_account)
            except ConnectionError as e:
                raise ConnectionError(500, e.message)

            if notify is not None:
                yield self.__send_message__(
                    gamespace_id, "user", str(target_account), account_id,
                    ConnectionsModel.MESSAGE_CONNECTION_CREATED, notify, ["remove_delivered"],
                    authoritative=True)

    @coroutine
    def __send_message__(self, gamespace_id, recipient_class, recipient_key,
                         account_id, message_type, payload, flags=None, authoritative=False):
        try:
            yield self.internal.rpc(
                "message", "send_message",
                gamespace=gamespace_id, sender=account_id,
                recipient_class=recipient_class, recipient_key=recipient_key,
                message_type=message_type, payload=payload, flags=flags or [],
                authoritative=authoritative)
        except InternalError:
            pass  # well

    @coroutine
    def cleanup(self, account_id):
        try:
            yield self.db.execute(
                """
                    DELETE FROM `account_connections`
                    WHERE `account_id`=%s OR `account_connection`=%s
                    LIMIT 2;
                """, account_id, account_id)
        except DatabaseError as e:
            raise ConnectionError(500, "Failed to delete a connection: " + e.args[1])

    @coroutine
    @validate(gamespace_id="int", account_id="int", target_account="int", notify="json_dict")
    def delete(self, gamespace_id, account_id, target_account, notify=None):

        try:
            yield self.db.execute(
                """
                    DELETE FROM `account_connections`
                    WHERE (`account_id`=%s AND `account_connection`=%s) OR
                          (`account_connection`=%s AND `account_id`=%s)
                    LIMIT 2;
                """, account_id, target_account, account_id, target_account)
        except DatabaseError as e:
            raise ConnectionError(500, "Failed to delete a connection: " + e.args[1])

        if notify is not None:
            yield self.__send_message__(
                gamespace_id, "user", str(target_account), account_id,
                ConnectionsModel.MESSAGE_CONNECTION_DELETED, notify, ["remove_delivered"],
                authoritative=True)

    @coroutine
    def get_connections_profiles(self, gamespace_id, account_id, profile_fields):
        connections = yield self.list_connections(account_id)

        try:
            connection_profiles = yield self.get_profiles(
                account_id,
                connections,
                profile_fields,
                gamespace_id)

        except profile.ProfileRequestError as e:
            raise ConnectionError(500, e.message)

        raise Return(connection_profiles)

    @coroutine
    def list_connections(self, account_id):
        try:
            connections = yield self.db.query(
                """
                    SELECT *
                    FROM `account_connections`
                    WHERE `account_id`=%s;
                """, account_id)
        except DatabaseError as e:
            raise ConnectionError(500, "Failed to get connections: " + e.args[1])

        raise Return([str(c["account_connection"]) for c in connections])
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
#
# The DRY Project documentation build configuration file, created by
# `sphinx-quickstart`.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys
import os

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))

# -- General configuration ------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
    'sphinx.ext.intersphinx',
    'sphinx.ext.todo',
    'sphinx.ext.ifconfig',
]

# Add any paths that contain templates here, relative to this directory.
templates_path = ['.templates']

# The suffix of source filenames.
source_suffix = '.rst'

# The encoding of source files.
#source_encoding = 'utf-8-sig'

# The master toctree document.
master_doc = 'index'

# General information about the project.
project = u'The DRY Project'
#copyright = None

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '2014-11-03'
# The full version, including alpha/beta/rc tags.
release = '2014-11-03'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None

# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['.build', '.themes', 'README.rst']

# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None

# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True

# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True

# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'

# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []

# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False

# -- Options for HTML output ----------------------------------------------
# http://sphinx-doc.org/config.html#options-for-html-output

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
#html_theme = 'default'
html_theme = 'drymanual'

# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# documentation.
html_theme_options = {
  'display_github': True,
  'github_user': 'dryproject',
  'github_repo': 'dryproject.org',
  'github_version': 'HEAD',
  'display_bitbucket': False,
  'bitbucket_user': 'dryproject',
  'bitbucket_repo': 'dryproject.org',
  'bitbucket_version': 'HEAD',
  #'google_analytics': '',
}
html_context = {
  'conf_py_path': '.',
  'source_suffix': source_suffix,
  'show_release': False, # TODO
  'versions': [(release, '#')], # TODO
  'downloads': [
    ('PDF',  '#'),
    ('HTML', '#'),
    ('EPUB', '#'),
  ]
}

# Add any paths that contain custom themes here, relative to this directory.
html_theme_path = ['.themes']

# The name for this set of Sphinx documents.  If None, it defaults to
# "<project> v<release> documentation".
html_title = "DRY Project Manual"

# A shorter title for the navigation bar.  Default is the same as html_title.
html_short_title = "DRY Project"

# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None

# The name of an image file (within the static path) to use as favicon of the
# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['.static']

# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []

# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'

# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
html_use_smartypants = True

# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}

# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}

# If false, no module index is generated.
html_domain_indices = True

# If false, no index is generated.
#html_use_index = True

# If true, the index is split into individual pages for each letter.
#html_split_index = False

# If true, links to the reST sources are added to the pages.
html_show_sourcelink = False

# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
html_show_sphinx = False

# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
html_show_copyright = False

# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it.  The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''

# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None

# Output file base name for HTML help builder.
htmlhelp_basename = 'dryproject'

# -- Options for LaTeX output ---------------------------------------------

latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
'papersize': 'a4paper',

# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',

# Additional stuff for the LaTeX preamble.
#'preamble': '',
}

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
#  author, documentclass [howto, manual, or own class]).
latex_documents = [
  ('index', 'dryproject.tex', u'The DRY Project Documentation',
   u'Arto Bendiken', 'manual'),
]

# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None

# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
latex_use_parts = True

# If true, show page references after internal links.
#latex_show_pagerefs = False

# If true, show URL addresses after external links.
#latex_show_urls = False

# Documents to append as an appendix to all manuals.
#latex_appendices = []

# If false, no module index is generated.
latex_domain_indices = False

# -- Options for manual page output ---------------------------------------
# http://sphinx-doc.org/config.html#options-for-manual-page-output

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
  ('index', 'dryproject', u'DRY Project Documentation', None, 7)
]

# If true, show URL addresses after external links.
man_show_urls = False

# -- Options for Texinfo output -------------------------------------------
# http://sphinx-doc.org/config.html#options-for-texinfo-output

# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
#  dir menu entry, description, category)
texinfo_documents = [
  ('index', 'dryproject', u'DRY Project Documentation',
   u'Arto Bendiken', 'dryproject', 'One line description of project.',
   'Miscellaneous'),
]

# Documents to append as an appendix to all manuals.
#texinfo_appendices = []

# If false, no module index is generated.
#texinfo_domain_indices = True

# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'

# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False

# -- Options for Epub output ----------------------------------------------

# Bibliographic Dublin Core info.
epub_title = u'The DRY Project'
epub_author = u'Arto Bendiken'
epub_publisher = u'Arto Bendiken'
epub_copyright = None

# The basename for the epub file. It defaults to the project name.
#epub_basename = project

# The HTML theme for the epub output. Since the default themes are not optimized
# for small screen space, using the same theme for HTML and epub output is
# usually not wise. This defaults to 'epub', a theme designed to save visual
# space.
#epub_theme = 'epub'

# The language of the text. It defaults to the language option
# or en if the language is not set.
epub_language = 'en'

# The scheme of the identifier. Typical schemes are ISBN or URL.
#epub_scheme = ''

# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#epub_identifier = ''

# A unique identification for the text.
#epub_uid = ''

# A tuple containing the cover image and cover page html template filenames.
#epub_cover = ()

# A sequence of (type, uri, title) tuples for the guide element of content.opf.
#epub_guide = ()

# HTML files that should be inserted before the pages created by sphinx.
# The format is a list of tuples containing the path and title.
#epub_pre_files = []

# HTML files shat should be inserted after the pages created by sphinx.
# The format is a list of tuples containing the path and title.
#epub_post_files = []

# A list of files that should not be packed into the epub file.
epub_exclude_files = ['search.html']

# The depth of the table of contents in toc.ncx.
#epub_tocdepth = 3

# Allow duplicate toc entries.
#epub_tocdup = True

# Choose between 'default' and 'includehidden'.
#epub_tocscope = 'default'

# Fix unsupported image types using the PIL.
#epub_fix_images = False

# Scale large images.
#epub_max_image_width = 0

# How to display URL addresses: 'footnote', 'no', or 'inline'.
#epub_show_urls = 'inline'

# If false, no index is generated.
#epub_use_index = True

# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'http://docs.python.org/': None}
<commit_msg>Fixed LaTeX UTF-8 problems due to characters in `tree` output.<commit_after># -*- coding: utf-8 -*-
#
# The DRY Project documentation build configuration file, created by
# `sphinx-quickstart`.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys
import os

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))

# -- General configuration ------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
    'sphinx.ext.intersphinx',
    'sphinx.ext.todo',
    'sphinx.ext.ifconfig',
]

# Add any paths that contain templates here, relative to this directory.
templates_path = ['.templates']

# The suffix of source filenames.
source_suffix = '.rst'

# The encoding of source files.
source_encoding = 'utf-8-sig'

# The master toctree document.
master_doc = 'index'

# General information about the project.
project = u'The DRY Project'
#copyright = None

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '2014-11-03'
# The full version, including alpha/beta/rc tags.
release = '2014-11-03'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None

# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['.build', '.themes', 'README.rst']

# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None

# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True

# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True

# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'

# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []

# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False

# -- Options for HTML output ----------------------------------------------
# http://sphinx-doc.org/config.html#options-for-html-output

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
#html_theme = 'default'
html_theme = 'drymanual'

# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# documentation.
html_theme_options = {
  'display_github': True,
  'github_user': 'dryproject',
  'github_repo': 'dryproject.org',
  'github_version': 'HEAD',
  'display_bitbucket': False,
  'bitbucket_user': 'dryproject',
  'bitbucket_repo': 'dryproject.org',
  'bitbucket_version': 'HEAD',
  #'google_analytics': '',
}
html_context = {
  'conf_py_path': '.',
  'source_suffix': source_suffix,
  'show_release': False, # TODO
  'versions': [(release, '#')], # TODO
  'downloads': [
    ('PDF',  '#'),
    ('HTML', '#'),
    ('EPUB', '#'),
  ]
}

# Add any paths that contain custom themes here, relative to this directory.
html_theme_path = ['.themes']

# The name for this set of Sphinx documents.  If None, it defaults to
# "<project> v<release> documentation".
html_title = "DRY Project Manual"

# A shorter title for the navigation bar.  Default is the same as html_title.
html_short_title = "DRY Project"

# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None

# The name of an image file (within the static path) to use as favicon of the
# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['.static']

# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []

# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'

# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
html_use_smartypants = True

# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}

# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}

# If false, no module index is generated.
html_domain_indices = True

# If false, no index is generated.
#html_use_index = True

# If true, the index is split into individual pages for each letter.
#html_split_index = False

# If true, links to the reST sources are added to the pages.
html_show_sourcelink = False

# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
html_show_sphinx = False

# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
html_show_copyright = False

# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it.  The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''

# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None

# Output file base name for HTML help builder.
htmlhelp_basename = 'dryproject'

# -- Options for LaTeX output ---------------------------------------------

latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
'papersize': 'a4paper',

# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',

# Additional stuff for the LaTeX preamble.
'preamble': "\n".join([
  '\\usepackage{amssymb}',
  '\\DeclareUnicodeCharacter{251C}{$\\vdash$}',
  '\\DeclareUnicodeCharacter{2514}{$\\llcorner$}']),
}

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
#  author, documentclass [howto, manual, or own class]).
latex_documents = [
  ('index', 'dryproject.tex', u'The DRY Project Documentation',
   u'Arto Bendiken', 'manual'),
]

# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None

# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
latex_use_parts = True

# If true, show page references after internal links.
#latex_show_pagerefs = False

# If true, show URL addresses after external links.
#latex_show_urls = False

# Documents to append as an appendix to all manuals.
#latex_appendices = []

# If false, no module index is generated.
latex_domain_indices = False

# -- Options for manual page output ---------------------------------------
# http://sphinx-doc.org/config.html#options-for-manual-page-output

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
  ('index', 'dryproject', u'DRY Project Documentation', None, 7)
]

# If true, show URL addresses after external links.
man_show_urls = False

# -- Options for Texinfo output -------------------------------------------
# http://sphinx-doc.org/config.html#options-for-texinfo-output

# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
#  dir menu entry, description, category)
texinfo_documents = [
  ('index', 'dryproject', u'DRY Project Documentation',
   u'Arto Bendiken', 'dryproject', 'One line description of project.',
   'Miscellaneous'),
]

# Documents to append as an appendix to all manuals.
#texinfo_appendices = []

# If false, no module index is generated.
#texinfo_domain_indices = True

# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'

# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False

# -- Options for Epub output ----------------------------------------------

# Bibliographic Dublin Core info.
epub_title = u'The DRY Project'
epub_author = u'Arto Bendiken'
epub_publisher = u'Arto Bendiken'
epub_copyright = None

# The basename for the epub file. It defaults to the project name.
#epub_basename = project

# The HTML theme for the epub output. Since the default themes are not optimized
# for small screen space, using the same theme for HTML and epub output is
# usually not wise. This defaults to 'epub', a theme designed to save visual
# space.
#epub_theme = 'epub'

# The language of the text. It defaults to the language option
# or en if the language is not set.
epub_language = 'en'

# The scheme of the identifier. Typical schemes are ISBN or URL.
#epub_scheme = ''

# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#epub_identifier = ''

# A unique identification for the text.
#epub_uid = ''

# A tuple containing the cover image and cover page html template filenames.
#epub_cover = ()

# A sequence of (type, uri, title) tuples for the guide element of content.opf.
#epub_guide = ()

# HTML files that should be inserted before the pages created by sphinx.
# The format is a list of tuples containing the path and title.
#epub_pre_files = []

# HTML files shat should be inserted after the pages created by sphinx.
# The format is a list of tuples containing the path and title.
#epub_post_files = []

# A list of files that should not be packed into the epub file.
epub_exclude_files = ['search.html']

# The depth of the table of contents in toc.ncx.
#epub_tocdepth = 3

# Allow duplicate toc entries.
#epub_tocdup = True

# Choose between 'default' and 'includehidden'.
#epub_tocscope = 'default'

# Fix unsupported image types using the PIL.
#epub_fix_images = False

# Scale large images.
#epub_max_image_width = 0

# How to display URL addresses: 'footnote', 'no', or 'inline'.
#epub_show_urls = 'inline'

# If false, no index is generated.
#epub_use_index = True

# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'http://docs.python.org/': None}
<|endoftext|>