import inspect

import ctk
import slicer
import numpy
import time
import qt
import vtk
import colorsys
from slicer.ScriptedLoadableModule import *

# Interface tools
class InterfaceTools:
    def __init__(self):
        pass

    @staticmethod
    def build_vertical_space(height=18):
        s = qt.QWidget()
        s.setFixedSize(10, height)
        return s

    @staticmethod
    def build_dropdown(title, disabled=False):
        d = ctk.ctkCollapsibleButton()
        d.text = title
        d.enabled = not disabled
        d.collapsed = disabled
        return d

    @staticmethod
    def build_frame():
        g = qt.QFrame()
        g.setFrameStyle(3)
        return g

    @staticmethod
    def build_volume_selector(on_click=None):
        s = slicer.qMRMLNodeComboBox()
        s.nodeTypes = ["vtkMRMLScalarVolumeNode"]
        s.noneEnabled = True
        s.addEnabled = False
        s.renameEnabled = True
        s.setMRMLScene(slicer.mrmlScene)
        if on_click is not None: s.connect("currentNodeChanged(bool)", on_click)
        return s

    @staticmethod
    def build_model_selector(on_click=None):
        s = slicer.qMRMLNodeComboBox()
        s.nodeTypes = ["vtkMRMLModelNode"]
        s.addEnabled = False
        s.renameEnabled = s.noneEnabled = False  # True
        s.setMRMLScene(slicer.mrmlScene)
        if on_click is not None: s.connect("currentNodeChanged(bool)", on_click)
        return s

    @staticmethod
    def build_combo_box(items, current_index_changed):
        comboBox = qt.QComboBox()
        comboBox.addItems(items)
        comboBox.setFixedWidth(350)
        comboBox.connect("currentIndexChanged(QString)", current_index_changed)
        box = qt.QHBoxLayout()
        box.addStretch()
        box.addWidget(comboBox)
        return box

    @staticmethod
    def build_spin_box(minimum, maximum, click=None, decimals=0, step=1.0, initial=0.0, width=None):
        box = qt.QDoubleSpinBox()
        box.setMinimum(minimum)
        box.setMaximum(maximum)
        box.setSingleStep(step)
        box.setDecimals(decimals)
        box.setValue(initial)
        if width is not None: box.setFixedWidth(width)
        if click is not None: box.connect('valueChanged(double)', click)
        return box

    @staticmethod
    def build_radio_button(title, on_click, checked=False, tooltip=None, width=None):
        b = qt.QRadioButton(title)
        b.connect('clicked(bool)', on_click)
        b.setChecked(checked)
        if tooltip is not None: b.setToolTip(tooltip)
        if width is not None: b.setFixedWidth(width)
        return b

    @staticmethod
    def build_label(text, width=None):
        b = qt.QLabel(text)
        if width is not None: b.setFixedWidth(width)
        return b

    @staticmethod
    def build_icon_button(icon_path, on_click, width=50, tooltip=None):
        path = slicer.os.path.dirname(slicer.os.path.abspath(inspect.getfile(inspect.currentframe()))) + icon_path
        icon = qt.QPixmap(path).scaled(qt.QSize(16, 16), qt.Qt.KeepAspectRatio, qt.Qt.SmoothTransformation)
        b = qt.QToolButton()
        b.setIcon(qt.QIcon(icon))
        b.setFixedSize(width, 24)
        if tooltip is not None: b.setToolTip(tooltip)
        b.connect('clicked(bool)', on_click)
        return b

    @staticmethod
    def build_min_max(initial, decimals=2, step=0.1, lb=0.0, hb=1000.0, units='mm', min_text='MIN: ', max_text='MAX: '):
        def set_min(value): initial[0] = value
        def set_max(value): initial[1] = value
        box = qt.QHBoxLayout()
        box.addStretch()
        box.addWidget(InterfaceTools.build_label(min_text, 40))
        lowerSb = InterfaceTools.build_spin_box(lb, hb, decimals=decimals, step=step, initial=initial[0], click=set_min, width=80)
        box.addWidget(lowerSb)
        box.addWidget(InterfaceTools.build_label(units, 50))
        box.addWidget(InterfaceTools.build_label(max_text, 40))
        higherSb = InterfaceTools.build_spin_box(lb, hb, decimals=decimals, step=step, initial=initial[1], click=set_max, width=80)
        box.addWidget(higherSb)
        box.addWidget(InterfaceTools.build_label(units, 30))

        def set_boxes(value=None, enabled=None):
            if value is not None:
                set_min(value[0])
                lowerSb.setValue(value[0])
                set_max(value[1])
                higherSb.setValue(value[1])
            if enabled is not None:
                lowerSb.enabled = enabled
                higherSb.enabled = enabled
        return box, set_boxes

class BoneThicknessMappingType:
    THICKNESS = 'Thickness to dura'
    AIR_CELL = 'Distance to first air cell'

class BoneSegmentationLowerBound:
    MANUAL = 'Manual'
    CLINICAL = 'Clinical CT'
    CONE_BEAM = 'Cone Beam CT'

class BoneDepthMappingPresets:
    MANUAL = 'Manual'
    BCI601 = 'BCI 601'
    BCI602 = 'BCI 602'

class BoneThicknessMappingState:
    WAITING = 1
    READY = 2
    EXECUTING = 3
    FINISHED = 4

class BoneThicknessMappingQuality:
    VERY_LOW = 'VERY LOW (ray every 4 dimensional units)'
    LOW = 'LOW (ray every 2 dimensional units)'
    MEDIUM = 'MEDIUM (ray every 1 dimensional unit)'
    HIGH = 'HIGH (ray every 0.5 dimensional units)'
    VERY_HIGH = 'VERY HIGH (ray every 0.25 dimensional units)'
    EXTREME = 'EXTREME (ray every 0.125 dimensional units)'

class HitPoint:
    pid = None
    point = None
    normal = [0.0, 0.0, 0.0]

    def __init__(self, pid, point):
        self.pid = pid
        self.point = point

class BoneThicknessMapping(ScriptedLoadableModule):
    def __init__(self, parent):
        ScriptedLoadableModule.__init__(self, parent)
        self.parent.title = "Bone Thickness Mapping"
        self.parent.categories = ["Shape Analysis"]
        self.parent.dependencies = []
        self.parent.contributors = ["Evan Simpson (Western University)"]
        self.parent.helpText = "The following module will segment and threshold a volume to isolate bone material, cast rays in one direction to calculate the thickness of segmented bone, finally a gradient visualization will be rendered on the 3D segment model." \
                               "\n[Version 1.2-2020.06.18]"
        self.parent.acknowledgementText = "This module was originally developed by Evan Simpson at The University of Western Ontario in the HML/SKA Auditory Biophysics Lab."

class BoneThicknessMappingWidget(ScriptedLoadableModuleWidget):
    # Data members --------------
    state = BoneThicknessMappingState.WAITING
    status, progress = 'N/A', 0
    thicknessScalarArray, airCellScalarArray = None, None
    thicknessColourNode, airCellColourNode = None, None
    modelPolyData = None
    segmentationBounds = None
    topLayerPolyData = None
    hitPointList = None
    modelNode = None

    # Configuration preferences
    CONFIG_precision = 1.0
    CONFIG_rayCastAxis = ctk.ctkAxesWidget.Left
    CONFIG_segmentThresholdRange = [600, 3071]
    CONFIG_regionOfInterest = [-100, 100]
    CONFIG_minMaxAirCell = [0.0, 4.0]
    CONFIG_minMaxSkullThickness = [0.0, 8.7]
    CONFIG_mmOfAirPastBone = 4.0

    # UI members (in order of appearance) --------------
    infoLabel = None
    volumeSelector = None
    configuration_tools = None
    statusLabel = None
    executeButton = None
    progressBar = None
    finishButton = None
    resultSection = None
    displayThicknessSelector = None
    displayFirstAirCellSelector = None
    displayScalarBarCheckbox = None

    def __init__(self, parent=None):
        ScriptedLoadableModuleWidget.__init__(self, parent)

    def setup(self):
        ScriptedLoadableModuleWidget.setup(self)
        self.layout.addLayout(self.build_input_tools())
        self.layout.addLayout(self.build_execution_tools())
        self.layout.addLayout(self.build_result_tools())
        self.layout.addStretch()
        BoneThicknessMappingLogic.reset_view(ctk.ctkAxesWidget.Left)
        self.update_all()
        slicer.app.aboutToQuit.connect(self.release_memory)

    # interface build ------------------------------------------------------------------------------
    def build_input_tools(self):
        layout = qt.QVBoxLayout()

        self.volumeSelector = InterfaceTools.build_volume_selector(on_click=self.click_input_selector)
        box = qt.QHBoxLayout()
        box.addWidget(self.volumeSelector)
        box.addWidget(InterfaceTools.build_icon_button('/Resources/Icons/fit.png', on_click=lambda: BoneThicknessMappingLogic.reset_view(self.CONFIG_rayCastAxis), tooltip="Reset 3D view."))
        form = qt.QFormLayout()
        form.addRow(qt.QLabel('Select an input volume to auto-segment, render, and calculate thickness.'))
        form.addRow("Input Volume: ", box)
        self.infoLabel = qt.QLabel()
        form.addWidget(self.infoLabel)

        title = qt.QHBoxLayout()
        path = slicer.os.path.dirname(slicer.os.path.abspath(inspect.getfile(inspect.currentframe()))) + "/Resources/Icons/logo.png"
        icon = qt.QPixmap(path).scaled(qt.QSize(240, 400), qt.Qt.KeepAspectRatio, qt.Qt.SmoothTransformation)
        logo = qt.QLabel()
        logo.setPixmap(icon)
        title.addWidget(logo)

        layout.addLayout(title)
        layout.addLayout(form)
        layout.setMargin(10)
        return layout

    def build_configuration_tools(self):
        self.configuration_tools = InterfaceTools.build_dropdown("Configuration")
        layout = qt.QFormLayout(self.configuration_tools)

        # threshold
        threshBox, setThresh = InterfaceTools.build_min_max(self.CONFIG_segmentThresholdRange, step=5.0, decimals=2, lb=-4000, hb=4000, units='')

        def current_index_changed(string):
            if string == BoneSegmentationLowerBound.MANUAL:
                setThresh([600.0, 3071.0], enabled=True)
            elif string == BoneSegmentationLowerBound.CLINICAL:
                setThresh([650.0, 3071.0], enabled=False)
            elif string == BoneSegmentationLowerBound.CONE_BEAM:
                setThresh([750.0, 3071.0], enabled=False)
        presets = InterfaceTools.build_combo_box(
            items=[BoneSegmentationLowerBound.MANUAL, BoneSegmentationLowerBound.CLINICAL, BoneSegmentationLowerBound.CONE_BEAM],
            current_index_changed=current_index_changed
        )

        group_box = qt.QGroupBox('Auto segmenting')
        group_layout = qt.QFormLayout(group_box)
        group_layout.addRow("Presets", presets)
        group_layout.addRow("Otsu bone-threshold range", threshBox)
        layout.addRow(group_box)

        # ray direction
        def set_axis(a):
            self.CONFIG_rayCastAxis = a
            slicer.app.layoutManager().threeDWidget(0).threeDView().lookFromViewAxis(a)

        dirBox = qt.QVBoxLayout()
        row1 = qt.QHBoxLayout()
        row1.addStretch()
        row1.addWidget(InterfaceTools.build_radio_button('R', lambda: set_axis(ctk.ctkAxesWidget.Right), width=100))
        row1.addWidget(InterfaceTools.build_radio_button('A', lambda: set_axis(ctk.ctkAxesWidget.Anterior), width=100))
        row1.addWidget(InterfaceTools.build_radio_button('S', lambda: set_axis(ctk.ctkAxesWidget.Superior), width=100))
        row2 = qt.QHBoxLayout()
        row2.addStretch()
        row2.addWidget(InterfaceTools.build_radio_button('L', lambda: set_axis(ctk.ctkAxesWidget.Left), width=100, checked=True))
        row2.addWidget(InterfaceTools.build_radio_button('P', lambda: set_axis(ctk.ctkAxesWidget.Posterior), width=100))
        row2.addWidget(InterfaceTools.build_radio_button('I', lambda: set_axis(ctk.ctkAxesWidget.Inferior), width=100))
        dirBox.addLayout(row1)
        dirBox.addLayout(row2)

        # mm of air afterbone
        airBox = qt.QHBoxLayout()
        def set_air(mm): self.CONFIG_mmOfAirPastBone = mm
        airBox.addStretch()
        airBox.addWidget(InterfaceTools.build_spin_box(0.0, 1000.0, decimals=2, click=set_air, step=0.1, initial=self.CONFIG_mmOfAirPastBone, width=260))
        airBox.addWidget(InterfaceTools.build_label("mm", width=30))

        # region of interest
        roiBox, setRoi = InterfaceTools.build_min_max(self.CONFIG_regionOfInterest, step=1.0, decimals=0, lb=-1000, hb=1000, units='units')

        # add ray-casting box
        group_box = qt.QGroupBox('Ray-casting')
        group_layout = qt.QFormLayout(group_box)
        group_layout.addRow("Cast direction: ", dirBox)
        group_layout.addRow("Air allowance after bone: ", airBox)
        group_layout.addRow("Casting bounds (along cast direction):", roiBox)
        layout.addRow(InterfaceTools.build_vertical_space())
        layout.addRow(group_box)

        # degrees of interest
        # TODO

        # min/max
        skullBox, setSkullBoxes = InterfaceTools.build_min_max(self.CONFIG_minMaxSkullThickness)
        airCellBox, setAirBoxes = InterfaceTools.build_min_max(self.CONFIG_minMaxAirCell)

        def pick_depth_preset(string):
            if string == BoneDepthMappingPresets.MANUAL:
                setSkullBoxes(enabled=True)
                setAirBoxes(enabled=True)
            elif string == BoneDepthMappingPresets.BCI601:
                setSkullBoxes([0.0, 8.7], enabled=False)
                setAirBoxes([0.0, 4.0], enabled=False)
            elif string == BoneDepthMappingPresets.BCI602:
                setSkullBoxes([0.0, 4.5], enabled=False)
                setAirBoxes([0.0, 4.0], enabled=False)
        comboBox = InterfaceTools.build_combo_box(
            items=[BoneDepthMappingPresets.MANUAL, BoneDepthMappingPresets.BCI601, BoneDepthMappingPresets.BCI602],
            current_index_changed=pick_depth_preset
        )

        # add ray-casting box
        group_box = qt.QGroupBox('Depth mapping')
        g_layout = qt.QFormLayout(group_box)
        g_layout.addRow('Depth preset: ', comboBox)
        g_layout.addRow("Thickness depth: ", skullBox)
        g_layout.addRow("Air cell depth: ", airCellBox)
        layout.addRow(InterfaceTools.build_vertical_space())
        layout.addRow(group_box)

        # quality
        def current_index_changed(string):
            if string == BoneThicknessMappingQuality.VERY_LOW: self.CONFIG_precision = 4.0
            elif string == BoneThicknessMappingQuality.LOW: self.CONFIG_precision = 2.0
            elif string == BoneThicknessMappingQuality.MEDIUM: self.CONFIG_precision = 1.0
            elif string == BoneThicknessMappingQuality.HIGH: self.CONFIG_precision = 0.50
            elif string == BoneThicknessMappingQuality.VERY_HIGH: self.CONFIG_precision = 0.25
            elif string == BoneThicknessMappingQuality.EXTREME: self.CONFIG_precision = 0.125
        comboBox = qt.QComboBox()
        comboBox.addItems([BoneThicknessMappingQuality.VERY_LOW, BoneThicknessMappingQuality.LOW, BoneThicknessMappingQuality.MEDIUM, BoneThicknessMappingQuality.HIGH, BoneThicknessMappingQuality.VERY_HIGH, BoneThicknessMappingQuality.EXTREME])
        comboBox.setCurrentIndex(2)
        comboBox.setFixedWidth(350)
        comboBox.connect("currentIndexChanged(QString)", current_index_changed)
        box = qt.QHBoxLayout()
        box.addStretch()
        box.addWidget(comboBox)

        # add ray-casting box
        group_box = qt.QGroupBox('Rendering')
        g_layout = qt.QFormLayout(group_box)
        g_layout.addRow("Render quality: ", box)
        layout.addRow(InterfaceTools.build_vertical_space())
        layout.addRow(group_box)

        layout.addRow(InterfaceTools.build_vertical_space())
        layout.setMargin(10)
        return self.configuration_tools

    def build_execution_tools(self):
        self.executeButton = qt.QPushButton('Execute')
        self.executeButton.setFixedHeight(36)
        self.executeButton.connect('clicked(bool)', self.click_execute)
        self.statusLabel = qt.QLabel('Status: ')
        self.statusLabel.enabled = False
        self.progressBar = qt.QProgressBar()
        self.progressBar.setFixedHeight(36)
        self.progressBar.minimum = 0
        self.progressBar.maximum = 100
        self.progressBar.value = 0
        self.progressBar.visible = False
        self.finishButton = qt.QPushButton('Finish')
        self.finishButton.visible = False
        self.finishButton.connect('clicked(bool)', self.click_finish)
        self.finishButton.setFixedHeight(36)
        box = qt.QHBoxLayout()
        box.addWidget(self.progressBar)
        box.addWidget(self.finishButton)

        layout = qt.QVBoxLayout()
        layout.addWidget(self.build_configuration_tools())
        layout.addWidget(self.statusLabel)
        layout.addWidget(self.executeButton)
        layout.addLayout(box)
        layout.setMargin(10)
        return layout

    def build_result_tools(self):
        self.resultSection = InterfaceTools.build_frame()

        self.displayThicknessSelector = InterfaceTools.build_radio_button(BoneThicknessMappingType.THICKNESS, self.click_result_radio, checked=True)
        self.displayFirstAirCellSelector = InterfaceTools.build_radio_button(BoneThicknessMappingType.AIR_CELL, self.click_result_radio)

        box = qt.QVBoxLayout()
        box.addWidget(self.displayThicknessSelector)
        box.addWidget(self.displayFirstAirCellSelector)

        self.displayScalarBarCheckbox = qt.QCheckBox()
        self.displayScalarBarCheckbox.checked = True
        self.displayScalarBarCheckbox.connect("stateChanged(int)", self.click_toggle_scalar_bar)

        form = qt.QFormLayout(self.resultSection)
        # form.addRow('Results', qt.QWidget())
        form.addRow("Map Display: ", box)
        # form.addRow(qt.QLayout())
        form.addRow("Display Scalar Bar: ", self.displayScalarBarCheckbox)
        form.setContentsMargins(10, 8, 10, 14)

        layout = qt.QVBoxLayout()
        layout.addWidget(self.resultSection)
        layout.setContentsMargins(12, 0, 12, 10)
        return layout

    # interface update ------------------------------------------------------------------------------
    def update_all(self):
        self.update_input_tools()
        self.update_execution_tools()
        self.update_results()

    def update_input_tools(self):
        if self.volumeSelector.currentNode() is None:
            self.volumeSelector.enabled = True
            self.infoLabel.text = 'Dimensions: '
            self.infoLabel.enabled = False
            self.state = BoneThicknessMappingState.WAITING
        elif self.state is BoneThicknessMappingState.WAITING and self.volumeSelector.currentNode() is not None:
            self.volumeSelector.enabled = True
            self.infoLabel.enabled = True
            self.infoLabel.text = 'Dimensions: ' + str(self.volumeSelector.currentNode().GetImageData().GetDimensions())
            self.state = BoneThicknessMappingState.READY
            # self.modelPolyData = SkullThicknessMappingLogic.process_segmentation(image=self.volumeSelector.currentNode(), update_status=self.update_status)
        elif self.state is BoneThicknessMappingState.EXECUTING or self.state is BoneThicknessMappingState.FINISHED:
            self.volumeSelector.enabled = False

    def update_execution_tools(self):
        if self.state is BoneThicknessMappingState.WAITING:
            self.configuration_tools.enabled = True
            self.configuration_tools.collapsed = True
            self.executeButton.visible = True
            self.executeButton.enabled = False
            self.progressBar.visible = False
            self.progressBar.value = 0
            self.statusLabel.enabled = False
            self.statusLabel.text = 'Status: WAITING'
            self.finishButton.visible = False
        elif self.state is BoneThicknessMappingState.READY:
            self.configuration_tools.enabled = True
            self.executeButton.visible = True
            self.executeButton.enabled = True
            self.progressBar.visible = False
            self.progressBar.value = 0
            self.statusLabel.enabled = True
            self.statusLabel.text = 'Status: READY'
            self.finishButton.visible = False
        elif self.state is BoneThicknessMappingState.EXECUTING:
            self.configuration_tools.enabled = False
            self.configuration_tools.collapsed = True
            self.executeButton.visible = False
            self.executeButton.enabled = False
            self.progressBar.visible = True
            self.progressBar.value = self.progress
            self.statusLabel.enabled = True
            self.statusLabel.text = 'Status: ' + str(self.status)
            self.finishButton.visible = False
        elif self.state is BoneThicknessMappingState.FINISHED:
            self.configuration_tools.enabled = False
            self.configuration_tools.collapsed = True
            self.progressBar.value = 100
            self.executeButton.visible = False
            self.finishButton.visible = True

    def update_results(self):
        if self.thicknessScalarArray is not None and self.airCellScalarArray is not None:
            self.resultSection.enabled = True
        else: self.resultSection.enabled = False

    def update_status(self, text=None, progress=None):
        if text is not None:
            print(text)
            self.status = str(text)
        if progress is not None:
            self.progress = progress
        self.update_all()
        slicer.app.processEvents()

    # interface click events ----------------------------------------------------------------------
    def click_input_selector(self):
        if self.volumeSelector.currentNode() is not None:
            BoneThicknessMappingLogic.update_input_volume(self.volumeSelector.currentNode().GetID())
        self.update_all()

    def click_execute(self):
        # TODO add try and catch
        if self.state is not BoneThicknessMappingState.READY: return
        self.state = BoneThicknessMappingState.EXECUTING
        self.update_status(text='Initializing execution..', progress=0)
        BoneThicknessMappingLogic.reset_view(self.CONFIG_rayCastAxis)
        BoneThicknessMappingLogic.clear_3d_view()
        BoneThicknessMappingLogic.set_scalar_colour_bar_state(0)
        self.modelPolyData, self.segmentationBounds = BoneThicknessMappingLogic.process_segmentation(
            threshold_range=self.CONFIG_segmentThresholdRange,
            image=self.volumeSelector.currentNode(),
            axis=self.CONFIG_rayCastAxis,
            update_status=self.update_status
        )
        self.topLayerPolyData, self.hitPointList = BoneThicknessMappingLogic.rainfall_quad_cast(
            poly_data=self.modelPolyData,
            seg_bounds=self.segmentationBounds,
            cast_axis=self.CONFIG_rayCastAxis,
            precision=self.CONFIG_precision,
            region_of_interest=self.CONFIG_regionOfInterest,
            update_status=self.update_status
        )
        self.modelNode = BoneThicknessMappingLogic.build_model(
            poly_data=self.topLayerPolyData,
            update_status=self.update_status
        )
        self.thicknessScalarArray, self.airCellScalarArray = BoneThicknessMappingLogic.ray_cast_color_thickness(
            poly_data=self.modelPolyData,
            hit_point_list=self.hitPointList,
            cast_axis=self.CONFIG_rayCastAxis,
            dimensions=self.volumeSelector.currentNode().GetImageData().GetDimensions(),
            mm_of_air_past_bone=self.CONFIG_mmOfAirPastBone,
            update_status=self.update_status
        )
        self.thicknessColourNode, self.airCellColourNode = BoneThicknessMappingLogic.build_color_table_nodes(
            minmax_thickness=self.CONFIG_minMaxSkullThickness,
            minmax_air_cell=self.CONFIG_minMaxAirCell
        )
        # finalize
        self.click_result_radio()
        self.state = BoneThicknessMappingState.FINISHED
        self.update_status(progress=100)

    def click_finish(self):
        self.state = BoneThicknessMappingState.WAITING
        self.update_all()

    def click_result_radio(self):
        if self.thicknessScalarArray is None or self.airCellScalarArray is None: return  # TODO add error message
        scalar, scalarName, colourNodeId = None, None, None
        if self.displayThicknessSelector.isChecked():
            scalar = self.thicknessScalarArray
            scalarName = BoneThicknessMappingType.THICKNESS
            colourNodeId = self.thicknessColourNode.GetID()
        elif self.displayFirstAirCellSelector.isChecked():
            scalar = self.airCellScalarArray
            scalarName = BoneThicknessMappingType.AIR_CELL
            colourNodeId = self.airCellColourNode.GetID()
        # update poly data
        self.topLayerPolyData.GetPointData().SetScalars(scalar)
        self.topLayerPolyData.Modified()
        # update display node
        displayNode = self.modelNode.GetDisplayNode()
        displayNode.SetActiveScalarName(scalarName)
        displayNode.SetAndObserveColorNodeID(colourNodeId)
        displayNode.ScalarVisibilityOn()
        displayNode.SetScalarRangeFlag(slicer.vtkMRMLDisplayNode.UseColorNodeScalarRange)
        # update scalar bar
        BoneThicknessMappingLogic.set_scalar_colour_bar_state(1, colourNodeId)
        # reset view
        # BoneThicknessMappingLogic.reset_view(self.CONFIG_rayCastAxis)

    def click_toggle_scalar_bar(self, state):
        if state == 0: BoneThicknessMappingLogic.set_scalar_colour_bar_state(0)
        elif state == 2:
            if self.displayThicknessSelector.isChecked(): BoneThicknessMappingLogic.set_scalar_colour_bar_state(1, self.thicknessColourNode)
            elif self.displayFirstAirCellSelector.isChecked(): BoneThicknessMappingLogic.set_scalar_colour_bar_state(1, self.airCellColourNode)

    def release_memory(self):

        # UI
        self.infoLabel = None
        self.volumeSelector = None
        self.configuration_tools = None
        self.statusLabel = None
        self.executeButton = None
        self.progressBar = None
        self.finishButton = None
        self.resultSection = None
        self.displayThicknessSelector = None
        self.displayFirstAirCellSelector = None
        self.displayScalarBarCheckbox = None

        # Config
        self.CONFIG_precision = None
        self.CONFIG_rayCastAxis = None
        self.CONFIG_segmentThresholdRange = None
        self.CONFIG_regionOfInterest = None
        self.CONFIG_minMaxAirCell = None
        self.CONFIG_minMaxSkullThickness = None
        self.CONFIG_mmOfAirPastBone = None

        # Data
        self.thicknessScalarArray, self.airCellScalarArray = None, None
        self.thicknessColourNode, self.airCellColourNode = None, None
        self.modelPolyData = None
        self.segmentationBounds = None
        self.topLayerPolyData = None
        self.hitPointList = None
        self.modelNode = None

class BoneThicknessMappingLogic(ScriptedLoadableModuleLogic):
    @staticmethod
    def update_input_volume(volume_id):
        for c in ['Red', 'Yellow', 'Green']:
            slicer.app.layoutManager().sliceWidget(c).sliceLogic().GetSliceCompositeNode().SetBackgroundVolumeID(volume_id)
        logic = slicer.app.layoutManager().mrmlSliceLogics()
        for i in range(logic.GetNumberOfItems()): logic.GetItemAsObject(i).FitSliceToAll()

    @staticmethod
    def reset_view(axis):
        m = slicer.app.layoutManager()
        m.setLayout(16)
        w = m.threeDWidget(0)
        w.threeDView().lookFromViewAxis(axis)
        w.threeDView().renderWindow().GetRenderers().GetFirstRenderer().ResetCamera()
        # c = w.threeDController()
        # for i in range(12): c.zoomIn()

    @staticmethod
    def clear_3d_view():
        for n in slicer.mrmlScene.GetNodesByClass("vtkMRMLModelNode"): n.GetDisplayNode().SetVisibility(0)
        for n in slicer.mrmlScene.GetNodesByClass("vtkMRMLSegmentationNode"): n.GetDisplayNode().SetVisibility(0)
        # hide 3D cube & labels
        v = slicer.util.getNode("View1")
        v.SetBoxVisible(False)
        v.SetAxisLabelsVisible(False)

    @staticmethod
    def process_segmentation(threshold_range, image, axis, update_status):
        # Fix Volume Orientation
        update_status(text="Rotating views to volume plane...", progress=2)
        manager = slicer.app.layoutManager()
        for name in manager.sliceViewNames():
            widget = manager.sliceWidget(name)
            node = widget.mrmlSliceNode()
            node.RotateToVolumePlane(image)

        # Create segmentation
        update_status(text="Creating segmentation...", progress=5)
        segmentationNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSegmentationNode")
        segmentationNode.CreateDefaultDisplayNodes()
        segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(image)
        segmentId = segmentationNode.GetSegmentation().AddEmptySegment("Bone")
        segmentationNode.GetSegmentation().GetSegment(segmentId).SetColor([0.9, 0.8, 0.7])

        # Create segment editor to get access to effects
        update_status(text="Starting segmentation editor...", progress=6)
        segmentEditorWidget = slicer.qMRMLSegmentEditorWidget()
        segmentEditorWidget.setMRMLScene(slicer.mrmlScene)
        segmentEditorNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSegmentEditorNode")
        segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode)
        segmentEditorWidget.setSegmentationNode(segmentationNode)
        segmentEditorWidget.setMasterVolumeNode(image)

        # Threshold
        update_status(text="Processing threshold segmentation...", progress=8)
        segmentEditorWidget.setActiveEffectByName("Threshold")
        effect = segmentEditorWidget.activeEffect()
        effect.setParameter("MinimumThreshold", str(threshold_range[0]))  # 1460 #1160 # 223
        effect.setParameter("MaximumThreshold", str(threshold_range[1]))
        effect.self().onApply()

        # Smoothing
        update_status(text="Processing smoothing segmentation...", progress=10)
        segmentEditorWidget.setActiveEffectByName("Smoothing")
        effect = segmentEditorWidget.activeEffect()
        effect.setParameter("SmoothingMethod", "MORPHOLOGICAL_OPENING")
        effect.setParameter("KernelSizeMm", 0.5)
        effect.self().onApply()

        # Islands
        update_status(text="Processing island segmentation...", progress=11)
        segmentEditorWidget.setActiveEffectByName("Islands")
        effect = segmentEditorWidget.activeEffect()
        effect.setParameter("Operation", "KEEP_LARGEST_ISLAND")
        effect.setParameter("MinimumSize", 1000)
        effect.self().onApply()

        # Crop
        # update_status("Cropping segmentation...")
        # segmentEditorWidget.setActiveEffectByName("Scissors")
        # effect = segmentEditorWidget.activeEffect()
        # effect.setParameter("MinimumThreshold", "223")
        # effect.setParameter("MaximumThreshold", "3071")
        # effect.self().onApply()

        # Clean up
        update_status(text="Cleaning up...", progress=13)
        segmentEditorWidget.setActiveEffectByName(None)
        slicer.mrmlScene.RemoveNode(segmentEditorNode)

        # Make segmentation results visible in 3D and set focal
        update_status(text="Rendering...", progress=15)
        segmentationNode.CreateClosedSurfaceRepresentation()
        BoneThicknessMappingLogic.reset_view(axis)

        # Retrieve segmentation bounds
        bounds = [0, 0, 0, 0, 0, 0]
        segmentationNode.GetBounds(bounds)

        # Make sure surface mesh cells are consistently oriented
        update_status(text="Retrieving surface mesh...", progress=18)
        if slicer.app.majorVersion == 4 and slicer.app.minorVersion <= 10:
            polyData = segmentationNode.GetClosedSurfaceRepresentation(segmentId)
        else:
            polyData = vtk.vtkPolyData()
            segmentationNode.GetClosedSurfaceRepresentation(segmentId, polyData)

        return polyData, bounds

    @staticmethod
    def determine_cast_axis_index(cast_axis):
        castIndex = None
        if cast_axis in [ctk.ctkAxesWidget.Right, ctk.ctkAxesWidget.Left]: castIndex = 0
        elif cast_axis in [ctk.ctkAxesWidget.Anterior, ctk.ctkAxesWidget.Posterior]: castIndex = 1
        elif cast_axis in [ctk.ctkAxesWidget.Superior, ctk.ctkAxesWidget.Inferior]: castIndex = 2
        return castIndex

    @staticmethod
    def rainfall_quad_cast(poly_data, seg_bounds, cast_axis, precision, region_of_interest, update_status):
        update_status(text="Building intersection object tree...", progress=41)
        bspTree = vtk.vtkModifiedBSPTree()
        bspTree.SetDataSet(poly_data)
        bspTree.BuildLocator()

        update_status(text="Calculating segmentation dimensions...", progress=42)
        negated = 1 if cast_axis in [ctk.ctkAxesWidget.Right, ctk.ctkAxesWidget.Anterior, ctk.ctkAxesWidget.Superior] else -1
        castIndex = BoneThicknessMappingLogic.determine_cast_axis_index(cast_axis)
        castVector = [0.0, 0.0, 0.0]
        castVector[castIndex] = 1.0 * negated
        castPlaneIndices = [0, 1, 2]
        castPlaneIndices.remove(castIndex)

        update_status(text="Calculating segmentation cast-plane...", progress=43)
        depthIncrements = [seg_bounds[castIndex], seg_bounds[castIndex+1]]
        if cast_axis in [ctk.ctkAxesWidget.Right, ctk.ctkAxesWidget.Posterior, ctk.ctkAxesWidget.Superior]: depthIncrements.reverse()
        horizontalIncrements = [seg_bounds[castPlaneIndices[0]*2], seg_bounds[castPlaneIndices[0]*2+1]]
        verticalIncrements = [seg_bounds[castPlaneIndices[1]*2],  seg_bounds[castPlaneIndices[1]*2+1]]
        castPlaneIncrements = [
            int(abs(horizontalIncrements[0] - horizontalIncrements[1])/precision),
            int(abs(verticalIncrements[0] - verticalIncrements[1])/precision),
        ]

        def build_ray(i, j):
            p1 = [None, None, None]
            p1[castIndex] = depthIncrements[0] + negated*100
            p1[castPlaneIndices[0]] = horizontalIncrements[0] + i*precision
            p1[castPlaneIndices[1]] = verticalIncrements[0] + j*precision
            p2 = p1[:]
            p2[castIndex] = depthIncrements[1] - negated*100
            return p1, p2

        # cast rays
        update_status(text="Casting " + str(int(castPlaneIncrements[0]*castPlaneIncrements[1])) + " rays...", progress=44)
        startTime = time.time()
        points, temporaryHitPoint = vtk.vtkPoints(), [0.0, 0.0, 0.0]
        hitPointMatrix = [[None for j in range(castPlaneIncrements[1])] for i in range(castPlaneIncrements[0])]
        for i in range(len(hitPointMatrix)):
            for j in range(len(hitPointMatrix[i])):
                start, end = build_ray(i, j)
                res = bspTree.IntersectWithLine(start, end, 0, vtk.reference(0), temporaryHitPoint, [0.0, 0.0, 0.0], vtk.reference(0), vtk.reference(0))
                # if hit is found, and the top hitpoint is within ROI bounds
                if res != 0 and region_of_interest[0] <= temporaryHitPoint[castIndex] < region_of_interest[1]:
                    temporaryHitPoint[castIndex] += 0.3 * negated  # raised to improve visibility
                    hitPointMatrix[i][j] = HitPoint(points.InsertNextPoint(temporaryHitPoint), temporaryHitPoint[:])

        # form quads/cells
        update_status(text="Forming top layer polygons", progress=64)
        cells = vtk.vtkCellArray()
        for i in range(len(hitPointMatrix)-1):  # -1 as the end row/col will be taken into account
            for j in range(len(hitPointMatrix[i])-1):
                hitPoints = [hitPointMatrix[i][j], hitPointMatrix[i+1][j], hitPointMatrix[i+1][j+1], hitPointMatrix[i][j+1]]
                # check if full quad
                if None in hitPoints: continue
                # check if area is not extremely large
                d1 = numpy.linalg.norm(numpy.array(hitPoints[0].point)-numpy.array(hitPoints[1].point))
                d2 = numpy.linalg.norm(numpy.array(hitPoints[0].point)-numpy.array(hitPoints[2].point))
                d3 = numpy.linalg.norm(numpy.array(hitPoints[0].point)-numpy.array(hitPoints[3].point))
                m = precision*6
                if d1 > m or d2 > m or d3 > m: continue
                # calculate normals
                rawNormal = numpy.linalg.solve(numpy.array([hitPoints[0].point, hitPoints[1].point, hitPoints[2].point]), [1, 1, 1])
                hitPointMatrix[i][j].normal = rawNormal / numpy.sqrt(numpy.sum(rawNormal**2))
                # # check if quad is acceptable by normal vs. cast vector
                # v1, v2 = numpy.array(hitPointMatrix[i][j].normal), numpy.array(castVector)
                # degrees = numpy.degrees(numpy.math.atan2(numpy.cross(v1, v2).shape[0], numpy.dot(v1, v2)))
                cells.InsertNextCell(4, [p.pid for p in hitPoints])
        update_status(text="Finished ray-casting in " + str("%.1f" % (time.time() - startTime)) + "s, found " + str(cells.GetNumberOfCells()) + " cells...", progress=80)

        # build poly data
        topLayerPolyData = vtk.vtkPolyData()
        topLayerPolyData.SetPoints(points)
        topLayerPolyData.SetPolys(cells)
        topLayerPolyData.Modified()
        return topLayerPolyData, [p for d0 in hitPointMatrix for p in d0 if p is not None]

    @staticmethod
    def build_model(poly_data, update_status):
        update_status(text="Rendering top layer...", progress=20)
        modelNode = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLModelNode')
        modelNode.SetAndObservePolyData(poly_data)
        modelNode.CreateDefaultDisplayNodes()
        modelDisplayNode = modelNode.GetModelDisplayNode()
        modelDisplayNode.SetFrontfaceCulling(0)
        modelDisplayNode.SetBackfaceCulling(0)
        update_status(text="Top layer rendered...", progress=40)
        return modelNode

    @staticmethod
    def ray_cast_color_thickness(poly_data, hit_point_list, cast_axis, dimensions, mm_of_air_past_bone, update_status, gradient_scale_factor=10.0):
        # ray direction cast axis index
        castIndex = BoneThicknessMappingLogic.determine_cast_axis_index(cast_axis)

        update_status(text="Building static cell locator...", progress=81)
        cellLocator = vtk.vtkStaticCellLocator()
        cellLocator.SetDataSet(poly_data)
        cellLocator.BuildLocator()

        total = len(hit_point_list)
        update_status(text="Calculating thickness (may take long, " + str(total) + " rays)...", progress=82)
        startTime = time.time()

        def init_array(name):
            a = vtk.vtkFloatArray()
            a.SetName(name)
            return a

        def interpret_distance(points):
            firstIn, lastOut = points[0], points[1]
            if len(points) > 2:
                for inOutPair in zip(*[iter(points[2:])] * 2):
                    # TODO incorporate cast bounds
                    # if newIn[1][cast_axis] < minBound and newOut[1][cast_axis] < minBound
                    if calculate_distance(lastOut[1], inOutPair[0][1]) < mm_of_air_past_bone*gradient_scale_factor: lastOut = inOutPair[1]
                return calculate_distance(firstIn[1], lastOut[1])
            else:
                return calculate_distance(firstIn[1], points[-1][1])

        def calculate_distance(point1, point2):
            d = numpy.linalg.norm(numpy.array((point1[0], point1[1], point1[2])) - numpy.array((point2[0], point2[1], point2[2])))
            d = d*gradient_scale_factor
            return d

        skullThicknessArray, airCellDistanceArray = init_array(BoneThicknessMappingType.THICKNESS), init_array(BoneThicknessMappingType.AIR_CELL)
        tol, pCoords, subId = 0.000, [0, 0, 0], vtk.reference(0)
        pointsOfIntersection, cellsOfIntersection = vtk.vtkPoints(), vtk.vtkIdList()
        for i, hitPoint in enumerate(hit_point_list):
            stretchFactor = dimensions[castIndex]
            start = [hitPoint.point[0] + hitPoint.normal[0]*stretchFactor, hitPoint.point[1] + hitPoint.normal[1]*stretchFactor, hitPoint.point[2] + hitPoint.normal[2]*stretchFactor]
            end = [hitPoint.point[0] - hitPoint.normal[0]*stretchFactor, hitPoint.point[1] - hitPoint.normal[1]*stretchFactor, hitPoint.point[2] - hitPoint.normal[2]*stretchFactor]
            cellLocator.FindCellsAlongLine(start, end, tol, cellsOfIntersection)
            distances = []
            for cellIndex in range(cellsOfIntersection.GetNumberOfIds()):
                t = vtk.reference(0.0)
                p = [0.0, 0.0, 0.0]
                if poly_data.GetCell(cellsOfIntersection.GetId(cellIndex)).IntersectWithLine(start, end, tol, t, p, pCoords, subId) and 0.0 <= t <= 1.0:
                    distances.append([t, p])
            if len(distances) >= 2:
                distances = sorted(distances, key=lambda kv: kv[0])
                skullThicknessArray.InsertTuple1(hitPoint.pid, interpret_distance(distances))
                airCellDistanceArray.InsertTuple1(hitPoint.pid, calculate_distance(distances[0][1], distances[1][1]))
            else:
                skullThicknessArray.InsertTuple1(hitPoint.pid, 0)
                airCellDistanceArray.InsertTuple1(hitPoint.pid, 0)
            # update rays casted status
            if i % 200 == 0: update_status(text=f"Calculating thickness (~{i} of {total} rays)", progress=82 + int(round((i*1.0/total*1.0)*18.0)))
        update_status(text="Finished thickness calculation in " + str("%.1f" % (time.time() - startTime)) + "s...", progress=100)
        return skullThicknessArray, airCellDistanceArray

    @staticmethod
    def build_color_table_node(name, table_max):
        table = slicer.vtkMRMLColorTableNode()
        table.SetName(name)
        table.SetHideFromEditors(0)
        table.SetTypeToFile()
        table.NamesInitialisedOff()
        table.SetNumberOfColors(table_max)
        table.GetLookupTable().SetTableRange(0, table_max)
        table.NamesInitialisedOn()
        slicer.mrmlScene.AddNode(table)
        return table

    @staticmethod
    def build_color_table_nodes(minmax_thickness, minmax_air_cell, gradient_scale_factor=10.0):
        print(minmax_air_cell)

        def calculate_and_set_colour(table, index, hue=0.0, sat=1.0, val=1.0):
            rgb = colorsys.hsv_to_rgb(hue, sat, val)
            table.SetColor(index, str(index/gradient_scale_factor) + ' mm', rgb[0], rgb[1], rgb[2], 1.0)

        def p(lhs, rhs, base, right_mod=1.0):
            return float(lhs-base)/float((rhs-base)*right_mod)

        # thickness table
        ix = [int(i) for i in [minmax_thickness[0]*gradient_scale_factor, (minmax_thickness[1])*gradient_scale_factor + 1]]
        thicknessTableNode = BoneThicknessMappingLogic.build_color_table_node('ThicknessColorMap', ix[-1])
        for i in range(ix[0], ix[-1]): calculate_and_set_colour(thicknessTableNode, i, hue=p(i, ix[-1], ix[0]) * 0.278, sat=0.9, val=0.9)

        # air cell table
        iy = [int(i) for i in [minmax_air_cell[0]*gradient_scale_factor, (minmax_air_cell[1])*gradient_scale_factor + 1]]
        airCellTableNode = BoneThicknessMappingLogic.build_color_table_node('AirCellColorMap', iy[-1])
        for i in range(iy[0], iy[-1]): calculate_and_set_colour(airCellTableNode, i, hue=0.696 - p(i, iy[-1], iy[0]) * 0.571, sat=0.9, val=0.9)

        return thicknessTableNode, airCellTableNode

    @staticmethod
    def set_scalar_colour_bar_state(state, color_node_id=None):
        colorWidget = slicer.modules.colors.widgetRepresentation()
        ctkBar = slicer.util.findChildren(colorWidget, name='VTKScalarBar')[0]
        ctkBar.setDisplay(state)
        if state == 0 or color_node_id is None: return
        slicer.util.findChildren(colorWidget, 'ColorTableComboBox')[0].setCurrentNodeID(color_node_id)
        slicer.util.findChildren(colorWidget, 'UseColorNameAsLabelCheckBox')[0].setChecked(True)


import math

def insertionSort(arr,e):
    arr.append(e)
    for i in range(1, len(arr)):
        key = arr[i]
        j = i-1
        while j >= 0 and key < arr[j] :
                arr[j + 1] = arr[j]
                j -= 1
        arr[j + 1] = key
    return arr

table={}

def median(arr,Q):#this function returns the sorted array
    #using DP to get the sorted array using recursive equation[  table[i,j]=insertionSort(table[i,j-1],arr[j]) ]
    l,r=Q
    try:
        return table[(l,r)]
    except:
        if(l==r):
            table[(l,r)]=[arr[l]]
            return [arr[l]]
        if(r<l):
            return "Error"
        else:
            table[(l,r)]=insertionSort(median(arr,(l,r-1)),arr[r])
    return table[(l,r)]

arr=[1,7,5,6,4,8,2,10,11,15,20,18,19,23,24,25,26,27,28,30,3,5,6,7,8]
Q=[(0,5),(4,6),(0,7),(2,6),(4,15)]

for i in Q:
    res=median(arr,i)
    print(res)#sorted array
    print(res[math.ceil(len(res)/2)-1])#median


'''
Created on Jan 28, 2017

@author: Angel
'''
import pandas as pd
import scipy.stats

path = r'C:\Users\angelddaz\OneDrive\Documents\data_training\data\RawDelData.csv'
data = pd.read_csv(path)

aDels = data.loc[data['PersonWhoDelivered']=='Angel'][['Tip']]
sDels = data.loc[data['PersonWhoDelivered']=='Sammie'][['Tip']]
bDels = aDels+sDels

#variables
mu_a = aDels.mean()
mu_s = sDels.mean()
sigma_a = aDels.std()
sigma_s = sDels.std()
variance_a = aDels.std() * aDels.std()
variance_s = sDels.std() * sDels.std()
n_a = aDels.count()
n_s = sDels.count()

X_a = 3 #value of a
X_s = 3
z_a = (X_a-mu_a)/sigma_a
z_s = (X_s-mu_s)/sigma_s
pval_a = scipy.stats.norm.sf(z_a)
pval_s = scipy.stats.norm.sf(z_s)

print("The probability that I receive a tip larger than %1.0f is %1.4f" % (X_a, pval_a))
print("The probability that Sam receives a tip larger than %1.0f is %1.4f" % (X_a, pval_a))

#What about low tips. 1 dollar or lower?
X_a = 1 #value of a
X_s = 1
z_a = (X_a-mu_a)/sigma_a
z_s = (X_s-mu_s)/sigma_s

pval_a = 1 - scipy.stats.norm.sf(z_a)
pval_s = 1 - scipy.stats.norm.sf(z_s)
print
print("The probability that I receive a tip less than %1.0f is %1.4f" % (X_a, pval_a))
print("The probability that Sam receives a tip less than %1.0f is %1.4f" % (X_a, pval_a))


import random
import math
from argparse import ArgumentParser
from typing import Tuple, List

from problem import Problem
from utils import re_float_fixed

class TriangularPrism(Problem):
    def __init__(
        self,
        assignment_path: str = "Assignment 1",
        student_path: str = None,
        excluded_students: List[str] = [],
        checkpoints_number: int = 20,
        generate_checkpoints: bool = True,
        compile: bool = True,
        run_checkpoints: bool = True,
        judge: bool = True,
    ):
        super().__init__(
            assignment_path,
            problem_name="2",  # name of source file: 2.cpp
            student_path=student_path,
            excluded_students=excluded_students,
            checkpoints_number=checkpoints_number,
            generate_checkpoints=generate_checkpoints,
            compile=compile,
            run_checkpoints=run_checkpoints,
            judge=judge,
        )

    def _generate_input(self, index) -> str:
        a = random.randint(0, 100000) / 1000
        h = random.randint(0, 100000) / 1000

        input_content = f"{a} {h}\n"

        return input_content

    def _compute(self, input_content: str) -> str:
        input_tokens = input_content.split()
        a, h = [float(token) for token in input_tokens]

        surface_area = 3 * a * h + math.sqrt(3) * a**2 / 2
        volume = math.sqrt(3) * h * a**2 / 4

        res = f"{surface_area:.3f} {volume:.3f}\n"

        return res

    def _judge_1_checkpoint(
        self, output_file_name, answer_file_name
    ) -> Tuple[int, int]:
        with open(answer_file_name, "r") as f_ans:
            standard_answers = []
            for line in f_ans.readlines():
                standard_answers.extend(re_float_fixed.findall(line))

        with open(output_file_name, "r") as f_out:
            answers = []
            for line in f_out.readlines():
                answers.extend(re_float_fixed.findall(line))

        correct, total = 0, len(standard_answers)
        for standard_answer, answer in zip(standard_answers, answers):
            standard_answer = float(standard_answer)
            answer = float(answer)
            if abs(answer - standard_answer) < 1e-3 * abs(standard_answer):
                correct += 1
        return correct, total

if __name__ == "__main__":
    parser = ArgumentParser()
    parser.add_argument("-s", "--student_path", type=str, default=None)
    parser.add_argument("-e", "--exclude_students", type=str, default=[], nargs="*")
    parser.add_argument("-g", "--generate_checkpoints", action="store_true")
    parser.add_argument("-c", "--compile", action="store_true")
    parser.add_argument("-r", "--run_checkpoints", action="store_true")
    parser.add_argument("-j", "--judge", action="store_true")
    args = parser.parse_args()

    triangular_prism = TriangularPrism(
        student_path=args.student_path,
        excluded_students=args.exclude_students,
        generate_checkpoints=args.generate_checkpoints,
        compile=args.compile,
        run_checkpoints=args.run_checkpoints,
        judge=args.judge,
    )


import sys
sys.stdin = open('15649_input.txt')

def perm(n, r, k):
    if k == r:
        for i in range(M):
            print(p[i], end=' ')
        print()
        return
    else:
        for i in range(N):
            if used[i] == 0:
                p[k] = arr[i]
                used[i] = 1
                perm(n, r, k + 1)
                used[i] = 0

N, M = map(int, input().split())
arr = list(range(1, N+1))
p = [0] * M
used = [0] * N
perm(N, M, 0)


#!/usr/bin/env python3

import os
import re
import sys
import copy
import math
import numpy
import string
import random
import crcmod.predefined

debug = False

phenotype_dict = {
	'a': 'amber',
	'b': 'bald',
	'c': 'conehead',
	'd': 'dumpy',
	'e': 'eyeless',
	'f': 'forked',
	'g': 'garnet',
	'h': 'hook',
	'i': 'indy',
	'j': 'jagged',
	'k': 'kidney',
	'l': 'lyra',
	'm': 'marula',
	'n': 'notch',
	'o': 'okra',
	'p': 'prickly',
	'q': 'quick',
	'r': 'rosy',
	's': 'scute',
	't': 'taxi',
	'u': 'upturned',
	'v': 'vestigial',
	'w': 'white',
	'x': 'xray',
	'y': 'yellow',
	'z': 'zipper',
}

def invertType(genotype, basetype):
	newtype = ''
	for i in range(3):
		if genotype[i] == '+':
			newtype += basetype[i]
		else:
			newtype += '+'
	return newtype

def flipGene(genotype, gene, basetype):
	newlist = list(genotype)
	for i in range(3):
		if basetype[i] == gene:
			if genotype[i] == '+':
				newlist[i] = basetype[i]
			else:
				newlist[i] = '+'
	newtype = ""
	for i in newlist:
		newtype += i
	return newtype

def getGeneOrder(basetype):
	basetype2 = basetype[0]+basetype[2]+basetype[1]
	basetype3 = basetype[1]+basetype[0]+basetype[2]

	#gene order
	if debug is True: print("selecting gene order")
	geneorder = random.choice([basetype, basetype2, basetype3])
	if debug is True: print(geneorder)
	return geneorder

def getDistances():
	#integers
	key_maps = {
		35:	[10, 20, 30, 40, ],
		30:	[ 5, 10, 15, 20, 25, 35,],
		25:	[ 2,  4,  6,  8, 12, 14, 16, 18, 22,],
		20:	[ 5, 10, 15, 25, 30, 35,],
		15:	[10, 20, 30, 40, ],
		10:	[ 5, 15, 20, 25, 30, 35,],
		5:	[10, 20, 30, 40, ],
	}
	#a = random.choice(list(key_maps.keys()))
	#b = random.choice(key_maps[a])
	a = random.randint(15,35)
	b = random.randint(2,a-2)
	if a == b:
		print("ERROR")
		sys.exit(1)
	if debug is True: print("determine gene distances")
	distances = [a, b]
	random.shuffle(distances)
	distance3 = int(distances[0] + distances[1] - (distances[0] * distances[1])/50)
	distances.append(distance3)
	if debug is True: print(distances)
	return distances

def getDistancesOriginal():
	if debug is True: print("determine gene distances")
	a = numpy.random.poisson(lam=12, size=7)
	a.sort()
	distances = [a[0], a[-1]]
	random.shuffle(distances)
	distance3 = distances[0] + distances[1] - (distances[0] * distances[1])/50.
	distances.append(distance3)
	if debug is True: print(distances)
	return distances

def getProgenySize(distances):
	if debug is True: print("determine progeny size")
	gcd1 = math.gcd(distances[0], 100)
	gcd2 = math.gcd(distances[1], 100)
	gcdfinal = math.gcd(gcd1, gcd2)
	if debug is True: print("Final GCD", gcdfinal)
	progenybase = 100/gcdfinal
	minprogeny =  900/progenybase
	maxprogeny = 6000/progenybase
	progs = numpy.arange(minprogeny, maxprogeny+1, 1, dtype=numpy.float64)*progenybase
	#print(progs)
	numpy.random.shuffle(progs)
	#print(progs)
	bases = progs * distances[0] * distances[1] / 1e4
	#print(bases)
	devs = (bases - numpy.around(bases, 0))**2
	#print(devs)
	argmin = numpy.argmin(devs)
	progeny_size = int(progs[argmin])
	if debug is True: print(("total progeny: %d\n"%(progeny_size)))
	return progeny_size

def getPhenotype(genotype):
	if genotype == "+++":
		return 'wildtype'
	phenotype_list = []
	for allele in genotype:
		if allele == '+':
			continue
		phenotype = phenotype_dict.get(allele)
		phenotype_list.append(phenotype)
	#print(phenotype_list)
	phenotype_string = ', '.join(phenotype_list)
	return phenotype_string

def makeProgenyHtmlTable(typemap, progeny_size):
	alltypes = list(typemap.keys())
	alltypes.sort()
	td_extra = 'align="center" style="border: 1px solid black;"'
	span = ''
	table = '
'
	table += '
'
	table += '  {1}Phenotype	'.format(td_extra, span)
	table += '  {1}Genotypes	'.format(td_extra, span)
	table += '  {1}Progeny
Count	'.format(td_extra, span)
	table += '
'
	for type in alltypes:
		phenotype_string = getPhenotype(type)
		table += '
'
		table += '  {1}{2}	'.format(td_extra.replace('center', 'left'), span, phenotype_string)
		table += ' {1}{2}	'.format(td_extra, span, type[0])
		table += ' {1}{2}	'.format(td_extra, span, type[1])
		table += ' {1}{2}	'.format(td_extra, span, type[2])
		table += ' {1}{2:d}	'.format(td_extra.replace('center', 'right'), span, typemap[type])
		table += '
'
	table += '
'
	table += '  {1}TOTAL =	'.format(td_extra.replace('center', 'right'), span)
	table += '  {1}{2:d}	'.format(td_extra.replace('center', 'right'), span, progeny_size)
	table += '
'
	table += '
'
	return table

def makeProgenyAsciiTable(typemap, progeny_size):
	alltypes = list(typemap.keys())
	alltypes.sort()
	table = ''
	for type in alltypes:
		phenotype_string = getPhenotype(type)
		table += ("{0}\t".format(type[0]))
		table += ("{0}\t".format(type[1]))
		table += ("{0}\t".format(type[2]))
		table += ("{0:d}\t".format(typemap[type]))
		table += ("{0}\t".format(phenotype_string))
		table += "\n"
	table +=  "\t\t\t-----\n"
	table +=  "\t\tTOTAL\t%d\n\n"%(progeny_size)
	return table

def generateProgenyData(types, type_counts, basetype):
	if debug is True: print("\n\ngenerate progeny data")
	typemap = {}
	for t in types:
		n = invertType(t, basetype)
		#rand = random.gauss(0.5, 0.01)
		try:
			count = type_counts[t]
		except KeyError:
			count = type_counts[n]
		tcount = 0
		ncount = 0
		for i in range(count):
			if random.random() > 0.5:
				tcount += 1
			else:
				ncount += 1
		sys.stderr.write(".")
		#typemap[t] = int(rand * count)
		#typemap[n] = count - typemap[t]
		typemap[t] = tcount
		typemap[n] = ncount
	sys.stderr.write("\n")
	return typemap

def generateTypeCounts(parental, doublecross, basetype):
	type_counts = {}
	if debug is True: print("determine double type")
	doubletype = flipGene(parental, geneorder[1], basetype)
	doublecount = int(round(doublecross*progeny_size/100.))
	if debug is True: print("  ", doubletype, invertType(doubletype, basetype), doublecount)
	type_counts[doubletype] = doublecount

	if debug is True: print("determine first flip")
	firsttype = flipGene(parental, geneorder[0], basetype)
	firstcount = int(round(distances[0]*progeny_size/100.)) - doublecount
	if debug is True: print("  ", firsttype, invertType(firsttype, basetype), firstcount)
	type_counts[firsttype] = firstcount

	if debug is True: print("determine second flip")
	secondtype = flipGene(parental, geneorder[2], basetype)
	secondcount = int(round(distances[1]*progeny_size/100.)) - doublecount
	if debug is True: print("  ", secondtype, invertType(secondtype, basetype), secondcount)
	type_counts[secondtype] = secondcount

	if debug is True: print("determine parental type count")
	parentcount = progeny_size - doublecount - firstcount - secondcount
	if debug is True: print("  ", parental, invertType(parental, basetype), parentcount)
	type_counts[parental] = parentcount

	return type_counts

def makeQuestion(basetype, geneorder, distances, progeny_size):
	if debug is True: print("------------")
	answerString = ("%s - %d - %s - %d - %s"
		%(geneorder[0], distances[0], geneorder[1], distances[1], geneorder[2]))
	print(answerString)
	if debug is True: print("------------")

	if debug is True: print("determine double crossovers")
	doublecross = distances[0]*distances[1]/100.
	if debug is True: print("doublecross", doublecross*10, 'per 1000')

	if debug is True: print("determine parental type")
	types = ['+++', '++'+basetype[2], '+'+basetype[1]+'+', '+'+basetype[1]+basetype[2]]
	parental = random.choice(types)
	if debug is True: print("  ", parental, invertType(parental, basetype))
	type_counts = generateTypeCounts(parental, doublecross, basetype)
	typemap = generateProgenyData(types, type_counts, basetype)
	return typemap

def questionText(basetype):
	question_string = '
Three-Point Test-Cross Gene Mapping
'
	question_string += '
A test-cross with a heterozygote fruit fly for three genes is conducted. '
	question_string += 'The resulting phenotypes are summarized in the table above.
 '
	question_string += '
Using the table above, determine the order of the genes and the distances between them. '
	question_string += 'Once calculated, fill in the following four blanks:

'
	question_string += '
The distance between genes {0} and {1} is [{0}{1}] cM ({0}{1})
'.format(basetype[0].upper(),basetype[1].upper())
	question_string += '
The distance between genes {0} and {1} is [{0}{1}] cM ({0}{1})
'.format(basetype[0].upper(),basetype[2].upper())
	question_string += '
The distance between genes {0} and {1} is [{0}{1}] cM ({0}{1})
'.format(basetype[1].upper(),basetype[2].upper())
	question_string += '
From this the correct order of the genes is [geneorder] (gene order).

'
	question_string += '
Hint 1: ALL gene distances will be whole numbers, '
	question_string += 'do NOT enter a decimal; if you have a decimal your calculations are wrong.
'
	question_string += '
Hint 2: enter your answer in the blank using only letters or numbers '
	question_string += ' with no spaces or commas. Also, do NOT add units, e.g. cM or m.u.
'
	return question_string

def getVariables(basetype):
	variable_list = []
	if basetype[0] < basetype[1]:
		variable = '{0}{1}'.format(basetype[0].upper(),basetype[1].upper())
	else:
		variable = '{0}{1}'.format(basetype[1].upper(),basetype[0].upper())
	variable_list.append(variable)
	if basetype[1] < basetype[2]:
		variable = '{0}{1}'.format(basetype[1].upper(),basetype[2].upper())
	else:
		variable = '{0}{1}'.format(basetype[2].upper(),basetype[1].upper())
	variable_list.append(variable)
	if basetype[0] < basetype[2]:
		variable = '{0}{1}'.format(basetype[0].upper(),basetype[2].upper())
	else:
		variable = '{0}{1}'.format(basetype[2].upper(),basetype[0].upper())
	variable_list.append(variable)
	variable = 'geneorder'
	variable_list.append(variable)
	return variable_list

#=======================
def getCrc16_FromString(mystr):
	crc16 = crcmod.predefined.Crc('xmodem')
	crc16.update(mystr.encode('ascii'))
	return crc16.hexdigest().lower()

#=====================
def makeQuestionPretty(question):
	pretty_question = copy.copy(question)
	#print(len(pretty_question))
	pretty_question = re.sub('\<table.+\<\/table\>', '[]\n', pretty_question)
	#print(len(pretty_question))
	pretty_question = re.sub('\<\/p\>\s*\
', '\n', pretty_question)
	#print(len(pretty_question))
	return pretty_question

#=====================
def formatBB_FIB_PLUS_Question(N, question, variable_list, geneorder, distances):
	number = "{0}. ".format(N)
	crc16 = getCrc16_FromString(question)

	#FIB_PLUS TAB question text TAB variable1 TAB answer1 TAB answer2 TAB TAB variable2 TAB answer3
	bb_question = 'FIB_PLUS\t
{0}. {1}
 {2}'.format(N, crc16, question)
	pretty_question = makeQuestionPretty(question)
	print('{0}. {1} -- {2}'.format(N, crc16, pretty_question))

	variable_to_distance = {}
	for i in range(len(variable_list)-1):
		variable_to_distance[variable_list[i]] = distances[i]
	variable_list.sort()
	for i in range(len(variable_list)-1):
		variable = variable_list[i]
		bb_question += '\t{0}\t{1}\t'.format(variable, variable_to_distance[variable])
	bb_question += '\tgeneorder\t{0}\t{1}'.format(geneorder, geneorder[::-1])
	bb_question += '\n'
	return bb_question

#=====================
#=====================
if __name__ == "__main__":
	lowercase = "abcdefghijklmnpqrsuvwxyz"

	outfile = 'bbq-' + os.path.splitext(os.path.basename(__file__))[0] + '-questions.txt'
	print('writing to file: '+outfile)
	f = open(outfile, 'w')
	duplicates = 1
	j = -1
	N = 0
	for i in range(duplicates):
		N += 1
		j += 1
		if j + 2 == len(lowercase):
			j = 0
		basetype = lowercase[j:j+3]
		geneorder = getGeneOrder(basetype)
		distances = getDistances()
		print(distances)
		progeny_size = getProgenySize(distances)
		typemap = makeQuestion(basetype, geneorder, distances, progeny_size)
		ascii_table = makeProgenyAsciiTable(typemap, progeny_size)
		print(ascii_table)
		html_table = makeProgenyHtmlTable(typemap, progeny_size)
		#print(html_table)
		question_string = questionText(basetype)
		variable_list = getVariables(geneorder)
		complete_question = html_table + question_string
		final_question = formatBB_FIB_PLUS_Question(N, complete_question, variable_list, geneorder, distances)
		#print(final_question)

		f.write(final_question)
	f.close()

#THE END


# -*- coding: utf-8 -*-
from django.db import IntegrityError
from django.db import transaction

from console.models.main import AutoscalerRules
from console.repositories.autoscaler_repo import autoscaler_rule_metrics_repo
from console.repositories.autoscaler_repo import autoscaler_rules_repo
from console.services.exception import ErrAutoscalerRuleNotFound
from console.services.exception import ErrDuplicateMetrics
from www.apiclient.regionapi import RegionInvokeApi
from www.utils.crypt import make_uuid

region_api = RegionInvokeApi()

class AutoscalerService(object):
    def get_by_rule_id(self, rule_id):
        try:
            rule = autoscaler_rules_repo.get_by_rule_id(rule_id)
            metrics = autoscaler_rule_metrics_repo.list_by_rule_ids([rule.rule_id])

            res = rule.to_dict()
            res["metrics"] = [m.to_dict() for m in metrics]
            return res
        except AutoscalerRules.DoesNotExist:
            raise ErrAutoscalerRuleNotFound

    def list_autoscaler_rules(self, service_id):
        rules = autoscaler_rules_repo.list_by_service_id(service_id)
        rule_ids = [rule.rule_id for rule in rules]

        metrics = autoscaler_rule_metrics_repo.list_by_rule_ids(rule_ids)
        # rule to metrics
        r2m = {}
        for metric in metrics:
            metric = metric.to_dict()
            if r2m.get(metric["rule_id"], None) is None:
                r2m[metric["rule_id"]] = [metric]
            else:
                r2m[metric["rule_id"]].append(metric)

        res = []
        for rule in rules:
            r = rule.to_dict()
            r["metrics"] = []
            if r2m.get(rule.rule_id, None) is not None:
                m = r2m[rule.rule_id]
                r["metrics"] = m
            res.append(r)

        return res

    @transaction.atomic
    def create_autoscaler_rule(self, region_name, tenant_name, service_alias, data):
        # create autoscaler rule
        autoscaler_rule = {
            "rule_id": make_uuid(),
            "service_id": data["service_id"],
            "xpa_type": data["xpa_type"],
            "enable": data["enable"],
            "min_replicas": data["min_replicas"],
            "max_replicas": data["max_replicas"],
        }
        autoscaler_rules_repo.create(**autoscaler_rule)

        # create autoscaler rule metrics
        metrics = []
        for metric in data["metrics"]:
            metrics.append({
                "rule_id": autoscaler_rule["rule_id"],
                "metric_type": metric["metric_type"],
                "metric_name": metric["metric_name"],
                "metric_target_type": metric["metric_target_type"],
                "metric_target_value": metric["metric_target_value"],
            })

        try:
            autoscaler_rule_metrics_repo.bulk_create(metrics)
        except IntegrityError:
            raise ErrDuplicateMetrics

        autoscaler_rule["metrics"] = metrics

        region_api.create_xpa_rule(region_name, tenant_name, service_alias, data=autoscaler_rule)

        return autoscaler_rule

    @transaction.atomic
    def update_autoscaler_rule(self, region_name, tenant_name, service_alias, rule_id, data, user_name=''):
        # create autoscaler rule
        autoscaler_rule = {
            "xpa_type": data["xpa_type"],
            "enable": data["enable"],
            "min_replicas": data["min_replicas"],
            "max_replicas": data["max_replicas"],
        }
        try:
            autoscaler_rule = autoscaler_rules_repo.update(rule_id, **autoscaler_rule)
        except AutoscalerRules.DoesNotExist:
            raise ErrAutoscalerRuleNotFound
        autoscaler_rule = autoscaler_rule.to_dict()

        # delete old autoscaler rule metrics
        autoscaler_rule_metrics_repo.delete_by_rule_id(rule_id)
        # create new ones
        metrics = []
        for metric in data["metrics"]:
            metrics.append({
                "rule_id": autoscaler_rule["rule_id"],
                "metric_type": metric["metric_type"],
                "metric_name": metric["metric_name"],
                "metric_target_type": metric["metric_target_type"],
                "metric_target_value": metric["metric_target_value"],
            })

        try:
            autoscaler_rule_metrics_repo.bulk_create(metrics)
        except IntegrityError:
            raise ErrDuplicateMetrics

        autoscaler_rule["metrics"] = metrics
        autoscaler_rule["operator"] = user_name

        region_api.update_xpa_rule(region_name, tenant_name, service_alias, data=autoscaler_rule)

        return autoscaler_rule

    @transaction.atomic
    def delete_autoscaler_rule(self, region_name, tenant_name, service_alias, rule_id):
        try:
            autoscaler_rule = autoscaler_rules_repo.delete(rule_id)
        except AutoscalerRules.DoesNotExist:
            raise ErrAutoscalerRuleNotFound
        autoscaler_rule = autoscaler_rule.to_dict()

class ScalingRecordsService(object):
    def list_scaling_records(self, region_name, tenant_name, service_alias, page=None, page_size=None):
        body = region_api.list_scaling_records(region_name, tenant_name, service_alias, page, page_size)
        return body["bean"]

autoscaler_service = AutoscalerService()
scaling_records_service = ScalingRecordsService()


#coding:UTF-8
from scrapy.selector import HtmlXPathSelector
from scrapy.spider import BaseSpider
from photo.items import TotalItem
from scrapy.http import Request
from scrapy import log
import urllib
class PhotoSpider(BaseSpider):
    name="photo"
    allowed_domains=["ileehoo.com"]
    start_urls=["http://hzp.ileehoo.com/brand/B_0_1.html"]
    set_url=[]
    def mm(self):
       string_url=[]
       string_a="http://hzp.ileehoo.com/brand/"
       string_b="_0_1.html#searchbrandlist"
       list_a=['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
       for letter in list_a:
           string_c=string_a+letter+string_b
           string_url.append(string_c)
       (self.set_url).extend(string_url)
       return string_url
    def nn(self,response):
        hxs=HtmlXPathSelector(response)
        for letter in self.mm():
            log.err("===========================")
            yield Request(letter,callback=self.kaka)

    def kaka(self,response):
        total=TotalItem()
       # image=ImageItem()
        hxs=HtmlXPathSelector(response)
        for letter in hxs.select("//div[@class='con']/div[@class='listimg']"):
            total_china=letter.select("./div[@class='tit']/a[1]/text()").extract()
            total['china']=total_china[0].strip(" ")
            total_english=letter.select("./div[@class='tit']/a[2]/text()").extract()
            total['english']=total_english[0].strip(" ")
            total_hold=letter.select("./div[@class='lis']/span[3]/text()").extract()
            total['hold']=total_hold[0]
            total_src=letter.select("./div[@class='']/a/img/@src").extract()
            total['src']=total_src[0]
            total['name']=total['china']+".jpg"
         #  image['url']=letter.select("./div[@class='']/a/img/@src")
         #  for letter_a in total['src']:
            path="/dir/image/"+total['name']
            urllib.urlretrieve(total['src'],path)
            yield total
        newurl=hxs.select("//div[@class='page']/a/@href").extract()
        if newurl:
            for letter in newurl:
                if letter not in self.set_url:
                    (self.set_url).append(letter)
                    yield  Request(letter,callback=self.kaka)
    def parse(self,response):
        hxs=HtmlXPathSelector(response)
        return self.nn(response)


from Module import AbstractModule

class Module(AbstractModule):
    def __init__(self):
        AbstractModule.__init__(self)

    def run(
        self, network, antecedents, out_attributes, user_options, num_cores,
        outfile):
        from genomicode import quantnorm
        import arrayio
        from genomicode import filelib
        in_data = antecedents
        M = arrayio.read(in_data.identifier)
        Y = quantnorm.normalize(M)
        f = file(outfile, 'w')
        Y_c = arrayio.convert(Y, to_format=arrayio.pcl_format)
        arrayio.tab_delimited_format.write(Y_c, f)
        f.close()
        assert filelib.exists_nz(outfile), (
            'the output file %s for quantile fails' % outfile
        )

    def name_outfile(self, antecedents, user_options):
        from Betsy import module_utils
        original_file = module_utils.get_inputid(antecedents.identifier)
        filename = 'signal_quantile_' + original_file + '.tdf'
        return filename

    def set_out_attributes(self, antecedents, out_attributes):
        new_parameters = antecedents.data.attributes.copy()
        new_parameters['quantile_norm'] = 'yes'
        return new_parameters


from django.urls import path
from . import views

urlpatterns = [
   path('products', views.products_list, name="products-list"),
   path('products/<str:slug>/add-to-cart', views.add_to_cart, name="add-to-cart"),
   path('products/<str:slug>', views.product_detail, name="product-detail"),
   path('cart', views.view_cart, name="cart"),
   path('cart/<str:slug>/update-quantity',views.update_product_quantity, name="update-product-quantity"),
   path('cart/<str:slug>/remove-quantity', views.remove_product_quantity, name="remove-product-quantity"),
   path('cart/<str:slug>/remove-orderitem',views.remove_orderitem, name="remove-orderitem"),
   path('cart/checkout', views.checkout, name="checkout"),
   path('products/category/<int:pk>', views.categorize_product, name="arranged"),
   path('products/sorted-by/<str:slug>', views.sort_prod, name="sorted"),
   path('products/color/<int:pk>', views.sort_with_colors, name="sorted-with-colors"),
   path('products/filter/bysearch', views.product_filter_by_search, name="by-search"),
]


import requests
import boto
import configparser
import logging
import numpy as np

Config = configparser.RawConfigParser()
Config.read('./config.cfg')

AWS_ACCESS_KEY_ID = Config.get('AWSSettings', 'AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = Config.get('AWSSettings', 'AWS_SECRET_ACCESS_KEY')

request_id_list = []

logger = logging.getLogger()
logger.setLevel(logging.INFO)
logging.basicConfig()

def copy_data_between_buckets(source_bucket, destination_bucket, data):

    # connect to the bucket
    conn = boto.connect_s3(AWS_ACCESS_KEY_ID,
                           AWS_SECRET_ACCESS_KEY)
    logger.info('Access granted to bucket')

    data = data[:-1]
    data = data[1:]

    bucket_src = conn.get_bucket(source_bucket)
    bucket_list = bucket_src.list()
    final_destination_bucket = data + '/'

    bucket_dst = conn.get_bucket(destination_bucket)

    for bucket_file in bucket_list:
        file_path = str(bucket_file.key)
        if file_path.startswith(final_destination_bucket):
            bucket_dst.copy_key(bucket_file.key, bucket_src.name, bucket_file.key)

def main():

    if True:
        # modify the bucket accordingly
        source_bucket = ''
        destination_bucket = ''
        # list of orders need to be copied
        filename = './list_of_data.csv'

        data_list = np.genfromtxt(filename, dtype=None, delimiter=',', names=True)

        # Scan S3
        for data in data_list:
            logger.info('Start copying data %s', data)
            copy_data_between_buckets(source_bucket, destination_bucket, (data['data']))
            logger.info('Finish copying data %s', data)

if __name__ == "__main__":

    main()


__author__ = "Amish Anand"
__copyright__ = "Copyright (c) 2016 Juniper Networks, Inc."

import logging

# Logging Parameters
DEFAULT_LOG_FILE_NAME = '/tmp/jetapp.log'
DEFAULT_LOG_LEVEL = logging.INFO

# Enable Logging to a file
FORMAT = "[%(filename)s:%(lineno)s - %(funcName)s ] %(message)s"
logging.basicConfig(filename=DEFAULT_LOG_FILE_NAME, level=DEFAULT_LOG_LEVEL, format = FORMAT)
LOG = logging.getLogger(__name__)


# Importing libraries
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt

# to compare our model's accuracy with sklearn model
from sklearn.linear_model import LogisticRegression

"""
def split(x, y):
    z = mt.floor(x.shape[1]*0.8)
    a = x.shape[1] - z
    x_train = x[:, :z]
    x_test = x[:, z:]

    y_train = y[:, :z]
    y_test = y[:, z:]
    return x_train, x_test, y_train, y_test
"""
def Normalize(X):
    _min = X.min(axis=0)
    _max = X.max(axis=0)
    z = np.divide(np.subtract(X, _min), np.subtract(_max, _min))
    return z

# Logistic Regression
class LogicRegression():
    def __init__(self, learning_rate, iterations):
        self.learning_rate = learning_rate
        self.iterations = iterations
        self.weight = None
        self.bias = None

    def fit (self,X,Y):
     n_samples , n_features = X.shape
     self.weight=np.zeros(n_features)
     self.bias=0
     costList= []
     #gredientdescent
     for i in range (self.iterations):
         #WX+=b
         linear_hx = np.dot(X,self.weight) + self.bias
         y_predict = self.sigmoid(linear_hx)

         #update the weight and bias
         dw = (1/n_samples) * np.dot(X.T,(y_predict - Y))
         db = (1/n_samples) * np.sum(y_predict - Y)

         self.weight -= self.learning_rate *dw
         self.bias -= self.learning_rate *db
         self.cost_function(y_predict,Y)
         cost = self.cost_function(y_predict,Y)
         costList.append(cost)

         if (i % (self.iterations / 10) == 0):
             print('cost after ', i, " iterations is ", cost)
     return costList

    def cost_function(self,A, Y):

        m = Y.shape[0]
        cost = -(1/m) * np.sum((Y*np.log(A)) + ((1-Y)*np.log(1-A)))
        return cost

    def sigmoid (self , z):
        return (1/ (1+ np.exp(-z)))

    def  predict (self,X):
        Z = 1 / (1 + np.exp(- (X.dot(self.weight) + self.bias)))
        y = np.where(Z > 0.5, 1, 0)
        return y

# Driver code

def main():
    # Importing dataset
    data = pd.read_csv('heart.csv')
    feature_cols = ['trestbps', 'chol', 'thalach', 'oldpeak']
    X = data[feature_cols].values  # Features
    Y = data['target'].values  # output
    X = Normalize(X)

    # Splitting dataset into train and test set
    X_train, X_test, Y_train, Y_test = train_test_split(
        X, Y, test_size=0.2, random_state=0)
    iterations =15000

    # Model training
    model = LogicRegression(learning_rate=0.1, iterations=15000)
    costList =model.fit(X_train, Y_train)
    model1 = LogisticRegression()
    model1.fit(X_train, Y_train)

    # Prediction on test set
    Y_pred = model.predict(X_test)

    # measure performance
    correctly_classified = 0
    accuaracy_skmodel = model1.score(X_test, Y_test)
    error_skmodel = 1 - accuaracy_skmodel

    # counter
    count = 0
    for count in range(np.size(Y_pred)):

        if Y_test[count] == Y_pred[count]:
            correctly_classified = correctly_classified + 1

        count = count + 1
    acc = correctly_classified / count *100
    print("Accuracy on test set by our model       :  ", acc )
    print("Accuracy on test set by sklearn model   :  ", (accuaracy_skmodel *100))
    print("Error in sklearn model",error_skmodel*100)
    print("Error by our model",(100-acc) )

    plt.plot(np.arange(iterations), costList)
    plt.show()

if __name__ == "__main__":
    main()


import pygame
import sys
import time
import random
from pygame.locals import *

pygame.init()
mainClock = pygame.time.Clock()
all_fonts = pygame.font.get_fonts()
basicFont = pygame.font.SysFont('arial', 20)

W = 550
H = 550

Surface = pygame.display.set_mode((W,H), 0, 32)
pygame.display.set_caption('Template')

BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
RED = (255, 0, 0)
YELLOW = (255, 255, 0)

def text_print(text,color1,color2,left,top,Font=basicFont):
    text = Font.render(text,True,color1,color2)
    text_rect = text.get_rect()
    text_rect.top = top
    text_rect.left = left
    Surface.blit(text, text_rect)

class Tile(object):
    def __init__(self,left,top,column,row,sur=0,width=40,height=40,color=WHITE):
        self.left = left
        self.top = top
        self.width = width
        self.height = height
        self.color = color
        self.rect = pygame.Rect(left,top,width,height)
        self.mine = False
        self.flag = False
        self.click = False
        self.column = column
        self.row = row
        self.sur = sur

def new_mines():
    for item in tile_list:
        item.mine = False
        item.color = WHITE
        item.click = False
        item.flag = False
    for i in range(0,mines):
        add = True
        while (add == True):
            row = random.randint(0,9)
            col = random.randint(1,9)
            num = (row * 10 + col)
            if (tile_list[num].mine == False):
                tile_list[num].mine = True
                #tile_list[num].color=RED
                add = False
    for item in tile_list:
        row = item.row
        col = item.column
        sur = 0
        for tile in tile_list:
            if tile.row <= row + 1 and tile.row >= row - 1:
                if tile.column <= col + 1 and tile.column >= col - 1:
                    if tile.mine == True:
                        sur += 1
        item.sur = sur

game = True
tile_list = []
mines = 15
click = False
button = 99
POS = (0,0)
state = -1

reset = pygame.Rect(W - 100,0,100,50)

for i in range(0,10):
    for j in range(0,10):
        tile_list.append(Tile(65 + i * 42,100 + j * 42,i + 1,j + 1))

new_mines()

while game == True:
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit(0)
        if event.type == KEYUP:
            if event.key == K_ESCAPE:
                pygame.quit()
                sys.exit(0)
        if event.type == MOUSEBUTTONUP:
            click = True
            button = event.button
            pos = event.pos
        if event.type == MOUSEMOTION:
            POS = event.pos

    if click:
        if reset.collidepoint(pos):
            state = -1
            mines = 15
            new_mines()
        if state == -1:
            for item in tile_list:
                if item.rect.collidepoint(pos):
                    if button == 1:
                        if item.mine == False:
                            item.click = True
                            if item.sur == 0:
                                for var in tile_list:
                                    if var.sur == 0:
                                        var.click = True
                        else:
                            item.color = RED
                            #mines -=1
                            state = 1
                            #game = False
                    if button == 3:
                        if item.flag == False:
                            item.flag = True
                            item.color = GREEN
                            mines -= 1
                        else:
                            if item.flag == True:
                                item.flag = False
                                item.color = WHITE
                                mines += 1
        click = False
        button = 99

    if mines == 0:
        unflagged = 0
        for item in tile_list:
            if item.mine == True and item.flag == False:
                unflagged += 1
        if unflagged == 0:
            state = 0

    Surface.fill(BLACK)

    pygame.draw.rect(Surface, RED, reset)

    for item in tile_list:
        pygame.draw.rect(Surface, item.color, item.rect)
        if item.mine == False and item.click == True:
            if item.sur == 0:
                col1 = BLACK
            if item.sur == 1:
                col1 = BLUE
            if item.sur == 2:
                col1 = GREEN
            if item.sur == 3:
                col1 = RED
            if item.sur == 4:
                col1 = YELLOW
            if item.sur > 4:
                col1 = BLACK
            text_print(str(item.sur),col1,WHITE,item.rect.centerx - 8,item.rect.centery - 10)
            #text_print(str(item.row)+','+str(item.column),BLACK,WHITE,item.rect.left,item.rect.top)

    text_print('Mines:' + str(mines),RED,BLACK,W / 2 - 45,10)
    text_print('RESET',BLACK,RED,reset.left + 17,reset.top + 13)

    if state == 0:
        text_print('YOU WON!',RED,WHITE,W / 2 - 55,50)
    else:
        if state == 1:
            text_print('You Lost... :(',RED,WHITE,W / 2 - 55,50)

    #text_print(str(POS[0])+','+str(POS[1]),RED,BLACK,10,10)

    pygame.display.flip()
    mainClock.tick(100)


from collections import defaultdict

def bridges(existing=set(), lookup=0):
    out = []
    for part in parts[lookup]:
        if part not in existing:
            bridge = existing | {part}
            strength = sum([p[0] + p[1] for p in bridge])
            out.append((len(bridge), strength, bridge))
            out += bridges(bridge, part[1] if lookup == part[0] else part[0])
    return out

with open("day24.txt") as f:
    data = [line.strip() for line in f]

    parts = defaultdict(set)
    for part in data:
        a, b = sorted([int(n) for n in part.split("/")])
        parts[a].add((a,b))
        parts[b].add((a,b))

    bridges = bridges()
    bystr = lambda x: x[1]
    print("2017 day 24 part 1: %d" % sorted(bridges, key=bystr)[-1][1])
    print("2017 day 24 part 2: %d" % sorted(bridges)[-1][1])


# -*- coding: utf-8 -*-
import pandas as pd
import plotly.graph_objs as go
import requests

from base64 import b64encode as be
from dash_html_components import Th, Tr, Td, A
from datetime import datetime, timedelta
from flask import request
from folium import Map
from operator import itemgetter
from os.path import join, dirname, realpath
from random import randint
from requests.auth import HTTPBasicAuth
from .maputils import create_dcircle_marker, create_tcircle_marker
from .utils import (
    api_request_to_json,
    json_to_dataframe,
    starttime_str_to_seconds,
)

TMP = join(dirname(realpath(__file__)), '../tmp/')
LCL = join(dirname(realpath(__file__)), '../images/')

def get_rsam(ch, st):
    j = api_request_to_json(f'rsam?channel={ch}&starttime={st}')
    data = []
    d = pd.DataFrame(j['records'][ch])
    if not d.empty:
        d.set_index('date', inplace=True)
        data = [go.Scatter(
            x=d.index,
            y=d.rsam,
            mode='markers',
            marker=dict(size=4)
        )]
    return {
        'data': data,
        'layout': {
            'margin': {
                't': 30
            },
            'xaxis': {
                'range': [d.index.min(), d.index.max()]
            },
            'yaxis': {
                'range': [d.rsam.min() - 20, 2 * d.rsam.mean()]
            }
        }
    }

def get_tilt(ch, st):
    j = api_request_to_json(f'tilt?channel={ch}&starttime={st}')
    d = pd.DataFrame(j['records'][ch])
    traces = []
    if not d.empty:
        d.set_index('date', inplace=True)
        traces.append({
            'x': d.index,
            'y': d['radial'],
            'name': f"radial {j['used_azimuth']:.1f}"
        })
        traces.append({
            'x': d.index,
            'y': d['tangential'],
            'name': f"tangential {j['tangential_azimuth']:.1f}"
        })
    return {
        'data': traces,
        'layout': {
            'margin': {
                't': 30
            }
        }
    }

def get_rtnet(ch, st):
    j = api_request_to_json(f'rtnet?channel={ch}&starttime={st}')
    d = pd.DataFrame(j['records'][ch])
    traces = []
    if not d.empty:
        d.set_index('date', inplace=True)
        traces.append({
            'x': d.index,
            'y': d.east,
            'name': 'East',
            'mode': 'markers',
            'marker': dict(
                size=4
            )
        })
        traces.append({
            'x': d.index,
            'y': d.north,
            'name': 'North',
            'mode': 'markers',
            'marker': dict(
                size=4
            )
        })
        traces.append({
            'x': d.index,
            'y': d.up,
            'name': 'Up',
            'mode': 'markers',
            'marker': dict(
                size=4
            )
        })
    return {
        'data': traces,
        'layout': {
            'margin': {
                't': 30
            }
        }
    }

def get_and_store_hypos(geo, st, current_data):
    if is_data_needed(st, current_data):
        return get_hypos(geo, st).to_json()
    else:
        return current_data

def is_data_needed(st, data):
    if not data:
        return True
    now = datetime.now()
    olddata = pd.read_json(data)
    mindate = olddata.date.min()
    maxdate = olddata.date.max()
    td = now - mindate
    # Requested more than is currently stored?
    seconds = starttime_str_to_seconds(st)
    if seconds > (td.days * 86400 + td.seconds):
        return True
    # Data is old
    td = now - maxdate
    if (td.seconds / 60) > 10:
        return True
    return False

def get_hypos(geo, st):
    j = api_request_to_json(f'hypocenter?geo={geo}&starttime={st}')
    d = pd.DataFrame(j['records'])
    if not d.empty:
        d['date'] = d['date'].str.slice(stop=-2)
        d['date'] = pd.to_datetime(d['date'])
        d.reset_index(drop=True, inplace=True)
    return d

def get_hypos_map(st, kind, data, region):
    filename = f'{TMP}hypos{randint(0,9999):04d}.html'
    d = json_to_dataframe(st, data)
    m = None
    if region == 'kism':
        m = Map(location=[19.41, -155.27], min_zoom=12, max_zoom=15,
                zoom_start=13, tiles='Stamen Terrain')
    elif region == 'lerz':
        m = Map(location=[19.43, -154.88], min_zoom=11, max_zoom=15,
                zoom_start=11, tiles='Stamen Terrain')
    if kind == 'T':
        mid = d.date.min()
        mad = d.date.max()
        d.apply(create_tcircle_marker, arg=(m, mid, mad), axis=1)
    elif kind == 'A':
        d.apply(create_dcircle_marker, args=(m,), axis=1)
    m.save(filename)
    return open(filename, 'r').read()

def get_hypos_legend(kind):
    encoded_img = None
    if kind == 'A':
        encoded_img = be(open(f'{LCL}dlegend.png', 'rb').read())
    elif kind == 'T':
        encoded_img = be(open(f'{LCL}tlegend.png', 'rb').read())
    return f"data:image/jpg;base64,{encoded_img.decode('utf8')}"

def get_hypos_table(st, data):
    d = json_to_dataframe(st, data)
    if not d.empty:
        d.sort_values('date', inplace=True)
    return d.to_dict('records')

def get_hypo_counts(st, data):
    d = json_to_dataframe(st, data)
    data = []
    if not d.empty:
        d.sort_values('date', inplace=True)
        d['moment'] = d.prefMag.apply(lambda x:
                                      pow(10.0, 16.0 + ((3.0 * x)/2.0)))
        d['cmoment'] = d.moment.cumsum()
        bins = d.groupby(pd.Grouper(freq='60min', key='date')).count()
        data = [go.Bar(
                {
                    'x': bins.index,
                    'y': bins.depth,
                    'name': 'Count'
                }), go.Scatter(
                {
                    'x': d.date,
                    'y': d.cmoment,
                    'name': 'Moment',
                    'yaxis': 'y2'
                })]
    return {
        'data': data,
        'layout': {
            'margin': {
                't': 30
                },
            'showlegend': False,
            'yaxis': {
                'title': 'Earthquakes per Hour'
            },
            'yaxis2': {
                'title': 'Cumulative Moment (dyn-cm)',
                'showgrid': False,
                'overlaying': 'y',
                'side': 'right'
            }
        }
    }

def get_spectrogram(src):
    now = datetime.utcnow()
    d = now.timetuple().tm_yday
    tm = now - timedelta(minutes=now.minute % 10, seconds=now.second,
                         microseconds=now.microsecond)
    if 'ipensive' in src:
        t = '%d%s%s-%s%s' % (now.year, str(now.month).zfill(2),
                             str(now.day).zfill(2), str(tm.hour).zfill(2),
                             str(tm.minute).zfill(2))
    else:
        t = '%d%s-%s%s' % (now.year, str(d).zfill(3), str(tm.hour).zfill(2),
                           str(tm.minute).zfill(2))
    return src.format(now.year, d, t)

def get_helicorder(ch):
    url = f'a=plot&o=png&tz=Pacific/Honolulu&w=900&h=636&n=1&x.0=75&y.0=20' \
          f'&w.0=750&h.0=576&mh.0=900&chCnt.0=1' \
          f'&src.0=hvo_seismic_winston_helicorders&st.0=-28800000&et.0=N' \
          f'&chNames.0={ch}&dataTypes.0=275.000000&tc.0=15&barMult.0=3' \
          f'&sc.0=T&plotSeparately.0=false'
    encoded_img = be(open(get_valve_plot(url), 'rb').read())
    return f"data:image/jpg;base64,{encoded_img.decode('utf8')}"

def get_tiltv(region):
    chs = ''
    if region == 'kism':
        chs = '18,20'
    elif region == 'merz':
        chs = '15,16'
    url = f'a=plot&o=png&tz=Pacific/Honolulu&w=900&h=1740&n=1&x.0=75&y.0=20' \
          f'&w.0=750&h.0=240&mh.0=900&chCnt.0=7&src.0=hvo_def_tilt' \
          f'&st.0=-28800000&et.0=N&lg.0=true&ch.0={chs}' \
          f'&dataTypes.0=NaN&plotType.0=tv&rk.0=1&ds.0=None&dsInt.0=&sdt.0=' \
          f'&az.0=n&azval.0=&linetype.0=l&ysLMin.0=&ysLMax.0=&ysRMin.0=' \
          f'&ysRMax.0=&despike_period.0=&filter_arg1.0=&filter_arg2.0=' \
          f'&despike.0=F&detrend.0=F&dmo_fl.0=0&filter_arg3.0=' \
          f'&dmo_arithmetic.0=None&dmo_arithmetic_value.0=&dmo_db.0=0' \
          f'&debias_period.0=&radial.0=T&tangential.0=T&xTilt.0=F&yTilt.0=F' \
          f'&magnitude.0=F&azimuth.0=F&holeTemp.0=F&boxTemp.0=F&instVolt.0=F' \
          f'&rainfall.0=F&vs.0=&plotSeparately.0=false'
    encoded_img = be(open(get_valve_plot(url), 'rb').read())
    return f"data:image/jpg;base64,{encoded_img.decode('utf8')}"

def get_valve_plot(itm):
    filename = f'{TMP}valve{randint(0,9999):04d}.jpg'
    url = f'https://hvovalve.wr.usgs.gov/valve3/valve3.jsp?{itm}'
    u = request.authorization.username
    p = request.authorization.password
    r = requests.get(url, auth=HTTPBasicAuth(u, p))
    with open(filename, 'wb') as f:
        f.write(r.content)
    return filename

def get_ash3d_img():
    url = ('https://volcanoes.usgs.gov/vsc/captures/ash3d/'
           '332010_1008443_D_deposit.gif')
    return url

def get_logs(max_rows=20):
    p = api_request_to_json('logs')['posts']
    headers = ['Post', 'Author', 'Date']
    d = sorted(p, key=itemgetter('date'), reverse=True)
    link = 'https://hvointernal.wr.usgs.gov/hvo_logs/read?id={}'
    return [[Tr([Th(col) for col in headers])] +
            [Tr([
               Td(A(href=link.format(d[i]['id']),
                    children='%s' % d[i]['subject'],
                    target='_blank')),
               Td(children='%s' % d[i]['user']),
               Td(children='%s' % d[i]['date'])
            ]) for i in range(0, max_rows)]]

def get_so2emissions(ch, st):
    j = api_request_to_json(f'so2emissions?channel={ch}&starttime={st}')
    data = []
    d = pd.DataFrame(j['records'][ch])
    if not d.empty:
        d.set_index('date', inplace=True)
        data = [go.Scatter(
            x=d.index,
            y=d.so2,
            mode='markers',
            marker=dict(size=10)
        )]
    return {
        'data': data,
        'layout': {
            'margin': {
                't': 30
            }
        }
    }

def get_nps_so2(ch, st):
    j = api_request_to_json(f'npsadvisory?channel={ch}&starttime={st}')
    data = []
    d = pd.DataFrame(j['records'][ch])
    if not d.empty:
        d.set_index('date', inplace=True)
        data = [go.Scatter(
            x=d.index,
            y=d.avgso2,
            mode='markers',
            marker=dict(size=6)
        )]
    return {
        'data': data,
        'layout': {
            'margin': {
                't': 30
            },
            'yaxis': {
                'exponentformat': 'none'
            }
        }
    }

def get_nps_wind(ch, st):
    url = (f'npsadvisory?channel={ch}&starttime={st}&series=windspeed,winddir')
    j = api_request_to_json(url)
    data = []
    d = pd.DataFrame(j['records'][ch])
    if not d.empty:
        d.set_index('date', inplace=True)
        data = [go.Scatter(
            x=d.index,
            y=d.windspeed,
            name='Wind Speed',
            mode='markers',
            marker=dict(size=6)
        ), go.Scatter(
            x=d.index,
            y=d.winddir,
            name='Wind Dir',
            yaxis='y2',
            mode='markers',
            marker=dict(size=6)
        )]
    return {
        'data': data,
        'layout': {
            'margin': {
                't': 30
            },
            'yaxis': {
                'title': 'Windspeed (m/s)'
            },
            'yaxis2': {
                'title': 'Wind Direction (deg)',
                'showgrid': False,
                'overlaying': 'y',
                'side': 'right'
            }
        }
    }


from modals import (DataSourceModal,
                    InterferenceModal,
                    ConnectionLineModal,
                    CorrelatorModal,
                    ClockGenModal,
                    ReferenceDSModal,
                    PivotDSModal,
                    DecisionDeviceModal)

blocks = [
    {
        "name": "Джерело сигналу",
        "description": "Генерує масив даних відповідних вибраному типу сигналу"\
                       " довжиною рівною кількості відліків на символ "\
                       "(у випадку вибору типу \"Гармонічний сигнал\" добуток "\
                       "кількості відліків на період та "\
                       "кількості періодів на символ) помножену на кількість "\
                       "бітів записаних в полі \"Символи для передачі\".",
        "abbr": "DS",
        "abbr-ua": "ДС",
        "allowed": ["CL"],
        "modal": DataSourceModal,
        "values": {
            "type": 0,
            "amplitude": 5,
            "frequency": 2,
            "phase": 0,
            "periods_per_symbol": 5,
            "counts_per_period": 10,
            "counts_per_symbol": 50,
            "bytes": "10"
        }
    },
    {
        "name": "Лінія зв'язку",
        "description": "З'єднує масиви даних відповідні переданому сигналу та"\
                       " заваді згідно до виставлених нижче коефіцієнтів."\
                       "Якщо на вході немає хоч одного з модулів ДС та Звд, то"\
                       " модуль на виході нічого не видає.",
        "abbr": "CL",
        "abbr-ua": "ЛЗ",
        "allowed": ["DS", "Infr", "Corr"],
        "modal": ConnectionLineModal,
        "values": {
            "infr_coef": 0.3,
            "signal_coef": 1,
            "counts_per_symbol": 50
        }
    },
    {
        "name": "Завада",
        "description": "Генерує масив даних згідно до вибраного типу завади та"\
                       " її амплітуди. Довжина масиву залежить від присутності"\
                       " цього модуля в одній системі з модулем ДС.",
        "abbr": "Infr",
        "abbr-ua": "Звд",
        "allowed": ["CL"],
        "modal": InterferenceModal,
        "values": {
            "type": 0,
            "amplitude": 5,
            "counts_per_symbol": 50
        }
    },
    {
        "name": "Коррелятор",
        "description": "Генерує масив, що ілюструє взаємну кореляцію сигналів"\
                       " від модулів ДЕС та ЛЗ. Також для роботи є необхідним "\
                       "модуль ТГ.",
        "abbr": "Corr",
        "abbr-ua": "Корр",
        "allowed": ["CL", "CG", "RDS", "DD"],
        "modal": CorrelatorModal,
        "values": {
            "counts_per_symbol": 50
        }
    },
    {
        "name": "Тактовий генератор",
        "description": "Скидає в нуль значення корелятора при закінченні"\
                       "передачі кожного з символів.",
        "abbr": "CG",
        "abbr-ua": "ТГ",
        "allowed": ["Corr"],
        "modal": ClockGenModal,
        "values": {
            "counts_per_symbol": 50
        }
    },
    {
        "name": "Джерело еталонного сигналу",
        "description": "Автоматично генерує сигнал, що є еталонним "\
                       "оригінальному. Якщо модуля ДС з таким оригінальним "\
                       "сигналом в системі немає, то на виході "\
                       "теж нічого немає.",
        "abbr": "RDS",
        "abbr-ua": "ДЕС",
        "allowed": ["Corr"],
        "modal": ReferenceDSModal,
        "values": {
            "id": "",
            "counts_per_symbol": 50
        }
    },
    {
        "name": "Джерело опорного сигналу",
        "description": "Контролює ймовірність допуску помилки модуля ППР.",
        "abbr": "PDS",
        "abbr-ua": "ДОС",
        "allowed": ["DD"],
        "modal": PivotDSModal,
        "values": {
            "pivot_signal_level": 70
        }
    },
    {
        "name": "Пристрій прийняття рішення",
        "description": "Аналізує масив даних переданий від модуля Корр "\
                       "та визначає кожен переданий символ. Якщо символ "\
                       "не вдалося розпізнати, то замінює його на '?'.",
        "abbr": "DD",
        "abbr-ua": "ППР",
        "allowed": ["Corr", "PDS"],
        "modal": DecisionDeviceModal,
        "values": {
            "received_message": ""
        }
    }
]