<commit_before>import React from 'react';
import { shallow } from 'enzyme';
import Percent from '../../Statistics/Percent/Percent'
import CircularProgress from 'material-ui/CircularProgress'
import Counter from '../../Statistics/Counter/Counter'
import Catalog from '../Catalog'
import { mountWithContext } from '../../../test/jsdom-setup'

import catalog from '../../fetch/__test__/catalog.json'
import metrics from '../../fetch/__test__/metrics.json'
jest.mock('../../fetch/fetchMetrics');

describe('<Catalog />', () => {

  describe('When all goes well', () => {
    const wrapper = shallow(<Catalog catalog={catalog} />);
    it('renders without crashing', () => {
      shallow(<Catalog catalog={catalog} />);
    });

    it('should display the name of the catalog', () => {
      const title = {catalog.name}
      expect(wrapper.contains(title)).toEqual(true);
    });

    it('should display the number of records', () => {
      const records = <Counter value={0} size="small" label="Records" />
      expect(wrapper.contains(records)).toEqual(true);
    });

    it('should display the openness percent', () => {
      const open = <Percent value={808} total={833} label="open data" icon="unlock alternate icon" size="small" />

      wrapper.setState({metrics: metrics});

      expect(wrapper.contains(open)).toEqual(true);
    });

    it('should display the downloadable percent', () => {
      const download = <Percent value={728} total={833} label="downloadable" icon="download" size="small" />

      wrapper.setState({metrics: metrics});

      expect(wrapper.contains(download)).toEqual(true);
    });
  })

  describe('fetch metrics', () => {
    it('should set metrics', () => {
      const wrapper = mountWithContext(<Catalog catalog={catalog} />)
      wrapper
        .instance()
        .componentWillMount()
        .then(() => expect(wrapper.state('metrics')).toEqual(metrics))
    });

    it('should display a loading.', () => {
      const loader = <CircularProgress size={1} />
      const wrapper = shallow(<Catalog catalog={catalog} />);
      expect(wrapper.contains(loader)).toEqual(true);
    });
  })

})
<commit_msg>Fix Catalog test<commit_after>import React from 'react';
import { shallow } from 'enzyme';
import Percent from '../../Statistics/Percent/Percent'
import CircularProgress from 'material-ui/CircularProgress'
import Counter from '../../Statistics/Counter/Counter'
import Catalog from '../Catalog'
import { mountWithContext } from '../../../test/jsdom-setup'

import catalog from '../../fetch/__test__/catalog.json'
import metrics from '../../fetch/__test__/metrics.json'
jest.mock('../../fetch/fetchMetrics');

describe('<Catalog />', () => {

  describe('When all goes well', () => {
    const wrapper = shallow(<Catalog catalog={catalog} />);
    it('renders without crashing', () => {
      shallow(<Catalog catalog={catalog} />);
    });

    it('should display the name of the catalog', () => {
      const title = {catalog.name}
      expect(wrapper.contains(title)).toEqual(true);
    });

    it('should display the number of records', () => {
      const records = <Counter value={0} size="small" label="Records" />
      expect(wrapper.contains(records)).toEqual(true);
    });

    it('should display the openness percent', () => {
      const open = <Percent value={808} total={833} label="open data" icon="unlock alternate icon" size="small" />

      wrapper.setState({metrics: metrics});

      expect(wrapper.contains(open)).toEqual(true);
    });

    it('should display the downloadable percent', () => {
      const download = <Percent value={728} total={833} label="downloadable" icon="download" size="small" />

      wrapper.setState({metrics: metrics});

      expect(wrapper.contains(download)).toEqual(true);
    });
  })

  describe('fetch metrics', () => {
    it('should set metrics', () => {
      const wrapper = mountWithContext(<Catalog catalog={catalog} />)
      return wrapper
        .instance()
        .componentWillMount()
        .then(() => expect(wrapper.state('metrics')).toEqual(metrics))
    });

    it('should display a loading.', () => {
      const loader = <CircularProgress size={1} />
      const wrapper = shallow(<Catalog catalog={catalog} />);
      expect(wrapper.contains(loader)).toEqual(true);
    });
  })

})
<|endoftext|>


<commit_before>/*global chrome:false */

// Build User: ${build.user}
// Version: ${build.version}
// Build Date: ${build.date}

// TODO: Safe callbacks

(function(root, factory) {
    'use strict';

    // Try to define a console object
    (function(){
        try {
            if (!console && ('undefined' !== typeof window)) {
                // Define the console if it does not exist
                if (!window.console) {
                    window.console = {};
                }

                // Union of Chrome, FF, IE, and Safari console methods
                var consoleFunctions = [
                    'log', 'info', 'warn', 'error', 'debug', 'trace', 'dir', 'group',
                    'groupCollapsed', 'groupEnd', 'time', 'timeEnd', 'profile', 'profileEnd',
                    'dirxml', 'assert', 'count', 'markTimeline', 'timeStamp', 'clear'
                ];
                // Define undefined methods as no-ops to prevent errors
                for (var i = 0; i < consoleFunctions.length; i++) {
                    if (!window.console[consoleFunctions[i]]) {
                        window.console[consoleFunctions[i]] = function() {};
                    }
                }
            }
        } catch(error) {
            // Not much to do if there is no console
        }

    })();

    // Determine the module system (if any)
    if (typeof define === 'function' && define.amd) {
        // AMD
        define(factory);
    } else {
        // Node
        if (typeof exports !== 'undefined') {
            module.exports = factory();
        } else {
            // None
            root.ChromeExtensionSettingsManager = factory();
        }
    }

})(this, function() {
    'use strict';

    var _isFunction = function(func) {
        return 'function' === typeof func;
    };

    var ChromeExtensionSettingsManager = function() {

        if (!(this instanceof ChromeExtensionSettingsManager)) {
            return new ChromeExtensionSettingsManager();
        }

        var _load = function(successCallback, errorCallback) {
            chrome.storage.sync.get({}, function(settings){
                if (chrome.runtime.lastError && _isFunction(errorCallback)) {
                    errorCallback.call(null);
                } else if (_isFunction(successCallback)) {
                    successCallback.call(null, settings);
                }
            });
        };

        var _save = function(settings, successCallback, errorCallback) {
            chrome.storage.sync.set(settings, function() {
                if (chrome.runtime.lastError && _isFunction(errorCallback)) {
                    errorCallback.call(null);
                } else if(_isFunction(successCallback)) {
                    successCallback.call(null);
                }
            });
        };

        var _clear = function(successCallback, errorCallback) {
            chrome.storage.sync.clear(function() {
                if (chrome.runtime.lastError && _isFunction(errorCallback)) {
                    errorCallback.call(null);
                } else {
                    // Is this necessary?
                    chrome.storage.sync.set(function() {
                        if(chrome.runtime.lastError && _isFunction(errorCallback)) {
                            errorCallback.call(null);
                        } else if(_isFunction(successCallback)) {
                            successCallback.call(null);
                        }
                    });
                }
            });
        };

        return {
            load: _load,
            save: _save,
            clear: _clear
        };

    };

    // Place the version as a member in the function
    ChromeExtensionSettingsManager.version = '${build.version}';

    return ChromeExtensionSettingsManager;

});<commit_msg>-Fixed _load bug<commit_after>/*global chrome:false */

// Build User: ${build.user}
// Version: ${build.version}
// Build Date: ${build.date}

// TODO: Safe callbacks

(function(root, factory) {
    'use strict';

    // Try to define a console object
    (function(){
        try {
            if (!console && ('undefined' !== typeof window)) {
                // Define the console if it does not exist
                if (!window.console) {
                    window.console = {};
                }

                // Union of Chrome, FF, IE, and Safari console methods
                var consoleFunctions = [
                    'log', 'info', 'warn', 'error', 'debug', 'trace', 'dir', 'group',
                    'groupCollapsed', 'groupEnd', 'time', 'timeEnd', 'profile', 'profileEnd',
                    'dirxml', 'assert', 'count', 'markTimeline', 'timeStamp', 'clear'
                ];
                // Define undefined methods as no-ops to prevent errors
                for (var i = 0; i < consoleFunctions.length; i++) {
                    if (!window.console[consoleFunctions[i]]) {
                        window.console[consoleFunctions[i]] = function() {};
                    }
                }
            }
        } catch(error) {
            // Not much to do if there is no console
        }

    })();

    // Determine the module system (if any)
    if (typeof define === 'function' && define.amd) {
        // AMD
        define(factory);
    } else {
        // Node
        if (typeof exports !== 'undefined') {
            module.exports = factory();
        } else {
            // None
            root.ChromeExtensionSettingsManager = factory();
        }
    }

})(this, function() {
    'use strict';

    var _isFunction = function(func) {
        return 'function' === typeof func;
    };

    var ChromeExtensionSettingsManager = function() {

        if (!(this instanceof ChromeExtensionSettingsManager)) {
            return new ChromeExtensionSettingsManager();
        }

        var _load = function(successCallback, errorCallback) {
            chrome.storage.sync.get(function(settings){
                if (chrome.runtime.lastError && _isFunction(errorCallback)) {
                    errorCallback.call(null);
                } else if (_isFunction(successCallback)) {
                    successCallback.call(null, settings);
                }
            });
        };

        var _save = function(settings, successCallback, errorCallback) {
            chrome.storage.sync.set(settings, function() {
                if (chrome.runtime.lastError && _isFunction(errorCallback)) {
                    errorCallback.call(null);
                } else if(_isFunction(successCallback)) {
                    successCallback.call(null);
                }
            });
        };

        var _clear = function(successCallback, errorCallback) {
            chrome.storage.sync.clear(function() {
                if (chrome.runtime.lastError && _isFunction(errorCallback)) {
                    errorCallback.call(null);
                } else {
                    // Is this necessary?
                    chrome.storage.sync.set(function() {
                        if(chrome.runtime.lastError && _isFunction(errorCallback)) {
                            errorCallback.call(null);
                        } else if(_isFunction(successCallback)) {
                            successCallback.call(null);
                        }
                    });
                }
            });
        };

        return {
            load: _load,
            save: _save,
            clear: _clear
        };

    };

    // Place the version as a member in the function
    ChromeExtensionSettingsManager.version = '${build.version}';

    return ChromeExtensionSettingsManager;

});<|endoftext|>


<commit_before>Ext.define('devilry_student.model.GroupInfo', {
    extend: 'Ext.data.Model',

    idProperty: 'id',
    fields: [
        {name: 'id', type: 'int'},
        {name: 'name', type: 'string'},
        {name: 'is_open', type: 'bool'},
        {name: 'deadline_handling', type: 'int'},
        {name: 'candidates', type: 'auto'},
        {name: 'examiners', type: 'auto'},
        {name: 'deadlines', type: 'auto'},
        {name: 'breadcrumbs', type: 'auto'},
        {name: 'add_delivery_url', type: 'string'},
        {name: 'active_feedback', type: 'auto'}
    ],

    proxy: {
        type: 'rest',
        url: DevilrySettings.DEVILRY_URLPATH_PREFIX + '/devilry_student/rest/aggregated-groupinfo',
        extraParams: {
            format: 'json'
        },
        reader: {
            type: 'json'
        }
    },

    hard_deadline_expired: function() {
        var hard_deadlines = this.get('deadline_handling') === 1;
        return this.deadline_expired() && hard_deadlines;
    },

    deadline_expired: function() {
        if(this.has_any_deadlines()) {
            return !this.get('deadlines')[0].in_the_future;
        } else {
            return false;
        }
    },

    has_any_deadlines: function() {
        var deadlines = this.get('deadlines');
        return deadlines.length > 0;
    },

    can_add_deliveries: function() {
        if(!this.get('is_open')) {
            return false;
        }
        if(!this.has_any_deadlines()) {
            return false;
        }
        var hard_deadlines = this.get('deadline_handling') === 1;
        if(hard_deadlines) {
            return this.get('deadlines')[0].in_the_future;
        } else {
            return true;
        }
    },

    statics: {
        parseDateTime: function(datetimeString) {
            return Ext.Date.parse(datetimeString, 'Y-m-d H:i:s');
        }
    }
});
<commit_msg>devilry_student...model.GroupInfo: Include delivery_types.<commit_after>Ext.define('devilry_student.model.GroupInfo', {
    extend: 'Ext.data.Model',

    idProperty: 'id',
    fields: [
        {name: 'id', type: 'int'},
        {name: 'name', type: 'string'},
        {name: 'is_open', type: 'bool'},
        {name: 'deadline_handling', type: 'int'},
        {name: 'candidates', type: 'auto'},
        {name: 'examiners', type: 'auto'},
        {name: 'deadlines', type: 'auto'},
        {name: 'breadcrumbs', type: 'auto'},
        {name: 'add_delivery_url', type: 'string'},
        {name: 'delivery_types', type: 'int'},
        {name: 'active_feedback', type: 'auto'}
    ],

    proxy: {
        type: 'rest',
        url: DevilrySettings.DEVILRY_URLPATH_PREFIX + '/devilry_student/rest/aggregated-groupinfo',
        extraParams: {
            format: 'json'
        },
        reader: {
            type: 'json'
        }
    },

    hard_deadline_expired: function() {
        var hard_deadlines = this.get('deadline_handling') === 1;
        return this.deadline_expired() && hard_deadlines;
    },

    deadline_expired: function() {
        if(this.has_any_deadlines()) {
            return !this.get('deadlines')[0].in_the_future;
        } else {
            return false;
        }
    },

    has_any_deadlines: function() {
        var deadlines = this.get('deadlines');
        return deadlines.length > 0;
    },

    can_add_deliveries: function() {
        if(!this.get('is_open')) {
            return false;
        }
        if(!this.has_any_deadlines()) {
            return false;
        }
        var hard_deadlines = this.get('deadline_handling') === 1;
        if(hard_deadlines) {
            return this.get('deadlines')[0].in_the_future;
        } else {
            return true;
        }
    },

    statics: {
        parseDateTime: function(datetimeString) {
            return Ext.Date.parse(datetimeString, 'Y-m-d H:i:s');
        }
    }
});
<|endoftext|>


<commit_before>define([
           'dojo/_base/declare',
           'dojo/_base/array',
           'JBrowse/Store/LRUCache',
           'jszlib/arrayCopy'
       ],
       function( declare, array, LRUCache, arrayCopy ) {

// contains chunks of files, stitches them together if necessary, wraps, and returns them
// to satisfy requests
return declare( null,

/**
 * @lends JBrowse.Store.RemoteBinaryFile
 */
{
    constructor: function( args ) {
        this.name = args.name;
        this._fetchCount = 0;
        this.minChunkSize = 'minChunkSize' in args ? args.minChunkSize : 65536;
        this.chunkCache = new LRUCache({
            name: args.name + ' chunk cache',
            fillCallback: dojo.hitch( this, '_fetch' )
        });

        this.totalSizes = {};
    },

    _escapeRegExp: function(str) {
        return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    },

    _relevantExistingChunks: function( url, start, end ) {
        // we can't actually use any existing chunks if we don't have an
        // end defined.  not possible in the HTTP spec to ask for all except
        // the first X bytes of a file
        if( !end )
            return [];

        start = start || 0;

        var fileChunks = this.chunkCache
                .query( new RegExp( '^'+this._escapeRegExp( url + ' (bytes' ) ) );

        // set 'start' and 'end' on any records that don't have them, but should
        array.forEach( fileChunks, function(c) {
                           if( c.size ) {
                               if( ! c.key.start )
                                   c.key.start = 0;
                               if( ! c.key.end )
                                   c.key.end = c.key.start + ( c.size || c.value.byteLength );
                           }
                       });

        // sort the records by start coordinate, then by length descending (so that we preferentially use big chunks)
        fileChunks = fileChunks.sort( function( a, b ) {
            return ( a.key.start - b.key.start ) || ((b.key.end - b.key.start) - ( a.key.end - a.key.start ));
        });

        // filter for the chunks that can actually be used for this request
        return array.filter( fileChunks,
                             function( chunk ) {
                                 return !( chunk.key.start > end || chunk.key.end < start );
                             }, this);
    },

    _fetchChunks: function( url, start, end, callback ) {
        start = start || 0;

        // // if we already know how big the file is, use that information for the end
        if( typeof end != 'number' && this.totalSizes[url] ) {
            end = this.totalSizes[ url ]-1;
        }
        // // NOTE: if end is undefined, take that to mean fetch all the way to the end of the file

        this._log( '_fetchChunks', url, start, end );

        // what chunks do we already have in the chunk cache?
        var existingChunks = this._relevantExistingChunks( url, start, end );
        this._log( 'existing', existingChunks );

        var needed = [];
        var currIndex = start;
        var goldenPath = [];
        var chunkToString = function() {
            return this.url+" (bytes "+this.start+".."+this.end+")";
        };

        array.forEach( existingChunks, function( chunk, i ) {
                           // can't use any existing chunks if we have no end specified
                           if( !end || currIndex > end ) {
                               return;
                           }
                           else if( chunk.key.start > currIndex ) {
                               // we need to get a chunk for this range
                               var n = {
                                   key: {
                                       url:   url,
                                       start: currIndex,
                                       end:   currIndex + Math.max( this.minChunkSize, chunk.key.start - currIndex ) - 1,
                                       toString: chunkToString
                                   }
                               };
                               needed.push( n );
                               goldenPath.push( n );
                           }
                           else if( chunk.key.end >= currIndex ) {
                               // we'll use this chunk
                               this.chunkCache.touch( chunk );
                               goldenPath.push( chunk );
                           }
                           else {
                               console.error( currIndex, chunk, i, existingChunks );
                               throw 'should not be reached';
                           }
                           currIndex = goldenPath[ goldenPath.length-1 ].key.end + 1;
        },this);

        if( !existingChunks.length || currIndex <= end ) {
            needed.push({ key: {
                              url: url,
                              start: currIndex,
                              end: end ? Math.max( currIndex+this.minChunkSize-1, end ) : undefined,
                              toString: chunkToString
                          }
                        });
            goldenPath.push( needed[needed.length-1] );
        }

        this._log( 'needed', needed );

        // now fetch all the needed chunks
        // remember that chunk records in the 'needed' array are also
        // present in the 'goldenPath' array, so setting their value
        // will affect both places
        if( needed.length ) {
            var fetchedCount = 0;
            array.forEach( needed, function( c ) {
                this.chunkCache.get( c.key, function( data ) {
                    c.value = data;
                    if( ++fetchedCount == needed.length )
                        callback( goldenPath );
                });
            }, this );
        }
        // or we might already have all the chunks we need
        else {
            callback( goldenPath );
        }
    },

    _fetch: function( request, callback, attempt, truncatedLength ) {

        this._log( 'fetch', request.url, request.start, request.end );
        this._fetchCount++;

        attempt = attempt || 1;
        if( attempt > 3 ) {
            callback(null);
            return;
        }

        var req = new XMLHttpRequest();
        var length;
        req.open('GET', request.url, true);
        if( req.overrideMimeType )
            req.overrideMimeType('text/plain; charset=x-user-defined');
        if (request.end) {
            req.setRequestHeader('Range', 'bytes=' + request.start + '-' + request.end);
            length = request.end - request.start + 1;
        }
        req.responseType = 'arraybuffer';

        var respond = function( response ) {
            if( response ) {
                if( ! request.start )
                    request.start = 0;
                if( ! request.end )
                    request.end = response.byteLength;
            }
            callback( response );
        };

        req.onreadystatechange = dojo.hitch( this, function() {
            if (req.readyState == 4) {
                if (req.status == 200 || req.status == 206) {

                    // if this response tells us the file's total size, remember that
                    this.totalSizes[request.url] = (function() {
                        var contentRange = req.getResponseHeader('Content-Range');
                        if( ! contentRange )
                            return undefined;
                        var match = contentRange.match(/\/(\d+)$/);
                        return match ? parseInt(match[1]) : undefined;
                    })();

                    var response = req.response || req.mozResponseArrayBuffer || (function() {
                        try{
                            var r = req.responseText;
                            if (length && length != r.length && (!truncatedLength || r.length != truncatedLength)) {
                                this._fetch( request, callback, attempt + 1, r.length );
                                return;
                            } else {
                                respond( this._stringToBuffer(req.responseText) );
                                return;
                            }
                        } catch (x) {
                            console.error(''+x);
                            respond( null );
                            return;
                        }
                    }).call(this);
                    if( response ) {
                        callback( response );
                    }
                } else {
                    return this._fetch( request, callback, attempt + 1);
                }
            }
            return null;
        });
        // if (this.opts.credentials) {
        //     req.withCredentials = true;
        //  }
        req.send('');
    },

    /**
     * @param args.url
     * @param args.start
     * @param args.end
     * @param args.success
     */
    get: function( args ) {
        this._log( 'get', args.url, args.start, args.end );

        var start = args.start || 0;
        var end = args.end;
        if( start && !end )
            throw "cannot specify a fetch start without a fetch end";

        this._fetchChunks( args.url, start, end, dojo.hitch( this, function( chunks ) {
            var fetchLength = end ? end - start + 1 // use start end end if we have it
                                  : Math.max.apply( Math, // otherwise calculate from the end offsets of the chunks
                                                    array.map(
                                                        chunks,
                                                        function(c) {
                                                            return c.key.end ||
                                                                // and possibly calculate the end offset of the chunk from its start + its length
                                                                (c.key.start + c.value.byteLength);
                                                        })
                                                  ) + 1;

            var returnBuffer = new Uint8Array( fetchLength );

            // stitch them together into one ArrayBuffer to return
            var cursor = 0;
            array.forEach( chunks, function( chunk ) {
                var b = new Uint8Array( chunk.value );
                var bOffset = Math.max( 0, start - chunk.key.start );
                var length = Math.min( b.length - bOffset, fetchLength - cursor );
                this._log( 'arrayCopy', b, bOffset, returnBuffer, cursor, length );
                arrayCopy( b, bOffset, returnBuffer, cursor, length );
                cursor += length;
            },this);

            // return the data buffer
            args.success( returnBuffer.buffer );
        }));
    },

    _stringToBuffer: function(result) {
        if( ! result || typeof Uint8Array != 'function' )
            return null;

        var ba = new Uint8Array( result.length );
        for ( var i = 0; i < ba.length; i++ ) {
            ba[i] = result.charCodeAt(i);
        }
        return ba.buffer;
    },

    _log: function() {
        //console.log.apply( console, this._logf.apply(this,arguments) );
    },
    _warn: function() {
        console.warn.apply( console, this._logf.apply(this,arguments) );
    },
    _error: function() {
        console.error.apply( console, this._logf.apply(this,arguments) );
    },
    _logf: function() {
        arguments[0] = this.name+' '+arguments[0];
        if( typeof arguments[0] == 'string' )
            while( arguments[0].length < 15 )
                arguments[0] += ' ';
        return arguments;
    }

});
});<commit_msg>another bugfix to remote binary file caching<commit_after>define([
           'dojo/_base/declare',
           'dojo/_base/array',
           'JBrowse/Store/LRUCache',
           'jszlib/arrayCopy'
       ],
       function( declare, array, LRUCache, arrayCopy ) {

// contains chunks of files, stitches them together if necessary, wraps, and returns them
// to satisfy requests
return declare( null,

/**
 * @lends JBrowse.Store.RemoteBinaryFile
 */
{
    constructor: function( args ) {
        this.name = args.name;
        this._fetchCount = 0;
        this.minChunkSize = 'minChunkSize' in args ? args.minChunkSize : 65536;
        this.chunkCache = new LRUCache({
            name: args.name + ' chunk cache',
            fillCallback: dojo.hitch( this, '_fetch' )
        });

        this.totalSizes = {};
    },

    _escapeRegExp: function(str) {
        return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    },

    _relevantExistingChunks: function( url, start, end ) {
        // we can't actually use any existing chunks if we don't have an
        // end defined.  not possible in the HTTP spec to ask for all except
        // the first X bytes of a file
        if( !end )
            return [];

        start = start || 0;

        var fileChunks = this.chunkCache
                .query( new RegExp( '^'+this._escapeRegExp( url + ' (bytes' ) ) );

        // set 'start' and 'end' on any records that don't have them, but should
        array.forEach( fileChunks, function(c) {
                           if( c.size ) {
                               if( ! c.key.start )
                                   c.key.start = 0;
                               if( ! c.key.end )
                                   c.key.end = c.key.start + ( c.size || c.value.byteLength );
                           }
                       });

        // sort the records by start coordinate, then by length descending (so that we preferentially use big chunks)
        fileChunks = fileChunks.sort( function( a, b ) {
            return ( a.key.start - b.key.start ) || ((b.key.end - b.key.start) - ( a.key.end - a.key.start ));
        });

        // filter for the chunks that can actually be used for this request
        return array.filter( fileChunks,
                             function( chunk ) {
                                 return !( chunk.key.start > end || chunk.key.end < start );
                             }, this);
    },

    _fetchChunks: function( url, start, end, callback ) {
        start = start || 0;

        // // if we already know how big the file is, use that information for the end
        if( typeof end != 'number' && this.totalSizes[url] ) {
            end = this.totalSizes[ url ]-1;
        }
        // // NOTE: if end is undefined, take that to mean fetch all the way to the end of the file

        this._log( '_fetchChunks', url, start, end );

        // what chunks do we already have in the chunk cache?
        var existingChunks = this._relevantExistingChunks( url, start, end );
        this._log( 'existing', existingChunks );

        var needed = [];
        var currIndex = start;
        var goldenPath = [];
        var chunkToString = function() {
            return this.url+" (bytes "+this.start+".."+this.end+")";
        };

        array.forEach( existingChunks, function( chunk, i ) {
                           // can't use any existing chunks if we have no end specified
                           if( !end || currIndex > end ) {
                               return;
                           }
                           else if( chunk.key.start > currIndex ) {
                               // we need to get a chunk for this range
                               var n = {
                                   key: {
                                       url:   url,
                                       start: currIndex,
                                       end:   currIndex + Math.max( this.minChunkSize, chunk.key.start - currIndex ) - 1,
                                       toString: chunkToString
                                   }
                               };
                               needed.push( n );
                               goldenPath.push( n );
                           }
                           else if( chunk.key.end >= currIndex ) {
                               // we'll use this chunk
                               this.chunkCache.touch( chunk );
                               goldenPath.push( chunk );
                           }
                           else {
                               console.error( currIndex, chunk, i, existingChunks );
                               throw 'should not be reached';
                           }
                           currIndex = goldenPath[ goldenPath.length-1 ].key.end + 1;
        },this);

        if( !existingChunks.length || currIndex <= end ) {
            needed.push({ key: {
                              url: url,
                              start: currIndex,
                              end: end ? Math.max( currIndex+this.minChunkSize-1, end ) : undefined,
                              toString: chunkToString
                          }
                        });
            goldenPath.push( needed[needed.length-1] );
        }

        this._log( 'needed', needed );

        // now fetch all the needed chunks
        // remember that chunk records in the 'needed' array are also
        // present in the 'goldenPath' array, so setting their value
        // will affect both places
        if( needed.length ) {
            var fetchedCount = 0;
            array.forEach( needed, function( c ) {
                this.chunkCache.get( c.key, function( data ) {
                    c.value = data;
                    if( ++fetchedCount == needed.length )
                        callback( goldenPath );
                });
            }, this );
        }
        // or we might already have all the chunks we need
        else {
            callback( goldenPath );
        }
    },

    _fetch: function( request, callback, attempt, truncatedLength ) {

        this._log( 'fetch', request.url, request.start, request.end );
        this._fetchCount++;

        attempt = attempt || 1;
        if( attempt > 3 ) {
            callback(null);
            return;
        }

        var req = new XMLHttpRequest();
        var length;
        req.open('GET', request.url, true);
        if( req.overrideMimeType )
            req.overrideMimeType('text/plain; charset=x-user-defined');
        if (request.end) {
            req.setRequestHeader('Range', 'bytes=' + request.start + '-' + request.end);
            length = request.end - request.start + 1;
        }
        req.responseType = 'arraybuffer';

        var respond = function( response ) {
            if( response ) {
                if( ! request.start )
                    request.start = 0;
                if( ! request.end )
                    request.end = response.byteLength;
            }
            callback( response );
        };

        req.onreadystatechange = dojo.hitch( this, function() {
            if (req.readyState == 4) {
                if (req.status == 200 || req.status == 206) {

                    // if this response tells us the file's total size, remember that
                    this.totalSizes[request.url] = (function() {
                        var contentRange = req.getResponseHeader('Content-Range');
                        if( ! contentRange )
                            return undefined;
                        var match = contentRange.match(/\/(\d+)$/);
                        return match ? parseInt(match[1]) : undefined;
                    })();

                    var response = req.response || req.mozResponseArrayBuffer || (function() {
                        try{
                            var r = req.responseText;
                            if (length && length != r.length && (!truncatedLength || r.length != truncatedLength)) {
                                this._fetch( request, callback, attempt + 1, r.length );
                                return;
                            } else {
                                respond( this._stringToBuffer(req.responseText) );
                                return;
                            }
                        } catch (x) {
                            console.error(''+x);
                            respond( null );
                            return;
                        }
                    }).call(this);
                    if( response ) {
                        callback( response );
                    }
                } else {
                    return this._fetch( request, callback, attempt + 1);
                }
            }
            return null;
        });
        // if (this.opts.credentials) {
        //     req.withCredentials = true;
        //  }
        req.send('');
    },

    /**
     * @param args.url
     * @param args.start
     * @param args.end
     * @param args.success
     */
    get: function( args ) {
        this._log( 'get', args.url, args.start, args.end );

        var start = args.start || 0;
        var end = args.end;
        if( start && !end )
            throw "cannot specify a fetch start without a fetch end";

        this._fetchChunks( args.url, start, end, dojo.hitch( this, function( chunks ) {
            this._log( 'golden path', chunks);

            var fetchLength = end ? end - start + 1 // use start end end if we have it
                                  : Math.max.apply( Math, // otherwise calculate from the end offsets of the chunks
                                                    array.map(
                                                        chunks,
                                                        function(c) {
                                                            return c.key.end ||
                                                                // and possibly calculate the end offset of the chunk from its start + its length
                                                                (c.key.start + c.value.byteLength);
                                                        })
                                                  ) + 1;

            var returnBuffer = new Uint8Array( fetchLength );

            // stitch them together into one ArrayBuffer to return
            var cursor = 0;
            array.forEach( chunks, function( chunk ) {
                var b = new Uint8Array( chunk.value );
                var bOffset = (start+cursor) - chunk.key.start; if( bOffset < 0 ) this._error('chunking error');
                var length = Math.min( b.byteLength - bOffset, fetchLength - cursor );
                this._log( 'arrayCopy', b, bOffset, returnBuffer, cursor, length );
                arrayCopy( b, bOffset, returnBuffer, cursor, length );
                cursor += length;
            },this);

            // return the data buffer
            args.success( returnBuffer.buffer );
        }));
    },

    _stringToBuffer: function(result) {
        if( ! result || typeof Uint8Array != 'function' )
            return null;

        var ba = new Uint8Array( result.length );
        for ( var i = 0; i < ba.length; i++ ) {
            ba[i] = result.charCodeAt(i);
        }
        return ba.buffer;
    },

    _log: function() {
        //console.log.apply( console, this._logf.apply(this,arguments) );
    },
    _warn: function() {
        console.warn.apply( console, this._logf.apply(this,arguments) );
    },
    _error: function() {
        console.error.apply( console,  this._logf.apply(this,arguments) );
        throw 'file error';
    },
    _logf: function() {
        arguments[0] = this.name+' '+arguments[0];
        if( typeof arguments[0] == 'string' )
            while( arguments[0].length < 15 )
                arguments[0] += ' ';
        return arguments;
    }

});
});<|endoftext|>


<commit_before>define([
           'dojo/_base/declare',
           'dojo/_base/array',
           'JBrowse/Store/LRUCache',
           'JBrowse/Model/XHRBlob',
           'JBrowse/Model/BGZip/BGZBlob',
           'JBrowse/Model/TabixIndex'
       ],
       function(
           declare,
           array,
           LRUCache,
           XHRBlob,
           BGZBlob,
           TabixIndex
       ) {

return declare( null, {

    constructor: function( args ) {
        this.browser = args.browser;
        this.index = new TabixIndex({ blob: new BGZBlob( args.tbi ), browser: args.browser } );
        this.data  = new BGZBlob( args.file );
        this.indexLoaded = this.index.load();
    },

    getLines: function( ref, min, max, itemCallback, finishCallback, errorCallback ) {
        var thisB = this;
        var args = Array.prototype.slice.call(arguments);
        this.indexLoaded.then(function() {
            thisB._fetch.apply( thisB, args );
        }, errorCallback);
    },

    _fetch: function( ref, min, max, itemCallback, finishCallback, errorCallback ) {
        var regRef = this.browser.regularizeReferenceName( ref );

        errorCallback = errorCallback || function(e) { console.error(e, e.stack); };

        var chunks = this.index.blocksForRange( ref, min, max);
        if ( ! chunks ) {
            errorCallback('Error in index fetch ('+[ref,min,max].join(',')+')');
            return;
        }

        // toString function is used by the cache for making cache keys
        chunks.toString = chunks.toUniqueString = function() {
            return this.join(', ');
        };

        var fetchError;
        try {
            this._fetchChunkData( chunks, function( items, error ) {
                if( fetchError )
                    return;

                if( error ) {
                    errorCallback( error );
                } else {
                    array.forEach( items, function(item) {
                        if( !( item.end < min || item.start > max )
                            && ( ref === undefined || item._regularizedRef == regRef ) ) {
                                itemCallback( item );
                            }
                    });
                    finishCallback();
                }
            });
        } catch( e ) {
            errorCallback( e );
        }
    },

    _fetchChunkData: function( chunks, callback ) {
        var thisB = this;

        if( ! chunks.length ) {
            callback([]);
            return;
        }

        var allItems = [];
        var chunksProcessed = 0;

        var cache = this.chunkCache = this.chunkCache || new LRUCache({
            name: 'TabixIndexedFileChunkedCache',
            fillCallback: dojo.hitch( this, '_readChunkItems' ),
            sizeFunction: function( chunkItems ) {
                return chunkItems.length;
            },
            maxSize: 100000 // cache up to 100,000 items
        });

        var error;
        array.forEach( chunks, function( c ) {
            cache.get( c, function( chunkItems, e ) {
                error = error || e;
                allItems.push.apply( allItems, chunkItems );
                if( ++chunksProcessed == chunks.length )
                    callback( allItems, error );
            });
        });
    },

    _readChunkItems: function( chunk, callback ) {
        var thisB = this;
        var items = [];

        thisB.data.read(chunk.minv.block, chunk.maxv.block - chunk.minv.block + 1, function( data ) {
            data = new Uint8Array(data);

            // throw away the first (probably incomplete) line
            var parseStart = array.indexOf( data, thisB._newlineCode, 0 ) + 1;

            try {
                thisB.parseItems(
                    data,
                    parseStart,
                    function(i) { items.push(i); },
                    function() { callback(items); }
                );
            } catch( e ) {
                callback( null, e );
            }
        },
        function(e) {
            callback( null, e );
        });
    },

    parseItems: function( data, blockStart, itemCallback, finishCallback ) {
        var that = this;
        var itemCount = 0;

        var maxItemsWithoutYielding = 300;
        var parseState = { data: data, offset: blockStart };

        while ( true ) {
            // if we've read no more than a certain number of items this cycle, read another one
            if( itemCount <= maxItemsWithoutYielding ) {
                var item = this.parseItem( parseState ); //< increments parseState.offset
                if( item ) {
                    itemCallback( item );
                    itemCount++;
                }
                else {
                    finishCallback();
                    return;
                }
            }
            // if we're not done but we've read a good chunk of
            // items, schedule the rest of our work in a timeout to continue
            // later, avoiding blocking any UI stuff that needs to be done
            else {
                window.setTimeout( function() {
                    that.parseItems( data, parseState.offset, itemCallback, finishCallback );
                }, 1);
                return;
            }
        }
    },

    // stub method, override in subclasses or instances
    parseItem: function( parseState ) {
        var metaChar = this.index.metaChar;

        var line;
        do {
            line = this._getline( parseState );
        } while( line && line[0] == metaChar );

        if( !line )
            return null;

        // function extractColumn( colNum ) {
        //     var skips = '';
        //     while( colNum-- > 1 )
        //         skips += '^[^\t]*\t';
        //     var match = (new Regexp( skips+'([^\t]*)' )).exec( line );
        //     if( ! match )
        //         return null;
        //     return match[1];
        // }
        var fields = line.split( "\t" );
        var item = { // note: index column numbers are 1-based
            ref:   fields[this.index.columnNumbers.ref-1],
            _regularizedRef: this.browser.regularizeReferenceName( fields[this.index.columnNumbers.ref-1] ),
            start: parseInt(fields[this.index.columnNumbers.start-1]),
            end:   parseInt(fields[this.index.columnNumbers.end-1]),
            fields: fields
        };
        return item;
    },

    _newlineCode: "\n".charCodeAt(0),

    _getline: function( parseState ) {
        var newlineIndex = array.indexOf( parseState.data, this._newlineCode, parseState.offset );

        if( newlineIndex == -1 ) // no more lines
            return null;

        var line = String.fromCharCode.apply( String, Array.prototype.slice.call( parseState.data, parseState.offset, newlineIndex ));
        parseState.offset = newlineIndex+1;
        return line;
    }
});
});
<commit_msg>avoid call-stack size problems when reading very long VCF lines<commit_after>define([
           'dojo/_base/declare',
           'dojo/_base/array',
           'JBrowse/Store/LRUCache',
           'JBrowse/Model/XHRBlob',
           'JBrowse/Model/BGZip/BGZBlob',
           'JBrowse/Model/TabixIndex'
       ],
       function(
           declare,
           array,
           LRUCache,
           XHRBlob,
           BGZBlob,
           TabixIndex
       ) {

return declare( null, {

    constructor: function( args ) {
        this.browser = args.browser;
        this.index = new TabixIndex({ blob: new BGZBlob( args.tbi ), browser: args.browser } );
        this.data  = new BGZBlob( args.file );
        this.indexLoaded = this.index.load();
    },

    getLines: function( ref, min, max, itemCallback, finishCallback, errorCallback ) {
        var thisB = this;
        var args = Array.prototype.slice.call(arguments);
        this.indexLoaded.then(function() {
            thisB._fetch.apply( thisB, args );
        }, errorCallback);
    },

    _fetch: function( ref, min, max, itemCallback, finishCallback, errorCallback ) {
        var regRef = this.browser.regularizeReferenceName( ref );

        errorCallback = errorCallback || function(e) { console.error(e, e.stack); };

        var chunks = this.index.blocksForRange( ref, min, max);
        if ( ! chunks ) {
            errorCallback('Error in index fetch ('+[ref,min,max].join(',')+')');
            return;
        }

        // toString function is used by the cache for making cache keys
        chunks.toString = chunks.toUniqueString = function() {
            return this.join(', ');
        };

        var fetchError;
        try {
            this._fetchChunkData( chunks, function( items, error ) {
                if( fetchError )
                    return;

                if( error ) {
                    errorCallback( error );
                } else {
                    array.forEach( items, function(item) {
                        if( !( item.end < min || item.start > max )
                            && ( ref === undefined || item._regularizedRef == regRef ) ) {
                                itemCallback( item );
                            }
                    });
                    finishCallback();
                }
            });
        } catch( e ) {
            errorCallback( e );
        }
    },

    _fetchChunkData: function( chunks, callback ) {
        var thisB = this;

        if( ! chunks.length ) {
            callback([]);
            return;
        }

        var allItems = [];
        var chunksProcessed = 0;

        var cache = this.chunkCache = this.chunkCache || new LRUCache({
            name: 'TabixIndexedFileChunkedCache',
            fillCallback: dojo.hitch( this, '_readChunkItems' ),
            sizeFunction: function( chunkItems ) {
                return chunkItems.length;
            },
            maxSize: 100000 // cache up to 100,000 items
        });

        var error;
        array.forEach( chunks, function( c ) {
            cache.get( c, function( chunkItems, e ) {
                error = error || e;
                allItems.push.apply( allItems, chunkItems );
                if( ++chunksProcessed == chunks.length )
                    callback( allItems, error );
            });
        });
    },

    _readChunkItems: function( chunk, callback ) {
        var thisB = this;
        var items = [];

        thisB.data.read(chunk.minv.block, chunk.maxv.block - chunk.minv.block + 1, function( data ) {
            data = new Uint8Array(data);

            // throw away the first (probably incomplete) line
            var parseStart = array.indexOf( data, thisB._newlineCode, 0 ) + 1;

            try {
                thisB.parseItems(
                    data,
                    parseStart,
                    function(i) { items.push(i); },
                    function() { callback(items); }
                );
            } catch( e ) {
                callback( null, e );
            }
        },
        function(e) {
            callback( null, e );
        });
    },

    parseItems: function( data, blockStart, itemCallback, finishCallback ) {
        var that = this;
        var itemCount = 0;

        var maxItemsWithoutYielding = 300;
        var parseState = { data: data, offset: blockStart };

        while ( true ) {
            // if we've read no more than a certain number of items this cycle, read another one
            if( itemCount <= maxItemsWithoutYielding ) {
                var item = this.parseItem( parseState ); //< increments parseState.offset
                if( item ) {
                    itemCallback( item );
                    itemCount++;
                }
                else {
                    finishCallback();
                    return;
                }
            }
            // if we're not done but we've read a good chunk of
            // items, schedule the rest of our work in a timeout to continue
            // later, avoiding blocking any UI stuff that needs to be done
            else {
                window.setTimeout( function() {
                    that.parseItems( data, parseState.offset, itemCallback, finishCallback );
                }, 1);
                return;
            }
        }
    },

    // stub method, override in subclasses or instances
    parseItem: function( parseState ) {
        var metaChar = this.index.metaChar;

        var line;
        do {
            line = this._getline( parseState );
        } while( line && line[0] == metaChar );

        if( !line )
            return null;

        // function extractColumn( colNum ) {
        //     var skips = '';
        //     while( colNum-- > 1 )
        //         skips += '^[^\t]*\t';
        //     var match = (new Regexp( skips+'([^\t]*)' )).exec( line );
        //     if( ! match )
        //         return null;
        //     return match[1];
        // }
        var fields = line.split( "\t" );
        var item = { // note: index column numbers are 1-based
            ref:   fields[this.index.columnNumbers.ref-1],
            _regularizedRef: this.browser.regularizeReferenceName( fields[this.index.columnNumbers.ref-1] ),
            start: parseInt(fields[this.index.columnNumbers.start-1]),
            end:   parseInt(fields[this.index.columnNumbers.end-1]),
            fields: fields
        };
        return item;
    },

    _newlineCode: "\n".charCodeAt(0),

    _getline: function( parseState ) {
        var data = parseState.data;
        var newlineIndex = array.indexOf( data, this._newlineCode, parseState.offset );

        if( newlineIndex == -1 ) // no more lines
            return null;

        var line = '';
        for( var i = parseState.offset; i < newlineIndex; i++ )
            line += String.fromCharCode( data[i] );
        parseState.offset = newlineIndex+1;
        return line;
    }
});
});
<|endoftext|>


<commit_before>function toggleClass() {
    var theme = document.getElementById("theme-area");
    theme.classList.toggle("active");
}
function setTheme(btn) {
    var newTheme = "cld-video-player-skin-" + btn.value;
    var oldTheme = "cld-video-player-skin-";
    if(btn.value == "dark") {
        oldTheme += "light";
    }
    else {
        oldTheme += "dark";
    }
    var vplayers = document.getElementsByClassName("cld-video-player");
    for(var i = 0; i < vplayers.length; i++) {
        vplayers[i].classList.remove(oldTheme);
        vplayers[i].classList.add(newTheme);
    }
    toggleClass();
}

window.addEventListener('scroll',checkPosition,false);

function checkPosition()
{
    var themeArea = document.getElementById("theme-area");
    if(window.scrollY > 50)
    {
        themeArea.classList.add("scrolling");
    } else {
        themeArea.classList.remove("scrolling");
    }
}

function showContentBlocks() {
    var contentBlocks = document.getElementsByClassName("content-block");
    for(var i = 0; i < contentBlocks.length; i++) {
        contentBlocks[i].classList.remove("hidden");
    }
    showProgressBar(true,"transcript");
    showProgressBar(true,"autotag");
}

function initScreen() {
    getTranscriptFile = true;
    transcriptComplete = false;
    progress = 0;
    autoTagProgress = 0;
    transcriptProgress = 0;
}

function uploadVideo(){
	cloudinary.openUploadWidget({ cloud_name: 'demo', upload_preset: 'video_autotag_transcript_sd_lambda', sources: [ 'local', 'url'], multiple: false, max_file_size: 100000000, resource_type: 'video'},
      function(error, result) { processResponse(error, result); }, false);
}

function useVideo(vid) {
    console.log("useVideo",vid.title);
    initScreen();
    publicId = vid.title + "_autotag";
    transcript = publicId + ".transcript";
    updatePlayers(vid.title + "_sd");
    showContentBlocks();
    progress = 20;
    updateProgress();
    updateAutoPlayers();
}

function updateAutoPlayers() {
    autoTagPlayer.source(publicId);
    transcriptPlayer.source(publicId);
}

function processResponse(error, result) {
    console.log(error, result);
    initScreen();
    if(result && result[0].bytes > 0 && result[0].bytes <= 100000000)
    {
        publicId = result[0].public_id;
        transcript = publicId + ".transcript";
        updatePlayers(publicId);
	showContentBlocks();
        updateProgress();
	updateAutoPlayers();
    }
    else if(result && result[0].bytes > 100000000) {
	    showContentBlocks();
            showError("Uploaded file is too big. This demo file size limit is 100MB");
    }
    else
        showError(error);
}

function updatePlayers(pid) {
    for(var i = 0; i < players.length; i++)
        players[i].source(pid);
    var links = document.getElementsByClassName("manipulation")
    for(var j = 0; j < links.length; j++) {
            var ref = links[j].getAttribute("data-href");
            links[j].setAttribute("href",ref+pid+".mp4");
    }
}

function updateProgress() {
    progress++;
    console.log("updateProgress", progress);
    if (progress == 30)
        checkLambda();
    if(autoTagProgress < 100)
        updateAutoTagProgress()
    if(transcriptProgress < 100)
        updateTranscriptProgress()
    if (autoTagProgress < 100 || transcriptProgress < 100)
        setTimeout(updateProgress,1500);
}

function getData() {
    if(getTranscriptFile && transcriptComplete)
        getTranscript();
    else if (autoTagProgress < 100 || transcriptProgress < 100)
        checkLambda();
    else
        console.log("getData Done");
}

  function getTranscript() {
	console.log("getTranscript", transcript);
	var checkUrl = url + transcript;
    httpTranscript.open('GET', checkUrl);
	httpTranscript.send();
}

function checkLambda() {
    console.log("checkLambda", transcript);
    var checkUrl = "https://4k4smz181f.execute-api.us-east-1.amazonaws.com/Prod/" + publicId;
    httpLambda.open('GET', checkUrl);
	httpLambda.send();
}

var httpLambda = new XMLHttpRequest();
httpLambda.onreadystatechange = function() {
    if (this.readyState == 4) {
        if(this.status == 200) {
          var notify = JSON.parse(httpLambda.responseText);
          checkLambdaNotification(notify);
        }
        setTimeout(getData,4000);
    }
    else
          console.log("onreadystatechange", this.readyState, this.status);
}

var httpTranscript = new XMLHttpRequest();
httpTranscript.onreadystatechange = function() {
    if (this.readyState == 4) {
        if(this.status == 200) {
          var notify = JSON.parse(httpTranscript.responseText);
          checkTranscriptFile(notify);
        }
        setTimeout(getData,3000);
    }
    else
          console.log("onreadystatechange", this.readyState, this.status);
}

function checkLambdaNotification(notify) {
        checkTranscript(notify);
        checkTags(notify);
}

function checkTranscriptFile(notify) {
    if(transcriptComplete && getTranscriptFile && Array.isArray(notify)) {
        transcriptProgress = 99;
        showJSON("transcript",notify);
        getTranscriptFile = false;
    }
}

function checkTranscript(notify) {
    if (notify.transcript.status == "pending") {
        console.log("transcript pending");
    }
    else if (notify.transcript.status == "complete") {
        transcriptComplete = true;
        transcriptPlayer.source(publicId,{ transformation: {overlay: "subtitles:"+transcript}}).play();
        console.log("transcript ready");
    }
    else
    {
        getTranscriptFile = false;
        transcriptComplete = true;
        transcriptPlayer.source(publicId).play();
        transcriptProgress = 99;
        showJSON("transcript","There is no transcript for this video");
        console.log("no transcript");
    }
}

function checkTags(notify) {
    if (notify.tags.status == "pending")
        console.log("autotag pending");
    else if (notify.tags.status == "complete") {
        autoTagProgress = 99;
        showJSON("autotag",notify.tags.data);
    }
    else
        console.log("no autotag");
}

function showProgressBar(show,id) {
    var pre = document.getElementById("pre-"+id);
    var bar = document.getElementById(id+"-bar");
    if(show) {
        bar.setAttribute("style","");
        pre.setAttribute("style","display: none");
    }
    else {
        bar.setAttribute("style","display: none");
        pre.setAttribute("style","");
    }
}

function showError(error) {
    showJSON("autotag",error);
    showJSON("transcript",error);
}

function showJSON(id,notify) {
    var content = document.getElementById(id);
    showProgressBar(false,id);
    var data = JSON.stringify(notify);
    content.innerText = data;
    Prism.highlightElement(content);
}

function updateAutoTagProgress() {
    autoTagProgress++;
    var autoTaggingBar = document.getElementById("autoTaggingBar");
    autoTaggingBar.style.width = autoTagProgress + '%';
}

function updateTranscriptProgress() {
    transcriptProgress++;
    var transcriptBar = document.getElementById("transcriptBar");
    transcriptBar.style.width = transcriptProgress + '%';
}

var url = "https://res.cloudinary.com/demo/raw/upload/";
var publicId = "sample";
var transcript = "sample.transcript"
var getTranscriptFile = true;
var transcriptComplete = false;
var progress = 0;
var autoTagProgress = 0;
var transcriptProgress = 0;

var cld = cloudinary.Cloudinary.new({ cloud_name: 'demo' });

var players = cld.videoPlayers('.demo-manipulation', {videojs: { bigPlayButton: false, controlBar: false } });

var transcriptPlayer = cld.videoPlayer('demo-transcript-player');

var autoTagPlayer = cld.videoPlayer('demo-autotag-player');

<commit_msg>Update transcode.js<commit_after>function toggleClass() {
    var theme = document.getElementById("theme-area");
    theme.classList.toggle("active");
}
function setTheme(btn) {
    var newTheme = "cld-video-player-skin-" + btn.value;
    var oldTheme = "cld-video-player-skin-";
    if(btn.value == "dark") {
        oldTheme += "light";
    }
    else {
        oldTheme += "dark";
    }
    var vplayers = document.getElementsByClassName("cld-video-player");
    for(var i = 0; i < vplayers.length; i++) {
        vplayers[i].classList.remove(oldTheme);
        vplayers[i].classList.add(newTheme);
    }
    toggleClass();
}

window.addEventListener('scroll',checkPosition,false);

function checkPosition()
{
    var themeArea = document.getElementById("theme-area");
    if(window.scrollY > 50)
    {
        themeArea.classList.add("scrolling");
    } else {
        themeArea.classList.remove("scrolling");
    }
}

function showContentBlocks() {
    var contentBlocks = document.getElementsByClassName("content-block");
    for(var i = 0; i < contentBlocks.length; i++) {
        contentBlocks[i].classList.remove("hidden");
    }
    showProgressBar(true,"transcript");
    showProgressBar(true,"autotag");
}

function initScreen() {
    getTranscriptFile = true;
    transcriptComplete = false;
    progress = 0;
    autoTagProgress = 0;
    transcriptProgress = 0;
}

function uploadVideo(){
	cloudinary.openUploadWidget({ cloud_name: 'demo', upload_preset: 'video_autotag_transcript_sd_lambda', sources: [ 'local', 'url'], multiple: false, max_file_size: 100000000, resource_type: 'video'},
      function(error, result) { processResponse(error, result); }, false);
}

function useVideo(vid) {
    console.log("useVideo",vid.title);
    initScreen();
    publicId = vid.title + "_autotag";
    transcript = publicId + ".transcript";
    updatePlayers(vid.title + "_sd");
    showContentBlocks();
    progress = 20;
    updateProgress();
    updateAutoPlayers();
}

function updateAutoPlayers() {
    autoTagPlayer.source(publicId);
    transcriptPlayer.source(publicId);
}

function processResponse(error, result) {
    console.log(error, result);
    initScreen();
    if(result && result[0].bytes > 0 && result[0].bytes <= 100000000)
    {
        publicId = result[0].public_id;
        transcript = publicId + ".transcript";
        updatePlayers(publicId);
	showContentBlocks();
        updateProgress();
	updateAutoPlayers();
    }
    else if(result && result[0].bytes > 100000000) {
	    showContentBlocks();
            showError("Uploaded file is too big. This demo file size limit is 100MB");
    }
    else
        showError(error);
}

function updatePlayers(pid) {
    for(var i = 0; i < players.length; i++)
        players[i].source(pid);
    var links = document.getElementsByClassName("manipulation")
    for(var j = 0; j < links.length; j++) {
            var ref = links[j].getAttribute("data-href");
            links[j].setAttribute("href",ref+pid+".mp4");
    }
}

function updateProgress() {
    progress++;
    console.log("updateProgress", progress);
    if (progress == 30)
        checkLambda();
    if(autoTagProgress < 100)
        updateAutoTagProgress()
    if(transcriptProgress < 100)
        updateTranscriptProgress()
    if (autoTagProgress < 100 || transcriptProgress < 100)
        setTimeout(updateProgress,3000);
}

function getData() {
    if(getTranscriptFile && transcriptComplete)
        getTranscript();
    else if (autoTagProgress < 100 || transcriptProgress < 100)
        checkLambda();
    else
        console.log("getData Done");
}

  function getTranscript() {
	console.log("getTranscript", transcript);
	var checkUrl = url + transcript;
    httpTranscript.open('GET', checkUrl);
	httpTranscript.send();
}

function checkLambda() {
    console.log("checkLambda", transcript);
    var checkUrl = "https://4k4smz181f.execute-api.us-east-1.amazonaws.com/Prod/" + publicId;
    httpLambda.open('GET', checkUrl);
	httpLambda.send();
}

var httpLambda = new XMLHttpRequest();
httpLambda.onreadystatechange = function() {
    if (this.readyState == 4) {
        if(this.status == 200) {
          var notify = JSON.parse(httpLambda.responseText);
          checkLambdaNotification(notify);
        }
        setTimeout(getData,4000);
    }
    else
          console.log("onreadystatechange", this.readyState, this.status);
}

var httpTranscript = new XMLHttpRequest();
httpTranscript.onreadystatechange = function() {
    if (this.readyState == 4) {
        if(this.status == 200) {
          var notify = JSON.parse(httpTranscript.responseText);
          checkTranscriptFile(notify);
        }
        setTimeout(getData,3000);
    }
    else
          console.log("onreadystatechange", this.readyState, this.status);
}

function checkLambdaNotification(notify) {
        checkTranscript(notify);
        checkTags(notify);
}

function checkTranscriptFile(notify) {
    if(transcriptComplete && getTranscriptFile && Array.isArray(notify)) {
        transcriptProgress = 99;
        showJSON("transcript",notify);
        getTranscriptFile = false;
    }
}

function checkTranscript(notify) {
    if (notify.transcript.status == "pending") {
        console.log("transcript pending");
    }
    else if (notify.transcript.status == "complete") {
        transcriptComplete = true;
        transcriptPlayer.source(publicId,{ transformation: {overlay: "subtitles:"+transcript}}).play();
        console.log("transcript ready");
    }
    else
    {
        getTranscriptFile = false;
        transcriptComplete = true;
        transcriptPlayer.source(publicId).play();
        transcriptProgress = 99;
        showJSON("transcript","There is no transcript for this video");
        console.log("no transcript");
    }
}

function checkTags(notify) {
    if (notify.tags.status == "pending")
        console.log("autotag pending");
    else if (notify.tags.status == "complete") {
        autoTagProgress = 99;
        showJSON("autotag",notify.tags.data);
    }
    else
        console.log("no autotag");
}

function showProgressBar(show,id) {
    var pre = document.getElementById("pre-"+id);
    var bar = document.getElementById(id+"-bar");
    if(show) {
        bar.setAttribute("style","");
        pre.setAttribute("style","display: none");
    }
    else {
        bar.setAttribute("style","display: none");
        pre.setAttribute("style","");
    }
}

function showError(error) {
    showJSON("autotag",error);
    showJSON("transcript",error);
}

function showJSON(id,notify) {
    var content = document.getElementById(id);
    showProgressBar(false,id);
    var data = JSON.stringify(notify);
    content.innerText = data;
    Prism.highlightElement(content);
}

function updateAutoTagProgress() {
    autoTagProgress++;
    var autoTaggingBar = document.getElementById("autoTaggingBar");
    autoTaggingBar.style.width = autoTagProgress + '%';
}

function updateTranscriptProgress() {
    transcriptProgress++;
    var transcriptBar = document.getElementById("transcriptBar");
    transcriptBar.style.width = transcriptProgress + '%';
}

var url = "https://res.cloudinary.com/demo/raw/upload/";
var publicId = "sample";
var transcript = "sample.transcript"
var getTranscriptFile = true;
var transcriptComplete = false;
var progress = 0;
var autoTagProgress = 0;
var transcriptProgress = 0;

var cld = cloudinary.Cloudinary.new({ cloud_name: 'demo' });

var players = cld.videoPlayers('.demo-manipulation', {videojs: { bigPlayButton: false, controlBar: false } });

var transcriptPlayer = cld.videoPlayer('demo-transcript-player');

var autoTagPlayer = cld.videoPlayer('demo-autotag-player');

<|endoftext|>


<commit_before>/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 * @format
 */

const {dirname, join, resolve} = require('path');

const FLOW_ROOT = resolve(__dirname, '../../../');
const defaultTestsDirName = 'newtests';

// This is where we look for tests to run and where we put newly converted
// tests
function getTestsDir(relative_to?: string): string {
  if (relative_to !== undefined) {
    return resolve(relative_to, defaultTestsDirName);
  } else {
    return dirname(require.resolve(join(defaultTestsDirName, 'package.json')));
  }
}

const binOptions: Array<string> = [
  resolve(FLOW_ROOT, '../buck-out/gen/flow/flow/flow'), // Buck
  resolve(FLOW_ROOT, 'bin/flow'), // Open source build
  resolve(FLOW_ROOT, 'bin/flow.exe'), // Open source windows build
];

const defaultFlowConfigName = '_flowconfig';

module.exports = {
  defaultTestsDirName,
  getTestsDir,
  binOptions,
  defaultFlowConfigName,
};
<commit_msg>[buck2] Update hardcoded buck-out constants to use buck2 paths<commit_after>/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 * @format
 */

const {dirname, join, resolve} = require('path');

const FLOW_ROOT = resolve(__dirname, '../../../');
const defaultTestsDirName = 'newtests';

// This is where we look for tests to run and where we put newly converted
// tests
function getTestsDir(relative_to?: string): string {
  if (relative_to !== undefined) {
    return resolve(relative_to, defaultTestsDirName);
  } else {
    return dirname(require.resolve(join(defaultTestsDirName, 'package.json')));
  }
}

const binOptions: Array<string> = [
  resolve(FLOW_ROOT, '../../buck-out/v2/gen/fbcode/flow/out/flow'), // Buck
  resolve(FLOW_ROOT, 'bin/flow'), // Open source build
  resolve(FLOW_ROOT, 'bin/flow.exe'), // Open source windows build
];

const defaultFlowConfigName = '_flowconfig';

module.exports = {
  defaultTestsDirName,
  getTestsDir,
  binOptions,
  defaultFlowConfigName,
};
<|endoftext|>


<commit_before>/**
 * A regex to match css `:host` selector.
 * @type {RegExp}
 * @private
 */
const HOST_REGEX = /:host(\(([^({)]+(\([^)]*\))?)+\))?/g;
/**
 * A regex to match content rule.
 * @type {RegExp}
 * @private
 */
const CONTENT_REGEX = /content:\s*([\w_-]*);/g;

/**
 * CSSKeyframesRule class.
 * @type {function}
 * @private
 */
const KFRule = self.CSSKeyframesRule ||
    self.WebKitCSSKeyframesRule ||
    self.MozCSSKeyframesRule;

/**
 * Add a scope to all selectors.
 * @private
 *
 * @param {CSSStyleSheet} sheet The css sheet to scope.
 * @param {String} scope The scope selector.
 */
function scoped(sheet, scope) {
    let rules = sheet.cssRules || sheet.rules;
    if (sheet.insertRule) {
        let reg = new RegExp(`${scope}([\\s.[:]|$)`);
        for (let i = 0, len = rules.length; i < len; i++) {
            let rule = rules[i];
            if (!(rule instanceof KFRule)) {
                try {
                    let body = rule.cssText;
                    if (rule.selectorText) {
                        let selector = rule.cssText.split('{').shift().split(',')
                            .map((rule) => {
                                rule = rule.trim();
                                if (rule.match(reg)) {
                                    return rule;
                                }
                                return `${scope} ${rule}`;
                            })
                            .join(', ');
                        body = rule.cssText
                            .replace(rule.selectorText, selector)
                            .replace(CONTENT_REGEX, 'content: "$1";');
                    } else if (rule.cssRules || rule.rules) {
                        scoped(rule, scope);
                        body = rule.cssText;
                    }
                    sheet.deleteRule(i);
                    sheet.insertRule(body, i);
                } catch (ex) {
                    //
                }
            }
        }
    }
    return [].map.call(
        rules,
        (rule) => rule.cssText.replace(CONTENT_REGEX, 'content: "$1";')
    ).join('');
}

/**
 * Convert a shadowDOM css string into a normal scoped css.
 * @private
 *
 * @param {HTMLStyleElement} style The style element.
 * @param {String} css The css string to convert.
 * @param {String} is The component name for scoping.
 */
export function convertShadowCSS(style, css, is) {
    let scope = `.${is}`;
    style.textContent = css
        .replace(HOST_REGEX, (fullMatch, mod) =>
            `${scope}${mod ? mod.slice(1, -1) : ''}`
        );
    style.textContent = scoped(style.sheet, scope);
}
<commit_msg>fix: update style text after shadow transpiling #22<commit_after>/**
 * A regex to match css `:host` selector.
 * @type {RegExp}
 * @private
 */
const HOST_REGEX = /:host(\(([^({)]+(\([^)]*\))?)+\))?/g;
/**
 * A regex to match content rule.
 * @type {RegExp}
 * @private
 */
const CONTENT_REGEX = /(?:^|\s)content:\s*([\w_-]*);/g;

/**
 * CSSKeyframesRule class.
 * @type {function}
 * @private
 */
const KFRule = self.CSSKeyframesRule ||
    self.WebKitCSSKeyframesRule ||
    self.MozCSSKeyframesRule;

/**
 * Add a scope to all selectors.
 * @private
 *
 * @param {CSSStyleSheet} sheet The css sheet to scope.
 * @param {String} scope The scope selector.
 */
function scoped(sheet, scope) {
    let rules = sheet.cssRules || sheet.rules;
    if (sheet.insertRule) {
        let reg = new RegExp(`${scope}([\\s.[:]|$)`);
        for (let i = 0, len = rules.length; i < len; i++) {
            let rule = rules[i];
            if (!(rule instanceof KFRule)) {
                try {
                    let body = rule.cssText;
                    if (rule.selectorText) {
                        let selector = rule.cssText.split('{').shift().split(',')
                            .map((rule) => {
                                rule = rule.trim();
                                if (rule.match(reg)) {
                                    return rule;
                                }
                                return `${scope} ${rule}`;
                            })
                            .join(', ');
                        body = rule.cssText
                            .replace(rule.selectorText, selector)
                            .replace(CONTENT_REGEX, 'content: "$1";');
                    } else if (rule.cssRules || rule.rules) {
                        scoped(rule, scope);
                        body = rule.cssText;
                    }
                    sheet.deleteRule(i);
                    sheet.insertRule(body, i);
                } catch (ex) {
                    //
                }
            }
        }
    }
    return [].map.call(
        rules,
        (rule) => rule.cssText.replace(CONTENT_REGEX, 'content: "$1";')
    ).join('');
}

/**
 * Convert a shadowDOM css string into a normal scoped css.
 * @private
 *
 * @param {HTMLStyleElement} style The style element.
 * @param {String} css The css string to convert.
 * @param {String} is The component name for scoping.
 */
export function convertShadowCSS(style, css, is) {
    let scope = `.${is}`;
    style.textContent = css
        .replace(HOST_REGEX, (fullMatch, mod) =>
            `${scope}${mod ? mod.slice(1, -1) : ''}`
        );
    style.textContent = scoped(style.sheet, scope);
}
<|endoftext|>