<commit_before>"""
Allows isometric viewing of a 3D data cube.

Click or click-drag in any data window to set the slice to view.
"""

# Outstanding TODOs:
#  - need to add line inspectors to side and bottom plots, and synchronize
#    with center plot
#  - need to set the various image plots to use the same colormap instance,
#    and that colormap's range needs to be set to min/max of the entire cube
#  - refactor create_window() so there is less code duplication
#  - try to eliminate the use of model.xs, ys, zs in favor of bounds tuples
from numpy import amin, amax, zeros, fromfile, transpose, uint8

# Standard library imports
import os, sys, shutil

# Major library imports
from numpy import arange, linspace, nanmin, nanmax, newaxis, pi, sin, cos

# Enthought library imports
from enthought.chaco.api import ArrayPlotData, Plot, GridPlotContainer, \
                                 BaseTool, DataRange1D
from enthought.chaco.default_colormaps import *
from enthought.chaco.tools.api import LineInspector, SimpleZoom
from enthought.enable.example_support import DemoFrame, demo_main
from enthought.enable.api import Window
from enthought.traits.api import Any, Array, Bool, Callable, CFloat, CInt, \
        Event, Float, HasTraits, Int, Trait, on_trait_change

# Will hold the path that the user chooses to download to. Will be an empty
# string if the user decides to download to the current directory.
dl_path = ''

# Determines if the script should ask the user if they would like to remove the
# downloaded data. Will remain True unless the download fails or the
# destination directory cannot be written to.
run_cleanup = True

class Model(HasTraits):
    npts_x = CInt(256)
    npts_y = CInt(256)
    npts_z = CInt(109)

    min_x = CFloat(-2*pi)
    max_x = CFloat(2*pi)
    min_y = CFloat(-2*pi)
    max_y = CFloat(2*pi)
    min_z = CFloat(-pi)
    max_z = CFloat(pi)

    xs = Array
    ys = Array
    vals = Array

    minval = Float
    maxval = Float

    model_changed = Event

    def __init__(self, *args, **kwargs):
        super(Model, self).__init__(*args, **kwargs)
        self.compute_model()

    @on_trait_change("npts_+", "min_+", "max_+")
    def compute_model(self):
        def vfunc(x, y, z):
            return sin(x*z) * cos(y)*sin(z) + sin(0.5*z)

        # Create the axes
        self.xs = linspace(self.min_x, self.max_x, self.npts_x)
        self.ys = linspace(self.min_y, self.max_y, self.npts_y)
        self.zs = linspace(self.min_z, self.max_z, self.npts_z)

        # Generate a cube of values by using newaxis to span new dimensions
        self.vals = vfunc(self.xs[:, newaxis, newaxis],
                          self.ys[newaxis, :, newaxis],
                          self.zs[newaxis, newaxis, :])

        self.minval = nanmin(self.vals)
        self.maxval = nanmax(self.vals)
        self.model_changed = True

class BrainModel(Model):
    def __init__(self, *args, **kwargs):
        download_data()
        super(BrainModel, self).__init__(*args, **kwargs)

    def compute_model(self):
        global dl_path
        mrbrain_path = os.path.join(dl_path, 'voldata', 'MRbrain.')
        nx = 256
        ny = 256
        nz = 109
        full_arr = zeros((nx, ny, nz), dtype='f')
        for i in range(1, 110):
            arr = fromfile(mrbrain_path + str(i), dtype='>u2')
            arr.shape = (256,256)
            full_arr[:,:,i-1] = arr
        self.vals = full_arr

        # Create the axes
        self.xs = arange(nx)
        self.ys = arange(ny)
        self.zs = arange(nz)

        # Generate a cube of values by using newaxis to span new dimensions
        self.minval = nanmin(self.vals)
        self.maxval = nanmax(self.vals)
        self.model_changed = True

class ImageIndexTool(BaseTool):
    """ A tool to set the slice of a cube based on the user's mouse movements
    or clicks.
    """

    # This callback will be called with the index into self.component's
    # index and value:
    #     callback(tool, x_index, y_index)
    # where *tool* is a reference to this tool instance.  The callback
    # can then use tool.token.
    callback = Any()

    # This callback (if it exists) will be called with the integer number
    # of mousewheel clicks
    wheel_cb = Any()

    # This token can be used by the callback to decide how to process
    # the event.
    token  = Any()

    # Whether or not to update the slice info; we enter select mode when
    # the left mouse button is pressed and exit it when the mouse button
    # is released
    # FIXME: This is not used right now.
    select_mode = Bool(False)

    def normal_left_down(self, event):
        self._update_slices(event)

    def normal_right_down(self, event):
        self._update_slices(event)

    def normal_mouse_move(self, event):
        if event.left_down or event.right_down:
            self._update_slices(event)

    def _update_slices(self, event):
            plot = self.component
            ndx = plot.map_index((event.x, event.y),
                                 threshold=5.0, index_only=True)
            if ndx:
                self.callback(self, *ndx)

    def normal_mouse_wheel(self, event):
        if self.wheel_cb is not None:
            self.wheel_cb(self, event.mouse_wheel)

class PlotFrame(DemoFrame):

    # These are the indices into the cube that each of the image plot views
    # will show; the default values are non-zero just to make it a little
    # interesting.
    slice_x = 10
    slice_y = 10
    slice_z = 10

    num_levels = Int(15)
    colormap = Any
    colorcube = Any

    #---------------------------------------------------------------------------
    # Private Traits
    #---------------------------------------------------------------------------

    _cmap = Trait(jet, Callable)

    def _index_callback(self, tool, x_index, y_index):
        plane = tool.token
        if plane == "xy":
            self.slice_x = x_index
            self.slice_y = y_index
        elif plane == "yz":
            # transposed because the plot is oriented vertically
            self.slice_z = x_index
            self.slice_y = y_index
        elif plane == "xz":
            self.slice_x = x_index
            self.slice_z = y_index
        else:
            warnings.warn("Unrecognized plane for _index_callback: %s" % plane)
        self._update_images()
        self.center.invalidate_and_redraw()
        self.right.invalidate_and_redraw()
        self.bottom.invalidate_and_redraw()
        return

    def _wheel_callback(self, tool, wheelamt):
        plane_slice_dict = {"xy": ("slice_z", 2),
                            "yz": ("slice_x", 0),
                            "xz": ("slice_y", 1)}
        attr, shape_ndx = plane_slice_dict[tool.token]
        val = getattr(self, attr)
        max = self.model.vals.shape[shape_ndx]
        if val + wheelamt > max:
            setattr(self, attr, max-1)
        elif val + wheelamt < 0:
            setattr(self, attr, 0)
        else:
            setattr(self, attr, val + wheelamt)

        self._update_images()
        self.center.invalidate_and_redraw()
        self.right.invalidate_and_redraw()
        self.bottom.invalidate_and_redraw()
        return

    def _create_window(self):
        # Create the model
        try:
            self.model = model = BrainModel()
            cmap = bone
        except SystemExit:
            sys.exit()
        except:
            self.model = model = Model()
            cmap = jet
        self._update_model(cmap)

        datacube = self.colorcube

        # Create the plot
        self.plotdata = ArrayPlotData()
        self._update_images()

        # Center Plot
        centerplot = Plot(self.plotdata, padding=0)
        imgplot = centerplot.img_plot("xy", xbounds=model.xs, ybounds=model.ys,
                            colormap=cmap)[0]
        self._add_plot_tools(imgplot, "xy")
        self.center = imgplot

        # Right Plot
        rightplot = Plot(self.plotdata, width=150, resizable="v", padding=0)
        rightplot.value_range = centerplot.value_range
        imgplot = rightplot.img_plot("yz", xbounds=model.zs, ybounds=model.ys,
                                     colormap=cmap)[0]
        self._add_plot_tools(imgplot, "yz")
        self.right = imgplot

        # Bottom Plot
        bottomplot = Plot(self.plotdata, height=150, resizable="h", padding=0)
        bottomplot.index_range = centerplot.index_range
        imgplot = bottomplot.img_plot("xz", xbounds=model.xs, ybounds=model.zs,
                                      colormap=cmap)[0]
        self._add_plot_tools(imgplot, "xz")
        self.bottom = imgplot

        # Create Container and add all Plots
        container = GridPlotContainer(padding=20, fill_padding=True,
                                      bgcolor="white", use_backbuffer=True,
                                      shape=(2,2), spacing=(12,12))
        container.add(centerplot)
        container.add(rightplot)
        container.add(bottomplot)

        self.container = container
        return Window(self, -1, component=container)

    def _add_plot_tools(self, imgplot, token):
        """ Add LineInspectors, ImageIndexTool, and SimpleZoom to the image plots. """

        imgplot.overlays.append(SimpleZoom(component=imgplot, tool_mode="box",
                                           enable_wheel=False, always_on=False))
        imgplot.overlays.append(LineInspector(imgplot, axis="index_y", color="white",
            inspect_mode="indexed", write_metadata=True, is_listener=True))
        imgplot.overlays.append(LineInspector(imgplot, axis="index_x", color="white",
            inspect_mode="indexed", write_metadata=True, is_listener=True))
        imgplot.tools.append(ImageIndexTool(imgplot, token=token,
            callback=self._index_callback, wheel_cb=self._wheel_callback))

    def _update_model(self, cmap):
        range = DataRange1D(low=amin(self.model.vals),
                            high=amax(self.model.vals))
        self.colormap = cmap(range)
        self.colorcube = (self.colormap.map_screen(self.model.vals) * 255).astype(uint8)

    def _update_images(self):
        """ Updates the image data in self.plotdata to correspond to the
        slices given.
        """
        cube = self.colorcube
        pd = self.plotdata
        # These are transposed because img_plot() expects its data to be in
        # row-major order
        pd.set_data("xy", transpose(cube[:, :, self.slice_z], (1,0,2)))
        pd.set_data("xz", transpose(cube[:, self.slice_y, :], (1,0,2)))
        pd.set_data("yz", cube[self.slice_x, :, :])

def download_data():
    global dl_path, run_cleanup

    print 'Please enter a path to download data to (7.8MB).'
    print 'Press <ENTER> to download to the current directory.'
    dl_path = raw_input('Path: ').strip()

    if len(dl_path) > 0 and not os.path.exists(dl_path):
        print 'The given path does not exist.'
        run_cleanup = False
        sys.exit()

    if not os.path.isabs(dl_path):
        print 'Downloading to: ' + os.path.join(os.getcwd(), dl_path)
    else:
        print 'Downloading to: ' + dl_path

    voldata_path = os.path.join(dl_path, 'voldata')
    tar_path = os.path.join(dl_path, 'MRbrain.tar.gz')

    data_good = True
    try:
        data_good = len(os.listdir(voldata_path)) == 109
    except:
        data_good = False

    if not data_good:
        import urllib
        import tarfile

        try:
            # download and extract the file
            print "Downloading data, Please Wait (7.8MB)"
            opener = urllib.urlopen('http://www-graphics.stanford.edu/data/voldata/MRbrain.tar.gz')
        except:
            print 'Download error. Opening backup data.'
            run_cleanup = False
            raise

        try:
            open(tar_path, 'wb').write(opener.read())
        except:
            print 'Cannot write to the destination directory specified. ' \
                  'Opening backup data.'
            run_cleanup = False
            raise

        tar_file = tarfile.open(tar_path)
        try:
            os.mkdir(voldata_path)
        except:
            pass
        tar_file.extractall(voldata_path)
        tar_file.close()
        os.unlink(tar_path)
    else:
        print 'Previously downloaded data detected.'

def cleanup_data():
    global dl_path

    answer = raw_input('Remove downloaded files? [Y/N]: ')
    if answer.lower() == 'y':
        try:
            shutil.rmtree(os.path.join(dl_path, 'voldata'))
        except:
            pass

if __name__ == "__main__":
    demo_main(PlotFrame, size=(800,700), title="Cube analyzer")
    if run_cleanup:
        cleanup_data()

<commit_msg>improving handling of how the data_cube.py example looks for previously downloaded data<commit_after>"""
Allows isometric viewing of a 3D data cube.

Click or click-drag in any data window to set the slice to view.
"""

# Outstanding TODOs:
#  - need to add line inspectors to side and bottom plots, and synchronize
#    with center plot
#  - need to set the various image plots to use the same colormap instance,
#    and that colormap's range needs to be set to min/max of the entire cube
#  - refactor create_window() so there is less code duplication
#  - try to eliminate the use of model.xs, ys, zs in favor of bounds tuples
from numpy import amin, amax, zeros, fromfile, transpose, uint8

# Standard library imports
import os, sys, shutil

# Major library imports
from numpy import arange, linspace, nanmin, nanmax, newaxis, pi, sin, cos

# Enthought library imports
from enthought.chaco.api import ArrayPlotData, Plot, GridPlotContainer, \
                                 BaseTool, DataRange1D
from enthought.chaco.default_colormaps import *
from enthought.chaco.tools.api import LineInspector, SimpleZoom
from enthought.enable.example_support import DemoFrame, demo_main
from enthought.enable.api import Window
from enthought.traits.api import Any, Array, Bool, Callable, CFloat, CInt, \
        Event, Float, HasTraits, Int, Trait, on_trait_change

# Will hold the path that the user chooses to download to. Will be an empty
# string if the user decides to download to the current directory.
dl_path = ''

# Determines if the script should ask the user if they would like to remove the
# downloaded data.  This defaults to False, because data deletion is
# irreversible, and in the worst case, the user will have to remove it
# manually themselves.
run_cleanup = False

class Model(HasTraits):
    npts_x = CInt(256)
    npts_y = CInt(256)
    npts_z = CInt(109)

    min_x = CFloat(-2*pi)
    max_x = CFloat(2*pi)
    min_y = CFloat(-2*pi)
    max_y = CFloat(2*pi)
    min_z = CFloat(-pi)
    max_z = CFloat(pi)

    xs = Array
    ys = Array
    vals = Array

    minval = Float
    maxval = Float

    model_changed = Event

    def __init__(self, *args, **kwargs):
        super(Model, self).__init__(*args, **kwargs)
        self.compute_model()

    @on_trait_change("npts_+", "min_+", "max_+")
    def compute_model(self):
        def vfunc(x, y, z):
            return sin(x*z) * cos(y)*sin(z) + sin(0.5*z)

        # Create the axes
        self.xs = linspace(self.min_x, self.max_x, self.npts_x)
        self.ys = linspace(self.min_y, self.max_y, self.npts_y)
        self.zs = linspace(self.min_z, self.max_z, self.npts_z)

        # Generate a cube of values by using newaxis to span new dimensions
        self.vals = vfunc(self.xs[:, newaxis, newaxis],
                          self.ys[newaxis, :, newaxis],
                          self.zs[newaxis, newaxis, :])

        self.minval = nanmin(self.vals)
        self.maxval = nanmax(self.vals)
        self.model_changed = True

class BrainModel(Model):
    def __init__(self, *args, **kwargs):
        download_data()
        super(BrainModel, self).__init__(*args, **kwargs)

    def compute_model(self):
        global dl_path
        mrbrain_path = os.path.join(dl_path, 'voldata', 'MRbrain.')
        nx = 256
        ny = 256
        nz = 109
        full_arr = zeros((nx, ny, nz), dtype='f')
        for i in range(1, 110):
            arr = fromfile(mrbrain_path + str(i), dtype='>u2')
            arr.shape = (256,256)
            full_arr[:,:,i-1] = arr
        self.vals = full_arr

        # Create the axes
        self.xs = arange(nx)
        self.ys = arange(ny)
        self.zs = arange(nz)

        # Generate a cube of values by using newaxis to span new dimensions
        self.minval = nanmin(self.vals)
        self.maxval = nanmax(self.vals)
        self.model_changed = True

class ImageIndexTool(BaseTool):
    """ A tool to set the slice of a cube based on the user's mouse movements
    or clicks.
    """

    # This callback will be called with the index into self.component's
    # index and value:
    #     callback(tool, x_index, y_index)
    # where *tool* is a reference to this tool instance.  The callback
    # can then use tool.token.
    callback = Any()

    # This callback (if it exists) will be called with the integer number
    # of mousewheel clicks
    wheel_cb = Any()

    # This token can be used by the callback to decide how to process
    # the event.
    token  = Any()

    # Whether or not to update the slice info; we enter select mode when
    # the left mouse button is pressed and exit it when the mouse button
    # is released
    # FIXME: This is not used right now.
    select_mode = Bool(False)

    def normal_left_down(self, event):
        self._update_slices(event)

    def normal_right_down(self, event):
        self._update_slices(event)

    def normal_mouse_move(self, event):
        if event.left_down or event.right_down:
            self._update_slices(event)

    def _update_slices(self, event):
            plot = self.component
            ndx = plot.map_index((event.x, event.y),
                                 threshold=5.0, index_only=True)
            if ndx:
                self.callback(self, *ndx)

    def normal_mouse_wheel(self, event):
        if self.wheel_cb is not None:
            self.wheel_cb(self, event.mouse_wheel)

class PlotFrame(DemoFrame):

    # These are the indices into the cube that each of the image plot views
    # will show; the default values are non-zero just to make it a little
    # interesting.
    slice_x = 10
    slice_y = 10
    slice_z = 10

    num_levels = Int(15)
    colormap = Any
    colorcube = Any

    #---------------------------------------------------------------------------
    # Private Traits
    #---------------------------------------------------------------------------

    _cmap = Trait(jet, Callable)

    def _index_callback(self, tool, x_index, y_index):
        plane = tool.token
        if plane == "xy":
            self.slice_x = x_index
            self.slice_y = y_index
        elif plane == "yz":
            # transposed because the plot is oriented vertically
            self.slice_z = x_index
            self.slice_y = y_index
        elif plane == "xz":
            self.slice_x = x_index
            self.slice_z = y_index
        else:
            warnings.warn("Unrecognized plane for _index_callback: %s" % plane)
        self._update_images()
        self.center.invalidate_and_redraw()
        self.right.invalidate_and_redraw()
        self.bottom.invalidate_and_redraw()
        return

    def _wheel_callback(self, tool, wheelamt):
        plane_slice_dict = {"xy": ("slice_z", 2),
                            "yz": ("slice_x", 0),
                            "xz": ("slice_y", 1)}
        attr, shape_ndx = plane_slice_dict[tool.token]
        val = getattr(self, attr)
        max = self.model.vals.shape[shape_ndx]
        if val + wheelamt > max:
            setattr(self, attr, max-1)
        elif val + wheelamt < 0:
            setattr(self, attr, 0)
        else:
            setattr(self, attr, val + wheelamt)

        self._update_images()
        self.center.invalidate_and_redraw()
        self.right.invalidate_and_redraw()
        self.bottom.invalidate_and_redraw()
        return

    def _create_window(self):
        # Create the model
        try:
            self.model = model = BrainModel()
            cmap = bone
        except SystemExit:
            sys.exit()
        except:
            print "Unable to load BrainModel, using generated data cube."
            self.model = model = Model()
            cmap = jet
        self._update_model(cmap)

        datacube = self.colorcube

        # Create the plot
        self.plotdata = ArrayPlotData()
        self._update_images()

        # Center Plot
        centerplot = Plot(self.plotdata, padding=0)
        imgplot = centerplot.img_plot("xy", xbounds=model.xs, ybounds=model.ys,
                            colormap=cmap)[0]
        self._add_plot_tools(imgplot, "xy")
        self.center = imgplot

        # Right Plot
        rightplot = Plot(self.plotdata, width=150, resizable="v", padding=0)
        rightplot.value_range = centerplot.value_range
        imgplot = rightplot.img_plot("yz", xbounds=model.zs, ybounds=model.ys,
                                     colormap=cmap)[0]
        self._add_plot_tools(imgplot, "yz")
        self.right = imgplot

        # Bottom Plot
        bottomplot = Plot(self.plotdata, height=150, resizable="h", padding=0)
        bottomplot.index_range = centerplot.index_range
        imgplot = bottomplot.img_plot("xz", xbounds=model.xs, ybounds=model.zs,
                                      colormap=cmap)[0]
        self._add_plot_tools(imgplot, "xz")
        self.bottom = imgplot

        # Create Container and add all Plots
        container = GridPlotContainer(padding=20, fill_padding=True,
                                      bgcolor="white", use_backbuffer=True,
                                      shape=(2,2), spacing=(12,12))
        container.add(centerplot)
        container.add(rightplot)
        container.add(bottomplot)

        self.container = container
        return Window(self, -1, component=container)

    def _add_plot_tools(self, imgplot, token):
        """ Add LineInspectors, ImageIndexTool, and SimpleZoom to the image plots. """

        imgplot.overlays.append(SimpleZoom(component=imgplot, tool_mode="box",
                                           enable_wheel=False, always_on=False))
        imgplot.overlays.append(LineInspector(imgplot, axis="index_y", color="white",
            inspect_mode="indexed", write_metadata=True, is_listener=True))
        imgplot.overlays.append(LineInspector(imgplot, axis="index_x", color="white",
            inspect_mode="indexed", write_metadata=True, is_listener=True))
        imgplot.tools.append(ImageIndexTool(imgplot, token=token,
            callback=self._index_callback, wheel_cb=self._wheel_callback))

    def _update_model(self, cmap):
        range = DataRange1D(low=amin(self.model.vals),
                            high=amax(self.model.vals))
        self.colormap = cmap(range)
        self.colorcube = (self.colormap.map_screen(self.model.vals) * 255).astype(uint8)

    def _update_images(self):
        """ Updates the image data in self.plotdata to correspond to the
        slices given.
        """
        cube = self.colorcube
        pd = self.plotdata
        # These are transposed because img_plot() expects its data to be in
        # row-major order
        pd.set_data("xy", transpose(cube[:, :, self.slice_z], (1,0,2)))
        pd.set_data("xz", transpose(cube[:, self.slice_y, :], (1,0,2)))
        pd.set_data("yz", cube[self.slice_x, :, :])

def download_data():
    global dl_path, run_cleanup

    print 'Please enter the location of the "voldata" subdirectory containing'
    print 'the data files for this demo, or enter a path to download to (7.8MB).'
    print 'Press <ENTER> to download to the current directory.'
    dl_path = raw_input('Path: ').strip().rstrip("/").rstrip("\\")

    if not dl_path.endswith("voldata"):
        voldata_path = os.path.join(dl_path, 'voldata')
    else:
        voldata_path = dl_path
    tar_path = os.path.join(dl_path, 'MRbrain.tar.gz')

    data_good = True
    try:
        for i in range(1,110):
            if not os.path.isfile(os.path.join(voldata_path, "MRbrain.%d" % i)):
                data_good = False
                break
        else:
            data_good = True
    except:
        data_good = False

    if not data_good:
        import urllib
        import tarfile

        if len(dl_path) > 0 and not os.path.exists(dl_path):
            print 'The given path does not exist.'
            run_cleanup = False
            sys.exit()

        if not os.path.isabs(dl_path):
            print 'Downloading to: ' + os.path.join(os.getcwd(), dl_path)
        else:
            print 'Downloading to: ' + dl_path

        try:
            # download and extract the file
            print "Downloading data, Please Wait (7.8MB)"
            opener = urllib.urlopen('http://www-graphics.stanford.edu/data/voldata/MRbrain.tar.gz')
        except:
            print 'Download error. Opening backup data.'
            run_cleanup = False
            raise

        try:
            open(tar_path, 'wb').write(opener.read())
        except:
            print 'Cannot write to the destination directory specified. ' \
                  'Opening backup data.'
            run_cleanup = False
            raise

        tar_file = tarfile.open(tar_path)
        try:
            os.mkdir(voldata_path)
        except:
            pass
        tar_file.extractall(voldata_path)
        tar_file.close()
        os.unlink(tar_path)
    else:
        print 'Previously downloaded data detected.'

def cleanup_data():
    global dl_path

    answer = raw_input('Remove downloaded files? [Y/N]: ')
    if answer.lower() == 'y':
        try:
            shutil.rmtree(os.path.join(dl_path, 'voldata'))
        except:
            pass

if __name__ == "__main__":
    demo_main(PlotFrame, size=(800,700), title="Cube analyzer")
    if run_cleanup:
        cleanup_data()

<|endoftext|>


<commit_before># Tai Sakuma <tai.sakuma@cern.ch>
import argparse
import sys
import os, errno
import itertools

from HeppyResult.HeppyResultReader import HeppyResultReader
from HeppyResult.HeppyResult import HeppyResult
from EventReader.EventReaderBundle import EventReaderBundle
from EventReader.EventReaderPackage import EventReaderPackage
from EventReader.EventLoopRunner import EventLoopRunner
from EventReader.MPEventLoopRunner import MPEventLoopRunner
from ProgressBar.ProgressBar import ProgressBar
from ProgressBar.ProgressMonitor import ProgressMonitor, MPProgressMonitor
from Counter.Counts import Counts
from Counter.GenericKeyComposer import GenericKeyComposer
from Counter.GenericKeyComposerB import GenericKeyComposerBFactory
from Counter.CounterFactory import CounterFactory
from CombineIntoList import CombineIntoList
from WriteListToFile import WriteListToFile
from EventReader.Collector import Collector

try:
    from HeppyResult.BEventBuilder import BEventBuilder as EventBuilder
except ImportError:
    pass

##____________________________________________________________________________||
def mkdir_p(path):
    # http://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python
    try:
        os.makedirs(path)
    except OSError as exc: # Python >2.5
        if exc.errno == errno.EEXIST and os.path.isdir(path):
            pass
        else: raise

##____________________________________________________________________________||
class ArgumentParser(argparse.ArgumentParser):

    def __init__(self, owner, *args, **kwargs):
        super(ArgumentParser, self).__init__(*args, **kwargs)
        self.owner = owner

    def parse_args(self, *args, **kwargs):
        args = super(ArgumentParser, self).parse_args(*args, **kwargs)
        self.owner.args = args
        return args

##____________________________________________________________________________||
defaultCountsClass = Counts

##____________________________________________________________________________||
def completeTableConfig(tblcfg, outDir):
    if 'outColumnNames' not in tblcfg: tblcfg['outColumnNames'] = tblcfg['branchNames']
    if 'indices' not in tblcfg: tblcfg['indices'] = None
    if 'outFileName' not in tblcfg: tblcfg['outFileName'] = createOutFileName(tblcfg['outColumnNames'], tblcfg['indices'])
    if 'countsClass' not in tblcfg: tblcfg['countsClass'] = defaultCountsClass
    if 'outFilePath' not in tblcfg: tblcfg['outFilePath'] = os.path.join(outDir, tblcfg['outFileName'])
    return tblcfg

##____________________________________________________________________________||
def createOutFileName(columnNames, indices, prefix = 'tbl_component_', suffix = '.txt'):
    # for example, if columnNames = ('var1', 'var2', 'var3') and indices = (1, None, 2),
    # l will be ['var1', '1', 'var2', 'var3', '2']
    l = columnNames if indices is None else [str(e) for sublist in zip(columnNames, indices) for e in sublist if e is not None]
    ret = prefix + '_'.join(l) + suffix # e.g. "tbl_component_var1_1_var2_var3_2.txt"
    return ret

##____________________________________________________________________________||
def createPackageFor(tblcfg):
    keyComposerFactory = GenericKeyComposerBFactory(tblcfg['branchNames'], tblcfg['binnings'], tblcfg['indices'])
    counterFactory = CounterFactory(
        countMethodClass = tblcfg['countsClass'],
        keyComposerFactory = keyComposerFactory,
        binnings = tblcfg['binnings']
    )
    resultsCombinationMethod = CombineIntoList(keyNames = tblcfg['outColumnNames'])
    deliveryMethod = WriteListToFile(tblcfg['outFilePath'])
    collector = Collector(resultsCombinationMethod, deliveryMethod)
    return EventReaderPackage(counterFactory, collector)

##____________________________________________________________________________||
def buildEventLoopRunner(progressBar, processes, quiet):
    if processes is None:
        progressMonitor = None if quiet else ProgressMonitor(presentation = progressBar)
        eventLoopRunner = EventLoopRunner(progressMonitor)
    else:
        progressMonitor = None if quiet else MPProgressMonitor(presentation = progressBar)
        eventLoopRunner = MPEventLoopRunner(processes, progressMonitor)
    return eventLoopRunner

##____________________________________________________________________________||
def createEventReaderBundle(eventBuilder, eventSelection, eventReaderPackages, processes, quiet):
    progressBar = None if quiet else ProgressBar()
    eventLoopRunner = buildEventLoopRunner(progressBar = progressBar, processes = processes, quiet = quiet)
    eventReaderBundle = EventReaderBundle(eventBuilder, eventLoopRunner, eventSelection = eventSelection, progressBar = progressBar)
    for package in eventReaderPackages:
        eventReaderBundle.addReaderPackage(package)
    return eventReaderBundle

##____________________________________________________________________________||
def createTreeReader(args, analyzerName, fileName, treeName, tableConfigs, eventSelection):
    tableConfigs = [completeTableConfig(c, args.outDir) for c in tableConfigs]
    if not args.force: tableConfigs = [c for c in tableConfigs if not os.path.exists(c['outFilePath'])]
    eventReaderPackages = [createPackageFor(c) for c in tableConfigs]
    eventBuilder = EventBuilder(analyzerName, fileName, treeName, args.nevents)
    eventReaderBundle = createEventReaderBundle(eventBuilder, eventSelection, eventReaderPackages, args.processes, args.quiet)
    return eventReaderBundle

##____________________________________________________________________________||
class AlphaTwirl(object):

    def __init__(self):
        self.args = None
        self.componentReaders = [ ]

    def ArgumentParser(self, *args, **kwargs):
        parser = ArgumentParser(self, *args, **kwargs)
        parser = self._add_arguments(parser)
        return parser

    def _add_arguments(self, parser):
        parser.add_argument('-i', '--heppydir', default = '/Users/sakuma/work/cms/c150130_RA1_data/PHYS14/20150507_SingleMu', action = 'store', help = "Heppy results dir")
        parser.add_argument("-p", "--processes", action = "store", default = None, type = int, help = "number of processes to run in parallel")
        parser.add_argument("-q", "--quiet", action = "store_true", default = False, help = "quiet mode")
        parser.add_argument('-o', '--outDir', default = 'tbl/out', action = 'store')
        parser.add_argument("-n", "--nevents", action = "store", default = -1, type = int, help = "maximum number of events to process for each component")
        parser.add_argument("--force", action = "store_true", default = False, dest="force", help = "recreate all output files")
        return parser

    def addComponentReader(self, reader):
        self.componentReaders.append(reader)

    def addTreeReader(self, **kargs):
        if self.args is None: self.ArgumentParser().parse_args()
        treeReader = createTreeReader(self.args, **kargs)
        self.addComponentReader(treeReader)

    def run(self):
        if self.args is None: self.ArgumentParser().parse_args()
        mkdir_p(self.args.outDir)
        heppyResultReader = self._buildHeppyResultReader()
        heppyResult = HeppyResult(self.args.heppydir)
        heppyResultReader.read(heppyResult)

    def _buildHeppyResultReader(self):
        heppyResultReader = HeppyResultReader()
        while len(self.componentReaders) > 0: heppyResultReader.addReader(self.componentReaders.pop(0))
        return heppyResultReader

##____________________________________________________________________________||
<commit_msg>replace HeppyResultReader with ComponentReaderBundle and ComponentLoop in AlphaTwirl.py<commit_after># Tai Sakuma <tai.sakuma@cern.ch>
import argparse
import sys
import os, errno
import itertools

from HeppyResult.ComponentReaderBundle import ComponentReaderBundle
from HeppyResult.ComponentLoop import ComponentLoop
from HeppyResult.HeppyResult import HeppyResult
from EventReader.EventReaderBundle import EventReaderBundle
from EventReader.EventReaderPackage import EventReaderPackage
from EventReader.EventLoopRunner import EventLoopRunner
from EventReader.MPEventLoopRunner import MPEventLoopRunner
from ProgressBar.ProgressBar import ProgressBar
from ProgressBar.ProgressMonitor import ProgressMonitor, MPProgressMonitor
from Counter.Counts import Counts
from Counter.GenericKeyComposer import GenericKeyComposer
from Counter.GenericKeyComposerB import GenericKeyComposerBFactory
from Counter.CounterFactory import CounterFactory
from CombineIntoList import CombineIntoList
from WriteListToFile import WriteListToFile
from EventReader.Collector import Collector

try:
    from HeppyResult.BEventBuilder import BEventBuilder as EventBuilder
except ImportError:
    pass

##____________________________________________________________________________||
def mkdir_p(path):
    # http://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python
    try:
        os.makedirs(path)
    except OSError as exc: # Python >2.5
        if exc.errno == errno.EEXIST and os.path.isdir(path):
            pass
        else: raise

##____________________________________________________________________________||
class ArgumentParser(argparse.ArgumentParser):

    def __init__(self, owner, *args, **kwargs):
        super(ArgumentParser, self).__init__(*args, **kwargs)
        self.owner = owner

    def parse_args(self, *args, **kwargs):
        args = super(ArgumentParser, self).parse_args(*args, **kwargs)
        self.owner.args = args
        return args

##____________________________________________________________________________||
defaultCountsClass = Counts

##____________________________________________________________________________||
def completeTableConfig(tblcfg, outDir):
    if 'outColumnNames' not in tblcfg: tblcfg['outColumnNames'] = tblcfg['branchNames']
    if 'indices' not in tblcfg: tblcfg['indices'] = None
    if 'outFileName' not in tblcfg: tblcfg['outFileName'] = createOutFileName(tblcfg['outColumnNames'], tblcfg['indices'])
    if 'countsClass' not in tblcfg: tblcfg['countsClass'] = defaultCountsClass
    if 'outFilePath' not in tblcfg: tblcfg['outFilePath'] = os.path.join(outDir, tblcfg['outFileName'])
    return tblcfg

##____________________________________________________________________________||
def createOutFileName(columnNames, indices, prefix = 'tbl_component_', suffix = '.txt'):
    # for example, if columnNames = ('var1', 'var2', 'var3') and indices = (1, None, 2),
    # l will be ['var1', '1', 'var2', 'var3', '2']
    l = columnNames if indices is None else [str(e) for sublist in zip(columnNames, indices) for e in sublist if e is not None]
    ret = prefix + '_'.join(l) + suffix # e.g. "tbl_component_var1_1_var2_var3_2.txt"
    return ret

##____________________________________________________________________________||
def createPackageFor(tblcfg):
    keyComposerFactory = GenericKeyComposerBFactory(tblcfg['branchNames'], tblcfg['binnings'], tblcfg['indices'])
    counterFactory = CounterFactory(
        countMethodClass = tblcfg['countsClass'],
        keyComposerFactory = keyComposerFactory,
        binnings = tblcfg['binnings']
    )
    resultsCombinationMethod = CombineIntoList(keyNames = tblcfg['outColumnNames'])
    deliveryMethod = WriteListToFile(tblcfg['outFilePath'])
    collector = Collector(resultsCombinationMethod, deliveryMethod)
    return EventReaderPackage(counterFactory, collector)

##____________________________________________________________________________||
def buildEventLoopRunner(progressBar, processes, quiet):
    if processes is None:
        progressMonitor = None if quiet else ProgressMonitor(presentation = progressBar)
        eventLoopRunner = EventLoopRunner(progressMonitor)
    else:
        progressMonitor = None if quiet else MPProgressMonitor(presentation = progressBar)
        eventLoopRunner = MPEventLoopRunner(processes, progressMonitor)
    return eventLoopRunner

##____________________________________________________________________________||
def createEventReaderBundle(eventBuilder, eventSelection, eventReaderPackages, processes, quiet):
    progressBar = None if quiet else ProgressBar()
    eventLoopRunner = buildEventLoopRunner(progressBar = progressBar, processes = processes, quiet = quiet)
    eventReaderBundle = EventReaderBundle(eventBuilder, eventLoopRunner, eventSelection = eventSelection, progressBar = progressBar)
    for package in eventReaderPackages:
        eventReaderBundle.addReaderPackage(package)
    return eventReaderBundle

##____________________________________________________________________________||
def createTreeReader(args, analyzerName, fileName, treeName, tableConfigs, eventSelection):
    tableConfigs = [completeTableConfig(c, args.outDir) for c in tableConfigs]
    if not args.force: tableConfigs = [c for c in tableConfigs if not os.path.exists(c['outFilePath'])]
    eventReaderPackages = [createPackageFor(c) for c in tableConfigs]
    eventBuilder = EventBuilder(analyzerName, fileName, treeName, args.nevents)
    eventReaderBundle = createEventReaderBundle(eventBuilder, eventSelection, eventReaderPackages, args.processes, args.quiet)
    return eventReaderBundle

##____________________________________________________________________________||
class AlphaTwirl(object):

    def __init__(self):
        self.args = None
        self.componentReaders = [ ]

    def ArgumentParser(self, *args, **kwargs):
        parser = ArgumentParser(self, *args, **kwargs)
        parser = self._add_arguments(parser)
        return parser

    def _add_arguments(self, parser):
        parser.add_argument('-i', '--heppydir', default = '/Users/sakuma/work/cms/c150130_RA1_data/PHYS14/20150507_SingleMu', action = 'store', help = "Heppy results dir")
        parser.add_argument("-p", "--processes", action = "store", default = None, type = int, help = "number of processes to run in parallel")
        parser.add_argument("-q", "--quiet", action = "store_true", default = False, help = "quiet mode")
        parser.add_argument('-o', '--outDir', default = 'tbl/out', action = 'store')
        parser.add_argument("-n", "--nevents", action = "store", default = -1, type = int, help = "maximum number of events to process for each component")
        parser.add_argument("--force", action = "store_true", default = False, dest="force", help = "recreate all output files")
        return parser

    def addComponentReader(self, reader):
        self.componentReaders.append(reader)

    def addTreeReader(self, **kargs):
        if self.args is None: self.ArgumentParser().parse_args()
        treeReader = createTreeReader(self.args, **kargs)
        self.addComponentReader(treeReader)

    def run(self):
        if self.args is None: self.ArgumentParser().parse_args()
        mkdir_p(self.args.outDir)
        componentReaderBundle = self._buildComponentReaderBundle()
        componentLoop = ComponentLoop(componentReaderBundle)
        heppyResult = HeppyResult(self.args.heppydir)
        componentLoop(heppyResult.components())

    def _buildComponentReaderBundle(self):
        componentReaderBundle = ComponentReaderBundle()
        while len(self.componentReaders) > 0: componentReaderBundle.addReader(self.componentReaders.pop(0))
        return componentReaderBundle

##____________________________________________________________________________||
<|endoftext|>


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

# Copyright(C) 2013 Bezleputh
#
# This file is part of weboob.
#
# weboob 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.
#
# weboob 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 weboob. If not, see <http://www.gnu.org/licenses/>.

import re
import sys
from datetime import date, timedelta, time, datetime

from weboob.tools.application.formatters.iformatter import IFormatter, PrettyFormatter
from weboob.capabilities.base import empty
from weboob.capabilities.calendar import ICapCalendarEvent
from weboob.tools.application.repl import ReplApplication, defaultcount

__all__ = ['Boobcoming']

class ICalFormatter(IFormatter):
    MANDATORY_FIELDS = ('id', 'start_date', 'end_date', 'summary')

    def start_format(self, **kwargs):
        self.output(u'BEGIN:VCALENDAR')
        self.output(u'VERSION:2.0')
        self.output(u'PRODID:-//hacksw/handcal//NONSGML v1.0//EN')

    def format_obj(self, obj, alias):
        result = u'BEGIN:VEVENT\n'
        result += u'DTSTART:%s\n' % obj.start_date.strftime("%Y%m%dT%H%M%SZ")
        result += u'DTEND:%s\n' % obj.end_date.strftime("%Y%m%dT%H%M%SZ")
        result += u'SUMMARY:%s\n' % obj.summary
        if hasattr(obj, 'location') and not empty(obj.location):
            result += u'LOCATION:%s\n' % obj.location

        if hasattr(obj, 'categories') and not empty(obj.categories):
            result += u'CATEGORIES:%s\n' % obj.categories

        if hasattr(obj, 'status') and not empty(obj.status):
            result += u'STATUS:%s\n' % obj.status

        if hasattr(obj, 'description') and not empty(obj.description):
            result += u'DESCRIPTION:%s\n' % obj.description.replace('\r\n', '\\n')

        if hasattr(obj, 'transp') and not empty(obj.transp):
            result += u'TRANSP:%s\n' % obj.transp

        if hasattr(obj, 'sequence') and not empty(obj.sequence):
            result += u'SEQUENCE:%s\n' % obj.sequence

        if hasattr(obj, 'url') and not empty(obj.url):
            result += u'URL:%s\n' % obj.url

        result += u'END:VEVENT'
        return result

    def flush(self, **kwargs):
        self.output(u'END:VCALENDAR')

class UpcomingListFormatter(PrettyFormatter):
    MANDATORY_FIELDS = ('id', 'start_date', 'end_date', 'summary', 'category')

    def get_title(self, obj):
        return ' %s - %s ' % (obj.category, obj.summary)

    def get_description(self, obj):
        result = u''
        result += u'\tDate: %s\n' % obj.start_date.strftime('%A %d %B %Y')
        result += u'\tHour: %s - %s \n' % (obj.start_date.strftime('%H:%M'), obj.end_date.strftime('%H:%M'))
        return result.strip('\n\t')

class UpcomingFormatter(IFormatter):
    MANDATORY_FIELDS = ('id', 'start_date', 'end_date', 'summary', 'category')

    def format_obj(self, obj, alias):
        result = u'%s%s - %s%s\n' % (self.BOLD, obj.category, obj.summary, self.NC)
        result += u'Date: %s\n' % obj.start_date.strftime('%A %d %B %Y')
        result += u'Hour: %s - %s\n' % (obj.start_date.strftime('%H:%M'), obj.end_date.strftime('%H:%M'))

        if hasattr(obj, 'location') and not empty(obj.location):
            result += u'Location: %s\n' % obj.location

        if hasattr(obj, 'description') and not empty(obj.description):
            result += u'Description:\n %s\n\n' % obj.description

        if hasattr(obj, 'price') and not empty(obj.price):
            result += u'Price: %s\n' % obj.price

        if hasattr(obj, 'url') and not empty(obj.url):
            result += u'url: %s\n' % obj.url

        return result

class Boobcoming(ReplApplication):
    APPNAME = 'boobcoming'
    VERSION = '0.h'
    COPYRIGHT = 'Copyright(C) 2012 Bezleputh'
    DESCRIPTION = "Console application to see upcoming events."
    SHORT_DESCRIPTION = "see upcoming events"
    CAPS = ICapCalendarEvent
    EXTRA_FORMATTERS = {'upcoming_list': UpcomingListFormatter,
                        'upcoming': UpcomingFormatter,
                        #'ical_formatter': ICalFormatter,
                        }
    COMMANDS_FORMATTERS = {'list': 'upcoming_list',
                           'info': 'upcoming',
                           #'export': 'ical_formatter',
                           }

    WEEK   = {'MONDAY': 0,
              'TUESDAY': 1,
              'WEDNESDAY': 2,
              'THURSDAY': 3,
              'FRIDAY': 4,
              'SATURDAY': 5,
              'SUNDAY': 6,
              'LUNDI': 0,
              'MARDI': 1,
              'MERCREDI': 2,
              'JEUDI': 3,
              'VENDREDI': 4,
              'SAMEDI': 5,
              'DIMANCHE': 6,
              }

    @defaultcount(10)
    def do_list(self, line):
        """
        list [PATTERN]
        List upcoming events, pattern can be an english or french  week day, 'today' or a date
        """

        self.change_path([u'events'])
        if line:
            _date = self.parse_date(line)
            if not _date:
                print >>sys.stderr, 'Invalid argument: %s' % self.get_command_help('list', short=True)
                return 2

            date_from = datetime.combine(_date, time.min)
            date_to = datetime.combine(_date, time.max)
        else:
            date_from = datetime.now()
            date_to = None

        for backend, event in self.do('list_events', date_from, date_to):
            self.cached_format(event)

    def complete_info(self, text, line, *ignored):
        args = line.split(' ')
        if len(args) == 2:
            return self._complete_object()

    def do_info(self, _id):
        """
        info ID

        Get information about an event.
        """

        if not _id:
            print >>sys.stderr, 'This command takes an argument: %s' % self.get_command_help('info', short=True)
            return 2

        event = self.get_object(_id, 'get_event')

        if not event:
            print >>sys.stderr, 'Upcoming event not found: %s' % _id
            return 3

        self.start_format()
        self.format(event)

    def start_format(self, **kwargs):
        result = u'BEGIN:VCALENDAR\n'
        result += u'VERSION:2.0\n'
        result += u'PRODID:-//hacksw/handcal//NONSGML v1.0//EN\n'
        return result

    def format_event(self, obj):
        result = u'BEGIN:VEVENT\n'
        result += u'DTSTART:%s\n' % obj.start_date.strftime("%Y%m%dT%H%M%SZ")
        result += u'DTEND:%s\n' % obj.end_date.strftime("%Y%m%dT%H%M%SZ")
        result += u'SUMMARY:%s\n' % obj.summary
        if hasattr(obj, 'location') and not empty(obj.location):
            result += u'LOCATION:%s\n' % obj.location

        if hasattr(obj, 'categories') and not empty(obj.categories):
            result += u'CATEGORIES:%s\n' % obj.categories

        if hasattr(obj, 'status') and not empty(obj.status):
            result += u'STATUS:%s\n' % obj.status

        if hasattr(obj, 'description') and not empty(obj.description):
            result += u'DESCRIPTION:%s\n' % obj.description.replace('\r\n', '\\n')

        if hasattr(obj, 'transp') and not empty(obj.transp):
            result += u'TRANSP:%s\n' % obj.transp

        if hasattr(obj, 'sequence') and not empty(obj.sequence):
            result += u'SEQUENCE:%s\n' % obj.sequence

        if hasattr(obj, 'url') and not empty(obj.url):
            result += u'URL:%s\n' % obj.url

        result += u'END:VEVENT\n'
        return result

    def end_format(self):
        return u'END:VCALENDAR'

    def do_export(self, line):
        """
        export FILENAME ID1 [ID2 ID3 ...]

        id is the identifier of the event
        FILENAME is where to write the file. If FILENAME is '-', the file is written to stdout.

        Export event in ICALENDAR format
        """
        if not line:
            print >>sys.stderr, 'This command takes two arguments: %s' % self.get_command_help('export')
            return 2

        _file, args = self.parse_command_args(line, 2, req_n=1)

        if not args:
            print >>sys.stderr, 'This command takes two arguments: %s' % self.get_command_help('export')
            return 2

        _ids = args.strip().split(' ')

        buff = self.start_format()

        for _id in _ids:
            event = self.get_object(_id, 'get_event')

            if not event:
                print >>sys.stderr, 'Upcoming event not found: %s' % _id
                return 3

            buff += self.format_event(event)

        buff += self.end_format()

        if _file == "-":
            print buff
        else:
            try:
                dest = self.check_file_ext(_file)
                with open(dest, 'w') as f:
                    f.write(buff.encode('ascii', 'ignore'))
            except IOError as e:
                print >>sys.stderr, 'Unable to write bill in "%s": %s' % (dest, e)
                return 1

    def check_file_ext(self, _file):
        splitted_file = _file.split('.')
        if splitted_file[-1] != 'ics':
            return "%s.ics" % _file
        else:
            return _file

    def get_date_from_day(self, day):
        today = date.today()
        today_day_number = today.weekday()

        requested_day_number = self.WEEK[day.upper()]

        if today_day_number < requested_day_number:
            day_to_go = requested_day_number - today_day_number
        else:
            day_to_go = 7 - today_day_number + requested_day_number

        requested_date = today + timedelta(day_to_go)
        return date(requested_date.year, requested_date.month, requested_date.day)

    def parse_date(self, string):
        matches = re.search('\s*([012]?[0-9]|3[01])\s*/\s*(0?[1-9]|1[012])\s*/?(\d{2}|\d{4})?$', string)
        if matches:
            year = matches.group(3)
            if not year:
                year = date.today().year
            elif len(year) == 2:
                year = 2000 + int(year)
            return date(int(year), int(matches.group(2)), int(matches.group(1)))

        elif string.upper() in self.WEEK.keys():
            return self.get_date_from_day(string)

        elif string.upper() == "TODAY":
            return date.today()
<commit_msg>[Boobcoming] add functionnalities<commit_after># -*- coding: utf-8 -*-

# Copyright(C) 2013 Bezleputh
#
# This file is part of weboob.
#
# weboob 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.
#
# weboob 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 weboob. If not, see <http://www.gnu.org/licenses/>.

import re
import sys
from datetime import date, timedelta, time, datetime

from weboob.tools.application.formatters.iformatter import IFormatter, PrettyFormatter
from weboob.capabilities.base import empty
from weboob.capabilities.calendar import ICapCalendarEvent
from weboob.tools.application.repl import ReplApplication, defaultcount

__all__ = ['Boobcoming']

class ICalFormatter(IFormatter):
    MANDATORY_FIELDS = ('id', 'start_date', 'end_date', 'summary')

    def start_format(self, **kwargs):
        self.output(u'BEGIN:VCALENDAR')
        self.output(u'VERSION:2.0')
        self.output(u'PRODID:-//hacksw/handcal//NONSGML v1.0//EN')

    def format_obj(self, obj, alias):
        result = u'BEGIN:VEVENT\n'
        result += u'DTSTART:%s\n' % obj.start_date.strftime("%Y%m%dT%H%M%SZ")
        result += u'DTEND:%s\n' % obj.end_date.strftime("%Y%m%dT%H%M%SZ")
        result += u'SUMMARY:%s\n' % obj.summary
        if hasattr(obj, 'location') and not empty(obj.location):
            result += u'LOCATION:%s\n' % obj.location

        if hasattr(obj, 'categories') and not empty(obj.categories):
            result += u'CATEGORIES:%s\n' % obj.categories

        if hasattr(obj, 'status') and not empty(obj.status):
            result += u'STATUS:%s\n' % obj.status

        if hasattr(obj, 'description') and not empty(obj.description):
            result += u'DESCRIPTION:%s\n' % obj.description.replace('\r\n', '\\n')

        if hasattr(obj, 'transp') and not empty(obj.transp):
            result += u'TRANSP:%s\n' % obj.transp

        if hasattr(obj, 'sequence') and not empty(obj.sequence):
            result += u'SEQUENCE:%s\n' % obj.sequence

        if hasattr(obj, 'url') and not empty(obj.url):
            result += u'URL:%s\n' % obj.url

        result += u'END:VEVENT'
        return result

    def flush(self, **kwargs):
        self.output(u'END:VCALENDAR')

class UpcomingListFormatter(PrettyFormatter):
    MANDATORY_FIELDS = ('id', 'start_date', 'end_date', 'summary', 'category')

    def get_title(self, obj):
        return ' %s - %s ' % (obj.category, obj.summary)

    def get_description(self, obj):
        result = u''
        result += u'\tDate: %s\n' % obj.start_date.strftime('%A %d %B %Y')
        result += u'\tHour: %s - %s \n' % (obj.start_date.strftime('%H:%M'), obj.end_date.strftime('%H:%M'))
        return result.strip('\n\t')

class UpcomingFormatter(IFormatter):
    MANDATORY_FIELDS = ('id', 'start_date', 'end_date', 'summary', 'category')

    def format_obj(self, obj, alias):
        result = u'%s%s - %s%s\n' % (self.BOLD, obj.category, obj.summary, self.NC)
        result += u'Date: %s\n' % obj.start_date.strftime('%A %d %B %Y')
        result += u'Hour: %s - %s\n' % (obj.start_date.strftime('%H:%M'), obj.end_date.strftime('%H:%M'))

        if hasattr(obj, 'location') and not empty(obj.location):
            result += u'Location: %s\n' % obj.location

        if hasattr(obj, 'event_planner') and not empty(obj.event_planner):
            result += u'Event planner: %s/%s \n' % (obj.event_planner)

        if hasattr(obj, 'entry') and not empty(obj.entry) and \
           hasattr(obj, 'max_entry') and not empty(obj.max_entry):
            result += u'Entry: %s/%s \n' % (obj.entry, obj.max_entry)
        elif hasattr(obj, 'entry') and not empty(obj.entry):
            result += u'Entry: %s \n' % (obj.entry)
        elif hasattr(obj, 'max_entry') and not empty(obj.max_entry):
            result += u'Max entries: %s \n' % (obj.max_entry)

        if hasattr(obj, 'description') and not empty(obj.description):
            result += u'Description:\n %s\n\n' % obj.description

        if hasattr(obj, 'price') and not empty(obj.price):
            result += u'Price: %i\n' % obj.price

        if hasattr(obj, 'url') and not empty(obj.url):
            result += u'url: %s\n' % obj.url

        return result

class Boobcoming(ReplApplication):
    APPNAME = 'boobcoming'
    VERSION = '0.h'
    COPYRIGHT = 'Copyright(C) 2012 Bezleputh'
    DESCRIPTION = "Console application to see upcoming events."
    SHORT_DESCRIPTION = "see upcoming events"
    CAPS = ICapCalendarEvent
    EXTRA_FORMATTERS = {'upcoming_list': UpcomingListFormatter,
                        'upcoming': UpcomingFormatter,
                        #'ical_formatter': ICalFormatter,
                        }
    COMMANDS_FORMATTERS = {'list': 'upcoming_list',
                           'info': 'upcoming',
                           #'export': 'ical_formatter',
                           }

    WEEK   = {'MONDAY': 0,
              'TUESDAY': 1,
              'WEDNESDAY': 2,
              'THURSDAY': 3,
              'FRIDAY': 4,
              'SATURDAY': 5,
              'SUNDAY': 6,
              'LUNDI': 0,
              'MARDI': 1,
              'MERCREDI': 2,
              'JEUDI': 3,
              'VENDREDI': 4,
              'SAMEDI': 5,
              'DIMANCHE': 6,
              }

    @defaultcount(10)
    def do_list(self, line):
        """
        list [PATTERN]
        List upcoming events, pattern can be an english or french  week day, 'today' or a date
        """

        self.change_path([u'events'])
        if line:
            _date = self.parse_date(line)
            if not _date:
                print >>sys.stderr, 'Invalid argument: %s' % self.get_command_help('list', short=True)
                return 2

            date_from = datetime.combine(_date, time.min)
            date_to = datetime.combine(_date, time.max)
        else:
            date_from = datetime.now()
            date_to = None

        for backend, event in self.do('list_events', date_from, date_to):
            self.cached_format(event)

    def complete_info(self, text, line, *ignored):
        args = line.split(' ')
        if len(args) == 2:
            return self._complete_object()

    def do_info(self, _id):
        """
        info ID

        Get information about an event.
        """

        if not _id:
            print >>sys.stderr, 'This command takes an argument: %s' % self.get_command_help('info', short=True)
            return 2

        event = self.get_object(_id, 'get_event')

        if not event:
            print >>sys.stderr, 'Upcoming event not found: %s' % _id
            return 3

        self.start_format()
        self.format(event)

    def start_format(self, **kwargs):
        result = u'BEGIN:VCALENDAR\n'
        result += u'VERSION:2.0\n'
        result += u'PRODID:-//hacksw/handcal//NONSGML v1.0//EN\n'
        return result

    def format_event(self, obj):
        result = u'BEGIN:VEVENT\n'
        result += u'DTSTART:%s\n' % obj.start_date.strftime("%Y%m%dT%H%M%SZ")
        result += u'DTEND:%s\n' % obj.end_date.strftime("%Y%m%dT%H%M%SZ")
        result += u'SUMMARY:%s\n' % obj.summary
        if hasattr(obj, 'location') and not empty(obj.location):
            result += u'LOCATION:%s\n' % obj.location

        if hasattr(obj, 'categories') and not empty(obj.categories):
            result += u'CATEGORIES:%s\n' % obj.categories

        if hasattr(obj, 'status') and not empty(obj.status):
            result += u'STATUS:%s\n' % obj.status

        if hasattr(obj, 'description') and not empty(obj.description):
            result += u'DESCRIPTION:%s\n' % obj.description.replace('\r\n', '\\n')

        if hasattr(obj, 'transp') and not empty(obj.transp):
            result += u'TRANSP:%s\n' % obj.transp

        if hasattr(obj, 'sequence') and not empty(obj.sequence):
            result += u'SEQUENCE:%s\n' % obj.sequence

        if hasattr(obj, 'url') and not empty(obj.url):
            result += u'URL:%s\n' % obj.url

        result += u'END:VEVENT\n'
        return result

    def end_format(self):
        return u'END:VCALENDAR'

    def do_export(self, line):
        """
        export FILENAME [ID1 ID2 ID3 ...]

        ID is the identifier of the event. If no ID every events are exported

        FILENAME is where to write the file. If FILENAME is '-', the file is written to stdout.

        Export event in ICALENDAR format
        """
        if not line:
            print >>sys.stderr, 'This command takes at leat one argument: %s' % self.get_command_help('export')
            return 2

        _file, args = self.parse_command_args(line, 2, req_n=1)

        l = self.retrieve_events(args)
        buff = self.create_buffer(l)

        if _file == "-":
            print buff
        else:
            try:
                dest = self.check_file_ext(_file)
                with open(dest, 'w') as f:
                    f.write(buff.encode('ascii', 'ignore'))
            except IOError as e:
                print >>sys.stderr, 'Unable to write bill in "%s": %s' % (dest, e)
                return 1

    def create_buffer(self, l):
        buff = self.start_format()

        for item in l:
            buff += self.format_event(item)

        buff += self.end_format()

        return buff

    def retrieve_events(self, args):
        l = []

        if not args:
            _ids = []
            for backend, event in self.do('list_events', datetime.now(), None):
                _ids.append(event.id)
        else:
            _id = args.strip().split(' ')

        for _id in _ids:
            event = self.get_object(_id, 'get_event')

            if not event:
                print >>sys.stderr, 'Upcoming event not found: %s' % _id
                return 3

            l.append(event)

        return l

    def check_file_ext(self, _file):
        splitted_file = _file.split('.')
        if splitted_file[-1] != 'ics':
            return "%s.ics" % _file
        else:
            return _file

    def get_date_from_day(self, day):
        today = date.today()
        today_day_number = today.weekday()

        requested_day_number = self.WEEK[day.upper()]

        if today_day_number < requested_day_number:
            day_to_go = requested_day_number - today_day_number
        else:
            day_to_go = 7 - today_day_number + requested_day_number

        requested_date = today + timedelta(day_to_go)
        return date(requested_date.year, requested_date.month, requested_date.day)

    def parse_date(self, string):
        matches = re.search('\s*([012]?[0-9]|3[01])\s*/\s*(0?[1-9]|1[012])\s*/?(\d{2}|\d{4})?$', string)
        if matches:
            year = matches.group(3)
            if not year:
                year = date.today().year
            elif len(year) == 2:
                year = 2000 + int(year)
            return date(int(year), int(matches.group(2)), int(matches.group(1)))

        elif string.upper() in self.WEEK.keys():
            return self.get_date_from_day(string)

        elif string.upper() == "TODAY":
            return date.today()

    def do_attends(self, line):
        """
        attend IS_ATTENDING [ID1 ID2 ID3 ...]

        ID is the identifier of the event. If no ID every events are exported

        IS_ATTENDING is a booleanizable value that indicate if attending or not

        Export event in ICALENDAR format
        """
        if not line:
            print >>sys.stderr, 'This command takes at leat one argument: %s' % self.get_command_help('export')
            return 2

        attending, args = self.parse_command_args(line, 2, req_n=1)

        l = self.retrieve_events(args)
        is_attending = self.booleanize(attending)

        for event in l:
            self.do('attends_event', event, is_attending)

    def booleanize(self, value):
        """Return value as a boolean."""

        true_values = ("yes", "true", "1")
        false_values = ("no", "false", "0")

        if isinstance(value, bool):
            return value

        if value.lower() in true_values:
            return True

        elif value.lower() in false_values:
            return False

        print >> sys.stderr, "Cannot booleanize ambiguous value '%s'" % value
<|endoftext|>


<commit_before># coding=utf-8

pluginsDir = "plugins"
assetsDir = "assets"
cacheDir = "cache"
logDir = "logs"
tmpDir = "tmp"

pluginReply = "reply"
pluginTimeline = "timeline"
pluginEvent = "event"
pluginThread = "thread"
pluginRegular = "regular"
pluginOther = "other"

pluginTypes = [
	pluginReply,
	pluginTimeline,
	pluginEvent,
	pluginThread,
	pluginRegular,
	pluginOther
]

pluginAttributeTarget = "TARGET"
pluginAttributePriority = "PRIORITY"
pluginAttributeAttachedStream = "STREAM"
pluginAttributeRatio = "RATIO"
pluginAttributeHour = "HOUR"
pluginAttributeMultipleHour = "MULTIPLE_HOUR"
pluginAttributeMinute = "MINUTE"
pluginAttributeMultipleMinute = "MULTIPLE_MINUTE"

defaultAttributeValid = None
defaultAttributePath = None
defaultAttributeSize = None
defaultAttributeName = None
defaultAttributeTarget = None
defaultAttributePriority = 0
defaultAttributeAttachedStream = 0
defaultAttributeRatio = 1
defaultAttributeHour = None
defaultAttributeMultipleHour = None
defaultAttributeMinute = None
defaultAttributeMultipleMinute = None

oneHourMinutes = 60
oneDayHours = 24
<commit_msg>Add: message constants<commit_after># coding=utf-8

pluginsDir = "plugins"
assetsDir = "assets"
cacheDir = "cache"
logDir = "logs"
tmpDir = "tmp"

pluginReply = "reply"
pluginTimeline = "timeline"
pluginEvent = "event"
pluginThread = "thread"
pluginRegular = "regular"
pluginOther = "other"

pluginTypes = [
	pluginReply,
	pluginTimeline,
	pluginEvent,
	pluginThread,
	pluginRegular,
	pluginOther
]

messageErrorLoadingPlugin = "Plugin \"{0}\"({1}) could not be loaded. Error Detail:\n{2}"
messageSuccessLoadingPlugin = "Plugin \"{0}\"({1}) has been loaded successfully."

pluginAttributeTarget = "TARGET"
pluginAttributePriority = "PRIORITY"
pluginAttributeAttachedStream = "STREAM"
pluginAttributeRatio = "RATIO"
pluginAttributeHour = "HOUR"
pluginAttributeMultipleHour = "MULTIPLE_HOUR"
pluginAttributeMinute = "MINUTE"
pluginAttributeMultipleMinute = "MULTIPLE_MINUTE"

defaultAttributeValid = None
defaultAttributePath = None
defaultAttributeSize = None
defaultAttributeName = None
defaultAttributeTarget = None
defaultAttributePriority = 0
defaultAttributeAttachedStream = 0
defaultAttributeRatio = 1
defaultAttributeHour = None
defaultAttributeMultipleHour = None
defaultAttributeMinute = None
defaultAttributeMultipleMinute = None

dayStartHour = 0
oneHourMinutes = 60
oneDayHours = 24
<|endoftext|>


<commit_before>#Copyright (C) 2014 Sergio Tafur <setafur@gmail.com>
#
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
#
#The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

import sys,getopt,time

#Define Default Values
Ntries = 100
Naddrs = 4
ExpectedCoinsToSend = 1.
minCoinsMultiplier = .00000001
coinBinResolution = 1

#Take command line arguments
opts, args = getopt.getopt(sys.argv[1:], 'o:v', ['addr=','tries=','coins=','multiplier=','resolution='])
for opt,arg in opts:
  if opt in ('-a', '--addr'):
    Naddrs = int(arg)
  elif opt in ('-t','--tries'):
    Ntries = int(arg)
  elif opt in ('-c','--coins'):
    ExpectedCoinsToSend = float(arg)
  elif opt in ('-m','--multiplier'):
    minCoinsMultiplier = float(arg)
  elif opt in ('-r','--resolution'):
    coinBinResolution = int(arg)

import random as rnd
import numpy as np

maxCoinsToSendPerAttempt = ExpectedCoinsToSend*10.*minCoinsMultiplier
minCoinsToSendPerAttempt = ExpectedCoinsToSend*minCoinsMultiplier

while minCoinsToSendPerAttempt < .00000001:
  print 'Correcting:',
  minCoinsToSendPerAttempt = minCoinsToSendPerAttempt*10.
  maxCoinsToSendPerAttempt = maxCoinsToSendPerAttempt*10.
  minCoinsMultplier = 10.*minCoinsMultiplier

print
print 'Max Coins to send per Attempt: ',maxCoinsToSendPerAttempt
print 'Min Coins to send per Attempt: ',minCoinsToSendPerAttempt

Ntries = Ntries + 1
countAddr = [0.]*Ntries
countTime = [0.]*Ntries
countCoins = [0.]*Ntries

coinBins = Ntries*coinBinResolution
coinDist=[0.]*Ntries
addrDist=[0.]*Ntries
for i in range(Ntries):
  coinDist[i]=[0.]*(coinBins)
  addrDist[i]=[0.]*(Ntries)

sentCoins = 0.
numTransactions = 0
numBlocks = 0
maxSentCoins = 0
maxCoinsPerBlock = maxCoinsToSendPerAttempt*float(Ntries)
while sentCoins < ExpectedCoinsToSend:
  print 'Current block:', numBlocks,'Sent Coins:',sentCoins,'\r',
  #print
  numBlocks = numBlocks + 1
  countAddr1 = 0
  countTime1 = 0
  countSentCoins = 0.
  sqCountSentCoins = 0.
  for i in range(Ntries-1):
    randTime = rnd.randint(0,1)
    if randTime == 0:
      countTime1 = countTime1 + 1
      randAddr = rnd.randint(0,Naddrs-1)
      if randAddr == 0:
        countAddr1 = countAddr1 + 1
        coinsToSendPerAttempt = rnd.uniform(minCoinsToSendPerAttempt,maxCoinsToSendPerAttempt)
        testSentCoins = countSentCoins + coinsToSendPerAttempt
        if testSentCoins <= ExpectedCoinsToSend:
          numTransactions = numTransactions + 1
          countSentCoins = testSentCoins
          sqCountSentCoins = testSentCoins*testSentCoins
          #print countSentCoins,sqCountSentCoins
        else:
          break
  #Count Total Coins Sent
  sentCoins = sentCoins + countSentCoins
  #print sentCoins
  #print countSentCoins,maxSentCoins

  #Count Total Times Transaction Occurred in Block
  #print countTime1,countAddr1
  addrDist[countTime1][countAddr1] = addrDist[countTime1][countAddr1] + 1

  #Count Total Coins Sent in Block
  if maxSentCoins <= countSentCoins:
    maxSentCoins = countSentCoins
  #if countAddr1 > 0:
  ratioToMaxCoinsPerBlock = countSentCoins/maxCoinsPerBlock
  coinBin = int(ratioToMaxCoinsPerBlock*float(coinBins)) #/minCoinsMultiplier)
    #print 'Ratio to Max: ',ratioToMaxCoinsPerBlock
    #print 'coinBin:',coinBin
    #coinDist[countTime1][countAddr1] = coinDist[countTime1][countAddr1] + 1
  coinDist[countTime1][coinBin] = coinDist[countTime1][coinBin] + 1

print 'Current block:', numBlocks,'Sent Coins:',sentCoins,'\r',
print '\n\nExpected Coins:',ExpectedCoinsToSend
print 'Sent Coins:',sentCoins
percentDiff = 100.*(abs(ExpectedCoinsToSend-sentCoins)/ExpectedCoinsToSend)
print "%%diff: %.8f" % percentDiff
print
print 'Total Transactions: ',numTransactions
print 'Total Blocks: ',numBlocks

#BEGIN ANALYSIS

#dist = np.array(addrDist)
dist = np.array(coinDist)
#print dist

sumDist=0.
for i in range(Ntries-1):
  #for j in range(Ntries-1):
  for j in range(coinBins-1):
    sumDist = sumDist+.25*(dist[i+1][j+1]+dist[i+1][j]+dist[i][j+1]+dist[i][j])
maxDist = np.amax(dist)
dist = dist/sumDist
print
print "Max. Dist, Sum. Dist: %.8f, %.8f" % (maxDist,sumDist)

normSumDist=0.
for i in range(Ntries-1):
  #for j in range(Ntries-1):
  for j in range(coinBins-1):
    normSumDist = normSumDist+.25*(dist[i+1][j+1]+dist[i+1][j]+dist[i][j+1]+dist[i][j])
normMaxDist = np.amax(dist)
print "Norm. Max. Dist., Norm. Sum. Dist.: %.8f, %.8f" % (normMaxDist,normSumDist)

#MLAB plot commands
#from mayavi.mlab import *
#x, y = np.mgrid[0:Ntries-1, 0:Ntries-1]
#fg_color = (0.06666, 0.06666, 0.1804)
#bg_color = (1, 1, 0.94118)
#figure(fgcolor=fg_color, bgcolor=bg_color)
#s = surf(x,y,dist, warp_scale='auto')
#outline(s, color=(.7, .7, .7))
#ax = axes(s, nb_labels=5,line_width=0.5,color=(.7, .7, .7),xlabel="Trans.", ylabel="Coins.",zlabel="Prob.",ranges=(0,Ntries-1,0,coinsToSendPerAttempt*(Ntries-1),0,normMaxDist))
#ax.axes.font_factor=1
#colorbar(title='Norm. Prob.', orientation='vertical',nb_labels=5)
#show()

#Pyplot commands
import matplotlib.pyplot as plt

fig,ax = plt.subplots()

max_x = float(Ntries)*maxCoinsToSendPerAttempt
#max_x = float(Ntries)
cax = ax.imshow(dist, cmap=plt.cm.jet, interpolation='none',extent=[0,max_x,0,Ntries-1],aspect="auto")
ax.set_title('Prob. of TRUST for %d TAddys.' % Naddrs)
#cax = ax.imshow(dist, cmap=plt.cm.jet, interpolation='none',extent=[0,Ntries-1,0,Ntries-1],aspect="auto")
#ax.set_title('Prob. of Trans. for 1 of %d Addrs.' % Naddrs)

xticks_loc = np.arange(0.,max_x,max_x/(6.*float(Naddrs)))
#xticks_loc = np.arange(0.,max_x,max_x/(6.*float(Naddrs)))
plt.xticks(xticks_loc)
ax.set_xlim(0,1.5*max_x/float(2*Naddrs))
#ax.set_xlim(0,1.5*max_x/float(Naddrs))
ax.ticklabel_format(style='sci', scilimits=(0,0), axis='x')
plt.xlabel('Coins per Block (TRUST)')
#plt.xlabel('Times Address Chosen per Block')

#yticks_loc = np.arange(0.,float(Ntries),float(Ntries)/6.)
#plt.yticks(yticks_loc)
ax.set_ylim(0.25*float(Ntries),0.75*float(Ntries-1))
plt.ylabel('Transactions per Block')

cbar_ticks = [-1,0,1]
cbar = fig.colorbar(cax)
#cbar.ax.set_yticklabels(['0', normMaxDist*0.25, normMaxDist*0.5, normMaxDist])
plt.subplots_adjust(left=0.085,right=1.02,top=.945,bottom=0.1)
plt.show()

<commit_msg>Made License eaiser to read.<commit_after>#Copyright (C) 2014 Sergio Tafur <setafur@gmail.com>
#
#Permission is hereby granted, free of charge, to any person obtaining
#a copy of this software and associated documentation files (the "Software"),
#to deal in the Software without restriction, including without limitation the
#rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
#sell copies of the Software, and to permit persons to whom the Software is
#furnished to do so, subject to the following conditions:
#
#The above copyright notice and this permission notice shall be included in all
#copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
#FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
#COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
#IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
#WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

import sys,getopt,time

#Define Default Values
Ntries = 100
Naddrs = 4
ExpectedCoinsToSend = 1.
minCoinsMultiplier = .00000001
coinBinResolution = 1

#Take command line arguments
opts, args = getopt.getopt(sys.argv[1:], 'o:v', ['addr=','tries=','coins=','multiplier=','resolution='])
for opt,arg in opts:
  if opt in ('-a', '--addr'):
    Naddrs = int(arg)
  elif opt in ('-t','--tries'):
    Ntries = int(arg)
  elif opt in ('-c','--coins'):
    ExpectedCoinsToSend = float(arg)
  elif opt in ('-m','--multiplier'):
    minCoinsMultiplier = float(arg)
  elif opt in ('-r','--resolution'):
    coinBinResolution = int(arg)

import random as rnd
import numpy as np

maxCoinsToSendPerAttempt = ExpectedCoinsToSend*10.*minCoinsMultiplier
minCoinsToSendPerAttempt = ExpectedCoinsToSend*minCoinsMultiplier

while minCoinsToSendPerAttempt < .00000001:
  print 'Correcting:',
  minCoinsToSendPerAttempt = minCoinsToSendPerAttempt*10.
  maxCoinsToSendPerAttempt = maxCoinsToSendPerAttempt*10.
  minCoinsMultplier = 10.*minCoinsMultiplier

print
print 'Max Coins to send per Attempt: ',maxCoinsToSendPerAttempt
print 'Min Coins to send per Attempt: ',minCoinsToSendPerAttempt

Ntries = Ntries + 1
countAddr = [0.]*Ntries
countTime = [0.]*Ntries
countCoins = [0.]*Ntries

coinBins = Ntries*coinBinResolution
coinDist=[0.]*Ntries
addrDist=[0.]*Ntries
for i in range(Ntries):
  coinDist[i]=[0.]*(coinBins)
  addrDist[i]=[0.]*(Ntries)

sentCoins = 0.
numTransactions = 0
numBlocks = 0
maxSentCoins = 0
maxCoinsPerBlock = maxCoinsToSendPerAttempt*float(Ntries)
while sentCoins < ExpectedCoinsToSend:
  print 'Current block:', numBlocks,'Sent Coins:',sentCoins,'\r',
  #print
  numBlocks = numBlocks + 1
  countAddr1 = 0
  countTime1 = 0
  countSentCoins = 0.
  sqCountSentCoins = 0.
  for i in range(Ntries-1):
    randTime = rnd.randint(0,1)
    if randTime == 0:
      countTime1 = countTime1 + 1
      randAddr = rnd.randint(0,Naddrs-1)
      if randAddr == 0:
        countAddr1 = countAddr1 + 1
        coinsToSendPerAttempt = rnd.uniform(minCoinsToSendPerAttempt,maxCoinsToSendPerAttempt)
        testSentCoins = countSentCoins + coinsToSendPerAttempt
        if testSentCoins <= ExpectedCoinsToSend:
          numTransactions = numTransactions + 1
          countSentCoins = testSentCoins
          sqCountSentCoins = testSentCoins*testSentCoins
          #print countSentCoins,sqCountSentCoins
        else:
          break
  #Count Total Coins Sent
  sentCoins = sentCoins + countSentCoins
  #print sentCoins
  #print countSentCoins,maxSentCoins

  #Count Total Times Transaction Occurred in Block
  #print countTime1,countAddr1
  addrDist[countTime1][countAddr1] = addrDist[countTime1][countAddr1] + 1

  #Count Total Coins Sent in Block
  if maxSentCoins <= countSentCoins:
    maxSentCoins = countSentCoins
  #if countAddr1 > 0:
  ratioToMaxCoinsPerBlock = countSentCoins/maxCoinsPerBlock
  coinBin = int(ratioToMaxCoinsPerBlock*float(coinBins)) #/minCoinsMultiplier)
    #print 'Ratio to Max: ',ratioToMaxCoinsPerBlock
    #print 'coinBin:',coinBin
    #coinDist[countTime1][countAddr1] = coinDist[countTime1][countAddr1] + 1
  coinDist[countTime1][coinBin] = coinDist[countTime1][coinBin] + 1

print 'Current block:', numBlocks,'Sent Coins:',sentCoins,'\r',
print '\n\nExpected Coins:',ExpectedCoinsToSend
print 'Sent Coins:',sentCoins
percentDiff = 100.*(abs(ExpectedCoinsToSend-sentCoins)/ExpectedCoinsToSend)
print "%%diff: %.8f" % percentDiff
print
print 'Total Transactions: ',numTransactions
print 'Total Blocks: ',numBlocks

#BEGIN ANALYSIS

#dist = np.array(addrDist)
dist = np.array(coinDist)
#print dist

sumDist=0.
for i in range(Ntries-1):
  #for j in range(Ntries-1):
  for j in range(coinBins-1):
    sumDist = sumDist+.25*(dist[i+1][j+1]+dist[i+1][j]+dist[i][j+1]+dist[i][j])
maxDist = np.amax(dist)
dist = dist/sumDist
print
print "Max. Dist, Sum. Dist: %.8f, %.8f" % (maxDist,sumDist)

normSumDist=0.
for i in range(Ntries-1):
  #for j in range(Ntries-1):
  for j in range(coinBins-1):
    normSumDist = normSumDist+.25*(dist[i+1][j+1]+dist[i+1][j]+dist[i][j+1]+dist[i][j])
normMaxDist = np.amax(dist)
print "Norm. Max. Dist., Norm. Sum. Dist.: %.8f, %.8f" % (normMaxDist,normSumDist)

#MLAB plot commands
#from mayavi.mlab import *
#x, y = np.mgrid[0:Ntries-1, 0:Ntries-1]
#fg_color = (0.06666, 0.06666, 0.1804)
#bg_color = (1, 1, 0.94118)
#figure(fgcolor=fg_color, bgcolor=bg_color)
#s = surf(x,y,dist, warp_scale='auto')
#outline(s, color=(.7, .7, .7))
#ax = axes(s, nb_labels=5,line_width=0.5,color=(.7, .7, .7),xlabel="Trans.", ylabel="Coins.",zlabel="Prob.",ranges=(0,Ntries-1,0,coinsToSendPerAttempt*(Ntries-1),0,normMaxDist))
#ax.axes.font_factor=1
#colorbar(title='Norm. Prob.', orientation='vertical',nb_labels=5)
#show()

#Pyplot commands
import matplotlib.pyplot as plt

fig,ax = plt.subplots()

max_x = float(Ntries)*maxCoinsToSendPerAttempt
#max_x = float(Ntries)
cax = ax.imshow(dist, cmap=plt.cm.jet, interpolation='none',extent=[0,max_x,0,Ntries-1],aspect="auto")
ax.set_title('Prob. of TRUST for %d TAddys.' % Naddrs)
#cax = ax.imshow(dist, cmap=plt.cm.jet, interpolation='none',extent=[0,Ntries-1,0,Ntries-1],aspect="auto")
#ax.set_title('Prob. of Trans. for 1 of %d Addrs.' % Naddrs)

xticks_loc = np.arange(0.,max_x,max_x/(6.*float(Naddrs)))
#xticks_loc = np.arange(0.,max_x,max_x/(6.*float(Naddrs)))
plt.xticks(xticks_loc)
ax.set_xlim(0,1.5*max_x/float(2*Naddrs))
#ax.set_xlim(0,1.5*max_x/float(Naddrs))
ax.ticklabel_format(style='sci', scilimits=(0,0), axis='x')
plt.xlabel('Coins per Block (TRUST)')
#plt.xlabel('Times Address Chosen per Block')

#yticks_loc = np.arange(0.,float(Ntries),float(Ntries)/6.)
#plt.yticks(yticks_loc)
ax.set_ylim(0.25*float(Ntries),0.75*float(Ntries-1))
plt.ylabel('Transactions per Block')

cbar_ticks = [-1,0,1]
cbar = fig.colorbar(cax)
#cbar.ax.set_yticklabels(['0', normMaxDist*0.25, normMaxDist*0.5, normMaxDist])
plt.subplots_adjust(left=0.085,right=1.02,top=.945,bottom=0.1)
plt.show()

<|endoftext|>