text:
#include <modules/space/rendering/renderablefluxnodes.h>

#include <openspace/engine/globals.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/orbitalnavigator.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scene.h>
#include <openspace/util/timemanager.h>
#include <openspace/util/updatestructures.h>
#include <openspace/query/query.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/logging/consolelog.h>
#include <ghoul/logging/visualstudiooutputlog.h>
#include <ghoul/opengl/programobject.h>
#include <ghoul/opengl/textureunit.h>
#include <fstream>
#include <functional>
#include <optional>
#include <sys/stat.h>
#include <thread>

namespace {
    constexpr std::string_view _loggerCat = "RenderableFluxNodes";

    constexpr std::array<const char*, 29> UniformNames = {
        "streamColor", "nodeSize", "proximityNodesSize",
        "thresholdFlux", "colorMode", "filterLower", "filterUpper", "scalingMode",
        "colorTableRange", "domainLimZ", "nodeSkip", "nodeSkipDefault", "nodeSkipEarth",
        "nodeSkipMethod", "nodeSkipFluxThreshold", "nodeSkipRadiusThreshold",
        "fluxColorAlpha", "earthPos", "distanceThreshold", "time", "maxNodeDistanceSize",
        "usingCameraPerspective", "drawCircles", "drawHollow", "useGaussian",
        "perspectiveDistanceFactor", "minMaxNodeSize", "usingPulse",
        "usingGaussianPulse"
    };

    constexpr openspace::properties::Property::PropertyInfo GoesEnergyBinsInfo = {
        "GoesEnergy",
        "GOES Energy",
        "Select which energy bin you want to show. GOES = Geostationary Operational "
        "Environmental Satellites. Emin01 is values > 10 MeV, "
        "Default is Emin03 where values > 100 MeV"
    };

    constexpr openspace::properties::Property::PropertyInfo ColorModeInfo = {
        "ColorMode",
        "Color Mode",
        "Color lines uniformly or using color tables based on specific values on nodes, "
        "for examples flux values"
    };

    constexpr openspace::properties::Property::PropertyInfo ColorTablePathInfo = {
        "ColorTablePath",
        "Path to Color Table",
        "Color Table/Transfer Function to use for 'By Flux Value' coloring"
    };

    constexpr openspace::properties::Property::PropertyInfo StreamColorInfo = {
        "Color",
        "Color",
        "Color of particles"
    };

    constexpr openspace::properties::Property::PropertyInfo NodeSizeInfo = {
       "NodeSize",
       "Size of nodes",
       "Change the size of the rendered points of the nodes"
    };

    constexpr openspace::properties::Property::PropertyInfo ThresholdFluxInfo = {
       "ThresholdFlux",
       "Threshold flux value",
       "This value specifies the threshold that will be changed with the flux value"
    };

    constexpr openspace::properties::Property::PropertyInfo FilteringInfo = {
        "FilterLower",
        "Filtering Lower Value in AU",
        "Use filtering to show nodes within a given range"
    };

    constexpr openspace::properties::Property::PropertyInfo FilteringUpperInfo = {
        "FilterUpper",
        "Filtering Upper Value in AU",
        "Use filtering to show nodes within a given range"
    };

    constexpr openspace::properties::Property::PropertyInfo AmountofNodesInfo = {
        "AmountOfNodes",
        "Every nth node to render in",
        "Show only every nth node"
    };

    constexpr openspace::properties::Property::PropertyInfo DefaultNodeSkipInfo = {
        "NodeSkip",
        "Every nth node to render default",
        "Show only every nth node outside of skippingmethod"
    };

    constexpr openspace::properties::Property::PropertyInfo EarthNodeSkipInfo = {
       "NodeSkipEarth",
       "Every nth node to render close to Earth",
       "Show only every nth node outside of skippingmethod"
    };

    constexpr openspace::properties::Property::PropertyInfo ScalingmethodInfo = {
        "ScalingFlux",
        "Scale the flux value with color table",
        "Use scaling to color nodes with a given method"
    };

    constexpr openspace::properties::Property::PropertyInfo NodeskipMethodInfo = {
        "SkippingNodes",
        "How to select nodes to skip",
        "Methods to select nodes to skip"
    };

    constexpr openspace::properties::Property::PropertyInfo colorTableRangeInfo = {
        "ColorTableRange",
        "Color Table Range",
        "Valid range for the color table as the exponent, with base 10, of flux values. "
        "[Min, Max]"
    };

    constexpr openspace::properties::Property::PropertyInfo DomainZInfo = {
        "ZLimit",
        "Z-limits",
        "Valid range along the Z-axis. [Min, Max]"
    };

    constexpr openspace::properties::Property::PropertyInfo FluxColorAlphaInfo = {
        "FluxColorAlpha",
        "Flux Color Alpha",
        "The value of alpha for the flux color mode"
    };

    constexpr openspace::properties::Property::PropertyInfo FluxNodeskipThresholdInfo = {
        "SkippingNodesByFlux",
        "Skipping Nodes By Flux",
        "Select nodes to skip depending on flux value"
    };

    constexpr openspace::properties::Property::PropertyInfo
                                                           RadiusNodeSkipThresholdInfo = {
        "SkippingNodesByRadius",
        "Skipping Nodes By Radius",
        "Select nodes to skip depending on Radius"
    };

    constexpr openspace::properties::Property::PropertyInfo DistanceThresholdInfo = {
        "DistancePlanetThreshold",
        "Threshold for distance between planet",
        "Changes threshold distance for highlighting nodes close to earth"
    };

    constexpr openspace::properties::Property::PropertyInfo ProximityNodesSizeInfo = {
        "ProximityNodesSize",
        "Earths Proximity Nodes Size",
        "Changes size of nodes only close to earth"
    };

    constexpr openspace::properties::Property::PropertyInfo MaxNodeDistanceSizeInfo = {
        "MaxNodeDistanceSize",
        "Max Node Distance Size",
        "The maximum size of the nodes at a certin distance"
    };

    constexpr openspace::properties::Property::PropertyInfo
                                                          CameraPerspectiveEnabledInfo = {
        "CameraPerspectiveEnabled",
        "Use Camera perspective",
        "Camera perspective changes the size of the nodes dependent on the "
        "distance from camera"
    };

    constexpr openspace::properties::Property::PropertyInfo DrawingCirclesInfo = {
        "RenderingCircles",
        "Render as circles",
        "Using fragment shader to draw nodes as circles instead of squares"
    };

    constexpr openspace::properties::Property::PropertyInfo DrawingHollowInfo = {
        "RenderingHollowCircles",
        "Render as hollow circles",
        "Using fragment shader to draw nodes as hollow circles"
    };

    constexpr openspace::properties::Property::PropertyInfo GaussiandAlphaFilterInfo = {
        "RenderingGaussianAlphaFilter",
        "Alpha by Gaussian",
        "Using fragment shader to draw nodes with Gaussian filter for alpha value"

    };

    constexpr openspace::properties::Property::PropertyInfo
                                                         PerspectiveDistanceFactorInfo = {
        "PerspectiveDistanceFactor",
        "Perspective Distance factor",
        "This value decides how far away the camera must be to start "
        "impacting the node size"
    };

    constexpr openspace::properties::Property::PropertyInfo MinMaxNodeSizeInfo = {
        "MinMaxNodeSize",
        "Min & Max node size",
        "The minimum and maximum node size"
    };

    constexpr openspace::properties::Property::PropertyInfo pulseEnabledInfo = {
        "PulseEnabled",
        "Nodes close to Earth pulsate",
        "Toggles the pulse for nodes close to Earth"
    };

    constexpr openspace::properties::Property::PropertyInfo gaussianPulseEnabledInfo = {
        "GaussianPulseEnabled",
        "Nodes close to Earth pulsate with alpha by gaussian",
        "Toggles the pulse with alpha by gaussian for nodes close to Earth"
    };

    struct [[codegen::Dictionary(RenderableFluxNodes)]] Parameters {
        // path to source folder with the 3 binary files in it
        std::filesystem::path sourceFolder [[codegen::directory()]];
        // [[codegen::verbatim(ColorTablePathInfo.description)]]
        std::string colorTablePath;
        // [[codegen::verbatim(GoesEnergyBinsInfo.description)]]
        std::optional<int> energyBin;
        // [[codegen::verbatim(colorTableRangeInfo.description)]]
        std::optional<glm::vec2> colorTableRange;
    };
#include "renderablefluxnodes_codegen.cpp"

} // namespace

namespace openspace {

documentation::Documentation RenderableFluxNodes::Documentation() {
    return codegen::doc<Parameters>("space_renderable_flux_nodes");
}

RenderableFluxNodes::RenderableFluxNodes(const ghoul::Dictionary& dictionary)
    : Renderable(dictionary)
    , _earthdistGroup({ "Earthfocus" })
    , _goesEnergyBins(GoesEnergyBinsInfo, properties::OptionProperty::DisplayType::Radio)
    , _styleGroup({ "Style" })
    , _colorMode(ColorModeInfo, properties::OptionProperty::DisplayType::Radio)
    , _streamColor(
        StreamColorInfo,
        glm::vec4(0.96f, 0.88f, 0.8f, 1.f),
        glm::vec4(0.f),
        glm::vec4(1.f)
    )
    , _colorTablePath(ColorTablePathInfo)
    , _colorTableRange(colorTableRangeInfo, { -2.f, 4.f }, { -8.f, -8.f }, { 8.f, 8.f })
    , _fluxColorAlpha(FluxColorAlphaInfo, 1.f, 0.f, 1.f)
    , _streamGroup({ "Streams" })
    , _scalingMethod(ScalingmethodInfo, properties::OptionProperty::DisplayType::Radio)
    , _nodesAmountGroup({ "NodeGroup" })
    , _nodeSize(NodeSizeInfo, 2.f, 1.f, 10.f)
    , _distanceThreshold(DistanceThresholdInfo, 0.f, 0.f, 1.f)
    , _proximityNodesSize(ProximityNodesSizeInfo, 1.f, 0.f, 100.f)
    , _maxNodeDistanceSize(MaxNodeDistanceSizeInfo, 1.f, 1.f, 10.f)
    , _minMaxNodeSize(MinMaxNodeSizeInfo, { 2.f, 30.f }, { 1.f, 1.f }, { 10.f, 200.f })
    , _domainZ(DomainZInfo, { -2.5f, 2.5f }, { -2.5f, -2.5f }, { 2.5f, 2.5f })
    , _thresholdFlux(ThresholdFluxInfo, -1.5f, -50.f, 10.f)
    , _filteringLower(FilteringInfo, 0.f, 0.f, 5.f)
    , _filteringUpper(FilteringUpperInfo, 5.f, 0.f, 5.f)
    , _amountofNodes(AmountofNodesInfo, 1, 1, 100)
    , _nodeskipMethod(NodeskipMethodInfo, properties::OptionProperty::DisplayType::Radio)
    , _defaultNodeSkip(DefaultNodeSkipInfo, 1, 1, 100)
    , _fluxNodeskipThreshold(FluxNodeskipThresholdInfo, 0, -20, 10)
    , _earthNodeSkip(EarthNodeSkipInfo, 1, 1, 100)
    , _radiusNodeSkipThreshold(RadiusNodeSkipThresholdInfo, 0.f, 0.f, 5.f)
    , _cameraPerspectiveGroup({ "CameraPerspective" })
    , _cameraPerspectiveEnabled(CameraPerspectiveEnabledInfo, false)
    , _drawingCircles(DrawingCirclesInfo, true)
    , _drawingHollow(DrawingHollowInfo, false)
    , _gaussianAlphaFilter(GaussiandAlphaFilterInfo, false)
    , _perspectiveDistanceFactor(PerspectiveDistanceFactorInfo, 2.67f, 1.f, 20.f)
    , _pulseEnabled(pulseEnabledInfo, false)
    , _gaussianPulseEnabled(gaussianPulseEnabledInfo, false)
{
    const Parameters p = codegen::bake<Parameters>(dictionary);

    _colorTablePath = p.colorTablePath;
    _transferFunction = std::make_unique<TransferFunction>(_colorTablePath);
    _colorTableRange = p.colorTableRange.value_or(_colorTableRange);

    _binarySourceFolderPath = p.sourceFolder;
    if (std::filesystem::is_directory(_binarySourceFolderPath)) {
        // Extract all file paths from the provided folder
        namespace fs = std::filesystem;
        for (const fs::directory_entry& e :
            fs::directory_iterator(_binarySourceFolderPath))
        {
            if (e.is_regular_file()) {
                _binarySourceFiles.push_back(e.path().string());
            }
        }
        std::sort(_binarySourceFiles.begin(), _binarySourceFiles.end());

        // Ensure that there are available and valid source files left
        if (_binarySourceFiles.empty()) {
            LERROR(fmt::format("{} contains no files", _binarySourceFolderPath));
        }
    }
    else {
        LERROR(fmt::format(
            "Source folder {} is not a valid directory", _binarySourceFolderPath
        ));
    }

    _goesEnergyBins.addOption(static_cast<int>(GoesEnergyBins::Emin01), "Emin01");
    _goesEnergyBins.addOption(static_cast<int>(GoesEnergyBins::Emin03), "Emin03");
    _colorMode.addOption(static_cast<int>(ColorMethod::ByFluxValue), "By Flux Value");
    _colorMode.addOption(static_cast<int>(ColorMethod::Uniform), "Uniform");

    _scalingMethod.addOption(static_cast<int>(ScalingMethod::Flux), "Flux");
    _scalingMethod.addOption(static_cast<int>(ScalingMethod::RFlux), "Radius * Flux");
    _scalingMethod.addOption(static_cast<int>(ScalingMethod::R2Flux), "Radius^2 * Flux");
    _scalingMethod.addOption(
        static_cast<int>(ScalingMethod::Log10RFlux), "log10(r) * Flux"
    );
    _scalingMethod.addOption(static_cast<int>(ScalingMethod::LnRFlux), "ln(r) * Flux");

    _nodeskipMethod.addOption(static_cast<int>(NodeSkipMethod::Uniform), "Uniform");
    _nodeskipMethod.addOption(static_cast<int>(NodeSkipMethod::Flux), "Flux");
    _nodeskipMethod.addOption(static_cast<int>(NodeSkipMethod::Radius), "Radius");

    if (p.energyBin.has_value()) {
        _goesEnergyBins.setValue(p.energyBin.value());
    }
    else { // default int 1 == Emin03 == MeV>100
        LINFO("Assuming default value 1, meaning Emin03");
        _goesEnergyBins.setValue(1);
    }
}

void RenderableFluxNodes::initialize() {
    populateStartTimes();
    loadNodeData(_goesEnergyBins.option().value);
    computeSequenceEndTime();
}

void RenderableFluxNodes::initializeGL() {
    // Setup shader program
    _shaderProgram = global::renderEngine->buildRenderProgram(
        "Fluxnodes",
        absPath("${MODULE_SPACE}/shaders/fluxnodes_vs.glsl"),
        absPath("${MODULE_SPACE}/shaders/fluxnodes_fs.glsl")
    );

    _uniformCache.streamColor = _shaderProgram->uniformLocation("streamColor");
    _uniformCache.nodeSize = _shaderProgram->uniformLocation("nodeSize");
    _uniformCache.thresholdFlux = _shaderProgram->uniformLocation("thresholdFlux");

    ghoul::opengl::updateUniformLocations(*_shaderProgram, _uniformCache, UniformNames);

    glGenVertexArrays(1, &_vertexArrayObject);
    glGenBuffers(1, &_vertexPositionBuffer);
    glGenBuffers(1, &_vertexColorBuffer);
    glGenBuffers(1, &_vertexFilteringBuffer);

    // Needed for alpha transparency
    setRenderBin(Renderable::RenderBin::PreDeferredTransparent);
    setupProperties();
}

void RenderableFluxNodes::definePropertyCallbackFunctions() {
    // Add Property Callback Functions
    _goesEnergyBins.onChange([this] {
        loadNodeData(_goesEnergyBins.option().value);
    });
    _colorTablePath.onChange([this]() {
        _transferFunction->setPath(_colorTablePath);
    });
}

void RenderableFluxNodes::loadNodeData(int energybinOption) {
    LDEBUG("Loading in binary files directly from sync folder");

    std::string energybin;
    switch (energybinOption) {
        case 0:
            energybin = "_emin01";
            break;
        case 1:
            energybin = "_emin03";
            break;
    }

    std::string file = _binarySourceFolderPath.string() + "\\positions" + energybin;
    std::string file2 = _binarySourceFolderPath.string() + "\\fluxes" + energybin;
    std::string file3 = _binarySourceFolderPath.string() + "\\radiuses" + energybin;

    std::ifstream fileStream(file, std::ifstream::binary);
    std::ifstream fileStream2(file2, std::ifstream::binary);
    std::ifstream fileStream3(file3, std::ifstream::binary);

    if (!fileStream.good()) {
        LERROR(fmt::format("Could not read file '{}'", file));
        return;
    }

    uint32_t nNodesPerTimestep = 0;
    fileStream.read(reinterpret_cast<char*>(&nNodesPerTimestep), sizeof(uint32_t));

    uint32_t nTimeSteps = 0;
    fileStream.read(reinterpret_cast<char*>(&nTimeSteps), sizeof(uint32_t));
    _nStates = nTimeSteps;

    if (_nStates != _startTimes.size()) {
        LERROR(
            "Number of states, _nStates, and number of start times, _startTimes, "
            "do not match"
        );
        return;
    }

    _statesColor.clear();
    _statesPos.clear();
    _statesRadius.clear();

    for (unsigned int i = 0; i < _nStates; ++i) {
        _vertexPositions.resize(nNodesPerTimestep);
        fileStream.read(reinterpret_cast<char*>(
            _vertexPositions.data()), nNodesPerTimestep * sizeof(glm::vec3)
        );

        _statesPos.push_back(_vertexPositions);
        _vertexPositions.clear();
    }
    for (unsigned int i = 0; i < _nStates; ++i) {
        _vertexColor.resize(nNodesPerTimestep);
        fileStream2.read(reinterpret_cast<char*>(
            _vertexColor.data()), nNodesPerTimestep * sizeof(float)
        );

        _statesColor.push_back(_vertexColor);
        _vertexColor.clear();
    }
    for (unsigned int i = 0; i < _nStates; ++i) {
        _vertexRadius.resize(nNodesPerTimestep);
        fileStream3.read(reinterpret_cast<char*>(
            _vertexRadius.data()), nNodesPerTimestep * sizeof(float)
        );

        _statesRadius.push_back(_vertexRadius);
        _vertexRadius.clear();
    }
}

void RenderableFluxNodes::setupProperties() {
    addProperty(_goesEnergyBins);

    addPropertySubOwner(_styleGroup);
    addPropertySubOwner(_streamGroup);
    addPropertySubOwner(_nodesAmountGroup);
    addPropertySubOwner(_earthdistGroup);
    addPropertySubOwner(_cameraPerspectiveGroup);

    _cameraPerspectiveGroup.addProperty(_cameraPerspectiveEnabled);
    _cameraPerspectiveGroup.addProperty(_perspectiveDistanceFactor);
    _minMaxNodeSize.setViewOption(properties::Property::ViewOptions::MinMaxRange);
    _cameraPerspectiveGroup.addProperty(_minMaxNodeSize);

    _earthdistGroup.addProperty(_distanceThreshold);
    _earthdistGroup.addProperty(_proximityNodesSize);
    _earthdistGroup.addProperty(_pulseEnabled);
    _earthdistGroup.addProperty(_gaussianPulseEnabled);

    _nodesAmountGroup.addProperty(_nodeskipMethod);
    _nodesAmountGroup.addProperty(_amountofNodes);
    _nodesAmountGroup.addProperty(_defaultNodeSkip);
    _nodesAmountGroup.addProperty(_earthNodeSkip);
    _nodesAmountGroup.addProperty(_nodeSize);
    _nodesAmountGroup.addProperty(_fluxNodeskipThreshold);
    _nodesAmountGroup.addProperty(_radiusNodeSkipThreshold);
    _nodesAmountGroup.addProperty(_maxNodeDistanceSize);

    _streamGroup.addProperty(_thresholdFlux);
    _streamGroup.addProperty(_filteringLower);
    _streamGroup.addProperty(_filteringUpper);
    _streamGroup.addProperty(_domainZ);

    _styleGroup.addProperty(_drawingCircles);
    _styleGroup.addProperty(_drawingHollow);
    _styleGroup.addProperty(_gaussianAlphaFilter);
    _styleGroup.addProperty(_colorMode);
    _styleGroup.addProperty(_scalingMethod);
    _colorTableRange.setViewOption(properties::Property::ViewOptions::MinMaxRange);
    _styleGroup.addProperty(_colorTableRange);
    _styleGroup.addProperty(_colorTablePath);
    _styleGroup.addProperty(_streamColor);
    _styleGroup.addProperty(_fluxColorAlpha);

    definePropertyCallbackFunctions();
}

void RenderableFluxNodes::deinitializeGL() {
    glDeleteVertexArrays(1, &_vertexArrayObject);
    _vertexArrayObject = 0;

    glDeleteBuffers(1, &_vertexPositionBuffer);
    _vertexPositionBuffer = 0;

    glDeleteBuffers(1, &_vertexColorBuffer);
    _vertexColorBuffer = 0;

    glDeleteBuffers(1, &_vertexFilteringBuffer);
    _vertexFilteringBuffer = 0;

    if (_shaderProgram) {
        global::renderEngine->removeRenderProgram(_shaderProgram.get());
        _shaderProgram = nullptr;
    }
}

bool RenderableFluxNodes::isReady() const {
    return _shaderProgram != nullptr;
}

void RenderableFluxNodes::populateStartTimes() {
    std::string timeFile;
    for (const std::string& filePath : _binarySourceFiles) {
        if (filePath.substr(filePath.find_last_of(".") + 1) == "csv") {
            timeFile = filePath;
            break;
        }
        else if (filePath.substr(filePath.find_last_of(".") + 1) == "dat") {
            timeFile = filePath;
            break;
        }
        else if (filePath.substr(filePath.find_last_of(".") + 1) == "txt") {
            timeFile = filePath;
            break;
        }
        //if no file extention but word "time" in file name
        else if (filePath.find("time") != std::string::npos &&
                    filePath.find(".") == std::string::npos)
        {
            timeFile = filePath;
            break;
        }
    }

    if (timeFile.empty()) {
        LERROR(
            "Could not find a metadata file with time steps, such as a csv, dat, txt or "
            "no file extention with 'time' in filename"
        );
    }

    // time filestream
    std::ifstream tfs(timeFile);
    if (!tfs.is_open()) {
        throw ghoul::RuntimeError("Could not open file");
    }

    std::string line;
    // gets only first line to "remove" header
    std::getline(tfs, line);
    std::stringstream s;
    s << line;

    int nColumns = 0;
    std::string columnName;
    // loops through the names/columns in first line/header
    while (s >> columnName) {
        ++nColumns;
    }
    while (std::getline(tfs, line)) {   // for each line of data
        std::istringstream iss(line);
        for (int i = 0; i < nColumns; ++i) {    // for each column in line
            std::string columnValue;
            iss >> columnValue;
            if (i != nColumns - 1) {    // last column
                continue;
            }
            if (columnValue.length() == 23) {
                // Ensure the separators are correct
                columnValue.replace(4, 1, "-");
                columnValue.replace(7, 1, "-");
                columnValue.replace(13, 1, ":");
                columnValue.replace(16, 1, ":");
                columnValue.replace(19, 1, ".");
                const double triggerTime = Time::convertTime(columnValue);
                _startTimes.push_back(triggerTime);
            }
            else {
                LERROR(fmt::format("Error in file formating. Last column in ",
                    "file '{}' is not on UTC ISO8601 format", timeFile
                ));
            }
        }
    }
}

void RenderableFluxNodes::updateActiveTriggerTimeIndex(double currentTime) {
    auto iter = std::upper_bound(_startTimes.begin(), _startTimes.end(), currentTime);
    if (iter != _startTimes.end()) {
        if (iter != _startTimes.begin()) {
            std::ptrdiff_t idx = std::distance(_startTimes.begin(), iter);
            _activeTriggerTimeIndex = static_cast<int>(idx) - 1;
        }
        else {
            _activeTriggerTimeIndex = 0;
        }
    }
    else {
        _activeTriggerTimeIndex = static_cast<int>(_nStates) - 1;
    }
}
void RenderableFluxNodes::render(const RenderData& data, RendererTasks&) {
    if (_activeTriggerTimeIndex == -1) {
        return;
    }
    _shaderProgram->activate();

    // Calculate Model View MatrixProjection
    const glm::dmat4 rotMat = glm::dmat4(data.modelTransform.rotation);
    const glm::dmat4 modelMat =
        glm::translate(glm::dmat4(1.0), data.modelTransform.translation) *
        rotMat * glm::scale(glm::dmat4(1.0), data.modelTransform.scale);
    const glm::dmat4 modelViewMat = data.camera.combinedViewMatrix() * modelMat;

    _shaderProgram->setUniform("modelViewProjection",
        data.camera.sgctInternal.projectionMatrix() * glm::mat4(modelViewMat)
    );

    SceneGraphNode* earthNode = sceneGraphNode("Earth");
    if (!earthNode) {
        LWARNING("Could not find scene graph node 'Earth'");
    }
    glm::vec3 earthPos = earthNode->worldPosition() * data.modelTransform.rotation;

    _shaderProgram->setUniform(_uniformCache.streamColor, _streamColor);
    _shaderProgram->setUniform(_uniformCache.nodeSize, _nodeSize);
    _shaderProgram->setUniform(_uniformCache.thresholdFlux, _thresholdFlux);
    _shaderProgram->setUniform(_uniformCache.colorMode, _colorMode);
    _shaderProgram->setUniform(_uniformCache.filterLower, _filteringLower);
    _shaderProgram->setUniform(_uniformCache.filterUpper, _filteringUpper);
    _shaderProgram->setUniform(_uniformCache.scalingMode, _scalingMethod);
    _shaderProgram->setUniform(_uniformCache.colorTableRange, _colorTableRange);
    _shaderProgram->setUniform(_uniformCache.domainLimZ, _domainZ);
    _shaderProgram->setUniform(_uniformCache.nodeSkip, _amountofNodes);
    _shaderProgram->setUniform(_uniformCache.nodeSkipDefault, _defaultNodeSkip);
    _shaderProgram->setUniform(_uniformCache.nodeSkipEarth, _earthNodeSkip);
    _shaderProgram->setUniform(_uniformCache.nodeSkipMethod, _nodeskipMethod);
    _shaderProgram->setUniform(
        _uniformCache.nodeSkipFluxThreshold,
        _fluxNodeskipThreshold
    );
    _shaderProgram->setUniform(
        _uniformCache.nodeSkipRadiusThreshold,
        _radiusNodeSkipThreshold
    );
    _shaderProgram->setUniform(_uniformCache.fluxColorAlpha, _fluxColorAlpha);

    _shaderProgram->setUniform(_uniformCache.earthPos, earthPos);
    _shaderProgram->setUniform(_uniformCache.distanceThreshold, _distanceThreshold);
    _shaderProgram->setUniform(_uniformCache.proximityNodesSize, _proximityNodesSize);
    _shaderProgram->setUniform(
        _uniformCache.time,
        global::windowDelegate->applicationTime()
    );
    _shaderProgram->setUniform(
        _uniformCache.maxNodeDistanceSize,
        _maxNodeDistanceSize
    );
    _shaderProgram->setUniform(
        _uniformCache.usingCameraPerspective,
        _cameraPerspectiveEnabled
    );
    _shaderProgram->setUniform(_uniformCache.drawCircles, _drawingCircles);
    _shaderProgram->setUniform(_uniformCache.drawHollow, _drawingHollow);
    _shaderProgram->setUniform(_uniformCache.useGaussian, _gaussianAlphaFilter);

    _shaderProgram->setUniform(
        _uniformCache.perspectiveDistanceFactor,
        _perspectiveDistanceFactor
    );
    _shaderProgram->setUniform(_uniformCache.minMaxNodeSize, _minMaxNodeSize);
    _shaderProgram->setUniform(_uniformCache.usingPulse, _pulseEnabled);
    _shaderProgram->setUniform(
        _uniformCache.usingGaussianPulse,
        _gaussianPulseEnabled
    );

    glm::vec3 cameraPos = data.camera.positionVec3() * data.modelTransform.rotation;

    _shaderProgram->setUniform("cameraPos", cameraPos);

    if (_colorMode == static_cast<int>(ColorMethod::ByFluxValue)) {
        ghoul::opengl::TextureUnit textureUnit;
        textureUnit.activate();
        _transferFunction->bind(); // Calls update internally
        _shaderProgram->setUniform("colorTable", textureUnit);
    }

    glBindVertexArray(_vertexArrayObject);

    glDrawArrays(
        GL_POINTS,
        0,
        static_cast<GLsizei>(_vertexPositions.size())
    );

    glBindVertexArray(0);
    _shaderProgram->deactivate();
}

void RenderableFluxNodes::computeSequenceEndTime() {
    if (_nStates > 1) {
        const double lastTriggerTime = _startTimes[_nStates - 1];
        const double sequenceDuration = lastTriggerTime - _startTimes[0];
        const double averageStateDuration = sequenceDuration /
            (static_cast<double>(_nStates) - 1.0);
        _sequenceEndTime = lastTriggerTime + averageStateDuration;
    }
    else if (_nStates == 1) {
        // If there's just one state it should never disappear!
        _sequenceEndTime = std::numeric_limits<double>::max();
    }
    else {
        LERROR("No states were found. The position file include this data");
    }
}

void RenderableFluxNodes::update(const UpdateData& data) {
    if (!_enabled) {
        return;
    }
    if (_shaderProgram->isDirty()) {
        _shaderProgram->rebuildFromFile();
    }
    bool needsUpdate = true;
    //Everything below is for updating depending on time
    const double currentTime = data.time.j2000Seconds();
    const bool isInInterval = (currentTime >= _startTimes[0]) &&
            (currentTime < _sequenceEndTime);
    //const bool isInInterval = true;
    if (isInInterval) {
        const size_t nextIdx = _activeTriggerTimeIndex + 1;
        if (
            // true => we were not in an interval the previous frame but now we are
            _activeTriggerTimeIndex == -1 ||
            // true => We stepped back to a time represented by another state
            currentTime < _startTimes[_activeTriggerTimeIndex] ||
            // true => We stepped forward to a time represented by another state
            (nextIdx < _nStates && currentTime >= _startTimes[nextIdx]))
        {
            updateActiveTriggerTimeIndex(currentTime);
        } // else {we're still in same state as previous frame (no changes needed)}
    }
    else {
        _activeTriggerTimeIndex = -1;
        needsUpdate = false;
    }

    if (needsUpdate && !_statesPos[_activeTriggerTimeIndex].empty()) {
        _vertexPositions = _statesPos[_activeTriggerTimeIndex];
        _vertexColor = _statesColor[_activeTriggerTimeIndex];
        _vertexRadius = _statesRadius[_activeTriggerTimeIndex];
        needsUpdate = false;
        updatePositionBuffer();
        updateVertexColorBuffer();
        updateVertexFilteringBuffer();
    }

    if (_shaderProgram->isDirty()) {
        _shaderProgram->rebuildFromFile();
        ghoul::opengl::updateUniformLocations(
            *_shaderProgram,
            _uniformCache,
            UniformNames
        );
    }
}

void RenderableFluxNodes::updatePositionBuffer() {
    glBindVertexArray(_vertexArrayObject);
    glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer);

    glBufferData(
        GL_ARRAY_BUFFER,
        _vertexPositions.size() * sizeof(glm::vec3),
        _vertexPositions.data(),
        GL_STATIC_DRAW
    );

    glEnableVertexAttribArray(0);
    glEnable(GL_PROGRAM_POINT_SIZE);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}

void RenderableFluxNodes::updateVertexColorBuffer() {
    glBindVertexArray(_vertexArrayObject);
    glBindBuffer(GL_ARRAY_BUFFER, _vertexColorBuffer);

    glBufferData(
        GL_ARRAY_BUFFER,
        _vertexColor.size() * sizeof(float),
        _vertexColor.data(),
        GL_STATIC_DRAW
    );

    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, nullptr);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}

void RenderableFluxNodes::updateVertexFilteringBuffer() {
    glBindVertexArray(_vertexArrayObject);
    glBindBuffer(GL_ARRAY_BUFFER, _vertexFilteringBuffer);

    glBufferData(
        GL_ARRAY_BUFFER,
        _vertexRadius.size() * sizeof(float),
        _vertexRadius.data(),
        GL_STATIC_DRAW
    );

    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 0, nullptr);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}
} // namespace openspace


text:
class Pistoncms::Public::PagesController < Pistoncms::Public::PistoncmsController

  before_action :_set_page

  def show

  end

  private

  def _set_page
    @page = Pistoncms::Page.find_by!(slug: params[:slug])
  end

end

redpajama_set_name: RedPajamaGithub


text:
import React, {useCallback, useState} from 'react';
import {useIntl} from 'react-intl';

import {doAppFetchForm, doAppLookup, doAppSubmit, postEphemeralCallResponseForContext} from '@actions/remote/apps';
import {handleGotoLocation} from '@actions/remote/command';
import {AppCallResponseTypes} from '@constants/apps';
import {useServerUrl} from '@context/server';
import {createCallRequest, makeCallErrorResponse} from '@utils/apps';

import AppsFormComponent from './apps_form_component';

export type Props = {
    form?: AppForm;
    context?: AppContext;
    componentId: string;
};

function AppsFormContainer({
    form,
    context,
    componentId,
}: Props) {
    const intl = useIntl();
    const [currentForm, setCurrentForm] = useState(form);
    const serverUrl = useServerUrl();

    const submit = useCallback(async (submission: {values: AppFormValues}): Promise<{data?: AppCallResponse<FormResponseData>; error?: AppCallResponse<FormResponseData>}> => {
        const makeErrorMsg = (msg: string) => {
            return intl.formatMessage(
                {
                    id: 'apps.error.form.submit.pretext',
                    defaultMessage: 'There has been an error submitting the modal. Contact the app developer. Details: {details}',
                },
                {details: msg},
            );
        };

        if (!currentForm) {
            return {error: makeCallErrorResponse(makeErrorMsg(intl.formatMessage(
                {
                    id: 'apps.error.form.no_form',
                    defaultMessage: '`form` is not defined',
                },
            )))};
        }

        if (!currentForm.submit) {
            return {error: makeCallErrorResponse(makeErrorMsg(intl.formatMessage(
                {
                    id: 'apps.error.form.no_submit',
                    defaultMessage: '`submit` is not defined',
                },
            )))};
        }

        if (!context) {
            return {error: makeCallErrorResponse('unreachable: empty context')};
        }

        const creq = createCallRequest(currentForm.submit, context, {}, submission.values);
        const res = await doAppSubmit<FormResponseData>(serverUrl, creq, intl);

        if (res.error) {
            return res;
        }

        const callResp = res.data!;
        switch (callResp.type) {
            case AppCallResponseTypes.OK:
                if (callResp.text) {
                    postEphemeralCallResponseForContext(serverUrl, callResp, callResp.text, creq.context);
                }
                break;
            case AppCallResponseTypes.FORM:
                setCurrentForm(callResp.form);
                break;
            case AppCallResponseTypes.NAVIGATE:
                if (callResp.navigate_to_url) {
                    handleGotoLocation(serverUrl, intl, callResp.navigate_to_url);
                }
                break;
            default:
                return {error: makeCallErrorResponse(makeErrorMsg(intl.formatMessage(
                    {
                        id: 'apps.error.responses.unknown_type',
                        defaultMessage: 'App response type not supported. Response type: {type}.',
                    }, {
                        type: callResp.type,
                    },
                )))};
        }
        return res;
    }, []);

    const refreshOnSelect = useCallback(async (field: AppField, values: AppFormValues): Promise<DoAppCallResult<FormResponseData>> => {
        const makeErrorMsg = (message: string) => intl.formatMessage(
            {
                id: 'apps.error.form.refresh',
                defaultMessage: 'There has been an error updating the modal. Contact the app developer. Details: {details}',
            },
            {details: message},
        );
        if (!currentForm) {
            return {error: makeCallErrorResponse(makeErrorMsg(intl.formatMessage({
                id: 'apps.error.form.no_form',
                defaultMessage: '`form` is not defined.',
            })))};
        }

        if (!currentForm.source) {
            return {error: makeCallErrorResponse(makeErrorMsg(intl.formatMessage({
                id: 'apps.error.form.no_source',
                defaultMessage: '`source` is not defined.',
            })))};
        }

        if (!field.refresh) {
            // Should never happen
            return {error: makeCallErrorResponse(makeErrorMsg(intl.formatMessage({
                id: 'apps.error.form.refresh_no_refresh',
                defaultMessage: 'Called refresh on no refresh field.',
            })))};
        }

        if (!context) {
            return {error: makeCallErrorResponse('unreachable: empty context')};
        }

        const creq = createCallRequest(currentForm.source, context, {}, values);
        creq.selected_field = field.name;

        const res = await doAppFetchForm<FormResponseData>(serverUrl, creq, intl);

        if (res.error) {
            return res;
        }
        const callResp = res.data!;
        switch (callResp.type) {
            case AppCallResponseTypes.FORM:
                setCurrentForm(callResp.form);
                break;
            case AppCallResponseTypes.OK:
            case AppCallResponseTypes.NAVIGATE:
                return {error: makeCallErrorResponse(makeErrorMsg(intl.formatMessage({
                    id: 'apps.error.responses.unexpected_type',
                    defaultMessage: 'App response type was not expected. Response type: {type}.',
                }, {
                    type: callResp.type,
                },
                )))};
            default:
                return {error: makeCallErrorResponse(makeErrorMsg(intl.formatMessage({
                    id: 'apps.error.responses.unknown_type',
                    defaultMessage: 'App response type not supported. Response type: {type}.',
                }, {
                    type: callResp.type,
                },
                )))};
        }
        return res;
    }, []);

    const performLookupCall = useCallback(async (field: AppField, values: AppFormValues, userInput: string): Promise<DoAppCallResult<AppLookupResponse>> => {
        const makeErrorMsg = (message: string) => intl.formatMessage(
            {
                id: 'apps.error.form.refresh',
                defaultMessage: 'There has been an error fetching the select fields. Contact the app developer. Details: {details}',
            },
            {details: message},
        );
        if (!field.lookup) {
            return {error: makeCallErrorResponse(makeErrorMsg(intl.formatMessage({
                id: 'apps.error.form.no_lookup',
                defaultMessage: '`lookup` is not defined.',
            })))};
        }

        if (!context) {
            return {error: makeCallErrorResponse('unreachable: empty context')};
        }

        const creq = createCallRequest(field.lookup, context, {}, values);
        creq.selected_field = field.name;
        creq.query = userInput;

        return doAppLookup<AppLookupResponse>(serverUrl, creq, intl);
    }, []);

    if (!currentForm?.submit || !context) {
        return null;
    }

    return (
        <AppsFormComponent
            form={currentForm}
            componentId={componentId}
            performLookupCall={performLookupCall}
            refreshOnSelect={refreshOnSelect}
            submit={submit}
        />
    );
}

export default AppsFormContainer;


text:
function Set-PowerShellWindowTitle {
    <#
    .SYNOPSIS
        Function to set the title of the PowerShell Window

    .DESCRIPTION
        Function to set the title of the PowerShell Window

    .PARAMETER Title
        Specifies the Title of the PowerShell Window

    .EXAMPLE
        PS C:\> Set-PowerShellWindowTitle -Title LazyWinAdmin.com

    .NOTES
        Francois-Xavier Cat
        lazywinadmin.com
        @lazywinadmin
#>
    [CmdletBinding()]
    PARAM($Title)
    try {
        $Host.UI.RawUI.WindowTitle = $Title
    }
    catch {
        $PSCmdlet.ThrowTerminatingError($_)
    }
}


text:
import {geoProjectionMutator as projectionMutator, geoAzimuthalEquidistantRaw as azimuthalEquidistantRaw} from "d3-geo";
import {abs, acos, asin, atan, atan2, cos, degrees, halfPi, pi, radians, round, sin, sqrt, tan} from "./math";

export function berghausRaw(lobes) {
  var k = 2 * pi / lobes;

  function forward(lambda, phi) {
    var p = azimuthalEquidistantRaw(lambda, phi);
    if (abs(lambda) > halfPi) { // back hemisphere
      var theta = atan2(p[1], p[0]),
          r = sqrt(p[0] * p[0] + p[1] * p[1]),
          theta0 = k * round((theta - halfPi) / k) + halfPi,
          alpha = atan2(sin(theta -= theta0), 2 - cos(theta)); // angle relative to lobe end
      theta = theta0 + asin(pi / r * sin(alpha)) - alpha;
      p[0] = r * cos(theta);
      p[1] = r * sin(theta);
    }
    return p;
  }

  forward.invert = function(x, y) {
    var r = sqrt(x * x + y * y);
    if (r > halfPi) {
      var theta = atan2(y, x),
          theta0 = k * round((theta - halfPi) / k) + halfPi,
          s = theta > theta0 ? -1 : 1,
          A = r * cos(theta0 - theta),
          cotAlpha = 1 / tan(s * acos((A - pi) / sqrt(pi * (pi - 2 * A) + r * r)));
      theta = theta0 + 2 * atan((cotAlpha + s * sqrt(cotAlpha * cotAlpha - 3)) / 3);
      x = r * cos(theta), y = r * sin(theta);
    }
    return azimuthalEquidistantRaw.invert(x, y);
  };

  return forward;
}

export default function() {
  var lobes = 5,
      m = projectionMutator(berghausRaw),
      p = m(lobes),
      projectionStream = p.stream,
      epsilon = 1e-2,
      cr = -cos(epsilon * radians),
      sr = sin(epsilon * radians);

  p.lobes = function(_) {
    return arguments.length ? m(lobes = +_) : lobes;
  };

  p.stream = function(stream) {
    var rotate = p.rotate(),
        rotateStream = projectionStream(stream),
        sphereStream = (p.rotate([0, 0]), projectionStream(stream));
    p.rotate(rotate);
    rotateStream.sphere = function() {
      sphereStream.polygonStart(), sphereStream.lineStart();
      for (var i = 0, delta = 360 / lobes, delta0 = 2 * pi / lobes, phi = 90 - 180 / lobes, phi0 = halfPi; i < lobes; ++i, phi -= delta, phi0 -= delta0) {
        sphereStream.point(atan2(sr * cos(phi0), cr) * degrees, asin(sr * sin(phi0)) * degrees);
        if (phi < -90) {
          sphereStream.point(-90, -180 - phi - epsilon);
          sphereStream.point(-90, -180 - phi + epsilon);
        } else {
          sphereStream.point(90, phi + epsilon);
          sphereStream.point(90, phi - epsilon);
        }
      }
      sphereStream.lineEnd(), sphereStream.polygonEnd();
    };
    return rotateStream;
  };

  return p
      .scale(87.8076)
      .center([0, 17.1875])
      .clipAngle(180 - 1e-3);
}


text:
/**
 *
 */
package com.browseengine.bobo.facets.impl;

import java.util.NoSuchElementException;

import com.browseengine.bobo.api.ShortFacetIterator;
import com.browseengine.bobo.facets.data.TermShortList;
import com.browseengine.bobo.util.BigSegmentedArray;

/**
 * @author "Xiaoyang Gu<xgu@linkedin.com>"
 *
 */
public class DefaultShortFacetIterator extends ShortFacetIterator {

  public TermShortList _valList;
  private BigSegmentedArray _count;
  private int _countlength;
  private int _countLengthMinusOne;
  private int _index;

  public DefaultShortFacetIterator(TermShortList valList, BigSegmentedArray countarray,
      int countlength, boolean zeroBased) {
    _valList = valList;
    _countlength = countlength;
    _count = countarray;
    _countLengthMinusOne = _countlength - 1;
    _index = -1;
    if (!zeroBased) _index++;
    facet = TermShortList.VALUE_MISSING;
    count = 0;
  }

  /*
   * (non-Javadoc)
   * @see com.browseengine.bobo.api.FacetIterator#getFacet()
   */
  public String getFacet() {
    if (facet == TermShortList.VALUE_MISSING) return null;
    return _valList.format(facet);
  }

  public String format(short val) {
    return _valList.format(val);
  }

  public String format(Object val) {
    return _valList.format(val);
  }

  /*
   * (non-Javadoc)
   * @see com.browseengine.bobo.api.FacetIterator#getFacetCount()
   */
  public int getFacetCount() {
    return count;
  }

  /*
   * (non-Javadoc)
   * @see java.util.Iterator#hasNext()
   */
  public boolean hasNext() {
    return (_index < _countLengthMinusOne);
  }

  /*
   * (non-Javadoc)
   * @see java.util.Iterator#next()
   */
  public String next() {
    if ((_index >= 0) && (_index >= _countLengthMinusOne)) throw new NoSuchElementException(
        "No more facets in this iteration");
    _index++;
    facet = _valList.getPrimitiveValue(_index);
    count = _count.get(_index);
    return _valList.get(_index);
  }

  /*
   * (non-Javadoc)
   * @see com.browseengine.bobo.api.ShortFacetIterator#nextShort()
   */
  public short nextShort() {
    if (_index >= _countLengthMinusOne) throw new NoSuchElementException(
        "No more facets in this iteration");
    _index++;
    facet = _valList.getPrimitiveValue(_index);
    count = _count.get(_index);
    return facet;
  }

  /*
   * (non-Javadoc)
   * @see java.util.Iterator#remove()
   */
  public void remove() {
    throw new UnsupportedOperationException("remove() method not supported for Facet Iterators");
  }

  /*
   * (non-Javadoc)
   * @see com.browseengine.bobo.api.FacetIterator#next(int)
   */
  public String next(int minHits) {
    while (++_index < _countlength) {
      if (_count.get(_index) >= minHits) {
        facet = _valList.getPrimitiveValue(_index);
        count = _count.get(_index);
        return _valList.format(facet);
      }
    }
    facet = TermShortList.VALUE_MISSING;
    count = 0;
    return null;
  }

  /*
   * (non-Javadoc)
   * @see com.browseengine.bobo.api.ShortFacetIterator#nextShort(int)
   */
  public short nextShort(int minHits) {
    while (++_index < _countlength) {
      if (_count.get(_index) >= minHits) {
        facet = _valList.getPrimitiveValue(_index);
        count = _count.get(_index);
        return facet;
      }
    }
    facet = TermShortList.VALUE_MISSING;
    count = 0;
    return facet;
  }

}


text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

namespace MCDA.Model
{
    internal sealed class Cluster
    {
        private readonly ToolParameterContainer _toolParameterContainer;
        private readonly DataTable _dataTable;
        private readonly EnumerableRowCollection<DataRow> _enumerableRowCollection;
        private readonly int _featureId;
        private readonly IList<int> _clusterIDs;
        private readonly NormalizationStrategy _transformationStrategy;

        private IList<Tuple<IToolParameter, double>> _globalRange;
        private IList<Tuple<IToolParameter, double>> _localRange;
        private IList<Tuple<IToolParameter, double?>> _scaledValues;
        private IList<Tuple<IToolParameter, double?>> _weights;

        public Cluster(int featureId, IList<int> clusterIDs, DataTable dt, ToolParameterContainer toolParameterContainer, NormalizationStrategy transformationStrategy)
        {
            _featureId = featureId;
            _clusterIDs = clusterIDs;
            _dataTable = dt;
            _enumerableRowCollection = _dataTable.AsEnumerable();
            _toolParameterContainer = toolParameterContainer;
            _transformationStrategy = transformationStrategy;

            //the feature id is also part of the cluster!
            _clusterIDs.Add(featureId);
        }

        private int GetOIDColumnIndex()
        {
            foreach (DataColumn currentDataColumn in _dataTable.Columns)
            {
                if (currentDataColumn.DataType == typeof(FieldTypeOID))
                {
                    return currentDataColumn.Ordinal;
                }
            }

            return -1;
        }

        private IList<Tuple<IToolParameter, double>> GlobalRange(ToolParameterContainer toolParameterContainer)
        {
            IList<Tuple<IToolParameter, double>> listOfRangeTuple = new List<Tuple<IToolParameter, double>>();

            foreach (var currentToolParameter in toolParameterContainer.ToolParameter)
            {
                IList<double> data = _enumerableRowCollection.Select(x => x.Field<double>(currentToolParameter.ColumnName)).ToList();

                listOfRangeTuple.Add(Tuple.Create(currentToolParameter, data.Max() - data.Min()));
            }

            return listOfRangeTuple;
        }

        private IList<Tuple<IToolParameter, double>> LocalRange(ToolParameterContainer toolParameterContainer)
        {
            int oidColumnIndex = GetOIDColumnIndex();

            IList<Tuple<IToolParameter, double>> listOfRangeTuple = new List<Tuple<IToolParameter, double>>();

            var rows = _enumerableRowCollection.Where(x => _clusterIDs.Contains(x.Field<FieldTypeOID>(oidColumnIndex).OID));
            foreach (var currentToolParameter in toolParameterContainer.ToolParameter)
            {
                IList<double> data = rows.Select(x => x.Field<double>(currentToolParameter.ColumnName)).ToList();

                listOfRangeTuple.Add(Tuple.Create(currentToolParameter, data.Max() - data.Min()));
            }

            return listOfRangeTuple;
        }

        private IList<Tuple<IToolParameter, double?>> Scale(ToolParameterContainer toolParameterContainer, IList<Tuple<IToolParameter, double>> localRangeList)
        {
            IList<Tuple<IToolParameter, double?>> listOfScaledTuple = new List<Tuple<IToolParameter, double?>>();

            var oidColumnIndex = GetOIDColumnIndex();
            var clusterIDsRows = _enumerableRowCollection.Where(x => _clusterIDs.Contains(x.Field<FieldTypeOID>(oidColumnIndex).OID));
            var featureIDRow = _enumerableRowCollection.Where(x => x.Field<FieldTypeOID>(oidColumnIndex).OID == _featureId);

            foreach (var currentToolParameter in toolParameterContainer.ToolParameter)
            {
                var currentLocalRange = localRangeList.FirstOrDefault(x => x.Item1 == currentToolParameter);

                IList<double> data = clusterIDsRows.Select(x => x.Field<double>(currentToolParameter.ColumnName)).Distinct().ToList();

                var actualValue = featureIDRow.Select(x => x.Field<double>(currentToolParameter.ColumnName)).FirstOrDefault();

                var result = NormalizationStrategyFactory.GetStrategy(_transformationStrategy).Transform(data, actualValue, currentToolParameter.IsBenefitCriterion);

                listOfScaledTuple.Add(Tuple.Create(currentToolParameter, result));
            }

            return listOfScaledTuple;
        }

        private static IList<Tuple<IToolParameter, double?>> LocalWeights(ToolParameterContainer toolParameterContainer, IList<Tuple<IToolParameter, double>> localRangeList, IList<Tuple<IToolParameter, double>> globalRangeList)
        {
            IList<Tuple<IToolParameter, double?>> listOfLocalWeightTupel = new List<Tuple<IToolParameter, double?>>();

            double? divisor = 0;

            foreach (var currentToolParameter2 in toolParameterContainer.ToolParameter)
            {
                var localRange2 = localRangeList.First(x => x.Item1 == currentToolParameter2).Item2;
                var globalRange2 = globalRangeList.First(x => x.Item1 == currentToolParameter2).Item2;

                if (globalRange2 == 0)
                {
                    divisor = null;
                    break;
                }

                divisor = divisor + ((currentToolParameter2.ScaledWeight * localRange2) / globalRange2);
            }

            if (divisor == 0)
            {
                divisor = null;
            }

            foreach (var currentToolParameter in toolParameterContainer.ToolParameter)
            {
                var localRange = localRangeList.FirstOrDefault(x => x.Item1 == currentToolParameter).Item2;
                var globalRange = globalRangeList.FirstOrDefault(x => x.Item1 == currentToolParameter).Item2;

                double? dividend;
                if (globalRange == 0)
                {
                    dividend = null;
                }
                else
                {
                    dividend = (currentToolParameter.ScaledWeight * localRange) / globalRange;
                }

                if (dividend.HasValue && divisor.HasValue)
                {
                    listOfLocalWeightTupel.Add(new Tuple<IToolParameter, double?>(currentToolParameter, dividend / divisor));
                }
                else
                {
                    listOfLocalWeightTupel.Add(new Tuple<IToolParameter, double?>(currentToolParameter, null));
                }
            }
            return listOfLocalWeightTupel;
        }

        public void Calculate()
        {
             _globalRange = GlobalRange(_toolParameterContainer);
             _localRange = LocalRange(_toolParameterContainer);

             _scaledValues = Scale(_toolParameterContainer, _localRange);
             _weights = LocalWeights(_toolParameterContainer, _localRange, _globalRange);
        }

        public bool IsResultNull()
        {
            Calculate();

            foreach (IToolParameter currentToolParameter in _toolParameterContainer.ToolParameter)
            {
                var scaledValue = _scaledValues.FirstOrDefault(x => x.Item1 == currentToolParameter).Item2;
                var weight = _weights.FirstOrDefault(x => x.Item1 == currentToolParameter).Item2;

                if (!scaledValue.HasValue || !weight.HasValue)
                {
                    return true;
                }
            }
            return false;
        }

        // oid/fid, r1,s1, w1, r2, s2, w3, result
        public DataRow FillRowWithResults(DataRow row)
        {
            row[0] = new FieldTypeOID(){ OID = _featureId};

            var stringBuilder = new StringBuilder();

            foreach(int currentId in _clusterIDs){

                if (stringBuilder.Length == 0)
                {
                    stringBuilder.Append(currentId);
                }
                else
                {
                    stringBuilder.Append("; " + currentId);
                }
            }

            row[1] = stringBuilder.ToString();

            var index = 2;
            double? result = 0;

            foreach (var currentToolParameter in _toolParameterContainer.ToolParameter)
            {
                var scaledValue = _scaledValues.First(x => x.Item1 == currentToolParameter).Item2;
                var weight = _weights.First(x => x.Item1 == currentToolParameter).Item2;

                row[index] = _localRange.First(x => x.Item1 == currentToolParameter).Item2;

                if (scaledValue.HasValue)
                {
                    row[index + 1] = scaledValue;
                }
                else
                {
                    row[index + 1] = DBNull.Value;
                }

                if (weight.HasValue)
                {
                    row[index + 2] = weight;
                }
                else
                {
                    row[index + 2] = DBNull.Value;
                }

                if (scaledValue.HasValue && weight.HasValue && result.HasValue)
                {
                    result += scaledValue*weight;
                }
                else
                {
                    result = null;
                }

                index += 3;
            }

            if (result.HasValue)
            {
                row.SetField(row.ItemArray.Length - 1, Math.Round(result.Value < 0 ? 0 : result.Value, 6));
            }
            else
            {
                row.SetField(row.ItemArray.Length - 1, DBNull.Value);
            }

            return row;
        }
    }
}


text:
START_ATF_NAMESPACE
    typedef IExtractImage *LPEXTRACTIMAGE;
END_ATF_NAMESPACE


text:
package org.apache.shardingsphere.infra.binder.statement;

import org.apache.shardingsphere.infra.binder.SQLStatementContextFactory;
import org.apache.shardingsphere.infra.binder.statement.dml.InsertStatementContext;
import org.apache.shardingsphere.infra.binder.statement.dml.SelectStatementContext;
import org.apache.shardingsphere.infra.database.DefaultSchema;
import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.assignment.AssignmentSegment;
import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.assignment.ColumnAssignmentSegment;
import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.assignment.SetAssignmentSegment;
import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.ColumnSegment;
import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ProjectionsSegment;
import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.pagination.limit.LimitSegment;
import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment;
import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.TableNameSegment;
import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.InsertStatement;
import org.apache.shardingsphere.sql.parser.sql.common.value.identifier.IdentifierValue;
import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.MySQLStatement;
import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dml.MySQLInsertStatement;
import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dml.MySQLSelectStatement;
import org.apache.shardingsphere.sql.parser.sql.dialect.statement.oracle.dml.OracleInsertStatement;
import org.apache.shardingsphere.sql.parser.sql.dialect.statement.postgresql.dml.PostgreSQLInsertStatement;
import org.apache.shardingsphere.sql.parser.sql.dialect.statement.sql92.dml.SQL92InsertStatement;
import org.apache.shardingsphere.sql.parser.sql.dialect.statement.sqlserver.dml.SQLServerInsertStatement;
import org.junit.Test;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.mock;

public final class SQLStatementContextFactoryTest {

    @Test
    public void assertSQLStatementContextCreatedWhenSQLStatementInstanceOfSelectStatement() {
        ProjectionsSegment projectionsSegment = new ProjectionsSegment(0, 0);
        MySQLSelectStatement selectStatement = new MySQLSelectStatement();
        selectStatement.setLimit(new LimitSegment(0, 10, null, null));
        selectStatement.setProjections(projectionsSegment);
        SQLStatementContext<?> sqlStatementContext = SQLStatementContextFactory.newInstance(mockMetaDataMap(), Collections.emptyList(), selectStatement, DefaultSchema.LOGIC_NAME);
        assertNotNull(sqlStatementContext);
        assertTrue(sqlStatementContext instanceof SelectStatementContext);
    }

    @Test
    public void assertSQLStatementContextCreatedWhenSQLStatementInstanceOfMySQLInsertStatement() {
        MySQLInsertStatement insertStatement = new MySQLInsertStatement();
        List<ColumnSegment> columnSegments = new LinkedList<>();
        columnSegments.add(new ColumnSegment(0, 0, new IdentifierValue("IdentifierValue")));
        AssignmentSegment assignment = new ColumnAssignmentSegment(0, 0, columnSegments, null);
        insertStatement.setSetAssignment(new SetAssignmentSegment(0, 0,
                Collections.singleton(assignment)));
        assertSQLStatementContextCreatedWhenSQLStatementInstanceOfInsertStatement(insertStatement);
    }

    @Test
    public void assertSQLStatementContextCreatedWhenSQLStatementInstanceOfOracleInsertStatement() {
        assertSQLStatementContextCreatedWhenSQLStatementInstanceOfInsertStatement(new OracleInsertStatement());
    }

    @Test
    public void assertSQLStatementContextCreatedWhenSQLStatementInstanceOfPostgreSQLInsertStatement() {
        assertSQLStatementContextCreatedWhenSQLStatementInstanceOfInsertStatement(new PostgreSQLInsertStatement());
    }

    @Test
    public void assertSQLStatementContextCreatedWhenSQLStatementInstanceOfSQL92InsertStatement() {
        assertSQLStatementContextCreatedWhenSQLStatementInstanceOfInsertStatement(new SQL92InsertStatement());
    }

    @Test
    public void assertSQLStatementContextCreatedWhenSQLStatementInstanceOfSQLServerInsertStatement() {
        assertSQLStatementContextCreatedWhenSQLStatementInstanceOfInsertStatement(new SQLServerInsertStatement());
    }

    private void assertSQLStatementContextCreatedWhenSQLStatementInstanceOfInsertStatement(final InsertStatement insertStatement) {
        insertStatement.setTable(new SimpleTableSegment(new TableNameSegment(0, 0, new IdentifierValue("tbl"))));
        SQLStatementContext<?> sqlStatementContext = SQLStatementContextFactory.newInstance(mockMetaDataMap(), Collections.emptyList(), insertStatement, DefaultSchema.LOGIC_NAME);
        assertNotNull(sqlStatementContext);
        assertTrue(sqlStatementContext instanceof InsertStatementContext);
    }

    @Test
    public void assertSQLStatementContextCreatedWhenSQLStatementNotInstanceOfSelectStatementAndInsertStatement() {
        SQLStatementContext<?> sqlStatementContext = SQLStatementContextFactory.newInstance(mockMetaDataMap(), Collections.emptyList(), mock(MySQLStatement.class), DefaultSchema.LOGIC_NAME);
        assertNotNull(sqlStatementContext);
        assertTrue(sqlStatementContext instanceof CommonSQLStatementContext);
    }

    private Map<String, ShardingSphereMetaData> mockMetaDataMap() {
        return Collections.singletonMap(DefaultSchema.LOGIC_NAME, mock(ShardingSphereMetaData.class, RETURNS_DEEP_STUBS));
    }
}


text:
IN_PWEAVE = __name__ == "__builtin__"

# python standard library
import threading

# this package
from theape import BaseClass

class EventTimer(BaseClass):
    """
    A timer object to set an event
    """
    def __init__(self, seconds=0.5, event=None):
        """
        EventTimer constructor

        :param:

         - `event`: a threading.Event to set
         - `seconds`: number of seconds to run the timer
        """
        self._event = event
        self.seconds = seconds
        self._timer = None
        return

    @property
    def event(self):
        """
        Threading event for the timer to set
        """
        if self._event is None:
            self._event = threading.Event()
            # I don't know about this, but I think
            # I want it to always rely on the timer to clear it
            self._event.set()
        return self._event

    @property
    def timer(self):
        """
        A threading.Timer object
        """
        # Timers can only be started once, so this can't be persistent
        return threading.Timer(self.seconds, self.set_event)

    def set_event(self):
        """
        Sets the event
        """
        self.event.set()
        return

    def start(self):
        """
        The main interface - clears the event then starts the timer
        """
        self.event.clear()
        self.timer.start()
        return

    def clear(self):
        """
        A convenience method for users to call the event.clear method.
        """
        self.event.clear()
        return

    def wait(self, timeout=None):
        """
        Calls event.wait if timeout is None, uses self.seconds
        """
        if timeout is None:
            timeout = self.seconds
        self.event.wait(timeout)
        return

    def close(self):
        """
        Cancels the timer and sets the event.
        """
        self.timer.cancel()
        self.event.set()
        return

    def is_set(self):
        """
        :return: True if self.event is set
        """
        return self.event.is_set()
# end class EventTimer

def wait(method):
    """
    Decorator to wait for previous timers and to start a new one on exit

    :param:

     - `method`: method to wrap with a timer.wait call

    :return: wrapped method
    """
    def _method(self, *args, **kwargs):
        # wait if timer is running but only up until the time-limit
        self.timer.wait(self.timer.seconds)
        self.timer.clear()
        outcome = method(self, *args, **kwargs)
        self.timer.start()
        return outcome
    return _method


text:
package service.impl;

import service.ActivityRecordService;
import dao.ActivityRecordDao;

public class ActivityRecordServiceImpl implements ActivityRecordService {

	private ActivityRecordDao activityRecordDao;

	private ActivityRecordServiceImpl(){

	}

	public ActivityRecordDao getActivityRecordDao() {
		return activityRecordDao;
	}

	public void setActivityRecordDao(ActivityRecordDao activityRecordDao) {
		this.activityRecordDao = activityRecordDao;
	}
}


text:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Data;

namespace System.Windows.Controls
{
    /// <summary>
    ///     A collection that simulates holding multiple copies of the same item.  Used as the ItemsSource for the DataGridCellsPresenter.
    ///     For our purposes this mirrors the DataGrid.Columns collection in that it has the same number of items and changes whenever
    ///     the columns collection changes (though the items in it are obviously different; each item is the data object for a given row).
    /// </summary>
    internal class MultipleCopiesCollection :
        IList,
        ICollection,
        IEnumerable,
        INotifyCollectionChanged,
        INotifyPropertyChanged
    {
        #region Construction

        internal MultipleCopiesCollection(object item, int count)
        {
            Debug.Assert(item != null, "item should not be null.");
            Debug.Assert(count >= 0, "count should not be negative.");

            CopiedItem = item;
            _count = count;
        }

        #endregion

        #region Item Management

        /// <summary>
        ///     Takes a collection change notifcation and causes the MultipleCopies collection to [....] to the changes.  For example,
        ///     if an item was removed at a given index, the MultipleCopiesCollection also removes an item at the same index and fires
        ///     its own collection changed event.
        /// </summary>
        internal void MirrorCollectionChange(NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    Debug.Assert(
                        e.NewItems.Count == 1,
                        "We're mirroring the Columns collection which is an ObservableCollection and only supports adding one item at a time");
                    Insert(e.NewStartingIndex);
                    break;

                case NotifyCollectionChangedAction.Move:
                    Debug.Assert(
                        e.NewItems.Count == 1,
                        "We're mirroring the Columns collection which is an ObservableCollection and only supports moving one item at a time");
                    Move(e.OldStartingIndex, e.NewStartingIndex);
                    break;

                case NotifyCollectionChangedAction.Remove:
                    Debug.Assert(
                        e.OldItems.Count == 1,
                        "We're mirroring the Columns collection which is an ObservableCollection and only supports removing one item at a time");
                    RemoveAt(e.OldStartingIndex);
                    break;

                case NotifyCollectionChangedAction.Replace:
                    Debug.Assert(
                        e.NewItems.Count == 1,
                        "We're mirroring the Columns collection which is an ObservableCollection and only supports replacing one item at a time");
                    OnReplace(CopiedItem, CopiedItem, e.NewStartingIndex);
                    break;

                case NotifyCollectionChangedAction.Reset:
                    Reset();
                    break;
            }
        }

        /// <summary>
        ///     Syncs up the count with the given one.  This is used when we know we've missed a CollectionChanged event (say this
        ///     MultipleCopiesCollection is inside a DataGridRow that was virtualized and recycled).  It attempts to resync
        ///     by adjusting the count and firing the proper property change notifications.
        /// </summary>
        /// <remarks>
        ///     This method works in concert with the DataGridCellsPresenter.  We don't know where items were removed / added, so containers
        ///     (DataGridCells) based off this collection could be stale (wrong column).  The cells presenter updates them.  We could have also
        ///     just fired a Reset event here and not bothered with work in the cells presenter, but that would cause all cells to be regenerated.
        ///
        ///     Note that this method is designed to [....] up to ALL collection changes that may have happened.
        ///     The job of this method is made significantly easier by the fact that the MultipleCopiesCollection really only cares about
        ///     the count of items in the given collection (since we keep it in [....] with the DataGrid Columns collection but host
        ///     a DataGridRow as the item).  This means we don't care about Move, Replace, etc.
        /// </remarks>
        internal void SyncToCount(int newCount)
        {
            int oldCount = RepeatCount;

            if (newCount != oldCount)
            {
                if (newCount > oldCount)
                {
                    // Insert at end
                    InsertRange(oldCount, newCount - oldCount);
                }
                else
                {
                    // Remove from the end
                    int numToRemove = oldCount - newCount;
                    RemoveRange(oldCount - numToRemove, numToRemove);
                }

                Debug.Assert(RepeatCount == newCount, "We should have properly updated the RepeatCount");
            }
        }

        /// <summary>
        ///     This is the item that is returned multiple times.
        /// </summary>
        internal object CopiedItem
        {
            get
            {
                return _item;
            }

            set
            {
                if (value == CollectionView.NewItemPlaceholder)
                {
                    // If we populate the collection with the CollectionView's
                    // NewItemPlaceholder, it will confuse the CollectionView.
                    value = DataGrid.NewItemPlaceholder;
                }

                if (_item != value)
                {
                    object oldValue = _item;
                    _item = value;

                    OnPropertyChanged(IndexerName);

                    // Report replacing each item with the new item
                    for (int i = 0; i < _count; i++)
                    {
                        OnReplace(oldValue, _item, i);
                    }
                }
            }
        }

        /// <summary>
        ///     This is the number of times the item is to be repeated.
        /// </summary>
        private int RepeatCount
        {
            get
            {
                return _count;
            }

            set
            {
                if (_count != value)
                {
                    _count = value;
                    OnPropertyChanged(CountName);
                    OnPropertyChanged(IndexerName);
                }
            }
        }

        private void Insert(int index)
        {
            RepeatCount++;
            OnCollectionChanged(NotifyCollectionChangedAction.Add, CopiedItem, index);
        }

        private void InsertRange(int index, int count)
        {
            // True range operations are not supported by CollectionView so we instead fire many changed events.
            for (int i = 0; i < count; i++)
            {
                Insert(index);
                index++;
            }
        }

        private void Move(int oldIndex, int newIndex)
        {
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, CopiedItem, newIndex, oldIndex));
        }

        private void RemoveAt(int index)
        {
            Debug.Assert((index >= 0) && (index < RepeatCount), "Index out of range");

            RepeatCount--;
            OnCollectionChanged(NotifyCollectionChangedAction.Remove, CopiedItem, index);
        }

        private void RemoveRange(int index, int count)
        {
            // True range operations are not supported by CollectionView so we instead fire many changed events.
            for (int i = 0; i < count; i++)
            {
                RemoveAt(index);
            }
        }

        private void OnReplace(object oldItem, object newItem, int index)
        {
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newItem, oldItem, index));
        }

        private void Reset()
        {
            RepeatCount = 0;
            OnCollectionReset();
        }

        #endregion

        #region IList Members

        public int Add(object value)
        {
            throw new NotSupportedException(SR.Get(SRID.DataGrid_ReadonlyCellsItemsSource));
        }

        public void Clear()
        {
            throw new NotSupportedException(SR.Get(SRID.DataGrid_ReadonlyCellsItemsSource));
        }

        public bool Contains(object value)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }

            return _item == value;
        }

        public int IndexOf(object value)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }

            return (_item == value) ? 0 : -1;
        }

        public void Insert(int index, object value)
        {
            throw new NotSupportedException(SR.Get(SRID.DataGrid_ReadonlyCellsItemsSource));
        }

        public bool IsFixedSize
        {
            get { return false; }
        }

        public bool IsReadOnly
        {
            get { return true; }
        }

        public void Remove(object value)
        {
            throw new NotSupportedException(SR.Get(SRID.DataGrid_ReadonlyCellsItemsSource));
        }

        void IList.RemoveAt(int index)
        {
            throw new NotSupportedException(SR.Get(SRID.DataGrid_ReadonlyCellsItemsSource));
        }

        public object this[int index]
        {
            get
            {
                if ((index >= 0) && (index < RepeatCount))
                {
                    Debug.Assert(_item != null, "_item should be non-null.");
                    return _item;
                }
                else
                {
                    throw new ArgumentOutOfRangeException("index");
                }
            }

            set
            {
                throw new InvalidOperationException();
            }
        }

        #endregion

        #region ICollection Members

        public void CopyTo(Array array, int index)
        {
            throw new NotSupportedException();
        }

        public int Count
        {
            get { return RepeatCount; }
        }

        public bool IsSynchronized
        {
            get { return false; }
        }

        public object SyncRoot
        {
            get { return this; }
        }

        #endregion

        #region IEnumerable Members

        public IEnumerator GetEnumerator()
        {
            return new MultipleCopiesCollectionEnumerator(this);
        }

        private class MultipleCopiesCollectionEnumerator : IEnumerator
        {
            public MultipleCopiesCollectionEnumerator(MultipleCopiesCollection collection)
            {
                _collection = collection;
                _item = _collection.CopiedItem;
                _count = _collection.RepeatCount;
                _current = -1;
            }

            #region IEnumerator Members

            object IEnumerator.Current
            {
                get
                {
                    if (_current >= 0)
                    {
                        if (_current < _count)
                        {
                            return _item;
                        }
                        else
                        {
                            throw new InvalidOperationException();
                        }
                    }
                    else
                    {
                        return null;
                    }
                }
            }

            bool IEnumerator.MoveNext()
            {
                if (IsCollectionUnchanged)
                {
                    int newIndex = _current + 1;
                    if (newIndex < _count)
                    {
                        _current = newIndex;
                        return true;
                    }

                    return false;
                }
                else
                {
                    throw new InvalidOperationException();
                }
            }

            void IEnumerator.Reset()
            {
                if (IsCollectionUnchanged)
                {
                    _current = -1;
                }
                else
                {
                    throw new InvalidOperationException();
                }
            }

            private bool IsCollectionUnchanged
            {
                get
                {
                    return (_collection.RepeatCount == _count) && (_collection.CopiedItem == _item);
                }
            }

            #endregion

            #region Data

            private object _item;
            private int _count;
            private int _current;
            private MultipleCopiesCollection _collection;

            #endregion
        }

        #endregion

        #region INotifyCollectionChanged Members

        public event NotifyCollectionChangedEventHandler CollectionChanged;

        /// <summary>
        ///     Helper to raise a CollectionChanged event when an item is added or removed.
        /// </summary>
        private void OnCollectionChanged(NotifyCollectionChangedAction action, object item, int index)
        {
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index));
        }

        /// <summary>
        ///     Helper to raise a CollectionChanged event when the collection is cleared.
        /// </summary>
        private void OnCollectionReset()
        {
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }

        private void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (CollectionChanged != null)
            {
                CollectionChanged(this, e);
            }
        }

        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        ///     Helper to raise a PropertyChanged event.
        /// </summary>
        private void OnPropertyChanged(string propertyName)
        {
            OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
        }

        private void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, e);
            }
        }

        #endregion

        #region Data

        private object _item; //
        private int _count;

        private const string CountName = "Count";
        private const string IndexerName = "Item[]";

        #endregion
    }
}


text:
class ReservationsController < ApplicationController

  customer_tab  :all
  before_action :authenticate_user!, except: [:index]
  before_action :check_acting_as, only: [:switch_instrument, :list]
  before_action :load_basic_resources, only: [:new, :create, :edit, :update]
  before_action :load_and_check_resources, only: [:move, :switch_instrument]
  authorize_resource only: [:edit, :update, :move]

  include TranslationHelper
  include FacilityReservationsHelper
  include ReservationSwitch
  helper TimelineHelper

  def initialize
    super
    @active_tab = "reservations"
  end

  def public_timeline
    @display_datetime = parse_usa_date(params[:date]) || Time.current.beginning_of_day

    @schedules = current_facility.schedules_for_timeline(:public_instruments)
    instrument_ids = @schedules.flat_map { |schedule| schedule.public_instruments.map(&:id) }
    @reservations_by_instrument = Reservation.for_timeline(@display_datetime, instrument_ids).group_by(&:product)
  end

  # GET /facilities/1/instruments/1/reservations.js?_=1279579838269&start=1279429200&end=1280034000
  def index
    @facility = Facility.find_by!(url_name: params[:facility_id])
    @instrument = @facility.instruments.find_by!(url_name: params[:instrument_id])

    @start_at = parse_time_param(params[:start]) || Time.zone.now
    @end_at = parse_time_param(params[:end]) || @start_at.end_of_day

    admin_reservations = @instrument.schedule.admin_reservations.in_range(@start_at, @end_at)
    user_reservations = @instrument.schedule
                                   .reservations
                                   .active
                                   .in_range(@start_at, @end_at)
                                   .includes(order_detail: { order: :user })
    offline_reservations = @instrument.offline_reservations.in_range(@start_at, @end_at)

    @reservations = admin_reservations + user_reservations + offline_reservations

    # We don't need the unavailable hours month view
    unless month_view?
      @rules = @instrument.schedule_rules

      if @instrument.requires_approval? && acting_user && acting_user.cannot_override_restrictions?(@instrument)
        @rules = @rules.available_to_user(acting_user)
      end

      @unavailable = ScheduleRule.unavailable(@rules)
    end

    @show_details = params[:with_details] == "true" && (@instrument.show_details? || can?(:administer, Reservation))

    respond_to do |format|
      as_calendar_object_options = { start_date: @start_at.beginning_of_day, with_details: @show_details }
      format.js do
        render json: Reservation.as_calendar_objects(@reservations, as_calendar_object_options) +
                     ScheduleRule.as_calendar_objects(@unavailable, as_calendar_object_options)
      end
    end
  end

  # GET /reservations
  # All My Resesrvations
  def list
    notices = []

    relation = acting_user.order_details
    in_progress = relation.with_in_progress_reservation
    @status = params[:status]
    @available_statuses = [in_progress.blank? ? "upcoming" : "upcoming_and_in_progress", "all"]

    if @status == "all"
      @order_details = relation.with_reservation
    elsif @status == "upcoming"
      @status = @available_statuses.first
      @order_details = in_progress + relation.with_upcoming_reservation
    else
      return redirect_to reservations_status_path(status: "upcoming")
    end

    @order_details = @order_details.paginate(page: params[:page])

    notices = @order_details.collect do |od|
      notice_for_reservation od.reservation
    end
    notices.compact!
    existing_notices = flash[:notice].presence ? [flash[:notice]] : []
    flash.now[:notice] = existing_notices.concat(notices).join("
").html_safe unless notices.empty?
  end

  # POST /orders/:order_id/order_details/:order_detail_id/reservations
  def create
    raise ActiveRecord::RecordNotFound unless @reservation.nil?

    creator = ReservationCreator.new(@order, @order_detail, params)
    if creator.save(session_user)
      @reservation = creator.reservation
      authorize! :create, @reservation
      flash[:notice] = I18n.t "controllers.reservations.create.success"
      flash[:error] = I18n.t("controllers.reservations.create.admin_hold_warning") if creator.reservation.conflicting_admin_reservation?

      if creator.merged_order?
        redirect_to facility_order_path(@order_detail.facility, @order_detail.order.merge_order || @order_detail.order)
      elsif creator.instrument_only_order?
        redirect_params = {}
        redirect_params[:send_notification] = "1" if params[:send_notification] == "1"
        # only trigger purchase if instrument
        # and is only thing in cart (isn't bundled or on a multi-add order)
        redirect_to purchase_order_path(@order, redirect_params)
      else
        redirect_to cart_path
      end
    else
      @reservation = creator.reservation
      # validation errors are handled by simple form
      flash.now[:error] = creator.error.html_safe if creator.error.present?
      set_windows
      render :new
    end
  end

  # GET /orders/:order_id/order_details/:order_detail_id/reservations/new
  def new
    raise ActiveRecord::RecordNotFound unless @reservation.nil?

    @reservation = NextAvailableReservationFinder.new(@instrument).next_available_for(current_user, acting_user)
    @reservation.order_detail = @order_detail

    authorize! :new, @reservation

    unless @instrument.can_be_used_by?(@order_detail.user)
      flash[:notice] = text(".acting_as_not_on_approval_list")
    end
    set_windows
  end

  # GET /orders/:order_id/order_details/:order_detail_id/reservations/:id(.:format)
  def show
    @order        = Order.find(params[:order_id])
    @order_detail = @order.order_details.find(params[:order_detail_id])
    @reservation  = Reservation.find(params[:id])
    authorize! :show, @reservation

    raise ActiveRecord::RecordNotFound if @reservation != @order_detail.reservation

    respond_to do |format|
      format.html

      format.ics do
        calendar = ReservationCalendar.new(@reservation)
        send_data(calendar.to_ical,
                  type: "text/calendar", disposition: "attachment",
                  filename: calendar.filename)
      end
    end
  end

  # GET /orders/1/order_details/1/reservations/1/edit
  def edit
    redirect_to [@order, @order_detail, @reservation] if invalid_for_update?
    set_windows
  end

  # PUT  /orders/1/order_details/1/reservations/1
  def update
    if invalid_for_update?
      redirect_to [@order, @order_detail, @reservation], notice: I18n.t("controllers.reservations.update.failure")
      return
    end

    @reservation.assign_times_from_params(reservation_params)
    with_dropped_params do
      reservation_update_attributes = params.require(:reservation).permit(:note)
      @reservation.assign_attributes(reservation_update_attributes)
    end

    render_edit && return unless changes_valid_for_update?

    Reservation.transaction do
      begin
        # merge state can change after call to #save! due to OrderDetailObserver#before_save
        mergeable = @order_detail.order.to_be_merged?

        save_reservation_and_order_detail

        flash[:notice] = "The reservation was successfully updated."
        if mergeable
          redirect_to facility_order_path(@order_detail.facility, @order_detail.order.merge_order || @order_detail.order)
        else
          redirect_to (@order.purchased? ? reservations_path : cart_path)
        end
        return
      rescue ActiveRecord::RecordInvalid => e
        raise ActiveRecord::Rollback
      end
    end
    render_edit
  end

  # POST /orders/:order_id/order_details/:order_detail_id/reservations/:reservation_id/move
  def move
    if @reservation.move_to_earliest
      flash[:notice] = "The reservation was moved successfully."
    else
      flash[:error] = @reservation.errors.full_messages.join("
").html_safe
    end

    redirect_to reservations_status_path(status: "upcoming")
  end

  # GET /orders/:order_id/order_details/:order_detail_id/reservations/:reservation_id/move
  def earliest_move_possible
    @reservation       = Reservation.find(params[:reservation_id])
    @earliest_possible = @reservation.earliest_possible

    if @earliest_possible
      @formatted_dates = {
        start_date: human_date(@earliest_possible.reserve_start_at),
        start_time: human_time(@earliest_possible.reserve_start_at),
        end_date: human_date(@earliest_possible.reserve_end_at),
        end_time: human_time(@earliest_possible.reserve_end_at),
      }
    end

    render layout: false
  end

  # GET /orders/:order_id/order_details/:order_detail_id/reservations/switch_instrument
  def switch_instrument
    authorize! :start_stop, @reservation

    raise ActiveRecord::RecordNotFound unless switch_value_present?

    switch_instrument!(params[:switch])

    if params[:switch] == "off" && @order_detail.accessories?
      redirect_to new_order_order_detail_accessory_path(@order, @order_detail)
      return
    end

    redirect_to params[:redirect_to] || request.referer || order_order_detail_path(@order, @order_detail)
  end

  private

  def reservation_params
    reservation_params = params.require(:reservation)
                               .except(:reserve_end_date, :reserve_end_hour, :reserve_end_min, :reserve_end_meridian)
                               .permit(:reserve_start_date,
                                       :reserve_start_hour,
                                       :reserve_start_min,
                                       :reserve_start_meridian,
                                       :duration_mins,
                                       :note)

    # Prevent overriding of start time params after purchase if start time is locked,
    # e.g. you are in the lock window or the reservation has already started and
    # you are only allowed to extend the reservation.
    reservation_params.merge!(reservation_start_as_params) if fixed_start_time? && !@reservation.in_cart?

    reservation_params
  end

  def fixed_start_time?
    !@reservation.admin_editable? || !@reservation.reserve_start_at_editable?
  end

  def reservation_start_as_params
    {
      reserve_start_date: @reservation.reserve_start_date,
      reserve_start_hour: @reservation.reserve_start_hour,
      reserve_start_min: @reservation.reserve_start_min,
      reserve_start_meridian: @reservation.reserve_start_meridian,
    }
  end

  def load_basic_resources
    @order = Order.find(params[:order_id])
    # It's important that the order_detail be the same object as the one in @order.order_details.first
    @order_detail = @order.order_details.find { |od| od.id.to_i == params[:order_detail_id].to_i }
    raise ActiveRecord::RecordNotFound if @order_detail.blank?
    @reservation = @order_detail.reservation
    @instrument = @order_detail.product
    @facility = @instrument.facility
  rescue ActiveRecord::RecordNotFound
    flash[:error] = text("order_detail_removed")
    if @order
      redirect_to facility_path(@order.facility)
    else
      raise
    end
  end

  def load_and_check_resources
    load_basic_resources
    raise ActiveRecord::RecordNotFound if @reservation.blank?
  end

  def ability_resource
    if action_name == "index"
      current_facility
    else
      @reservation
    end
  end

  # TODO: you shouldn't be able to edit reservations that have passed or are outside of the cancellation period (check to make sure order has been placed)
  def invalid_for_update?
    params[:id].to_i != @reservation.id ||
      @reservation.actual_end_at ||
      !editable_by_current_user?
  end

  def editable_by_current_user?
    if current_ability.can?(:manage, @reservation) && @reservation.admin_editable?
      true
    elsif @reservation.can_customer_edit?
      true
    else
      false
    end
  end

  def save_reservation_and_order_detail
    @reservation.save_as_user!(session_user)
    @order_detail.assign_estimated_price(@reservation.reserve_end_at)
    @order_detail.save_as_user!(session_user)
  end

  def set_windows
    @reservation_window = ReservationWindow.new(@reservation, current_user)
  end

  def notice_for_reservation(reservation)
    return unless reservation

    if reservation.can_switch_instrument_off? # do you need to click stop
      I18n.t("reservations.notices.can_switch_off", reservation: reservation)
    elsif reservation.can_switch_instrument_on? # do you need to begin your reservation
      I18n.t("reservations.notices.can_switch_on", reservation: reservation)
    elsif reservation.canceled?
    # no message
    # do you have a reservation for today that hasn't ended
    elsif upcoming_today? reservation
      I18n.t("reservations.notices.upcoming", reservation: reservation)
    end
  end

  def upcoming_today?(reservation)
    now = Time.zone.now
    (reservation.reserve_start_at.to_date == now.to_date || reservation.reserve_start_at < now) && reservation.reserve_end_at > now
  end

  # Some browsers are not updating their cached JS and have an out-of-date calendar
  # JS library which uses unix timestamps for the parameters. This allows us to handle both.
  def parse_time_param(string_value)
    return unless string_value
    Time.zone.parse(string_value)
  rescue ArgumentError
    Time.zone.at(string_value.to_i)
  end

  def helpers
    ActionController::Base.helpers
  end

  # `1.week` causes a problem with daylight saving week since it's technically longer
  # than a week
  def month_view?
    @end_at - @start_at > 8.days
  end

  def render_edit
    set_windows
    render action: "edit"
  end

  def changes_valid_for_update?
    duration_change_valid? && NotePresenceValidator.new(@reservation).valid?
  end

  def duration_change_valid?
    validator = Reservations::DurationChangeValidations.new(@reservation)
    validator.valid?
  end

end


text:
function seismic1=s_dsvector2ds(seismic)
% Combine the traces of a dataset vector into a single seismic dataset.
%
% See also: s_ds2dsvector
%
% Written by: E. Rietsch: September 19, 2006
% Last updated: February 5, 2008: add a header to the output dataset to indicate
%                                 from which vector element a trace comes
%
%           seismic1=s_dsvector2ds(seismic)
% INPUT
% seismic   seismic dataset vector
% OUTPUT
% seismic1  single seismic dataset;
%           the field "name" of the output dataset is set to "seismic(1).name"
%           provided it is the same for all datasets;
%           if not, is set to the variable name of the input dataset vector,
%           if it is not empty, or to "Seismic from DS vector" if it is empty.
%           A new trace header, "vector_index", indicates from which vector
%           element a particular trace comes.
%           Another header, "orig_trace_no", indicates the number of the trace
%           in that vector element.
%
% EXAMPLE
%           seismic=s_data;
%           seismic1=s_ds2dsvector(seismic);   % Create dataset vector
%           seismic2=s_dsvector2ds(seismic1);  % Convert dataset vector back to single dataset
%           s_compare(seismic,seismic2)        % Must be the same

% UPDATE HISTORY
%           May 2, 2007: Improved handling of new dataset name.

param.null=NaN;

nds=length(seismic);

%        Add header identifying the index of the dataset vector
if isfield(seismic(1),'headers')
   for ii=1:nds
      ntr=size(seismic(ii).traces,2);
      seismic(ii)=ds_add_header(seismic(ii),ii,{'vector_index','n/a','Index of original vector'});
      seismic(ii)=ds_add_header(seismic(ii),1:ntr,{'orig_trace_no','n/a','Original trace number'});
   end
else
   [seismic.header_info]=deal({'vector_index','n/a','Index of original vector'});
   [seismic.header]=deal(1);
   for ii=1:nds
      ntr=size(seismic(ii).traces,2);
      seismic(ii).header=[ii*ones(1,ntr);1:ntr];
   end
end

seismic1=seismic(1);

%% Try straight-forward concatenation
try
%   problem='differing start times';
   first=[seismic.first];
   if any(diff(first) ~= 0)
      error('Incompatible start times.')
   end

%   problem='differing end times';
   last=[seismic.last];
   if any(diff(last) ~= 0)
      error('Incompatible end times.')
   end

%   problem='incompatible headers';
   seismic1.headers=[seismic.headers];

%   problem='incompatible seismic traces';
   seismic1.traces=[seismic.traces];
   header_mnem=[seismic.header_info];
   header_mnem=header_mnem(:,1:3:end);
   if length(unique(header_mnem)) ~= size(seismic1.header_info,1)
      disp(' Input datasets do not have the same header mnemonics.')
      drawnow
      error('Abnormal termination.')
   end

%%       Staight-forward concatenation was not possible
catch
   seismic1=add_header(seismic1,1,{'vector_index','n/a','Index of original vector'});
   for ii=2:size(seismic(:));
      seismic1=s_append(seismic1,seismic(ii),{'null',param.null});
   end
end

%%    Do final clean-up

%       Establish a name for the dataset
name={seismic.name};
seismic1.name=unique(name);
if length(name) > 1
   if ~isempty(inputname(1))
      seismic1.name=inputname(1);
   else
      seismic1.name='Seismic from DS vector';
   end
else
   seismic1.name=name{1};
end

if ~isnull(seismic1)
   if any(isnan(seismic1.traces(:)))
      if strcmp(class(seismic1.traces),'single')
         seismic1.null=single(NaN);
      else
         seismic1.null=NaN;
      end
   end
end