<commit_before>var cornerstoneTools = (function ($, cornerstone, cornerstoneTools) {

    "use strict";

    if (cornerstoneTools === undefined) {
        cornerstoneTools = {};
    }

    var toolType = "stackPrefetch";
    var defaultMaxRequests = 11;
    var configuration = {};
    var reenablePrefetchTimeout;

    function renablePrefetch(e, data) {
        // Use timeouts here to prevent this being called over and over
        // during scrolling
        clearTimeout(reenablePrefetchTimeout);
        reenablePrefetchTimeout = setTimeout(function() {
            var element = data.element;
            var stackData = cornerstoneTools.getToolState(element, 'stack');
            if (!stackData || !stackData.data || !stackData.data.length) {
                return;
            }
            // Get the stackPrefetch tool data
            var stackPrefetchData = cornerstoneTools.getToolState(element, toolType);
            if (!stackPrefetchData || !stackPrefetchData.data || !stackPrefetchData.data.length) {
                // should not happen
                return;
            }

            var stackPrefetch = stackPrefetchData.data[0];
            if (stackPrefetch.indicesToRequest.length > 0 && !stackPrefetch.enabled) {
                //console.log("Re-enabling prefetch");
                stackPrefetch.enabled = true;
                prefetch(element);
            }
        }, 50);
    }

    function range(lowEnd, highEnd) {
        // Javascript version of Python's range function
        // http://stackoverflow.com/questions/3895478/does-javascript-have-a-method-like-range-to-generate-an-array-based-on-suppl
        var arr = [],
            c = highEnd - lowEnd + 1;

        while ( c-- ) {
            arr[c] = highEnd--;
        }
        return arr;
    }

    function prefetch(element) {
        // Check to make sure stack data exists
        var stackData = cornerstoneTools.getToolState(element, 'stack');
        if (stackData === undefined || stackData.data === undefined || stackData.data.length === 0) {
            return;
        }
        var stack = stackData.data[0];
        var currentImageIdIndex = stack.currentImageIdIndex;

        // Get the stackPrefetch tool data
        var stackPrefetchData = cornerstoneTools.getToolState(element, toolType);
        if (stackPrefetchData === undefined) {
            // should not happen
            return;
        }
        var stackPrefetch = stackPrefetchData.data[0];

        // If all the requests are complete, disable the stackPrefetch tool
        if (stackPrefetch.indicesToRequest.length === 0) {
            stackPrefetch.enabled = false;
        }

        // Make sure the tool is still enabled
        if (stackPrefetch.enabled === false) {
            return;
        }

        // Get tool configuration
        var config = cornerstoneTools.stackPrefetch.getConfiguration();

        var stackLength = stack.imageIds.length;
        
        var lastImageIdIndexFetched = stackPrefetch.lastImageIdIndexFetched;
        if (!lastImageIdIndexFetched) {
            lastImageIdIndexFetched = currentImageIdIndex;
        }

        var maxImageIdIndex = lastImageIdIndexFetched + config.maxSimultaneousRequests;
        if (maxImageIdIndex > stackLength) {
            maxImageIdIndex = stackLength - 1;
        }

        var imageIdIndices = range(lastImageIdIndexFetched, maxImageIdIndex);
        stackPrefetch.lastImageIdIndexFetched = maxImageIdIndex + 1;

        // Remove an imageIdIndex from the list of indices to request
        // This fires when the individual image loading deferred is resolved        
        function removeFromList(imageIdIndex) {
            var index = stackPrefetch.indicesToRequest.indexOf(imageIdIndex);
            stackPrefetch.indicesToRequest.splice(index, 1);
        }
        
        // Throws an error if something has gone wrong
        function errorHandler(imageId) {
            throw "stackPrefetch: image not retrieved: " + imageId;
        }

        // Loop through the images that should be requested in this batch

        var deferredList = [];
        var lastCacheInfo;

        if (imageIdIndices.length === 0) {
            stackPrefetch.enabled = false;
            return;
        }

        //console.log(imageIdIndices);
        imageIdIndices.forEach(function(imageIdIndex) {
            var imageId = stack.imageIds[imageIdIndex];

            if (!stackPrefetch.enabled) {
                return;
            }
            // Check if we already have this image promise in the cache
            var imagePromise = cornerstone.imageCache.getImagePromise(imageId);
            
            if(imagePromise !== undefined) {
                // If we do, remove from list and stop processing this iteration
                removeFromList(imageIdIndex);
                return;
            }
            
            // Load and cache the image
            var loadImageDeferred = cornerstone.loadAndCacheImage(imageId);

            // When this is complete, remove the imageIdIndex from the list
            loadImageDeferred.done(function() {
                removeFromList(imageIdIndex);

                var cacheInfo = cornerstone.imageCache.getCacheInfo();

                // Check if the cache is full
                if (lastCacheInfo && cacheInfo.cacheSizeInBytes === lastCacheInfo.cacheSizeInBytes) {
                    //console.log("Cache full, stopping");
                    stackPrefetch.enabled = false;
                }

                lastCacheInfo = cacheInfo;
            });

            loadImageDeferred.fail(function() {
                errorHandler(imageId);
            });

            // Add the image promises to a list
            deferredList.push(loadImageDeferred);
        });

        // When this batch of images is loaded (all async requests have finished)
        $.when.apply($, deferredList).done(function () {
            // If there are still images that need to be requested, and the 
            // cache is not full, call this function again
            //console.log("Batch finished");
            if (stackPrefetch.indicesToRequest.length > 0 && stackPrefetch.enabled) {
                //console.log("Running prefetch again");
                // Set a timeout here to prevent locking up the UI
                setTimeout(prefetch(element), 1);
            }
        });

        // If the entire batch of requests has failed, throw an error
        $.when.apply($, deferredList).fail(function () {
            throw "stackPrefetch: batch failed for element: " + element.id;
        });
    }

    function enable(element) {
        var config = cornerstoneTools.stackPrefetch.getConfiguration();

        // Clear old prefetch data. Skipping this can cause problems when changing the series inside an element
        var stackPrefetchData = cornerstoneTools.getToolState(element, toolType);
        stackPrefetchData = [];

        // First check that there is stack data available
        var stackData = cornerstoneTools.getToolState(element, 'stack');
        if (stackData === undefined || stackData.data === undefined || stackData.data.length === 0) {
            return;
        }
        var stack = stackData.data[0];

        // The maximum simultaneous requests is capped at 
        // a rather arbitrary number of 11, since we don't want to overload any servers
        if (config === undefined || config.maxSimultaneousRequests === undefined) {
            config = {
                "maxSimultaneousRequests" : Math.max(Math.ceil(stack.imageIds.length / 5), defaultMaxRequests)
            };
        }

        cornerstoneTools.stackPrefetch.setConfiguration(config);

        // Use the currentImageIdIndex from the stack as the initalImageIdIndex
        stackPrefetchData = {
            indicesToRequest : range(0, stack.imageIds.length - 1),<commit_msg>Fixes for prefetch edge cases<commit_after>var cornerstoneTools = (function ($, cornerstone, cornerstoneTools) {

    "use strict";

    if (cornerstoneTools === undefined) {
        cornerstoneTools = {};
    }

    var toolType = "stackPrefetch";
    var defaultMaxRequests = 11;
    var configuration = {};
    var reenablePrefetchTimeout;

    function renablePrefetch(e, data) {
        // Use timeouts here to prevent this being called over and over
        // during scrolling
        clearTimeout(reenablePrefetchTimeout);
        reenablePrefetchTimeout = setTimeout(function() {
            var element = data.element;
            var stackData = cornerstoneTools.getToolState(element, 'stack');
            if (!stackData || !stackData.data || !stackData.data.length) {
                return;
            }
            // Get the stackPrefetch tool data
            var stackPrefetchData = cornerstoneTools.getToolState(element, toolType);
            if (!stackPrefetchData || !stackPrefetchData.data || !stackPrefetchData.data.length) {
                // should not happen
                return;
            }

            var stackPrefetch = stackPrefetchData.data[0];
            if (stackPrefetch.indicesToRequest.length > 0 && !stackPrefetch.enabled) {
                //console.log("Re-enabling prefetch");
                stackPrefetch.enabled = true;
                prefetch(element);
            }
        }, 50);
    }

    function range(lowEnd, highEnd) {
        // Javascript version of Python's range function
        // http://stackoverflow.com/questions/3895478/does-javascript-have-a-method-like-range-to-generate-an-array-based-on-suppl
        var arr = [],
            c = highEnd - lowEnd + 1;

        while ( c-- ) {
            arr[c] = highEnd--;
        }
        return arr;
    }

    function prefetch(element) {
        // Check to make sure stack data exists
        var stackData = cornerstoneTools.getToolState(element, 'stack');
        if (stackData === undefined || stackData.data === undefined || stackData.data.length === 0) {
            return;
        }
        var stack = stackData.data[0];
        var currentImageIdIndex = stack.currentImageIdIndex;

        // Get the stackPrefetch tool data
        var stackPrefetchData = cornerstoneTools.getToolState(element, toolType);
        if (stackPrefetchData === undefined) {
            // should not happen
            return;
        }
        var stackPrefetch = stackPrefetchData.data[0];


        // If all the requests are complete, disable the stackPrefetch tool
        if (stackPrefetch.indicesToRequest.length === 0) {
            stackPrefetch.enabled = false;
        }

        // Make sure the tool is still enabled
        if (stackPrefetch.enabled === false) {
            return;
        }

        // Remove an imageIdIndex from the list of indices to request
        // This fires when the individual image loading deferred is resolved        
        function removeFromList(imageIdIndex) {
            var index = stackPrefetch.indicesToRequest.indexOf(imageIdIndex);
            if (index > -1){ // don't remove last element if imageIdIndex not found
                stackPrefetch.indicesToRequest.splice(index, 1);
            }
        }
        
        // Throws an error if something has gone wrong
        function errorHandler(imageId) {
            throw "stackPrefetch: image not retrieved: " + imageId;
        }

        // remove all already cached images from the
        // indicesToRequest array
        var indicesToRequestCopy = stackPrefetch.indicesToRequest.slice();
        for (var i=0; i<indicesToRequestCopy.length; i++){
            var imageIdIndex = indicesToRequestCopy[i],
                imageId = stack.imageIds[imageIdIndex],
                imagePromise = cornerstone.imageCache.getImagePromise(imageId);

            if (imagePromise !== undefined && imagePromise.state() === "resolved"){
                removeFromList(imageIdIndex);
            }
        }

        // Get tool configuration
        var config = cornerstoneTools.stackPrefetch.getConfiguration();

        var stackLength = stack.imageIds.length;
        
        var lastImageIdIndexFetched = stackPrefetch.lastImageIdIndexFetched;
        if (!lastImageIdIndexFetched) {
            lastImageIdIndexFetched = currentImageIdIndex;
        }

        var maxImageIdIndex = lastImageIdIndexFetched + config.maxSimultaneousRequests;
        if (maxImageIdIndex > stackLength) {
            maxImageIdIndex = stackLength - 1;
        }

        var imageIdIndices = range(lastImageIdIndexFetched, maxImageIdIndex);
        stackPrefetch.lastImageIdIndexFetched = maxImageIdIndex + 1;


        // Loop through the images that should be requested in this batch

        var deferredList = [];
        var lastCacheInfo;

        if (imageIdIndices.length === 0) {
            stackPrefetch.enabled = false;
            return;
        }

        function onLoadImageComplete(imageIdIndex){
            removeFromList(imageIdIndex);

            var cacheInfo = cornerstone.imageCache.getCacheInfo();

            // Check if the cache is full
            if (lastCacheInfo && cacheInfo.cacheSizeInBytes === lastCacheInfo.cacheSizeInBytes) {
                //console.log("Cache full, stopping");
                stackPrefetch.enabled = false;
            }

            lastCacheInfo = cacheInfo;
        }

        //console.log(imageIdIndices);
        imageIdIndices.forEach(function(imageIdIndex) {
            var imageId = stack.imageIds[imageIdIndex];

            if (!stackPrefetch.enabled) {
                return;
            }
            // Check if we already have this image promise in the cache
            var imagePromise = cornerstone.imageCache.getImagePromise(imageId);
            
            if(imagePromise !== undefined) {
                // If we do, remove from list (when resolved, as we could have
                // pending prefetch requests) and stop processing this iteration
                imagePromise.done(function(){
                    onLoadImageComplete(imageIdIndex);
                });
                return;
            }
            
            // Load and cache the image
            var loadImageDeferred = cornerstone.loadAndCacheImage(imageId);

            // When this is complete, remove the imageIdIndex from the list
            loadImageDeferred.done(function(){
                onLoadImageComplete(imageIdIndex);
            });

            loadImageDeferred.fail(function() {
                errorHandler(imageId);
            });

            // Add the image promises to a list
            deferredList.push(loadImageDeferred);
        });

        // When this batch of images is loaded (all async requests have finished)
        $.when.apply($, deferredList).done(function () {
            // If there are still images that need to be requested, and the 
            // cache is not full, call this function again
            //console.log("Batch finished");
            if (stackPrefetch.indicesToRequest.length > 0 && stackPrefetch.enabled) {
                //console.log("Running prefetch again");
                // Set a timeout here to prevent locking up the UI
                setTimeout(prefetch(element), 1);
            }
        });

        // If the entire batch of requests has failed, throw an error
        $.when.apply($, deferredList).fail(function () {
            throw "stackPrefetch: batch failed for element: " + element.id;
        });
    }

    function enable(element) {
        var config = cornerstoneTools.stackPrefetch.getConfiguration();

        // Clear old prefetch data. Skipping this can cause problems when changing the series inside an element
        var stackPrefetchData = cornerstoneTools.getToolState(element, toolType);
        stackPrefetchData = [];

        // First check that there is stack data available
        var stackData = cornerstoneTools.getToolState(element, 'stack');
        if (stackData === undefined || stackData.data === undefined || stackData.data.length === 0) {
            return;
        }
        var stack = stackData.data[0];

        // The maximum simultaneous requests is capped at 
        // a rather arbitrary number of 11, since we don't want to overload any servers
        if (config === undefined || config.maxSimultaneousRequests === undefined) {
            config = {
                "maxSimultaneousRequests" : Math.min(Math.ceil(stack.imageIds.length / 5), defaultMaxRequests)
            };
        }

        cornerstoneTools.stackPrefetch.setConfiguration(config);

        // Use the currentImageIdIndex from the stack as the initalImageIdIndex
        stackPrefetchData = {
            indicesToRequest : range(0, stack.imageIds.length - 1),
{'fraction_non_alphanumeric': 0.08750447975152312, 'fraction_numerical': 0.003822721299725242, 'mean_word_length': 1.980772654441873, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 10, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7534808', 'n_tokens_mistral': 4259, 'n_tokens_neox': 4069, 'n_words': 1117}