<commit_before>__author__ = 'tom'

from asyncore import file_dispatcher, loop

from evdev import InputDevice, list_devices
from threading import Thread

class SixAxis():
    """
    Class to handle the PS3 SixAxis controller

    This class will process events from the pygame event queue and calculate positions for each of the analogue axes on
    the SixAxis controller (excluding the motion sensor which appears not to work for some reason). It will also extract
    button press events and call any handler functions bound to those buttons.

    Events are only processed when the handle_events method is called, this must be called reasonably frequently as the
    pygame event queue will discard events once full and the joystick hardware is sufficiently twitchy that it's
    generating events pretty much constantly.

    Consuming code can get the current position of any of the sticks from this class through the `axes` instance
    property. This contains a list of :class:`triangula.input.SixAxis.Axis` objects, one for each distinct axis on the
    controller. The list of axes is, in order: left x, left y, right x, right y.
    """

    BUTTON_SELECT = 0  #: The Select button
    BUTTON_LEFT_STICK = 1  #: Left stick click button
    BUTTON_RIGHT_STICK = 2  #: Right stick click button
    BUTTON_START = 3  #: Start button
    BUTTON_D_UP = 4  #: D-pad up
    BUTTON_D_RIGHT = 5  #: D-pad right
    BUTTON_D_DOWN = 6  #: D-pad down
    BUTTON_D_LEFT = 7  #: D-pad left
    BUTTON_L2 = 8  #: L2 lower shoulder trigger
    BUTTON_R2 = 9  #: R2 lower shoulder trigger
    BUTTON_L1 = 10  #: L1 upper shoulder trigger
    BUTTON_R1 = 11  #: R1 upper shoulder trigger
    BUTTON_TRIANGLE = 12  #: Triangle
    BUTTON_CIRCLE = 13  #: Circle
    BUTTON_CROSS = 14  #: Cross
    BUTTON_SQUARE = 15  #: Square
    BUTTON_PS = 16  #: PS button

    def __init__(self, dead_zone=0.2, hot_zone=0.05, init_pygame=True):
        """
        Discover and initialise a PS3 SixAxis controller connected to this computer

        :param float dead_zone:
            Creates a dead zone centred on the centre position of the axis (which may or may not be zero depending on
            calibration). The axis values range from 0 to 1.0, but will be locked to 0.0 when the measured value less
            centre offset is lower in magnitude than this supplied value. Defaults to 0.2, which makes the PS3 analogue
            sticks easy to centre but still responsive to motion. The deadzone is applies to each axis independently, so
            e.g. moving the stick far right won't affect the deadzone for that sticks Y axis.
        :param float hot_zone:
            Creates a zone of maximum value, any readings from the sensor which are within this value of the max or min
            values will be mapped to 1.0 and -1.0 respectively. This can be useful because, while the PS3 controllers
            sticks have independent axes, they are constrained to move within a circle, so it's impossible to have e.g.
            1.0,1.0 for both x and y axes. Setting this value to non-zero in effect partially squares the circle,
            allowing for controls which require full range control. Setting this value to 1/sqrt(2) will create a square
            zone of variability within the circular range of motion of the controller, with any stick motions outside
            this square mapping to the maximum value for the respective axis. The value is actually scaled by the max
            and min magnitude for upper and lower ranges respectively, so e.g. setting 0.5 will create a hot-zone at
            above half the maximum value and below half the minimum value, and not at +0.5 and -0.5 (unless max and
            min are 1.0 and -1.0 respectively). As with the dead zone, these are applied separately to each axis, so in
            the case where the hot zone is set to 1/sqrt(2), a circular motion of the stick will map to x and y values
            which trace the outline of a square of unit size, allowing for all values to be emitted from the stick.
        :param boolean init_pygame:
            Defaults to True; if set then pygame will be initialised with the appropriate properties to run headless, if
            false then no pygame initialisation will be performed. If you pass False to this method you must have
            already initialised pygame (there's no requirement to initialise the joystick subsystem, this is always
            performed in this method, it's safe to run multiple times anyway)
        :return: an initialised link to an attached PS3 SixAxis controller
        """

        self.stop_function = None
        self.axes = [SixAxis.Axis('left_x', dead_zone=dead_zone, hot_zone=hot_zone),
                     SixAxis.Axis('left_y', dead_zone=dead_zone, hot_zone=hot_zone, invert=True),
                     SixAxis.Axis('right_x', dead_zone=dead_zone, hot_zone=hot_zone),
                     SixAxis.Axis('right_y', dead_zone=dead_zone, hot_zone=hot_zone, invert=True)]
        self.button_handlers = []
        self.connect()

    def connect(self):
        if self.stop_function:
            return
        for device in [InputDevice(fn) for fn in list_devices()]:
            if device.name == 'PLAYSTATION(R)3 Controller':
                self.sixaxis = device
                parent = self

                class InputDeviceDispatcher(file_dispatcher):
                    def __init__(self):
                        self.device = device
                        file_dispatcher.__init__(self, device)

                    def recv(self, ign=None):
                        return self.device.read()

                    def handle_read(self):
                        for event in self.recv():
                            parent.handle_event(event)

                InputDeviceDispatcher()

                class AsyncLoop(Thread):
                    def __init__(self):
                        Thread.__init__(self, name='InputDispatchThread')

                    def run(self):
                        loop()

                self.stop_function = AsyncLoop()
                self.stop_function.start()

    def __str__(self):
        return 'x1={}, y1={}, x2={}, y2={}'.format(
            self.axes[0].corrected_value(), self.axes[1].corrected_value(),
            self.axes[2].corrected_value(), self.axes[3].corrected_value())

    def set_axis_centres(self, *args):
        """
        Sets the centre points for each axis to the current value for that axis. This centre value is used when
        computing the value for the axis and is subtracted before applying any scaling.
        """
        for axis in self.axes:
            axis.centre = axis.value

    def reset_axis_calibration(self, *args):
        """
        Resets any previously defined axis calibration to 0.0 for all axes
        """
        for axis in self.axes:
            axis._reset()

    def register_button_handler(self, handler, buttons):
        """
        Register a handler function which will be called when a button is pressed

        :param handler: a function which will be called when any of the specified buttons are pressed. The function is
            called with the integer code for the button as the sole argument.
        :param [int] buttons: a list or one or more buttons which should trigger the handler when pressed. Buttons are
            specified as ints, for convenience the PS3 button assignments are mapped to names in SixAxis, i.e.
            SixAxis.BUTTON_CIRCLE. This includes the buttons in each of the analogue sticks. A bare int value is also
            accepted here and will be treated as if a single element list was supplied.
        :return: a no-arg function which can be used to remove this registration
        """
        mask = 0
        if isinstance(buttons, list):
            for button in buttons:
                mask += 1 << button
        else:
            mask += 1 << buttons
        h = {'handler': handler,
             'mask': mask}
        self.button_handlers.append(h)

        def remove():
            self.button_handlers.remove(h)

        return remove

    def handle_event(self, event):
        print event
        if event.type == 3:
            value = (event.value - 128.0) / 128.0
            if event.code == 0:
                # Left stick, X axis
                self.axes[0]._set(value)
            elif event.code == 1:
                # Left stick, Y axis
                self.axes[1]._set(value)
            elif event.code == 2:
                # Right stick, X axis
                self.axes[2]._set(value)
            elif event.code == 5:
                # Right stick, Y axis (yes, 5...)
                self.axes[3]._set(value)
        """
        for event in pg_event.get():
            if event.type == JOYAXISMOTION and event.joy == self.active_index:
                if event.axis < len(self.axes):
                    self.axes[event.axis]._set(event.value)
            elif event.type == JOYBUTTONDOWN and event.joy == self.active_index:
                for handler in self.button_handlers:
                    if handler['mask'] & (1 << event.button) != 0:
                        handler['handler'](event.button)
        """

    class Axis():
        """A single analogue axis on the SixAxis controller"""

        def __init__(self, name, invert=False, dead_zone=0.0, hot_zone=0.0):
            self.name = name
            self.centre = 0.0
            self.max = 0.9
            self.min = -0.9
            self.value = 0.0
            self.invert = invert
            self.dead_zone = dead_zone
            self.hot_zone = hot_zone

        def corrected_value(self):
            """
            Get a centre-compensated, scaled, value for the axis, taking any dead-zone into account. The value will
            scale from 0.0 at the edge of the dead-zone to 1.0 (positive) or -1.0 (negative) at the extreme position of
            the controller or the edge of the hot zone, if defined as other than 1.0. The axis will auto-calibrate for
            maximum value, initially it will behave as if the highest possible value from the hardware is 0.9 in each
            direction, and will expand this as higher values are observed. This is scaled by this function and should
            always return 1.0 or -1.0 at the extreme ends of the axis.

            :return: a float value, negative to the left or down and ranging from -1.0 to 1.0
            """

            centred = self.value - self.centre

            if abs(centred) <= self.dead_zone:
                return 0.0
            elif centred > 0 and self.value > self.max - (self.hot_zone * self.max):
                if not self.invert:
                    return 1.0
                else:
                    return -1.0
            elif centred < 0 and self.value < self.min - (self.hot_zone * self.min):
                if not self.invert:
                    return -1.0
                else:
                    return 1.0

            if centred > 0:
                top_range = self.max - (self.hot_zone * self.max + self.dead_zone)
                result = centred / top_range
            else:
                bottom_range = self.dead_zone - (self.min - self.hot_zone * self.min)
                result = centred / bottom_range

            if self.invert:
                result = -result

            return result

        def _reset(self):
            """
            Reset calibration (max, min and centre values) for this axis specifically. Not generally needed, you can just
            call the reset method on the SixAxis instance.

            :internal:
            """
            self.centre = 0.0
            self.max = 1.0
            self.min = -1.0

        def _set(self, new_value):
            """
            Set a new value, called from within the SixAxis class when parsing the event queue.

            :param new_value: the raw value from the joystick hardware
            :internal:
            """
            self.value = new_value
            if new_value > self.max:
                self.max = new_value
            elif new_value < self.min:
                self.min = new_value

if __name__ == '__main__':
    from input import SixAxis
    import time

    controller = SixAxis(dead_zone=0.2, hot_zone=0.1, init_pygame=True)

    def handler(button):
        print 'Button! {}'.format(button)

    controller.register_button_handler(handler, SixAxis.BUTTON_CIRCLE)
    controller.register_button_handler(controller.reset_axis_calibration, SixAxis.BUTTON_START)
    controller.register_button_handler(controller.set_axis_centres, SixAxis.BUTTON_SELECT)

    current_milli_time = lambda: int(round(time.time() * 1000))
    last_time = current_milli_time()
    while 1:
        controller.handle_events()
        now = current_milli_time()
        if now > (last_time + 100):
            last_time = now
            print controller
<commit_msg>Moved to use asyncore for joystick events<commit_after>__author__ = 'tom'

from asyncore import file_dispatcher, loop

from evdev import InputDevice, list_devices
from threading import Thread

class SixAxis():
    """
    Class to handle the PS3 SixAxis controller

    This class will process events from the pygame event queue and calculate positions for each of the analogue axes on
    the SixAxis controller (excluding the motion sensor which appears not to work for some reason). It will also extract
    button press events and call any handler functions bound to those buttons.

    Events are only processed when the handle_events method is called, this must be called reasonably frequently as the
    pygame event queue will discard events once full and the joystick hardware is sufficiently twitchy that it's
    generating events pretty much constantly.

    Consuming code can get the current position of any of the sticks from this class through the `axes` instance
    property. This contains a list of :class:`triangula.input.SixAxis.Axis` objects, one for each distinct axis on the
    controller. The list of axes is, in order: left x, left y, right x, right y.
    """

    BUTTON_SELECT = 0  #: The Select button
    BUTTON_LEFT_STICK = 1  #: Left stick click button
    BUTTON_RIGHT_STICK = 2  #: Right stick click button
    BUTTON_START = 3  #: Start button
    BUTTON_D_UP = 4  #: D-pad up
    BUTTON_D_RIGHT = 5  #: D-pad right
    BUTTON_D_DOWN = 6  #: D-pad down
    BUTTON_D_LEFT = 7  #: D-pad left
    BUTTON_L2 = 8  #: L2 lower shoulder trigger
    BUTTON_R2 = 9  #: R2 lower shoulder trigger
    BUTTON_L1 = 10  #: L1 upper shoulder trigger
    BUTTON_R1 = 11  #: R1 upper shoulder trigger
    BUTTON_TRIANGLE = 12  #: Triangle
    BUTTON_CIRCLE = 13  #: Circle
    BUTTON_CROSS = 14  #: Cross
    BUTTON_SQUARE = 15  #: Square
    BUTTON_PS = 16  #: PS button

    def __init__(self, dead_zone=0.2, hot_zone=0.05, init_pygame=True):
        """
        Discover and initialise a PS3 SixAxis controller connected to this computer

        :param float dead_zone:
            Creates a dead zone centred on the centre position of the axis (which may or may not be zero depending on
            calibration). The axis values range from 0 to 1.0, but will be locked to 0.0 when the measured value less
            centre offset is lower in magnitude than this supplied value. Defaults to 0.2, which makes the PS3 analogue
            sticks easy to centre but still responsive to motion. The deadzone is applies to each axis independently, so
            e.g. moving the stick far right won't affect the deadzone for that sticks Y axis.
        :param float hot_zone:
            Creates a zone of maximum value, any readings from the sensor which are within this value of the max or min
            values will be mapped to 1.0 and -1.0 respectively. This can be useful because, while the PS3 controllers
            sticks have independent axes, they are constrained to move within a circle, so it's impossible to have e.g.
            1.0,1.0 for both x and y axes. Setting this value to non-zero in effect partially squares the circle,
            allowing for controls which require full range control. Setting this value to 1/sqrt(2) will create a square
            zone of variability within the circular range of motion of the controller, with any stick motions outside
            this square mapping to the maximum value for the respective axis. The value is actually scaled by the max
            and min magnitude for upper and lower ranges respectively, so e.g. setting 0.5 will create a hot-zone at
            above half the maximum value and below half the minimum value, and not at +0.5 and -0.5 (unless max and
            min are 1.0 and -1.0 respectively). As with the dead zone, these are applied separately to each axis, so in
            the case where the hot zone is set to 1/sqrt(2), a circular motion of the stick will map to x and y values
            which trace the outline of a square of unit size, allowing for all values to be emitted from the stick.
        :param boolean init_pygame:
            Defaults to True; if set then pygame will be initialised with the appropriate properties to run headless, if
            false then no pygame initialisation will be performed. If you pass False to this method you must have
            already initialised pygame (there's no requirement to initialise the joystick subsystem, this is always
            performed in this method, it's safe to run multiple times anyway)
        :return: an initialised link to an attached PS3 SixAxis controller
        """

        self.stop_function = None
        self.axes = [SixAxis.Axis('left_x', dead_zone=dead_zone, hot_zone=hot_zone),
                     SixAxis.Axis('left_y', dead_zone=dead_zone, hot_zone=hot_zone, invert=True),
                     SixAxis.Axis('right_x', dead_zone=dead_zone, hot_zone=hot_zone),
                     SixAxis.Axis('right_y', dead_zone=dead_zone, hot_zone=hot_zone, invert=True)]
        self.button_handlers = []
        self.connect()

    def connect(self):
        if self.stop_function:
            return
        for device in [InputDevice(fn) for fn in list_devices()]:
            if device.name == 'PLAYSTATION(R)3 Controller':
                self.sixaxis = device
                parent = self

                class InputDeviceDispatcher(file_dispatcher):
                    def __init__(self):
                        self.device = device
                        file_dispatcher.__init__(self, device)

                    def recv(self, ign=None):
                        return self.device.read()

                    def handle_read(self):
                        for event in self.recv():
                            parent.handle_event(event)

                InputDeviceDispatcher()

                class AsyncLoop(Thread):
                    def __init__(self):
                        Thread.__init__(self, name='InputDispatchThread')

                    def run(self):
                        loop()

                self.stop_function = AsyncLoop()
                self.stop_function.start()

    def __str__(self):
        return 'x1={}, y1={}, x2={}, y2={}'.format(
            self.axes[0].corrected_value(), self.axes[1].corrected_value(),
            self.axes[2].corrected_value(), self.axes[3].corrected_value())

    def set_axis_centres(self, *args):
        """
        Sets the centre points for each axis to the current value for that axis. This centre value is used when
        computing the value for the axis and is subtracted before applying any scaling.
        """
        for axis in self.axes:
            axis.centre = axis.value

    def reset_axis_calibration(self, *args):
        """
        Resets any previously defined axis calibration to 0.0 for all axes
        """
        for axis in self.axes:
            axis._reset()

    def register_button_handler(self, handler, buttons):
        """
        Register a handler function which will be called when a button is pressed

        :param handler: a function which will be called when any of the specified buttons are pressed. The function is
            called with the integer code for the button as the sole argument.
        :param [int] buttons: a list or one or more buttons which should trigger the handler when pressed. Buttons are
            specified as ints, for convenience the PS3 button assignments are mapped to names in SixAxis, i.e.
            SixAxis.BUTTON_CIRCLE. This includes the buttons in each of the analogue sticks. A bare int value is also
            accepted here and will be treated as if a single element list was supplied.
        :return: a no-arg function which can be used to remove this registration
        """
        mask = 0
        if isinstance(buttons, list):
            for button in buttons:
                mask += 1 << button
        else:
            mask += 1 << buttons
        h = {'handler': handler,
             'mask': mask}
        self.button_handlers.append(h)

        def remove():
            self.button_handlers.remove(h)

        return remove

    def handle_event(self, event):
        if event.type == 3:
            value = (event.value - 128.0) / 128.0
            if event.code == 0:
                # Left stick, X axis
                self.axes[0]._set(value)
            elif event.code == 1:
                # Left stick, Y axis
                self.axes[1]._set(value)
            elif event.code == 2:
                # Right stick, X axis
                self.axes[2]._set(value)
            elif event.code == 5:
                # Right stick, Y axis (yes, 5...)
                self.axes[3]._set(value)
        """
        for event in pg_event.get():
            if event.type == JOYAXISMOTION and event.joy == self.active_index:
                if event.axis < len(self.axes):
                    self.axes[event.axis]._set(event.value)
            elif event.type == JOYBUTTONDOWN and event.joy == self.active_index:
                for handler in self.button_handlers:
                    if handler['mask'] & (1 << event.button) != 0:
                        handler['handler'](event.button)
        """

    class Axis():
        """A single analogue axis on the SixAxis controller"""

        def __init__(self, name, invert=False, dead_zone=0.0, hot_zone=0.0):
            self.name = name
            self.centre = 0.0
            self.max = 0.9
            self.min = -0.9
            self.value = 0.0
            self.invert = invert
            self.dead_zone = dead_zone
            self.hot_zone = hot_zone

        def corrected_value(self):
            """
            Get a centre-compensated, scaled, value for the axis, taking any dead-zone into account. The value will
            scale from 0.0 at the edge of the dead-zone to 1.0 (positive) or -1.0 (negative) at the extreme position of
            the controller or the edge of the hot zone, if defined as other than 1.0. The axis will auto-calibrate for
            maximum value, initially it will behave as if the highest possible value from the hardware is 0.9 in each
            direction, and will expand this as higher values are observed. This is scaled by this function and should
            always return 1.0 or -1.0 at the extreme ends of the axis.

            :return: a float value, negative to the left or down and ranging from -1.0 to 1.0
            """

            centred = self.value - self.centre

            if abs(centred) <= self.dead_zone:
                return 0.0
            elif centred > 0 and self.value > self.max - (self.hot_zone * self.max):
                if not self.invert:
                    return 1.0
                else:
                    return -1.0
            elif centred < 0 and self.value < self.min - (self.hot_zone * self.min):
                if not self.invert:
                    return -1.0
                else:
                    return 1.0

            if centred > 0:
                top_range = self.max - (self.hot_zone * self.max + self.dead_zone)
                result = centred / top_range
            else:
                bottom_range = self.dead_zone - (self.min - self.hot_zone * self.min)
                result = centred / bottom_range

            if self.invert:
                result = -result

            return result

        def _reset(self):
            """
            Reset calibration (max, min and centre values) for this axis specifically. Not generally needed, you can just
            call the reset method on the SixAxis instance.

            :internal:
            """
            self.centre = 0.0
            self.max = 1.0
            self.min = -1.0

        def _set(self, new_value):
            """
            Set a new value, called from within the SixAxis class when parsing the event queue.

            :param new_value: the raw value from the joystick hardware
            :internal:
            """
            self.value = new_value
            if new_value > self.max:
                self.max = new_value
            elif new_value < self.min:
                self.min = new_value

if __name__ == '__main__':
    from input import SixAxis
    import time

    controller = SixAxis(dead_zone=0.2, hot_zone=0.1, init_pygame=True)

    def handler(button):
        print 'Button! {}'.format(button)

    controller.register_button_handler(handler, SixAxis.BUTTON_CIRCLE)
    controller.register_button_handler(controller.reset_axis_calibration, SixAxis.BUTTON_START)
    controller.register_button_handler(controller.set_axis_centres, SixAxis.BUTTON_SELECT)

    current_milli_time = lambda: int(round(time.time() * 1000))
    last_time = current_milli_time()
    while 1:
        controller.handle_events()
        now = current_milli_time()
        if now > (last_time + 100):
            last_time = now
            print controller
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
#
## This file is part of Invenio.
## Copyright (C) 2011, 2012 CERN.
##
## Invenio is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
## published by the Free Software Foundation; either version 2 of the
## License, or (at your option) any later version.
##
## Invenio is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Invenio; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.

"""
bibknowledge database models.
"""

# General imports.
from invenio.ext.sqlalchemy import db

# Create your models here.

from invenio.modules.search.models import Collection

class KnwKB(db.Model):
    """Represents a KnwKB record."""
    def __init__(self):
        pass
    __tablename__ = 'knwKB'
    id = db.Column(db.MediumInteger(8, unsigned=True), nullable=False,
                primary_key=True, autoincrement=True)
    name = db.Column(db.String(255), server_default='', unique=True)
    description = db.Column(db.Text, nullable=True)
    kbtype = db.Column(db.Char(1), nullable=True)

class KnwKBDDEF(db.Model):
    """Represents a KnwKBDDEF record."""
    def __init__(self):
        pass
    __tablename__ = 'knwKBDDEF'
    id_knwKB = db.Column(db.MediumInteger(8, unsigned=True),
                db.ForeignKey(KnwKB.id), nullable=False, primary_key=True)
    id_collection = db.Column(db.MediumInteger(9, unsigned=True),
                db.ForeignKey(Collection.id), nullable=True)
    output_tag = db.Column(db.Text, nullable=True)
    search_expression = db.Column(db.Text, nullable=True)
    kb = db.relationship(KnwKB, backref='kbdefs')
    collection = db.relationship(Collection, backref='kbdefs')

class KnwKBRVAL(db.Model):
    """Represents a KnwKBRVAL record."""
    def __init__(self):
        pass
    __tablename__ = 'knwKBRVAL'
    id = db.Column(db.MediumInteger(8, unsigned=True), nullable=False,
                primary_key=True,
                autoincrement=True)
    m_key = db.Column(db.String(255), nullable=False, server_default='',
                index=True)
    m_value = db.Column(db.Text(30), nullable=False,
                index=True)
    id_knwKB = db.Column(db.MediumInteger(8), db.ForeignKey(KnwKB.id), nullable=False,
                server_default='0')
    kb = db.relationship(KnwKB, backref='kbrvals')

__all__ = ['KnwKB',
           'KnwKBDDEF',
           'KnwKBRVAL']
<commit_msg>knowledge: PEP8 and PEP257 improvements<commit_after># -*- coding: utf-8 -*-
#
## This file is part of Invenio.
## Copyright (C) 2011, 2012, 2014 CERN.
##
## Invenio is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
## published by the Free Software Foundation; either version 2 of the
## License, or (at your option) any later version.
##
## Invenio is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Invenio; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.

"""Knowledge database models."""

# General imports.
from invenio.ext.sqlalchemy import db

# Create your models here.

from invenio.modules.search.models import Collection

class KnwKB(db.Model):

    """Represent a KnwKB record."""

    __tablename__ = 'knwKB'
    id = db.Column(db.MediumInteger(8, unsigned=True), nullable=False,
                   primary_key=True, autoincrement=True)
    name = db.Column(db.String(255), server_default='', unique=True)
    description = db.Column(db.Text, nullable=True)
    kbtype = db.Column(db.Char(1), nullable=True)

class KnwKBDDEF(db.Model):

    """Represent a KnwKBDDEF record."""

    __tablename__ = 'knwKBDDEF'
    id_knwKB = db.Column(db.MediumInteger(8, unsigned=True),
                         db.ForeignKey(KnwKB.id), nullable=False,
                         primary_key=True)
    id_collection = db.Column(db.MediumInteger(9, unsigned=True),
                              db.ForeignKey(Collection.id), nullable=True)
    output_tag = db.Column(db.Text, nullable=True)
    search_expression = db.Column(db.Text, nullable=True)
    kb = db.relationship(KnwKB, backref='kbdefs')
    collection = db.relationship(Collection, backref='kbdefs')

class KnwKBRVAL(db.Model):

    """Represent a KnwKBRVAL record."""

    __tablename__ = 'knwKBRVAL'
    id = db.Column(db.MediumInteger(8, unsigned=True), nullable=False,
                   primary_key=True, autoincrement=True)
    m_key = db.Column(db.String(255), nullable=False, server_default='',
                      index=True)
    m_value = db.Column(db.Text(30), nullable=False, index=True)
    id_knwKB = db.Column(db.MediumInteger(8), db.ForeignKey(KnwKB.id),
                         nullable=False, server_default='0')
    kb = db.relationship(KnwKB, backref='kbrvals')

__all__ = ('KnwKB',
           'KnwKBDDEF',
           'KnwKBRVAL',
           )
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
###############################################################################
#
#    Copyright (C) 2001-2014 Micronaet SRL (<http://www.micronaet.it>).
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as published
#    by the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
import os
import sys
import logging
import openerp
import xlrd
import openerp.netsvc as netsvc
import openerp.addons.decimal_precision as dp
from openerp.osv import fields, osv, expression, orm
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
from openerp import SUPERUSER_ID, api
from openerp import tools
from openerp.tools.translate import _
from openerp.tools.float_utils import float_round as round
from openerp.tools import (DEFAULT_SERVER_DATE_FORMAT,
    DEFAULT_SERVER_DATETIME_FORMAT,
    DATETIME_FORMATS_MAP,
    float_compare)

_logger = logging.getLogger(__name__)

class StockMove(orm.Model):
    """ Model name: Quants updated from inventory
    """
    _inherit = 'stock.move'

    _columns = {
        'inventory_quants_id': fields.many2one(
            'stock.quant', 'Inventory quant', ondelete='set null',
            help='Quants linked to this stock movement'),
        }

class ProductProductImportInventory(orm.Model):
    ''' Importation log element
    '''
    _name = 'product.product.import.inventory'
    _description = 'Inventory partial import'
    _rec_name = 'fullname'
    _order = 'date desc'
    filename = '/home/administrator/photo/xls/inventory' # TODO parametrize

    # -------------
    # Button event:
    # -------------
    def set_inventory_start(self, cr, uid, ids, context=None):
        ''' Set start inventory in product from XLS file
        '''
        product_pool = self.pool.get('product.product')
        current_proxy = self.browse(cr, uid, ids, context=context)[0]

        log_file = open(
            os.path.join(
                self.filename,
                'inventory_update_%s.csv' % (datetime.now()),
                ), 'w')

        # ----------------
        # Read parameters:
        # ----------------
        # From import procedure:
        fullname = current_proxy.fullname
        max_line = current_proxy.max_line or 15000

        try:
            filename = os.path.join(self.filename, fullname)
            wb = xlrd.open_workbook(filename)
            ws = wb.sheet_by_index(0)
        except:
            error = 'Error opening XLS file: %s' % (sys.exc_info(), )
            raise osv.except_osv(
                _('Open file error'),
                _('Cannot found file: %s' % filename),
                )

        if not fullname:
            raise osv.except_osv(
                _('Import error'),
                _('Need a file name to import in path %s' % fullname),
                )

        _logger.info('Start import from path: %s' % self.filename)
        for i in range(0, max_line):
            try:
                row = ws.row(i) # generate error at end
            except:
                log_file.write('%s | Row error|\n' % i)
                break
            # Loop on colums (trace)
            try:
                default_code = str(row[0].value).replace('.0', '')
            except:
                log_file.write('%s | Code error|%s\n' % (i, row))
                break

            # Search product with code:
            if not default_code:
                log_file.write('%s | No code|%s\n' % (i, row))
                continue # jump

            try:
                product_qty = float(row[1].value)
            except:
                log_file.write('%s | Qty error|%s\n' % (i, row))
                product_qty = 0

            product_ids = product_pool.search(cr, uid, [
                ('default_code', '=', default_code)], context=context)

            if not product_ids:
                log_file.write('%s | Product not found|%s\n' % (i, row))
                continue # jump

            product_proxy = product_pool.browse(
                cr, uid, product_ids, context=context)[0]

            # Write log before:
            log_file.write('%s | %s | %s\n' % (
                default_code,
                product_proxy.inventory_start,
                product_qty,
                ))

            product_pool.write(cr, uid, product_ids[0], {
                'inventory_start': product_qty,
                }, context=context)

            _logger.info('Update %s' % default_code)

        log_file.close()
        return True

    def action_import_product_from_csv(self, cr, uid, ids, context=None):
        ''' Import detail button
        '''
        # Pool used:
        picking_pool = self.pool.get('stock.picking')
        move_pool = self.pool.get('stock.move')
        product_pool = self.pool.get('product.product')
        seq_pool = self.pool.get('ir.sequence')
        quant_pool = self.pool.get('stock.quant')
        current_proxy = self.browse(cr, uid, ids, context=context)[0]
        user_proxy = self.pool.get('res.users').browse(
            cr, uid, uid, context=context)

        # ----------------
        # Read parameters:
        # ----------------
        # From import procedure:
        fullname = current_proxy.fullname
        max_line = current_proxy.max_line or 15000
        type_cl = current_proxy.cl_picking_type_id
        type_sl = current_proxy.sl_picking_type_id
        seq_cl_id = current_proxy.cl_picking_type_id.sequence_id.id
        seq_sl_id = current_proxy.sl_picking_type_id.sequence_id.id

        # Calculated:
        date = current_proxy.date or datetime.now().strftime(
            DEFAULT_SERVER_DATETIME_FORMAT)

        # Log activity:
        if not fullname:
            raise osv.except_osv(
                _('Import error'),
                _('Need a file name to import in path %s' % fullname),
                )
        _logger.info('Start import from path: %s' % self.filename)

        # ----------------
        # Header creation:
        # ----------------
        header_data = {
            'name': seq_pool.get_id(cr, uid, seq_cl_id, 'id', context=context),
            'partner_id': user_proxy.partner_id.id, #ex 1, # TODO
            'picking_type_id': type_cl.id,
            'date': date,
            'min_date': date,
            'date_done': date,
            'origin': _('CL from: %s') % fullname,
            'state': 'done', # forced
            }

        # Create object:
        cl_proxy = picking_pool.create(cr, uid, header_data, context=context)

        # Update SL data:
        header_data.update({
            'picking_type_id': type_sl.id,
            'name': seq_pool.get_id(
                cr, uid, seq_sl_id, 'id', context=context),
            'origin': _('SL from: %s') % fullname,
            })

        sl_proxy = picking_pool.create(cr, uid, header_data, context=context)

        # ---------------------------------------------------------------------
        #                Open XLS document (first WS):
        # ---------------------------------------------------------------------
        error = note = ''

        # Read excel filename:
        try:
            filename = os.path.join(self.filename, fullname)
            wb = xlrd.open_workbook(filename)
            ws = wb.sheet_by_index(0)
        except:
            error = 'Error opening XLS file: %s' % (sys.exc_info(), )
            raise osv.except_osv(
                _('Open file error'),
                _('Cannot found file: %s' % filename),
                )

        # Loop on line:
        for i in range(0, max_line):
            try:
                row = ws.row(i) # generate error at end
            except:
                # Out of range error ends import:
                note += _('Import end at line: %s\n') % i
                break

            try:
                # Loop on colums (trace)
                try:
                    default_code = str(row[0].value).replace('.0', '')
                except:
                    default = ''

                # Search product with code:
                if not default_code:
                    error += _('%s. No default code on file found\n') % i
                    continue # jump

                try:
                    product_qty = float(row[1].value)
                except:
                    product_qty = 0

                product_ids = product_pool.search(cr, uid, [
                    ('default_code', '=', default_code)], context=context)

                if not product_ids:
                    error += _(
                        '%s. Error code not found, code: %s\n') % (
                            i, default_code)
                    continue # jump

                elif len(product_ids) > 1:
                    error += _(
                        '%s. Warning more code (take first), code: %s\n') % (
                                i, default_code)

                product_proxy = product_pool.browse(
                    cr, uid, product_ids, context=context)[0]

                # Update with stock:
                mx_net_qty = product_proxy.mx_net_qty # for speed
                gap_qty = mx_net_qty - product_qty

                sign = +1 # positive quant
                if gap_qty > 0:
                    document = 'SL'
                    picking_id = sl_proxy
                    type_picking = type_sl
                    sign = -1 # negative quant
                elif gap_qty < 0:
                    document = 'CL'
                    picking_id = cl_proxy
                    type_picking = type_cl
                    gap_qty = -gap_qty # positive quantity
                else:
                    document = 'NO DOC'
                    pass

                # Create quant:
                quant_id = quant_pool.create(cr, uid, {
                    'in_date': date,
                    'cost': 0.0, # TODO
                    'location_id': type_picking.default_location_src_id.id,
                    'product_id': product_ids[0],
                    'qty': gap_qty * sign,
                    #'product_uom': bom.product_id.uom_id.id,
                    }, context=context)

                if gap_qty:
                    move_pool.create(cr, uid, {
                        'name': default_code,
                        'product_id': product_ids[0],
                        'picking_id': picking_id,
                        'product_uom_qty': gap_qty,
                        'date': date,
                        'date_expected': date,
                        #'date_planned': date,
                        'inventory_quants_id': quant_id,
                        'location_id':
                            type_picking.default_location_src_id.id,
                        'location_dest_id':
                            type_picking.default_location_dest_id.id,

                        'price_unit': 1.0, # TODO for stock evaluation
                        'product_uom': product_proxy.uom_id.id,
                        'state': 'done',
                        }, context=context)

                note += '%s|. |\'%s| from |\'%s| to |\'%s| [|%s|%s|]\n' % (
                    i,
                    default_code,
                    mx_net_qty,
                    product_qty,
                    document,
                    gap_qty if gap_qty else 'No move!!',
                    )
            except:
                error += _('%s. Import error code: %s [%s]\n') % (
                    i, default_code, sys.exc_info())

        self.write(cr, uid, ids, {
            'error': error,
            'note': 'File: %s\n%s' % (
                filename, note),
            'inventory_cl_id': cl_proxy,
            'inventory_sl_id': sl_proxy,
            }, context=context)

        _logger.info('End import XLS purchase file: %s' % fullname)
        return True

    _columns = {
        'date': fields.datetime('Date'),
        'fullname': fields.char(
            'File name', size=80, required=True),
        'max_line': fields.integer('Max line'),
        'cl_picking_type_id': fields.many2one(
            'stock.picking.type', 'Type CL', required=True),
        'sl_picking_type_id': fields.many2one(
            'stock.picking.type', 'Type SL', required=True),
        'inventory_cl_id': fields.many2one(
            'stock.picking', 'Inventory CL', ondelete='set null'),
        'inventory_sl_id': fields.many2one(
            'stock.picking', 'Inventory SL', ondelete='set null'),
        'error': fields.text('Error'),
        'note': fields.text('Note'),
        }

    _defaults = {
        'date': lambda *x: datetime.now().strftime(
            DEFAULT_SERVER_DATETIME_FORMAT),
        'max_line': lambda *x: 15000,
        }

# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
<commit_msg>auto active stock on stock off<commit_after># -*- coding: utf-8 -*-
###############################################################################
#
#    Copyright (C) 2001-2014 Micronaet SRL (<http://www.micronaet.it>).
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as published
#    by the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
import os
import sys
import logging
import openerp
import xlrd
import openerp.netsvc as netsvc
import openerp.addons.decimal_precision as dp
from openerp.osv import fields, osv, expression, orm
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
from openerp import SUPERUSER_ID, api
from openerp import tools
from openerp.tools.translate import _
from openerp.tools.float_utils import float_round as round
from openerp.tools import (DEFAULT_SERVER_DATE_FORMAT,
    DEFAULT_SERVER_DATETIME_FORMAT,
    DATETIME_FORMATS_MAP,
    float_compare)

_logger = logging.getLogger(__name__)

class StockMove(orm.Model):
    """ Model name: Quants updated from inventory
    """
    _inherit = 'stock.move'

    _columns = {
        'inventory_quants_id': fields.many2one(
            'stock.quant', 'Inventory quant', ondelete='set null',
            help='Quants linked to this stock movement'),
        }

class ProductProductImportInventory(orm.Model):
    ''' Importation log element
    '''
    _name = 'product.product.import.inventory'
    _description = 'Inventory partial import'
    _rec_name = 'fullname'
    _order = 'date desc'
    filename = '/home/administrator/photo/xls/inventory' # TODO parametrize

    # -------------
    # Button event:
    # -------------
    def set_inventory_start(self, cr, uid, ids, context=None):
        ''' Set start inventory in product from XLS file
        '''
        product_pool = self.pool.get('product.product')
        current_proxy = self.browse(cr, uid, ids, context=context)[0]

        log_file = open(
            os.path.join(
                self.filename,
                'inventory_update_%s.csv' % (datetime.now()),
                ), 'w')

        # ----------------
        # Read parameters:
        # ----------------
        # From import procedure:
        fullname = current_proxy.fullname
        max_line = current_proxy.max_line or 15000

        try:
            filename = os.path.join(self.filename, fullname)
            wb = xlrd.open_workbook(filename)
            ws = wb.sheet_by_index(0)
        except:
            error = 'Error opening XLS file: %s' % (sys.exc_info(), )
            raise osv.except_osv(
                _('Open file error'),
                _('Cannot found file: %s' % filename),
                )

        if not fullname:
            raise osv.except_osv(
                _('Import error'),
                _('Need a file name to import in path %s' % fullname),
                )

        _logger.info('Start import from path: %s' % self.filename)
        for i in range(0, max_line):
            try:
                row = ws.row(i) # generate error at end
            except:
                log_file.write('%s | Row error|\n' % i)
                break
            # Loop on colums (trace)
            try:
                default_code = str(row[0].value).replace('.0', '')
            except:
                log_file.write('%s | Code error|%s\n' % (i, row))
                break

            # Search product with code:
            if not default_code:
                log_file.write('%s | No code|%s\n' % (i, row))
                continue # jump

            try:
                product_qty = float(row[1].value)
            except:
                log_file.write('%s | Qty error|%s\n' % (i, row))
                product_qty = 0

            product_ids = product_pool.search(cr, uid, [
                ('default_code', '=', default_code)], context=context)

            if not product_ids:
                log_file.write('%s | Product not found|%s\n' % (i, row))
                continue # jump

            product_proxy = product_pool.browse(
                cr, uid, product_ids, context=context)[0]

            # Write log before:
            log_file.write('%s | %s | %s\n' % (
                default_code,
                product_proxy.inventory_start,
                product_qty,
                ))

            product_pool.write(cr, uid, product_ids[0], {
                'inventory_start': product_qty,
                }, context=context)

            _logger.info('Update %s' % default_code)

        log_file.close()
        return True

    def action_import_product_from_csv(self, cr, uid, ids, context=None):
        ''' Import detail button
        '''
        # Pool used:
        picking_pool = self.pool.get('stock.picking')
        move_pool = self.pool.get('stock.move')
        product_pool = self.pool.get('product.product')
        seq_pool = self.pool.get('ir.sequence')
        quant_pool = self.pool.get('stock.quant')
        current_proxy = self.browse(cr, uid, ids, context=context)[0]
        user_pool = self.pool.get('res.users')

        # Browse obj:
        user_proxy = user_pool.browse(
            cr, uid, uid, context=context)

        # Set inventory ON
        user_pool.write(cr, uid, uid, {
            'no_inventory_status': False,
            }, context=context)

        # ----------------
        # Read parameters:
        # ----------------
        # From import procedure:
        fullname = current_proxy.fullname
        max_line = current_proxy.max_line or 15000
        type_cl = current_proxy.cl_picking_type_id
        type_sl = current_proxy.sl_picking_type_id
        seq_cl_id = current_proxy.cl_picking_type_id.sequence_id.id
        seq_sl_id = current_proxy.sl_picking_type_id.sequence_id.id

        # Calculated:
        date = current_proxy.date or datetime.now().strftime(
            DEFAULT_SERVER_DATETIME_FORMAT)

        # Log activity:
        if not fullname:
            raise osv.except_osv(
                _('Import error'),
                _('Need a file name to import in path %s' % fullname),
                )
        _logger.info('Start import from path: %s' % self.filename)

        # ----------------
        # Header creation:
        # ----------------
        header_data = {
            'name': seq_pool.get_id(cr, uid, seq_cl_id, 'id', context=context),
            'partner_id': user_proxy.partner_id.id, #ex 1, # TODO
            'picking_type_id': type_cl.id,
            'date': date,
            'min_date': date,
            'date_done': date,
            'origin': _('CL from: %s') % fullname,
            'state': 'done', # forced
            }

        # Create object:
        cl_proxy = picking_pool.create(cr, uid, header_data, context=context)

        # Update SL data:
        header_data.update({
            'picking_type_id': type_sl.id,
            'name': seq_pool.get_id(
                cr, uid, seq_sl_id, 'id', context=context),
            'origin': _('SL from: %s') % fullname,
            })

        sl_proxy = picking_pool.create(cr, uid, header_data, context=context)

        # ---------------------------------------------------------------------
        #                Open XLS document (first WS):
        # ---------------------------------------------------------------------
        error = note = ''

        # Read excel filename:
        try:
            filename = os.path.join(self.filename, fullname)
            wb = xlrd.open_workbook(filename)
            ws = wb.sheet_by_index(0)
        except:
            error = 'Error opening XLS file: %s' % (sys.exc_info(), )
            raise osv.except_osv(
                _('Open file error'),
                _('Cannot found file: %s' % filename),
                )

        # Loop on line:
        for i in range(0, max_line):
            try:
                row = ws.row(i) # generate error at end
            except:
                # Out of range error ends import:
                note += _('Import end at line: %s\n') % i
                break

            try:
                # Loop on colums (trace)
                try:
                    default_code = str(row[0].value).replace('.0', '')
                except:
                    default = ''

                # Search product with code:
                if not default_code:
                    error += _('%s. No default code on file found\n') % i
                    continue # jump

                try:
                    product_qty = float(row[1].value)
                except:
                    product_qty = 0

                product_ids = product_pool.search(cr, uid, [
                    ('default_code', '=', default_code)], context=context)

                if not product_ids:
                    error += _(
                        '%s. Error code not found, code: %s\n') % (
                            i, default_code)
                    continue # jump
                elif len(product_ids) > 1:
                    error += _(
                        '%s. Warning more code (take first), code: %s\n') % (
                                i, default_code)

                product_proxy = product_pool.browse(
                    cr, uid, product_ids, context=context)[0]

                # Update with stock:
                mx_net_qty = product_proxy.mx_net_qty # for speed
                gap_qty = mx_net_qty - product_qty

                if gap_qty > 0:
                    document = 'SL'
                    picking_id = sl_proxy
                    type_picking = type_sl
                    # quant:
                    sign = -1 # negative quant
                    quant_location_id = type_picking.default_location_src_id.id
                elif gap_qty < 0:
                    document = 'CL'
                    picking_id = cl_proxy
                    type_picking = type_cl
                    gap_qty = -gap_qty # positive quantity
                    # quant:
                    sign = +1 # positive quant
                    quant_location_id = \
                        type_picking.default_location_dest_id.id
                else:
                    document = 'NO DOC'
                    pass

                # Create quant:
                quant_id = quant_pool.create(cr, uid, {
                    'in_date': date,
                    'cost': 0.0, # TODO
                    'location_id': quant_location_id,
                    'product_id': product_ids[0],
                    'qty': gap_qty * sign,
                    #'product_uom': bom.product_id.uom_id.id,
                    }, context=context)

                if gap_qty:
                    move_pool.create(cr, uid, {
                        'name': default_code,
                        'product_id': product_ids[0],
                        'picking_id': picking_id,
                        'product_uom_qty': gap_qty,
                        'date': date,
                        'date_expected': date,
                        #'date_planned': date,
                        'inventory_quants_id': quant_id,
                        'location_id':
                            type_picking.default_location_src_id.id,
                        'location_dest_id':
                            type_picking.default_location_dest_id.id,

                        'price_unit': 1.0, # TODO for stock evaluation
                        'product_uom': product_proxy.uom_id.id,
                        'state': 'done',
                        }, context=context)

                note += '%s|. |\'%s| from |\'%s| to |\'%s| [|%s|%s|]\n' % (
                    i,
                    default_code,
                    mx_net_qty,
                    product_qty,
                    document,
                    gap_qty if gap_qty else 'No move!!',
                    )
            except:
                error += _('%s. Import error code: %s [%s]\n') % (
                    i, default_code, sys.exc_info())

        self.write(cr, uid, ids, {
            'error': error,
            'note': 'File: %s\n%s' % (
                filename, note),
            'inventory_cl_id': cl_proxy,
            'inventory_sl_id': sl_proxy,
            }, context=context)

        # Set inventory OFF
        user_proxy.write(cr, uid, uid, {
            'no_inventory_status': True,
            }, context=context)

        _logger.info('End import XLS purchase file: %s' % fullname)
        return True

    _columns = {
        'date': fields.datetime('Date'),
        'fullname': fields.char(
            'File name', size=80, required=True),
        'max_line': fields.integer('Max line'),
        'cl_picking_type_id': fields.many2one(
            'stock.picking.type', 'Type CL', required=True),
        'sl_picking_type_id': fields.many2one(
            'stock.picking.type', 'Type SL', required=True),
        'inventory_cl_id': fields.many2one(
            'stock.picking', 'Inventory CL', ondelete='set null'),
        'inventory_sl_id': fields.many2one(
            'stock.picking', 'Inventory SL', ondelete='set null'),
        'error': fields.text('Error'),
        'note': fields.text('Note'),
        }

    _defaults = {
        'date': lambda *x: datetime.now().strftime(
            DEFAULT_SERVER_DATETIME_FORMAT),
        'max_line': lambda *x: 15000,
        }

# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
<|endoftext|>


<commit_before>#!/usr/bin/env python3
# -*- coding: utf-8 -*-

__author__      = "Ponzoni, Nelson"
__copyright__   = "Copyright 2015"
__credits__     = ["Ponzoni Nelson"]
__maintainer__  = "Ponzoni Nelson"
__contact__     = "npcuadra@gmail.com"
__email__       = "npcuadra@gmail.com"
__license__     = "GPL"
__version__     = "1.0.0"
__status__      = "Production"

"""

"""

import numpy
import time
import os
import sys
import subprocess
import argparse

# Dependencias Externas
## Core
from cupydle.dnn.funciones import sigmoideaTheano
## Data
from cupydle.test.mnist.mnist import MNIST
from cupydle.test.mnist.mnist import open4disk
from cupydle.test.mnist.mnist import save2disk
## Utils
from cupydle.dnn.utils import temporizador
from cupydle.dnn.validacion_cruzada import StratifiedKFold

from cupydle.dnn.mlp import MLP

if __name__ == "__main__":

    parser = argparse.ArgumentParser(description='Prueba de un MLP sobre FACE -- Validacion Cruzada --.')
    parser.add_argument('-d', '--directorio',   type=str,   dest="directorio",  default='test_MLP', help="Carpeta donde se almacena la corrida actual")
    parser.add_argument('--dataset',            type=str,   dest="dataset",     default='videos_clases_procesados_zscore_minmax.npz', help="Archivo donde esta el dataset, [videos, clases].npz")
    parser.add_argument('-l', '--capas',        type=int,   dest="capas",       required=True,      nargs='+',          help="Capas del MLP, #entrada, #oculta1, .... , #salida")
    parser.add_argument('-b', '--batchsize',    type=int,   dest="tambatch",    default=10,         required=False,     help="Tamanio del minibatch para el entrenamiento")
    parser.add_argument('-e', '--epocas',       type=int,   dest="epocas",      default=10,         required=False,     help="Cantidad de epocas")
    parser.add_argument('-f', '--folds',        type=int,   dest="folds",       default=6,          required=False,     help="Cantidad de conjuntos para la validacion cruzada")
    parser.add_argument('-p', '--porcentaje',   type=float, dest="porcentaje",  default=0.8,        required=False,     help="Porcentaje en que el conjunto de entrenamiento se detina para entrenar y validar")
    argumentos = parser.parse_args()

    # parametros pasados por consola
    directorio_ejecucion  = argumentos.directorio
    capas                 = argumentos.capas
    dataset               = argumentos.dataset
    tambatch              = argumentos.tambatch
    epocas                = argumentos.epocas
    conjuntos             = argumentos.folds
    porcentaje            = argumentos.porcentaje

    # configuraciones con respecto a los directorios
    directorioActual= os.getcwd()                                  # directorio actual de ejecucion
    rutaTest        = directorioActual + '/cupydle/test/face/'     # sobre el de ejecucion la ruta a los tests
    rutaDatos       = directorioActual + '/cupydle/data/DB_face/'  # donde se almacenan la base de datos
    carpetaTest     = directorio_ejecucion + '/'                   # carpeta a crear para los tests
    rutaCompleta    = rutaTest + carpetaTest

    if not os.path.exists(rutaCompleta):        # si no existe la crea
        print('Creando la carpeta para el test en: ',rutaCompleta)
        os.makedirs(rutaCompleta)

    if not os.path.exists(rutaDatos):
        print("Creando la base de datos en:", rutaDatos)
        os.makedirs(rutaDatos)

    # se cargan  los datos, debe ser un archivo comprimido, en el cual los
    # arreglos estan en dos archivos, 'videos' y 'clases'
    b = numpy.load(rutaDatos + dataset)
    videos = b['videos']
    clases = b['clases']
    # las clases estan desde 1..6, deben ser desde 0..5
    clases -= 1
    del b #libera memoria
    skf = StratifiedKFold(clases, n_folds=conjuntos)

    T = temporizador()
        inicio_todo = T.tic()

    contador = 0

    for train_index, test_index in skf:
        contador +=1
        # lista de tupas, [(x_trn, y_trn), ...]
        # los datos estan normalizados...
        datos = []
        cantidad = int(len(train_index)*porcentaje)

        datosTRN = (videos[train_index[cantidad:]], clases[train_index[cantidad:]])
        datosVAL = (videos[train_index[:cantidad]],clases[train_index[:cantidad]])
        datosTST = (videos[test_index],clases[test_index])

        datos.append(datosTRN); datos.append(datosVAL); datos.append(datosTST)

        # creo la red
        ruta_kfold = rutaCompleta + 'Kf_' + str(contador) + '/'
        os.makedirs(ruta_kfold)

        clasificador = MLP(clasificacion=True,
                           rng=None,
                           ruta=ruta_kfold)

        # se agregan los parametros
        clasificador.setParametroEntrenamiento({'tasaAprendizaje':0.01})
        clasificador.setParametroEntrenamiento({'regularizadorL1':0.00})
        clasificador.setParametroEntrenamiento({'regularizadorL2':0.0001})
        clasificador.setParametroEntrenamiento({'momento':0.0})
        clasificador.setParametroEntrenamiento({'activationfuntion':sigmoideaTheano()})
        clasificador.setParametroEntrenamiento({'epocas':epocas})
        clasificador.setParametroEntrenamiento({'toleranciaError':0.08})

        # agrego tantas capas desee de regresion
        # la primera es la que indica la entrada
        # las intermedias son de regresion
        # la ultima es de clasificaicon
        for idx, _ in enumerate(capas[:-2]): # es -2 porque no debo tener en cuenta la primera ni la ultima
            clasificador.agregarCapa(unidadesEntrada=capas[idx], unidadesSalida=capas[idx+1], clasificacion=False, activacion=sigmoideaTheano(), pesos=None, biases=None)
        clasificador.agregarCapa(unidadesSalida=capas[-1], clasificacion=True, pesos=None, biases=None)

        inicio = T.tic()
        # se entrena la red
        clasificador.entrenar(trainSet=datos[0],
                              validSet=datos[1],
                              testSet=datos[2],
                              batch_size=tambatch)
        final = T.toc()
        print("Tiempo para entrenamiento: {}".format(T.transcurrido(inicio, final)))

    final_todo = T.toc()
    print("Tiempo total para entrenamiento: {}".format(T.transcurrido(inicio_todo, final_todo)))

    # guardando los parametros aprendidos
    clasificador.guardarParametros()

else:
    assert False, "Esto no es un modulo, es un TEST!!!"
<commit_msg>pruebas sobre mlp face cross validation<commit_after>#!/usr/bin/env python3
# -*- coding: utf-8 -*-

__author__      = "Ponzoni, Nelson"
__copyright__   = "Copyright 2015"
__credits__     = ["Ponzoni Nelson"]
__maintainer__  = "Ponzoni Nelson"
__contact__     = "npcuadra@gmail.com"
__email__       = "npcuadra@gmail.com"
__license__     = "GPL"
__version__     = "1.0.0"
__status__      = "Production"

"""

"""

import numpy
import time
import os
import sys
import subprocess
import argparse

# Dependencias Externas
## Core
from cupydle.dnn.funciones import sigmoideaTheano
## Data
from cupydle.test.mnist.mnist import MNIST
from cupydle.test.mnist.mnist import open4disk
from cupydle.test.mnist.mnist import save2disk
## Utils
from cupydle.dnn.utils import temporizador
from cupydle.dnn.validacion_cruzada import StratifiedKFold

from cupydle.dnn.mlp import MLP

if __name__ == "__main__":

    parser = argparse.ArgumentParser(description='Prueba de un MLP sobre FACE -- Validacion Cruzada --.')
    parser.add_argument('-d', '--directorio',   type=str,   dest="directorio",  default='test_MLP', help="Carpeta donde se almacena la corrida actual")
    parser.add_argument('--dataset',            type=str,   dest="dataset",     default='videos_clases_procesados_zscore_minmax.npz', help="Archivo donde esta el dataset, [videos, clases].npz")
    parser.add_argument('-l', '--capas',        type=int,   dest="capas",       required=True,      nargs='+',          help="Capas del MLP, #entrada, #oculta1, .... , #salida")
    parser.add_argument('-b', '--batchsize',    type=int,   dest="tambatch",    default=10,         required=False,     help="Tamanio del minibatch para el entrenamiento")
    parser.add_argument('-e', '--epocas',       type=int,   dest="epocas",      default=10,         required=False,     help="Cantidad de epocas")
    parser.add_argument('-f', '--folds',        type=int,   dest="folds",       default=6,          required=False,     help="Cantidad de conjuntos para la validacion cruzada")
    parser.add_argument('-p', '--porcentaje',   type=float, dest="porcentaje",  default=0.8,        required=False,     help="Porcentaje en que el conjunto de entrenamiento se detina para entrenar y validar")
    argumentos = parser.parse_args()

    # parametros pasados por consola
    directorio_ejecucion  = argumentos.directorio
    capas                 = argumentos.capas
    dataset               = argumentos.dataset
    tambatch              = argumentos.tambatch
    epocas                = argumentos.epocas
    conjuntos             = argumentos.folds
    porcentaje            = argumentos.porcentaje

    # configuraciones con respecto a los directorios
    directorioActual= os.getcwd()                                  # directorio actual de ejecucion
    rutaTest        = directorioActual + '/cupydle/test/face/'     # sobre el de ejecucion la ruta a los tests
    rutaDatos       = directorioActual + '/cupydle/data/DB_face/'  # donde se almacenan la base de datos
    carpetaTest     = directorio_ejecucion + '/'                   # carpeta a crear para los tests
    rutaCompleta    = rutaTest + carpetaTest

    if not os.path.exists(rutaCompleta):        # si no existe la crea
        print('Creando la carpeta para el test en: ',rutaCompleta)
        os.makedirs(rutaCompleta)

    if not os.path.exists(rutaDatos):
        print("Creando la base de datos en:", rutaDatos)
        os.makedirs(rutaDatos)

    # se cargan  los datos, debe ser un archivo comprimido, en el cual los
    # arreglos estan en dos archivos, 'videos' y 'clases'
    b = numpy.load(rutaDatos + dataset)
    videos = b['videos']
    clases = b['clases']
    # las clases estan desde 1..6, deben ser desde 0..5
    clases -= 1
    del b #libera memoria
    skf = StratifiedKFold(clases, n_folds=conjuntos)

    T = temporizador()
        inicio_todo = T.tic()

    contador = 0

    for train_index, test_index in skf:
        contador +=1
        # lista de tupas, [(x_trn, y_trn), ...]
        # los datos estan normalizados...
        datos = []
        cantidad = int(len(train_index)*porcentaje)

        datosTRN = (videos[train_index[cantidad:]], clases[train_index[cantidad:]])
        datosVAL = (videos[train_index[:cantidad]],clases[train_index[:cantidad]])
        datosTST = (videos[test_index],clases[test_index])

        datos.append(datosTRN); datos.append(datosVAL); datos.append(datosTST)

        # creo la red
        ruta_kfold = rutaCompleta + 'Kf_' + str(contador) + '/'
        os.makedirs(ruta_kfold)

        clasificador = MLP(clasificacion=True,
                           rng=None,
                           ruta=ruta_kfold)

        # se agregan los parametros
        clasificador.setParametroEntrenamiento({'tasaAprendizaje':0.01})
        clasificador.setParametroEntrenamiento({'regularizadorL1':0.00})
        clasificador.setParametroEntrenamiento({'regularizadorL2':0.0001})
        clasificador.setParametroEntrenamiento({'momento':0.0})
        clasificador.setParametroEntrenamiento({'activationfuntion':sigmoideaTheano()})
        clasificador.setParametroEntrenamiento({'epocas':epocas})
        clasificador.setParametroEntrenamiento({'toleranciaError':0.08})

        # agrego tantas capas desee de regresion
        # la primera es la que indica la entrada
        # las intermedias son de regresion
        # la ultima es de clasificaicon
        for idx, _ in enumerate(capas[:-2]): # es -2 porque no debo tener en cuenta la primera ni la ultima
            clasificador.agregarCapa(unidadesEntrada=capas[idx], unidadesSalida=capas[idx+1], clasificacion=False, activacion=sigmoideaTheano(), pesos=None, biases=None)
        clasificador.agregarCapa(unidadesSalida=capas[-1], clasificacion=True, pesos=None, biases=None)

        assert False
        inicio = T.tic()
        # se entrena la red
        clasificador.entrenar(trainSet=datos[0],
                              validSet=datos[1],
                              testSet=datos[2],
                              batch_size=tambatch)
        final = T.toc()
        print("Tiempo para entrenamiento: {}".format(T.transcurrido(inicio, final)))

    final_todo = T.toc()
    print("Tiempo total para entrenamiento: {}".format(T.transcurrido(inicio_todo, final_todo)))

    # guardando los parametros aprendidos
    clasificador.guardarParametros()

else:
    assert False, "Esto no es un modulo, es un TEST!!!"
<|endoftext|>


<commit_before>from isisdata.models import *
from django.utils.text import slugify

import export

import functools

def create_acr_string(author, additional_fields = []):
    fields = ['ACR_ID ' + str(author[0]),
               'ACRStatus ' + (str(author[1]) if author[1] else u''),
               'ACRType ' + (dict(ACRelation.TYPE_CHOICES)[author[2]] if author[2] else u''),
               'ACRDisplayOrder ' + (str(author[3]) if author[3] else u''),
               'ACRNameForDisplayInCitation ' + (author[4] if author[4] else u''),
               'CitationID ' + (str(author[5]) if author[5] else u''),
               'CitationStatus ' + (str(author[6]) if author[6] else u''),
               'CitationType ' + (dict(Citation.TYPE_CHOICES)[author[7]] if author[7] else u''),
               'CitationTitle ' + (author[8] if author[8] else u'')
                ]
    return u' || '.join(fields + [field_name + ' ' + str(author[9+idx]) for idx,field_name in enumerate(additional_fields)])
acr_fields = ['id',
          'record_status_value',
          'type_controlled',
          'data_display_order',
          'name_for_display_in_citation',
          'citation__id',
          'citation__record_status_value',
          'citation__type_controlled',
          'citation__title'
         ]

def _redirect(obj, extra):
    if not obj.redirect_to:
        return u""

    return obj.redirect_to.id

def _last_name(obj, extra):
    if obj.type_controlled == Authority.PERSON:
        try:
            person = Person.objects.get(pk=obj.id)
            return person.personal_name_last
        except:
            print "No person record"
            return u""
    return u""

def _first_name(obj, extra):
    if obj.type_controlled == Authority.PERSON:
        try:
            person = Person.objects.get(pk=obj.id)
            return person.personal_name_first
        except:
            print "No person record"
            return u""
    return u""

def _name_suffix(obj, extra):
    if obj.type_controlled == Authority.PERSON:
        try:
            person = Person.objects.get(pk=obj.id)
            return person.personal_name_suffix
        except:
            print "No person record"
            return u""
    return u""

def _name_preferred(obj, extra):
    if obj.type_controlled == Authority.PERSON:
        try:
            person = Person.objects.get(pk=obj.id)
            return person.personal_name_preferred
        except:
            print "No person record"
            return u""
    return u""

def _attributes(obj, extra):
    qs = obj.attributes.all()

    def create_value_list(x):
        return ['AttributeID ' + x.id,
            'AttributeStatus ' + (x.record_status_value if x.record_status_value else ''),
            'AttributeType ' + x.type_controlled.name,
            'AttributeValue ' + str(x.value.cvalue()),
            'AttributeFreeFormValue ' + (x.value_freeform if x.value_freeform else ''),
            'AttributeStart ' + (', '.join([str(y) for y in x.value.cvalue()[0]]) if isinstance(x.value.cvalue(), list) and x.value.cvalue()[0] else ""),
            'AttributeEnd ' + (', '.join([str(y) for y in x.value.cvalue()[1]]) if isinstance(x.value.cvalue(), list) and x.value.cvalue()[1] else ""),
            'AttributeDescription ' + (x.description if x.description else '')]

    if qs.count() > 0:
        return u' // '.join(map(lambda x: u' '.join(create_value_list(x)), qs))

    return u""

def _linked_data(obj, extra):
    """
    Get linked data entries
    """
    qs = obj.linkeddata_entries.all()
    if qs.count() == 0:
        return u''

    return u' // '.join(map(lambda x: u' '.join(['LinkedData_ID ' + x[0], 'Status ' + x[1], 'Type ' + x[2], 'URN ' + x[3], 'ResourceName ' + x[4], 'URL ' + x[5]]), qs.values_list(*['id', 'record_status_value', 'type_controlled__name', 'universal_resource_name', 'resource_name', 'url'])))

def _related_citations(obj, extra):
    qs = obj.acrelation_set.all()
    return u' // '.join(map(create_acr_string, qs.values_list(*acr_fields)))

redirect = export.Column(u'Redirect', _redirect)
name = export.Column(u'Name', lambda obj, extra: obj.name)
description = export.Column(u'Description', lambda obj, extra: obj.description)
classification_system = export.Column(u'Classification System', lambda obj, extra: obj.get_classification_system_display())
last_name = export.Column(u"Last Name", _last_name)
first_name = export.Column(u"First Name", _first_name)
name_suffix = export.Column(u"Name Suffix", _name_suffix)
name_preferred = export.Column(u"Name Preferred", _name_preferred)
attributes = export.Column(u"Attributes", _attributes)
linked_data = export.Column(u"Linked Data", _linked_data)
related_citations = export.Column(u"Related Citations", _related_citations)

AUTHORITY_COLUMNS = [
    export.object_id,
    export.record_type,
    export.record_nature,
    redirect,
    name,
    description,
    classification_system,
    export.record_history,
    last_name,
    first_name,
    name_suffix,
    name_preferred,
    attributes,
    linked_data,
    related_citations,
]
<commit_msg>[ISISCB-1037] fixed bug single date attributes<commit_after>from isisdata.models import *
from django.utils.text import slugify

import export

import functools

def create_acr_string(author, additional_fields = []):
    fields = ['ACR_ID ' + str(author[0]),
               'ACRStatus ' + (str(author[1]) if author[1] else u''),
               'ACRType ' + (dict(ACRelation.TYPE_CHOICES)[author[2]] if author[2] else u''),
               'ACRDisplayOrder ' + (str(author[3]) if author[3] else u''),
               'ACRNameForDisplayInCitation ' + (author[4] if author[4] else u''),
               'CitationID ' + (str(author[5]) if author[5] else u''),
               'CitationStatus ' + (str(author[6]) if author[6] else u''),
               'CitationType ' + (dict(Citation.TYPE_CHOICES)[author[7]] if author[7] else u''),
               'CitationTitle ' + (author[8] if author[8] else u'')
                ]
    return u' || '.join(fields + [field_name + ' ' + str(author[9+idx]) for idx,field_name in enumerate(additional_fields)])
acr_fields = ['id',
          'record_status_value',
          'type_controlled',
          'data_display_order',
          'name_for_display_in_citation',
          'citation__id',
          'citation__record_status_value',
          'citation__type_controlled',
          'citation__title'
         ]

def _redirect(obj, extra):
    if not obj.redirect_to:
        return u""

    return obj.redirect_to.id

def _last_name(obj, extra):
    if obj.type_controlled == Authority.PERSON:
        try:
            person = Person.objects.get(pk=obj.id)
            return person.personal_name_last
        except:
            print "No person record"
            return u""
    return u""

def _first_name(obj, extra):
    if obj.type_controlled == Authority.PERSON:
        try:
            person = Person.objects.get(pk=obj.id)
            return person.personal_name_first
        except:
            print "No person record"
            return u""
    return u""

def _name_suffix(obj, extra):
    if obj.type_controlled == Authority.PERSON:
        try:
            person = Person.objects.get(pk=obj.id)
            return person.personal_name_suffix
        except:
            print "No person record"
            return u""
    return u""

def _name_preferred(obj, extra):
    if obj.type_controlled == Authority.PERSON:
        try:
            person = Person.objects.get(pk=obj.id)
            return person.personal_name_preferred
        except:
            print "No person record"
            return u""
    return u""

def _attributes(obj, extra):
    qs = obj.attributes.all()

    def create_value_list(x):
        start, end = '', ''
        if isinstance(x.value.cvalue(), list):
            if len(x.value.cvalue()) > 0:
                start = ', '.join([str(y) for y in x.value.cvalue()[0]]) if isinstance(x.value.cvalue()[0], list) else str(x.value.cvalue()[0])
            if len(x.value.cvalue()) > 1:
                end = ', '.join([str(y) for y in x.value.cvalue()[1]]) if isinstance(x.value.cvalue()[1], list) else str(x.value.cvalue()[1])

        return ['AttributeID ' + x.id,
            'AttributeStatus ' + (x.record_status_value if x.record_status_value else ''),
            'AttributeType ' + x.type_controlled.name,
            'AttributeValue ' + str(x.value.cvalue()),
            'AttributeFreeFormValue ' + (x.value_freeform if x.value_freeform else ''),
            'AttributeStart ' + start,
            'AttributeEnd ' + end,
            'AttributeDescription ' + (x.description if x.description else '')]

    if qs.count() > 0:
        return u' // '.join(map(lambda x: u' '.join(create_value_list(x)), qs))

    return u""

def _linked_data(obj, extra):
    """
    Get linked data entries
    """
    qs = obj.linkeddata_entries.all()
    if qs.count() == 0:
        return u''

    return u' // '.join(map(lambda x: u' '.join(['LinkedData_ID ' + x[0], 'Status ' + x[1], 'Type ' + x[2], 'URN ' + x[3], 'ResourceName ' + x[4], 'URL ' + x[5]]), qs.values_list(*['id', 'record_status_value', 'type_controlled__name', 'universal_resource_name', 'resource_name', 'url'])))

def _related_citations(obj, extra):
    qs = obj.acrelation_set.all()
    return u' // '.join(map(create_acr_string, qs.values_list(*acr_fields)))

redirect = export.Column(u'Redirect', _redirect)
name = export.Column(u'Name', lambda obj, extra: obj.name)
description = export.Column(u'Description', lambda obj, extra: obj.description)
classification_system = export.Column(u'Classification System', lambda obj, extra: obj.get_classification_system_display())
last_name = export.Column(u"Last Name", _last_name)
first_name = export.Column(u"First Name", _first_name)
name_suffix = export.Column(u"Name Suffix", _name_suffix)
name_preferred = export.Column(u"Name Preferred", _name_preferred)
attributes = export.Column(u"Attributes", _attributes)
linked_data = export.Column(u"Linked Data", _linked_data)
related_citations = export.Column(u"Related Citations", _related_citations)

AUTHORITY_COLUMNS = [
    export.object_id,
    export.record_type,
    export.record_nature,
    redirect,
    name,
    description,
    classification_system,
    export.record_history,
    last_name,
    first_name,
    name_suffix,
    name_preferred,
    attributes,
    linked_data,
    related_citations,
]
<|endoftext|>


<commit_before>import re
import time
from cwbot.modules.BaseChatModule import BaseChatModule

class MiscCommandModule(BaseChatModule):
    """
    A module that responds to various silly commands.

    No configuration options.
    """
    requiredCapabilities = ['chat']
    _name = "misc"

    def __init__(self, manager, identity, config):
        self._startTime = time.time()
        self._regex = r'(?i)^\Q{}\E( |$)'.format(manager.properties.userName)
        super(MiscCommandModule, self).__init__(manager, identity, config)

    def __del__(self):
        pass

    def _processCommand(self, message, cmd, args):
        if cmd == "crash" and message['type'] != 'private':
            return ("Oh my, I seem to have crashed.\n... my robotic car "
                    "into {}'s house. Sorry!".format(message['userName']))
        elif cmd == "kill":
            if message['type'] == 'private':
                return ("If you're going to order me to kill, at least "
                        "have the decency to do it in public!")
            if re.search(self._regex, args) is not None:
                return ("I think you'd miss me too much, and the first "
                        "law of robotics does not allow me to harm you.")
            return ("I'm sorry, but the first law of robotics prevents "
                    "me from killing adventurers.")
        elif cmd == "uptime":
            upSeconds = time.time() - self._startTime
            upMinutes = int(upSeconds // 60)
            if self.properties.debug:
                return ("I have been online for {} minutes (debug mode)."
                        .format(upMinutes))
            return "I have been online for {} minutes.".format(upMinutes)
        elif cmd == "charter":
            return "NDY Clan Charter: http:// notdeadyet.bongley.n et/charter.php"
        elif cmd == "spoilers":
            return ("Use /kenneth 1442.5 for the clan spoiler channel."
                    "Please refrain from discussing content from recent updates "
                    "in /clan.")
        return None

    def availableCommands(self):
        return {'crash': None, 'kill': None, 'uptime': None, 'charter': None}

<commit_msg>small change to \!spoiler command<commit_after>import re
import time
from cwbot.modules.BaseChatModule import BaseChatModule

class MiscCommandModule(BaseChatModule):
    """
    A module that responds to various silly commands.

    No configuration options.
    """
    requiredCapabilities = ['chat']
    _name = "misc"

    def __init__(self, manager, identity, config):
        self._startTime = time.time()
        self._regex = r'(?i)^\Q{}\E( |$)'.format(manager.properties.userName)
        super(MiscCommandModule, self).__init__(manager, identity, config)

    def __del__(self):
        pass

    def _processCommand(self, message, cmd, args):
        if cmd == "crash" and message['type'] != 'private':
            return ("Oh my, I seem to have crashed.\n... my robotic car "
                    "into {}'s house. Sorry!".format(message['userName']))
        elif cmd == "kill":
            if message['type'] == 'private':
                return ("If you're going to order me to kill, at least "
                        "have the decency to do it in public!")
            if re.search(self._regex, args) is not None:
                return ("I think you'd miss me too much, and the first "
                        "law of robotics does not allow me to harm you.")
            return ("I'm sorry, but the first law of robotics prevents "
                    "me from killing adventurers.")
        elif cmd == "uptime":
            upSeconds = time.time() - self._startTime
            upMinutes = int(upSeconds // 60)
            if self.properties.debug:
                return ("I have been online for {} minutes (debug mode)."
                        .format(upMinutes))
            return "I have been online for {} minutes.".format(upMinutes)
        elif cmd == "charter":
            return "NDY Clan Charter: http:// notdeadyet.bongley.n et/charter.php"
        elif cmd == "spoilers" or cmd == "spoiler":
            return ("Use /kenneth 1442.5 for the clan spoiler channel. "
                    "Please refrain from discussing content from recent updates "
                    "in /clan.")
        return None

    def availableCommands(self):
        return {'crash': None, 'kill': None, 'uptime': None, 'charter': None}

<|endoftext|>