<commit_before>/*
 * 	BBB v0.2
 * 		By Steven Weerdenburg and Kevin Lasconia
 * 		Last Modification: 11/16/2010
 */
var Mgr = (function(){
    var _chapters = []; // Array of Chapters/Bookmarks
    var _vid = 0, _toc = 0; // id to store the table of contents and video player
    var _hasMadeToc = false;
    var _hasTocChanged = false;

    var _curr = -1;
    var currChap = 0;
    var _playSeq = 0;

    var canVideo = !!document.createElement('video').play;

    return {
        // A Bookmark object for the manager to work with
        Bookmark: function(params) {
            var title = "";
            var description = "";
            var src = "";
            var startTime = 0;
            var endTime = 0;

            if (params) {
                title = params["title"];
                description = params["description"];
                src = params["src"];
                startTime = parseInt(params["startTime"]);
                endTime = parseInt(params["endTime"]);

                if (startTime < 0 || endTime < 0)
                    throw "Start and end times must be positive!";
                else if (startTime < endTime) {
                    startTime = startTime;
                    endTime = endTime;
                } else {
                    endTime = startTime;
                    startTime = endTime;
                }
            }

            return {
                getTitle: function() { return title; },
                getDescription: function() { return description; },
                getSrc: function() { return src; },
                getStartTime: function() { return startTime; },
                getEndTime: function() { return endTime; },
                toString: function(){
                    return "Source: " + src + "\nTitle: " + title + "\nDescription: " + description + "\nStart Time: " + startTime + "\nEnd Time: " + endTime;
                },
                toJSON: function(){
                    return '{ "src": "' + src + '", "title": "' + title + '", "description": "' + description + '", "startTime": ' + startTime + ', "endTime": ' + endTime + ' }';
                },
                equals: function(bkmrk) {
                    return src === bkmrk.getSrc() && title === bkmrk.getTitle() && description === bkmrk.getDescription() &&
                        startTime === bkmrk.getStartTime() && endTime === bkmrk.getEndTime();
                },
                fromJSON: function(str){
                    //var obj = jsonParse(str);

                    var currStart = -1;
                    var currEnd = 0;
                    var obj = {};

                    while ((currStart = str.indexOf('"', currEnd + 1)) !== -1 && (currEnd = str.indexOf('"', currStart + 1)) !== -1) {
                        // Has found another attribute

                        var attrName = str.substring(currStart + 1, currEnd);
                        var foundAttr = false;
                        var foundSemi = false;
                        var foundType = 0; // 0 = none, 1 = string, 2 = numeric, 3 = float
                        var currItem;

                        // Process value, eagerly assume comma follows when value found
                        while ((currItem = str[++currEnd]) !== '"' || !foundAttr) {
                            if (str[currEnd] === ':') {
                                foundSemi = true;
                            } else {
                                if (str[currEnd] === '"') { // Check for strings
                                    if (foundSemi && str[currEnd - 1] !== '\\') {
                                        if (!foundType) {
                                            foundType = 1;
                                            currStart = currEnd;
                                        } else {
                                            obj[attrName] = str.substring(currStart + 1, currEnd);
                                            foundAttr = true;
                                            break; // Go into outer loop to find next attribute
                                        }
                                    }
                                } else {
                                    if (str[currEnd] === '.') { // Check for decimal for numeric->float data
                                        if (foundType === 2)
                                            foundType = 3;
                                    } else {
                                        if (str[currEnd] === ' ') {
                                            if (foundType === 2 || foundType === 3) { // Check for end of numeric data
                                                if (foundType === 2) // Integer
                                                    obj[attrName] = parseInt(str.substring(currStart, currEnd));
                                                else
                                                    if (foundType === 3) // Float
                                                        obj[attrName] = parseFloat(str.substring(currStart, currEnd));

                                                foundAttr = true;
                                                break;
                                            }
                                        } else {
                                            if (!foundType) {
                                                if (!isNaN(str[currEnd])) {
                                                    currStart = str[currEnd - 1] === '-' ? currEnd - 1 : currEnd;
                                                    foundType = 2; // Numeric, may be upgraded to float later
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    return Mgr.Bookmark(obj);
                }
            }
        },
        // A Statistics object for the manager to work with
		Statistics: function() {
			var a = "";

			return {

			}
		},
        fetchBookmarks: function() {
            // Stub code, will eventually get bookmarks from server call

            Mgr.addChapter({
                src: 'http://upload.wikimedia.org/wikipedia/commons/7/75/Big_Buck_Bunny_Trailer_400p.ogg',
                title: 'Big Buck Bunny',
                description: 'An animated video',
                startTime: 5,
                endTime: 14});

            Mgr.addChapter({
                src: 'http://www.archive.org/download/deadmandirewolffanclub/DireWolfFanClub.ogv',
                title: 'Dire Wolf Fan Club',
                description: 'An unusual video',
                startTime: 10,
                endTime: 29});

            Mgr.addChapter({
                src: 'http://jbuckley.ca/~hoops/elephant.ogv',
                title: 'Elephants Dream',
                description: 'Elephants',
                startTime: 145,
                endTime: 200});

            Mgr.addChapter({
                src: 'http://www.archive.org/download/Kinetic_Art_Demo_Video/nym.ogv',
                title: 'Kinetic Art',
                description: 'Domino fun',
                startTime: 60,
                endTime: 66});

            Mgr.addChapter({
                src: 'http://ftp.gnu.org/video/Stephen_Fry-Happy_Birthday_GNU-hq_600px_780kbit.ogv',
                title: 'Freedom Fry',
                description: 'Happy B-Day',
                startTime: 1,
                endTime: 60});
        },
        // (Re-)initialize all values except internal element pointers
        init: function(vidId, tocId, updateEvent, canPlayEvent, ip){
            _chapters = [];
            _hasMadeToc = false;
            _hasTocChanged = true; // In event TOC has been output before calling init, this will redraw table
            _curr = -1;

            this.setVideoId(vidId, updateEvent, canPlayEvent);
            this.setTOCId(tocId);
            Mgr.fetchBookmarks();
			//Mgr.trackStatistics();
        },
        // Add a chapter
        addChapter: function(_c){
            _chapters.push(Mgr.Bookmark(_c));
            _hasTocChanged = true;
        },
        // Add a chapter
        removeChapter: function(_idx){
            _chapters.splice(_idx, 1);
            _hasTocChanged = true;
        },

        // Set the table of contents (<table>) and player (<video>) elements based on id
        // Only set them if the currently stored element is null or has a differing id
        setTOCId: function(_id){
            if (_id && (!this._toc || this._toc.id !== _id)) { // Valid id given and No id supplied yet or different id supplied
                this._toc = document.getElementById(_id);
                _hasTocChanged = true;
            }
        },

        setVideoId: function(_id){
            if (canVideo) {
                if (_id && (!this._vid || this._vid.id !== _id)) { // valid id given and No id supplied yet or different id supplied
                    // Store locally for easy reference for event setup
                    this._vid = document.getElementById(_id);
                }
            }
        },

        // output the TOC
        printTOC: function(){
            if (canVideo) {
                if (this._toc) {
                    var tr = 0;
                    var srcElem = 0;
                    var th = 0;
                    if (!_hasMadeToc) {
                        tr = this._toc.insertRow(0);

                        // DOM approach for tables (IE doesn't like tr.innerHTML)
                        th = document.createElement('th');
                        th.innerHTML = "Chapter Title";
                        tr.appendChild(th);

                        th = document.createElement('th');
                        th.innerHTML = "Description";
                        tr.appendChild(th);

                        th = document.createElement('th');
                        th.innerHTML = "Start Time";
                        tr.appendChild(th);

                        th = document.createElement('th');
                        th.innerHTML = "End Time";
                        tr.appendChild(th);

                        th = document.createElement('th');
                        th.innerHTML = 'Delete';
                        tr.appendChild(th);

                        _hasMadeToc = true;
                    }

                    // Delete existing rows
                    for (var i = this._toc.rows.length - 1; i > 0; i--)
                        this._toc.deleteRow(i);

                    if (_hasTocChanged) {
                        for (var i = _chapters.length - 1; i >= 0; i--) {
                            tr = this._toc.insertRow(1);
                            srcElem = document.createElement('a');
                            var item = _chapters[i];

                            srcElem.href = 'javascript:Mgr.playChapter(' + i + ');';
                            srcElem.innerHTML = item.getTitle();
                            tr.insertCell(0).appendChild(srcElem);
                            tr.insertCell(1).appendChild(document.createTextNode(item.getDescription()));
                            tr.insertCell(2).appendChild(document.createTextNode(item.getStartTime()));
                            tr.insertCell(3).appendChild(document.createTextNode(item.getEndTime()));
                            tr.insertCell(4).innerHTML = '<input type="checkbox" onclick="Mgr.removeChapter('+i+'); Mgr.printTOC();" />';
                        }

                        tr = this._toc.insertRow(1);
                        tr.colspan = 4;

                        srcElem = document.createElement('a');
                        srcElem.href = 'javascript:Mgr.playChapter(0, 1);';
                        srcElem.innerHTML = 'Play All';
                        tr.insertCell(0).appendChild(srcElem);

                        _hasTocChanged = false;
                    }
                }
            }
        },

        playChapter: function(idx, sequential){
            if (canVideo) {
                if (idx !== _curr && idx >= 0 && idx < _chapters.length) {
                    var vid = this._vid;

                    _curr = idx;
                    currChap = _chapters[_curr];

                    vid.addEventListener('loadedmetadata', function(){
                        vid.currentTime = currChap.getStartTime();
                    }, true);

                    vid.addEventListener('canplay', function(){
                        vid.play();
                    }, true);

                    vid.addEventListener('timeupdate', function(){
                        if (vid.currentTime >= currChap.getEndTime()) {
                            if (sequential) {
                                Mgr.playChapter(idx+1, sequential);
                            }
                            else {
                                vid.pause();
                            }
                        }
                    }, true);

                    vid.src = currChap.getSrc();
                    vid.load();
                    vid.play();
                }
            }
        },

        trackStatistics: function(ip) {
			var stats = {ip : 0, onLoad : false, _25 : false, _50 : false, _75 : false, _90 : false, _100 : false, cc_on : false, cc_off : false, ad_on : false, ad_off : false};
			var vid = this._vid;
            var duration = vid.duration;

			stats.ip = ip;

            var durationListener = function() {
                if (parseInt(vid.currentTime, 10) === parseInt(duration * 0.25, 10)) {
                    vid.removeEventListener('timeupdate', durationListener, false);
					stats._25 = true;
                }
                else if (parseInt(vid.currentTime, 10) === parseInt(duration * 0.50, 10)) {
                	vid.removeEventListener('timeupdate', durationListener, false);
                    stats._50 = true;
                }
                else if (parseInt(vid.currentTime, 10) === parseInt(duration * 0.75, 10)) {
                	vid.removeEventListener('timeupdate', durationListener, false);
                    stats._75 = true;
                }
                else if (parseInt(vid.currentTime, 10) === parseInt(duration * 0.90, 10)) {
                	vid.removeEventListener('timeupdate', durationListener, false);
                    stats._90 = true;
                }
                vid.addEventListener('timeupdate', durationListener, false);
            }

            var endListener = function(){
                stats._100 = true;
				//Debugging purposes
				alert(stats._25 + ' ' + stats._50 + ' ' + stats._75 + ' ' + stats._90 + ' ' + stats._100);
            }

            vid.addEventListener('timeupdate', durationListener, false);
            vid.addEventListener('ended', endListener, false);
        },

		displayWatermark: function(src, opacity, alpha) {
			//Try and clean up code later :(
			var vid = this._vid;
			// Position of video player
			var videoTop = parseInt(vid.clientTop);
			var videoLeft = parseInt(vid.clientLeft);
			// Create div element
			var watermarkDiv = document.createElement('div');
			// Set div attributes
			watermarkDiv.setAttribute('id', 'watermark');
			watermarkDiv.className = 'watermark';
			watermarkDiv.style.position= 'absolute';
			watermarkDiv.style.left = videoLeft + 5 + 'px';
			watermarkDiv.style.top = videoTop + 5 + 'px';
			// Width and height will be hard-coded for now, will re-factor later
			watermarkDiv.style.width = 150 + 'px';
			watermarkDiv.style.height = 70 + 'px' ;
			// If image source is not specificed, default image will be used
			if (!src) {
				watermarkDiv.style.backgroundImage = 'url("watermark.png")';
			}
			else {
				watermarkDiv.style.backgroundImage = 'url("' + src + '")';
			}
			watermarkDiv.style.backgroundRepeat = "no-repeat";
			// Arbitrary zIndex value to ensure watermark is above video player
			watermarkDiv.style.zIndex = 100;
			watermarkDiv.style.opacity = 0.4;
			var alpha = 40;
			watermarkDiv.style.filter  = "alpha(opacity=" + alpha + ")";
			document.body.appendChild(watermarkDiv);
		}
    };
})();
<commit_msg>Beautified js file<commit_after>/*
 * 	BBB v0.2
 * 		By Steven Weerdenburg and Kevin Lasconia
 * 		Last Modification: 11/16/2010
 */
var Mgr = (function () {
    var _chapters = []; // Array of Chapters/Bookmarks
    var _vid = 0,
        _toc = 0; // id to store the table of contents and video player
    var _hasMadeToc = false;
    var _hasTocChanged = false;

    var _curr = -1;
    var currChap = 0;
    var _playSeq = 0;

    var canVideo = !! document.createElement('video').play;

    return {
        // A Bookmark object for the manager to work with
        Bookmark: function (params) {
            var title = "";
            var description = "";
            var src = "";
            var startTime = 0;
            var endTime = 0;

            if (params) {
                title = params["title"];
                description = params["description"];
                src = params["src"];
                startTime = parseInt(params["startTime"]);
                endTime = parseInt(params["endTime"]);

                if (startTime < 0 || endTime < 0) throw "Start and end times must be positive!";
                else if (startTime < endTime) {
                    startTime = startTime;
                    endTime = endTime;
                } else {
                    endTime = startTime;
                    startTime = endTime;
                }
            }

            return {
                getTitle: function () {
                    return title;
                },
                getDescription: function () {
                    return description;
                },
                getSrc: function () {
                    return src;
                },
                getStartTime: function () {
                    return startTime;
                },
                getEndTime: function () {
                    return endTime;
                },
                toString: function () {
                    return "Source: " + src + "\nTitle: " + title + "\nDescription: " + description + "\nStart Time: " + startTime + "\nEnd Time: " + endTime;
                },
                toJSON: function () {
                    return '{ "src": "' + src + '", "title": "' + title + '", "description": "' + description + '", "startTime": ' + startTime + ', "endTime": ' + endTime + ' }';
                },
                equals: function (bkmrk) {
                    return src === bkmrk.getSrc() && title === bkmrk.getTitle() && description === bkmrk.getDescription() && startTime === bkmrk.getStartTime() && endTime === bkmrk.getEndTime();
                },
                fromJSON: function (str) {
                    //var obj = jsonParse(str);
                    var currStart = -1;
                    var currEnd = 0;
                    var obj = {};

                    while ((currStart = str.indexOf('"', currEnd + 1)) !== -1 && (currEnd = str.indexOf('"', currStart + 1)) !== -1) {
                        // Has found another attribute
                        var attrName = str.substring(currStart + 1, currEnd);
                        var foundAttr = false;
                        var foundSemi = false;
                        var foundType = 0; // 0 = none, 1 = string, 2 = numeric, 3 = float
                        var currItem;

                        // Process value, eagerly assume comma follows when value found
                        while ((currItem = str[++currEnd]) !== '"' || !foundAttr) {
                            if (str[currEnd] === ':') {
                                foundSemi = true;
                            } else {
                                if (str[currEnd] === '"') { // Check for strings
                                    if (foundSemi && str[currEnd - 1] !== '\\') {
                                        if (!foundType) {
                                            foundType = 1;
                                            currStart = currEnd;
                                        } else {
                                            obj[attrName] = str.substring(currStart + 1, currEnd);
                                            foundAttr = true;
                                            break; // Go into outer loop to find next attribute
                                        }
                                    }
                                } else {
                                    if (str[currEnd] === '.') { // Check for decimal for numeric->float data
                                        if (foundType === 2) foundType = 3;
                                    } else {
                                        if (str[currEnd] === ' ') {
                                            if (foundType === 2 || foundType === 3) { // Check for end of numeric data
                                                if (foundType === 2) // Integer
                                                obj[attrName] = parseInt(str.substring(currStart, currEnd));
                                                else if (foundType === 3) // Float
                                                obj[attrName] = parseFloat(str.substring(currStart, currEnd));

                                                foundAttr = true;
                                                break;
                                            }
                                        } else {
                                            if (!foundType) {
                                                if (!isNaN(str[currEnd])) {
                                                    currStart = str[currEnd - 1] === '-' ? currEnd - 1 : currEnd;
                                                    foundType = 2; // Numeric, may be upgraded to float later
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    return Mgr.Bookmark(obj);
                }
            }
        },
        // A Statistics object for the manager to work with
        Statistics: function () {
            var a = "";

            return {

            }
        },
        fetchBookmarks: function () {
            // Stub code, will eventually get bookmarks from server call
            Mgr.addChapter({
                src: 'http://upload.wikimedia.org/wikipedia/commons/7/75/Big_Buck_Bunny_Trailer_400p.ogg',
                title: 'Big Buck Bunny',
                description: 'An animated video',
                startTime: 5,
                endTime: 14
            });

            Mgr.addChapter({
                src: 'http://www.archive.org/download/deadmandirewolffanclub/DireWolfFanClub.ogv',
                title: 'Dire Wolf Fan Club',
                description: 'An unusual video',
                startTime: 10,
                endTime: 29
            });

            Mgr.addChapter({
                src: 'http://jbuckley.ca/~hoops/elephant.ogv',
                title: 'Elephants Dream',
                description: 'Elephants',
                startTime: 145,
                endTime: 200
            });

            Mgr.addChapter({
                src: 'http://www.archive.org/download/Kinetic_Art_Demo_Video/nym.ogv',
                title: 'Kinetic Art',
                description: 'Domino fun',
                startTime: 60,
                endTime: 66
            });

            Mgr.addChapter({
                src: 'http://ftp.gnu.org/video/Stephen_Fry-Happy_Birthday_GNU-hq_600px_780kbit.ogv',
                title: 'Freedom Fry',
                description: 'Happy B-Day',
                startTime: 1,
                endTime: 60
            });
        },
        // (Re-)initialize all values except internal element pointers
        init: function (vidId, tocId, updateEvent, canPlayEvent, ip) {
            _chapters = [];
            _hasMadeToc = false;
            _hasTocChanged = true; // In event TOC has been output before calling init, this will redraw table
            _curr = -1;

            this.setVideoId(vidId, updateEvent, canPlayEvent);
            this.setTOCId(tocId);
            Mgr.fetchBookmarks();
            //Mgr.trackStatistics();
        },
        // Add a chapter
        addChapter: function (_c) {
            _chapters.push(Mgr.Bookmark(_c));
            _hasTocChanged = true;
        },
        // Add a chapter
        removeChapter: function (_idx) {
            _chapters.splice(_idx, 1);
            _hasTocChanged = true;
        },

        // Set the table of contents (<table>) and player (<video>) elements based on id
        // Only set them if the currently stored element is null or has a differing id
        setTOCId: function (_id) {
            if (_id && (!this._toc || this._toc.id !== _id)) { // Valid id given and No id supplied yet or different id supplied
                this._toc = document.getElementById(_id);
                _hasTocChanged = true;
            }
        },

        setVideoId: function (_id) {
            if (canVideo) {
                if (_id && (!this._vid || this._vid.id !== _id)) { // valid id given and No id supplied yet or different id supplied
                    // Store locally for easy reference for event setup
                    this._vid = document.getElementById(_id);
                }
            }
        },

        // output the TOC
        printTOC: function () {
            if (canVideo) {
                if (this._toc) {
                    var tr = 0;
                    var srcElem = 0;
                    var th = 0;
                    if (!_hasMadeToc) {
                        tr = this._toc.insertRow(0);

                        // DOM approach for tables (IE doesn't like tr.innerHTML)
                        th = document.createElement('th');
                        th.innerHTML = "Chapter Title";
                        tr.appendChild(th);

                        th = document.createElement('th');
                        th.innerHTML = "Description";
                        tr.appendChild(th);

                        th = document.createElement('th');
                        th.innerHTML = "Start Time";
                        tr.appendChild(th);

                        th = document.createElement('th');
                        th.innerHTML = "End Time";
                        tr.appendChild(th);

                        th = document.createElement('th');
                        th.innerHTML = 'Delete';
                        tr.appendChild(th);

                        _hasMadeToc = true;
                    }

                    // Delete existing rows
                    for (var i = this._toc.rows.length - 1; i > 0; i--)
                    this._toc.deleteRow(i);

                    if (_hasTocChanged) {
                        for (var i = _chapters.length - 1; i >= 0; i--) {
                            tr = this._toc.insertRow(1);
                            srcElem = document.createElement('a');
                            var item = _chapters[i];

                            srcElem.href = 'javascript:Mgr.playChapter(' + i + ');';
                            srcElem.innerHTML = item.getTitle();
                            tr.insertCell(0).appendChild(srcElem);
                            tr.insertCell(1).appendChild(document.createTextNode(item.getDescription()));
                            tr.insertCell(2).appendChild(document.createTextNode(item.getStartTime()));
                            tr.insertCell(3).appendChild(document.createTextNode(item.getEndTime()));
                            tr.insertCell(4).innerHTML = '<input type="checkbox" onclick="Mgr.removeChapter(' + i + '); Mgr.printTOC();" />';
                        }

                        tr = this._toc.insertRow(1);
                        tr.colspan = 4;

                        srcElem = document.createElement('a');
                        srcElem.href = 'javascript:Mgr.playChapter(0, 1);';
                        srcElem.innerHTML = 'Play All';
                        tr.insertCell(0).appendChild(srcElem);

                        _hasTocChanged = false;
                    }
                }
            }
        },

        playChapter: function (idx, sequential) {
            if (canVideo) {
                if (idx !== _curr && idx >= 0 && idx < _chapters.length) {
                    var vid = this._vid;

                    _curr = idx;
                    currChap = _chapters[_curr];

                    vid.addEventListener('loadedmetadata', function () {
                        vid.currentTime = currChap.getStartTime();
                    }, true);

                    vid.addEventListener('canplay', function () {
                        vid.play();
                    }, true);

                    vid.addEventListener('timeupdate', function () {
                        if (vid.currentTime >= currChap.getEndTime()) {
                            if (sequential) {
                                Mgr.playChapter(idx + 1, sequential);
                            }
                            else {
                                vid.pause();
                            }
                        }
                    }, true);

                    vid.src = currChap.getSrc();
                    vid.load();
                    vid.play();
                }
            }
        },

        trackStatistics: function (ip) {
            var stats = {
                ip: 0,
                onLoad: false,
                _25: false,
                _50: false,
                _75: false,
                _90: false,
                _100: false,
                cc_on: false,
                cc_off: false,
                ad_on: false,
                ad_off: false
            };
            var vid = this._vid;
            var duration = vid.duration;

            stats.ip = ip;

            var durationListener = function () {
                if (parseInt(vid.currentTime, 10) === parseInt(duration * 0.25, 10)) {
                    vid.removeEventListener('timeupdate', durationListener, false);
                    stats._25 = true;
                }
                else if (parseInt(vid.currentTime, 10) === parseInt(duration * 0.50, 10)) {
                    vid.removeEventListener('timeupdate', durationListener, false);
                    stats._50 = true;
                }
                else if (parseInt(vid.currentTime, 10) === parseInt(duration * 0.75, 10)) {
                    vid.removeEventListener('timeupdate', durationListener, false);
                    stats._75 = true;
                }
                else if (parseInt(vid.currentTime, 10) === parseInt(duration * 0.90, 10)) {
                    vid.removeEventListener('timeupdate', durationListener, false);
                    stats._90 = true;
                }
                vid.addEventListener('timeupdate', durationListener, false);
            }

            var endListener = function () {
                stats._100 = true;
                //Debugging purposes
                alert(stats._25 + ' ' + stats._50 + ' ' + stats._75 + ' ' + stats._90 + ' ' + stats._100);
            }

            vid.addEventListener('timeupdate', durationListener, false);
            vid.addEventListener('ended', endListener, false);
        },

        displayWatermark: function (src, opacity, alpha) {
            //Try and clean up code later :(
            var vid = this._vid;
            // Position of video player
            var videoTop = parseInt(vid.clientTop);
            var videoLeft = parseInt(vid.clientLeft);
            // Create div element
            var watermarkDiv = document.createElement('div');
            // Set div attributes
            watermarkDiv.setAttribute('id', 'watermark');
            watermarkDiv.className = 'watermark';
            watermarkDiv.style.position = 'absolute';
            watermarkDiv.style.left = videoLeft + 5 + 'px';
            watermarkDiv.style.top = videoTop + 5 + 'px';
            // Width and height will be hard-coded for now, will re-factor later
            watermarkDiv.style.width = 150 + 'px';
            watermarkDiv.style.height = 70 + 'px';
            // If image source is not specificed, default image will be used
            if (!src) {
                watermarkDiv.style.backgroundImage = 'url("watermark.png")';
            }
            else {
                watermarkDiv.style.backgroundImage = 'url("' + src + '")';
            }
            watermarkDiv.style.backgroundRepeat = "no-repeat";
            // Arbitrary zIndex value to ensure watermark is above video player
            watermarkDiv.style.zIndex = 100;
            watermarkDiv.style.opacity = 0.4;
            var alpha = 40;
            watermarkDiv.style.filter = "alpha(opacity=" + alpha + ")";
            document.body.appendChild(watermarkDiv);
        }
    };
})();<|endoftext|>


<commit_before>import Dialog from '../libs/dialog';

$(function() {
    'use strict';

    $.uploader = function(options) {
        let defaults = {
            input: 'photo',
            changeButton: $('#btn-change-photo'),
            deleteButton: $('#btn-delete-photo'),
            onChanged: function(data) {},
            onDeleted: function() {}
        };

        let setup = $.extend(defaults, options);

        let form = $('<form />', {method: 'post', 'action': setup.changeButton.attr('href')});
        let input = $('<input />', {type: 'file', id: 'input-file', name: setup.input, style: 'visibility: hidden; height: 0'}).appendTo(form);

        form.appendTo('body');

        input.change(function() {
            let formData = new FormData(form[0]);

            $.ajax({
                url: form.attr('action'),
                type: 'POST',
                data: formData,
                cache: false,
                contentType: false,
                processData: false,
                beforeSend: function () {
                    setup.changeButton.attr('disabled', 'disabled');
                },
                success: function (data) {
                    $('.img-container > img').attr('src', data.url);

                    $('.img-container').show();
                    $('.img-placeholder').hide();

                    setup.onChanged(data);
                },
                complete: function() {
                    setup.changeButton.removeAttr('disabled');
                },
                error: function (err) {
                    let keys = Object.keys(err.responseJSON);

                    Dialog.alert({message: err.responseJSON[keys[0]][0]}).show();
                }
            }, 'json');
        });

        setup.changeButton.on('click', function() {
            input.click();

            return false;
        });

        setup.deleteButton.on('click', function() {
            let dialog = Dialog.confirm({
                message: 'Czy na pewno usunąć?',
                buttons: [{
                    label: 'Anuluj',
                    attr: {
                        'class': 'btn btn-default',
                        'type': 'button',
                        'data-dismiss': 'modal'
                    }
                },
                {
                    label: 'Tak, usuń',
                    attr: {
                        'class': 'btn btn-danger',
                        'type': 'submit',
                        'data-submit-state': 'Usuwanie...'
                    },
                    onClick: () => {
                        if (typeof $(this).attr('href') != 'undefined') {
                            $.post($(this).attr('href'));
                        }

                        $('.img-container').hide();
                        $('.img-placeholder').show();

                        setup.onChanged({url: $('.img-placeholder > img').attr('src')});
                        setup.onDeleted();

                        dialog.close();
                    }
                }]
            });

            dialog.show();

            return false;
        });
    };
});
<commit_msg>poprawione wyswietlanie komunikatu bledu walidacji<commit_after>import Dialog from '../libs/dialog';

$(function() {
    'use strict';

    $.uploader = function(options) {
        let defaults = {
            input: 'photo',
            changeButton: $('#btn-change-photo'),
            deleteButton: $('#btn-delete-photo'),
            onChanged: function(data) {},
            onDeleted: function() {}
        };

        let setup = $.extend(defaults, options);

        let form = $('<form />', {method: 'post', 'action': setup.changeButton.attr('href')});
        let input = $('<input />', {type: 'file', id: 'input-file', name: setup.input, style: 'visibility: hidden; height: 0'}).appendTo(form);

        form.appendTo('body');

        input.change(function() {
            let formData = new FormData(form[0]);

            $.ajax({
                url: form.attr('action'),
                type: 'POST',
                data: formData,
                cache: false,
                contentType: false,
                processData: false,
                beforeSend: function () {
                    setup.changeButton.attr('disabled', 'disabled');
                },
                success: function (data) {
                    $('.img-container > img').attr('src', data.url);

                    $('.img-container').show();
                    $('.img-placeholder').hide();

                    setup.onChanged(data);
                },
                complete: function() {
                    setup.changeButton.removeAttr('disabled');
                },
                error: function (err) {
                    let errors = err.responseJSON.errors;
                    let error = errors[Object.keys(errors)[0]][0];

                    Dialog.alert({message: error}).show();
                }
            }, 'json');
        });

        setup.changeButton.on('click', function() {
            input.click();

            return false;
        });

        setup.deleteButton.on('click', function() {
            let dialog = Dialog.confirm({
                message: 'Czy na pewno usunąć?',
                buttons: [{
                    label: 'Anuluj',
                    attr: {
                        'class': 'btn btn-default',
                        'type': 'button',
                        'data-dismiss': 'modal'
                    }
                },
                {
                    label: 'Tak, usuń',
                    attr: {
                        'class': 'btn btn-danger',
                        'type': 'submit',
                        'data-submit-state': 'Usuwanie...'
                    },
                    onClick: () => {
                        if (typeof $(this).attr('href') != 'undefined') {
                            $.post($(this).attr('href'));
                        }

                        $('.img-container').hide();
                        $('.img-placeholder').show();

                        setup.onChanged({url: $('.img-placeholder > img').attr('src')});
                        setup.onDeleted();

                        dialog.close();
                    }
                }]
            });

            dialog.show();

            return false;
        });
    };
});
<|endoftext|>


<commit_before>var meetingtools = {};

(function(ns){
	function shuffle(o) {
		for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
		return o;
	};

	ns.createDailyMeeting = function (members, initialDuration){
		var members = members;
		var initialDuration = initialDuration;
		var orderedMembers;

		return {
			startMeeting: function(){
				//console.log(Math.floor((new Date).getTime()/1000));

				orderedMembers = shuffle(members);
				console.log(orderedMembers);
			},
			interventionOrder: function(){
				return orderedMembers;
			},
			remainingTime: function(){
				return initialDuration;
			},
		}
	};

}(meetingtools));

<commit_msg>Refactor<commit_after>var meetingtools = {};

(function(ns){
	function shuffle(o) {
		for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
		return o;
	};

	ns.createDailyMeeting = function (members, initialDuration){
		var members = members;
		var initialDuration = initialDuration;
		var orderedMembers;

		return {
			startMeeting: function(){
				//console.log(Math.floor((new Date).getTime()/1000));
				orderedMembers = shuffle(members);
			},
			interventionOrder: function(){
				return orderedMembers;
			},
			remainingTime: function(){
				return initialDuration;
			},
		}
	};

}(meetingtools));

<|endoftext|>


<commit_before>import { combineReducers } from 'redux';

import addonsReducer from './addons';
import projectReducer from './project';
import filesReducer from './files';

export default combineReducers({
    project: projectReducer,
    integrations: integrationsReducer,
    files: filesReducer
});<commit_msg>update reducers to match change in name<commit_after>import { combineReducers } from 'redux';

import addonsReducer from './addons';
import projectReducer from './project';
import filesReducer from './files';

export default combineReducers({
    project: projectReducer,
    addons: addonsReducer,
    files: filesReducer
});<|endoftext|>


<commit_before>var GitHubApi = require("github");
var async = require("async");

var github = new GitHubApi({
  version: "3.0.0",
  protocol: "https"
});

if (process.argv.length < 4) {
  console.log('Usage: headhunter.js <GitHub API token> <location>');
  process.exit(1);
}

github.authenticate({
  type: "token",
  token: process.argv[2]
});

var users = [];
var wantUsers = -1;
var pageNumber = 0;

var location = process.argv[3];

async.series([
  function(nextStep) {
    async.whilst(
      function() { return ((wantUsers < 0)||(users.length < wantUsers)); },
      function(nextPage) {
        github.search.users({
          q: 'location:"' + location + '"',
          page: pageNumber,
          per_page: 100
        },function(err,result) {
          if (err)
            return nextStep(err);
          if (result.items)
            users = users.concat(result.items);
          if ((wantUsers < 0)&&(result.total_count))
            wantUsers = result.total_count;
          //console.log('got page '+pageNumber);
          pageNumber += 1;
          return nextPage(null);
        });
      },
      nextStep
    );
  },
  function(nextStep) {
    async.eachSeries(users,function(user,nextUser) {
      github.repos.getFromUser({
        user: user.login,
        sort: 'updated',
        direction: 'desc',
        page: 0,
        per_page: 100
      },function(err,result) {
        if (result) {
          for(var i=0;i<result.length;++i) {
            if ((!result[i].fork)&&(result[i].full_name)) {
              console.log("git clone '"+result[i].full_name+"' './heads/"+location+"/"+result[i].full_name+"'");
              console.log("sleep 30");
            }
          }
        }
        return nextUser(null);
      });
    },nextStep);
  }
],function(err) {
  if(err)
    console.log(err);
  process.exit(0);
});
<commit_msg>Fix GitHub command to have full path.<commit_after>var GitHubApi = require("github");
var async = require("async");

var github = new GitHubApi({
  version: "3.0.0",
  protocol: "https"
});

if (process.argv.length < 4) {
  console.log('Usage: headhunter.js <GitHub API token> <location>');
  process.exit(1);
}

github.authenticate({
  type: "token",
  token: process.argv[2]
});

var users = [];
var wantUsers = -1;
var pageNumber = 0;

var location = process.argv[3];

async.series([
  function(nextStep) {
    async.whilst(
      function() { return ((wantUsers < 0)||(users.length < wantUsers)); },
      function(nextPage) {
        github.search.users({
          q: 'location:"' + location + '"',
          page: pageNumber,
          per_page: 100
        },function(err,result) {
          if (err)
            return nextStep(err);
          if (result.items)
            users = users.concat(result.items);
          if ((wantUsers < 0)&&(result.total_count))
            wantUsers = result.total_count;
          //console.log('got page '+pageNumber);
          pageNumber += 1;
          return nextPage(null);
        });
      },
      nextStep
    );
  },
  function(nextStep) {
    async.eachSeries(users,function(user,nextUser) {
      github.repos.getFromUser({
        user: user.login,
        sort: 'updated',
        direction: 'desc',
        page: 0,
        per_page: 100
      },function(err,result) {
        if (result) {
          for(var i=0;i<result.length;++i) {
            if ((!result[i].fork)&&(result[i].full_name)) {
              console.log("git clone 'https://github.com/"+result[i].full_name+"' './heads/"+location+"/"+result[i].full_name+"'");
              console.log("sleep 30");
            }
          }
        }
        return nextUser(null);
      });
    },nextStep);
  }
],function(err) {
  if(err)
    console.log(err);
  process.exit(0);
});
<|endoftext|>


<commit_before>module.exports = {
  'sciebpc-empire': {
    lang: 'zh/en',
    desc: '这是一个关于微信的调查。所有收集的数据仅做研究用途。数据为匿名收集并且无个人信息。感谢您抽出宝贵时间参与。 / This survey is about WeChat. All data is collected for research usage. No personal detail will be collected, and all response is anonymous. Thank you for helping us.',
    q: [
      {
        question: '请选择您的年龄段… / What is your age group?',
        answer: [
          '≤19', '20-34', '35-49', '50-64', '≥65'
        ],
        mode: 'single'
      },
      {
        question: '您使用微信吗？多久使用一次？ / Do you use WeChat? How often do you check it?',
        answer: [
          '一天使用多次 / Many times every day',
          '一天偶尔使用 / One or few times every day',
          '一周偶尔使用 / Few times a week',
          '从不使用 / Never'
        ],
        mode: 'single'
      },
      {
        question: '您的国籍？ / What is your nationality?',
        mode: 'input',
        placeholder: 'CN'
      },
      {
        question: '您主要用微信做什么？ / What do you mostly do using WeChat?',
        answer: [
          '聊天 / Chat with friends',
          '看朋友圈 / See how others are doing on Moment',
          '使用微信支付 / Pay expenses with WeChat Pay',
          '使用微信游戏 / Share gaming achievements with WeChat Game',
          '看公众号 / Get information from official accounts',
          '消磨时间 / Kill time',
          '使用微信运动 / WeRun motivates me to walk/exercise more'
        ],
        mode: 'select-orother'
      },
      {
        question: '您认为微信支付会取代现金支付吗？ / Do you think WeChat Pay will replace cash payment?',
        answer: ['会 / Yes for sure', '可能 / Maybe', '不会 / No'],
        mode: 'single'
      },
      {
        question: '您最常使用哪一种社交软件？ / What social network do you use the most?',
        answer: [
          '微信 / WeChat',
          'QQ',
          'Facebook',
          '微博 / Weibo'
        ],
        mode: 'single-orother'
      },
      {
        question: '在1-5的程度中，您在日常生活中对微信的依赖有多少？ / On a scale of 1-5, how much do you depend on WeChat in your everyday life?',
        answer: [
          '1 (一点也不依赖 / Not at all)', '2', '3', '4', "5 (无法离开微信 / Can't live without)"
        ],
        mode: 'single',
        singleLine: true
      },
      {
        question: '在1-5的程度中，您目前对微信的满意度是多少？ / On a scale of 1-5, rate your satisfaction with WeChat currently.',
        answer: [
          '1 (完全不满意 / Not satisfied at all)', '2', '3', '4', '5 (非常满意 / Deeply impressed)'
        ],
        mode: 'single',
        singleLine: true
      },
      {
        question: '您觉得微信在十年之后还能像今天一样受欢迎吗？ / Do you think WeChat will remain its current popularity after 10 years from now?',
        mode: 'open',
        placeholder: '必填，请简单解释原因 / Required, please briefly explain why.'
      }
    ]
  },
  'schsrch-mr': {
    lang: 'zh',
    title: 'Schsrch小调查【假装不是Market research',
    descHtml: '
如果你从未使用过schsrch.xyz，请忽略此调查！【谢谢你关注我

准备抽时间写一些比较大的新功能！但是这挺费时间的，所以我想避免出现设计上的问题。在这之前我希望能了解你刷paper的习惯=.=
请亲抽出几分钟完成这个小调查…谢谢！\u{1F60A}【遗憾的是新功能考试前可能出不来，因为我非常需要复习。
',
    q: [
      {
        mode: 'select-orother',
        question: '你经常在哪些设备上使用Schsrch？',
        answer: [
          '手机，iOS',
          '手机，国内Android + 国内浏览器',
          '手机，Android + Chrome',
          '手机，Android + 其他浏览器',
          '学校电脑',
          '电脑，Chrome / Firefox （学校电脑除外）',
          '电脑，Windows + IE / Edge',
          '电脑，Windows + 其他浏览器',
          '电脑，Mac OS + Safari',
          '电脑，Mac OS + 其他浏览器'
        ]
      },
      {
        mode: 'select-orother',
        question: '在Schsrch上看paper 大多数时候你会直接在网页上看（在点开结果后出现的那个里直接看）还是把整个pdf下载下来或者浏览器打开pdf（点那个下载按钮）再看？为什么？',
        answer: [
          '在网页上看，因为打开就是这样，并且也没什么不好用的',
          '在网页上看，因为跳转问题及Mark scheme方便',
          '在网页上看，因为切换到其他paper方便',
          '在网页上看，因为手机上不想下载pdf（内存不够/省流量）',
          '在网页上看，因为PDF下载很慢',
          '下载PDF，因为网页上加载很慢',
          '下载PDF，因为网页上翻页不方便（不考虑加载慢）',
          '下载PDF，因为网页上不能放大缩小（Mac好像有这个问题）',
          '下载PDF，因为网页上很卡（放大什么的时候有些浏览器可能会特别卡）',
          '下载PDF，因为很多时候我要一次看很多页',
          '下载PDF，因为网页上不能复制',
          '下载PDF，因为网页上显示不了（比如学校电脑上）',
          '两个都很慢\u{1F641}'
        ]
      },
      {
        mode: 'single',
        question: '最近一段时间，你觉得在网页上看时打开paper的速度…',
        answer: [
          '很快',
          '一般',
          '太慢了，无法忍受',
          '有时候很快，但是有时候很慢'
        ]
      },
      {
        mode: 'single',
        question: '你觉得下载PDF的速度…',
        answer: [
          '很快',
          '一般',
          '太慢了，无法忍受',
          '有时候很快，但是有时候特别慢'
        ]
      },
      {
        mode: 'single',
        question: '最近一段时间，你觉得全文搜索的速度…',
        answer: [
          '很快',
          '一般',
          '很慢，以至于我会尽量避免搜索',
          '有时候很快，但是有时候很慢'
        ]
      },
      {
        mode: 'single',
        question: '你的学校 / 工作单位是NCIC的吗？',
        answer: [
          '是',
          '不是',
          '不告诉你'
        ]
      },
      {
        mode: 'single',
        question: '你在NCIC的Wifi下使用Schsrch多吗？',
        answer: [
          '不是NCIC的 / 不告诉你',
          '我不用学校Wifi',
          '基本上都是在学校用的',
          '大部分时间是在学校用',
          '一半一半',
          '很少在学校用'
        ]
      },
      {
        mode: 'single',
        question: '最近一段时间，你觉得按题目全文搜索的精确度…',
        answer: [
          '很满意：每次都能在前几个找到我要的',
          '还可以：大部分时候都能找到我要找的',
          '有待提高：想要的paper经常被排在很后面',
          '有待提高：经常根本找不到'
        ]
      },
      {
        mode: 'open',
        optional: true,
        question: '（可选）列举一些不知道为什么搜不到但是明明在past paper里有的题目？（附上出现在哪个paper里）',
        placeholder: 'What did Clemenceau want to achieve from the peace settlement of 1919-20? / 0470 s07 paper 1'
      },
      {
        mode: 'single-orother',
        question: '如果你可以把一个科目所有的paper都缓存下来离线看，并且就算在线加载也会更快，但是这会用掉平均700M/科的存储，你会使用这个功能吗？',
        answer: [
          '会，这样很好',
          '不会，没那么多存储',
          '电脑上会，手机没那么多存储',
          '不会，我很少没网，而且感觉现在还挺快的'
        ]
      },
      {
        mode: 'single',
        question: '如果速度都一样，你更喜欢真正的App还是网页（Web App）？（网页也可以离线用的）',
        answer: [
          '网页',
          'App',
          '都OK'
        ]
      },
      {
        mode: 'select-orother',
        question: '你对Schsrch界面的满意度如何？',
        answer: [
          '好：简洁清晰',
          '好：配色不辣眼镜',
          '好：总体好看',
          '不好：不清晰，功能复杂 / 模糊，难以理解',
          '不好：配色风格奇怪',
          '不好：总体不好看'
        ]
      },
      {
        mode: 'select-orother',
        question: '你对Schsrch的总体满意度如何？',
        answer: [
          '没什么不满意的',
          '比其他的Past paper网站要好',
          '有些问题，但是总体还不错',
          '问题很多，有待改进',
          '不够稳定，经常用不了 / 出问题',
          '还没有其他的Past paper网站好'
        ]
      },
      {
        mode: 'single-orother',
        question: '你会把Schsrch推荐给别的需要找Past paper的人吗？',
        answer: [
          '肯定会',
          '也许会',
          '不会，因为Schsrch不够好',
          '不会，因为我不给别人推荐网站'
        ]
      },
      {
        mode: 'single-orother',
        question: '下列哪个选项最贴近你的身份？',
        answer: [
          '不告诉你',
          'IGCSE学生',
          'AS / A Level学生',
          'A Level 毕业学生',
          '老师'
        ]
      },
      {
        mode: 'open',
        optional: true,
        question: '（可选）这个网站可能会面临经济问题（i.e. 我没钱，服务器贵）。你有什么好的想法能帮我解决这个问题，或者有什么建议？',
        placeholder: '募捐、广告等，NCIC的人请尽量考虑我目前的实际情况，谢谢您的宝贵意见！'
      },
      {
        mode: 'open',
        optional: true,
        question: '（可选）有什么关于这个网站的其他意见（功能或者界面之类的）？'
      },
      {
        mode: 'select',
        question: '你知道我多少？',
        answer: [
          '不告诉你',
          '你是NCIC的',
          '你目前是IG1的',
          '你目前是IG2的',
          '你是3班的',
          '你是3班的Tim',
          '你是3班的Lynn',
          '并不知道'
        ]
      },
      {
        mode: 'input',
        question: '可选联系方式',
        optional: true,
        placeholder: 'm@maowtm.org'
      }
    ]
  },
  '__unit_test': {
    lang: 'en',
    desc: 'This survey is for testing porpuse. Ignore it.',
    q: [
      {
        question: 'single',
        mode: 'single',
        answer: ['H', 'E', 'L', 'l', 'O']
      },
      {
        question: 'select',
        mode: 'select',
        answer: ['H', 'E', 'L', 'l', 'O']
      },
      {
        question: 'single-orother',
        mode: 'single-orother',
        answer: ['H', 'E', 'L', 'l', 'O']
      },
      {
        question: 'select-orother',
        mode: 'select-orother',
        answer: ['H', 'E', 'L', 'l', 'O']
      },
      {
        question: 'input',
        mode: 'input',
        placeholder: 'ph'
      },
      {
        question: 'open',
        mode: 'open',
        placeholder: 'ph'
      }
    ]
  },
  'jose-proxy-purchasing': {
    lang: 'zh/en',
    title: '小调查 / Survey',
    desc: '小调查 / Survey',
    q: [
      {
        question: '你网上购物的频率是？ / How often do you buy items on the Internet?',
        mode: 'single',
        answer: ['一周一次 / Once per week', '几周一次 / Once per several week', '一年一次 / Once per year', '几乎不 / Hardly']
      },
      {
        question: '你的年龄段？ / What is your age group?',
        answer: [
          '≤15', '16-24', '25-34', '35-49', '50-64', '≥65'
        ],
        mode: 'single'
      },
      {
        mode: 'input',
        question: '你住在哪？ / Where are you living?',
        placeholder: '中国大陆 / Mainland China'
      },
      {
        mode: 'open',
        question: '你一般买什么东西？ / What kind of item?'
      },
      {
        mode: 'single-orother',
        question: '一般买哪的东西？ / Where are they from?',
        answer: ['国内 / China (including HK TW & MA)', '日本 / Japan', '欧洲 / Europe', '美国 / US']
      },
      {
        mode: 'single',
        question: '交税吗？ / Do you pay taxes on them?',
        answer: ['我交 / I explicitly pay taxes', '商家交 / Seller pays taxes', '都不交 / No one pays taxes']
      },
      {
        mode: 'single-orother',
        question: '你帮别人代购过吗？ / Had you previously purchased oversea items on behalf of others?',
        answer: [
          "没有，也并不想专门帮 / No, and I don't want to do this often.",
          '没有，但是可以考虑通过这个赚些钱 / Not yet, but I do want to do it for profit.',
          '有，但没有想赚钱 / Yes, but not for profit.',
          '很多次了，且也赚过一点钱 / Many times, and I did earned some money from it.',
          '我专门做代购 / I do it regularly (and professionally)'
        ]
      },
      {
        mode: 'single',
        question: '你出国或者回国的时候会带很多东西吗？ / When you go to a foreign country, do you bring a lot of items?',
        answer: ['会 / Yes', '没 / Not much']
      },
      {
        mode: 'single',
        question: '你出国旅游的频率？ / How often do you travel overseas?',
        answer: ['几乎不 / hardly', '一年一到两次 / Once or twice per year', '一个月一次 / One per month']
      }
    ]
  }
}
<commit_msg>Survey thing.<commit_after>module.exports = {
  'sciebpc-empire': {
    lang: 'zh/en',
    desc: '这是一个关于微信的调查。所有收集的数据仅做研究用途。数据为匿名收集并且无个人信息。感谢您抽出宝贵时间参与。 / This survey is about WeChat. All data is collected for research usage. No personal detail will be collected, and all response is anonymous. Thank you for helping us.',
    q: [
      {
        question: '请选择您的年龄段… / What is your age group?',
        answer: [
          '≤19', '20-34', '35-49', '50-64', '≥65'
        ],
        mode: 'single'
      },
      {
        question: '您使用微信吗？多久使用一次？ / Do you use WeChat? How often do you check it?',
        answer: [
          '一天使用多次 / Many times every day',
          '一天偶尔使用 / One or few times every day',
          '一周偶尔使用 / Few times a week',
          '从不使用 / Never'
        ],
        mode: 'single'
      },
      {
        question: '您的国籍？ / What is your nationality?',
        mode: 'input',
        placeholder: 'CN'
      },
      {
        question: '您主要用微信做什么？ / What do you mostly do using WeChat?',
        answer: [
          '聊天 / Chat with friends',
          '看朋友圈 / See how others are doing on Moment',
          '使用微信支付 / Pay expenses with WeChat Pay',
          '使用微信游戏 / Share gaming achievements with WeChat Game',
          '看公众号 / Get information from official accounts',
          '消磨时间 / Kill time',
          '使用微信运动 / WeRun motivates me to walk/exercise more'
        ],
        mode: 'select-orother'
      },
      {
        question: '您认为微信支付会取代现金支付吗？ / Do you think WeChat Pay will replace cash payment?',
        answer: ['会 / Yes for sure', '可能 / Maybe', '不会 / No'],
        mode: 'single'
      },
      {
        question: '您最常使用哪一种社交软件？ / What social network do you use the most?',
        answer: [
          '微信 / WeChat',
          'QQ',
          'Facebook',
          '微博 / Weibo'
        ],
        mode: 'single-orother'
      },
      {
        question: '在1-5的程度中，您在日常生活中对微信的依赖有多少？ / On a scale of 1-5, how much do you depend on WeChat in your everyday life?',
        answer: [
          '1 (一点也不依赖 / Not at all)', '2', '3', '4', "5 (无法离开微信 / Can't live without)"
        ],
        mode: 'single',
        singleLine: true
      },
      {
        question: '在1-5的程度中，您目前对微信的满意度是多少？ / On a scale of 1-5, rate your satisfaction with WeChat currently.',
        answer: [
          '1 (完全不满意 / Not satisfied at all)', '2', '3', '4', '5 (非常满意 / Deeply impressed)'
        ],
        mode: 'single',
        singleLine: true
      },
      {
        question: '您觉得微信在十年之后还能像今天一样受欢迎吗？ / Do you think WeChat will remain its current popularity after 10 years from now?',
        mode: 'open',
        placeholder: '必填，请简单解释原因 / Required, please briefly explain why.'
      }
    ]
  },
  'schsrch-mr': {
    lang: 'zh',
    title: 'Schsrch小调查【假装不是Market research',
    descHtml: '
如果你从未使用过schsrch.xyz，请忽略此调查！【谢谢你关注我

准备抽时间写一些比较大的新功能！但是这挺费时间的，所以我想避免出现设计上的问题。在这之前我希望能了解你刷paper的习惯=.=
请亲抽出几分钟完成这个小调查…谢谢！\u{1F60A}【遗憾的是新功能考试前可能出不来，因为我非常需要复习。
',
    q: [
      {
        mode: 'select-orother',
        question: '你经常在哪些设备上使用Schsrch？',
        answer: [
          '手机，iOS',
          '手机，国内Android + 国内浏览器',
          '手机，Android + Chrome',
          '手机，Android + 其他浏览器',
          '学校电脑',
          '电脑，Chrome / Firefox （学校电脑除外）',
          '电脑，Windows + IE / Edge',
          '电脑，Windows + 其他浏览器',
          '电脑，Mac OS + Safari',
          '电脑，Mac OS + 其他浏览器'
        ]
      },
      {
        mode: 'select-orother',
        question: '在Schsrch上看paper 大多数时候你会直接在网页上看（在点开结果后出现的那个里直接看）还是把整个pdf下载下来或者浏览器打开pdf（点那个下载按钮）再看？为什么？',
        answer: [
          '在网页上看，因为打开就是这样，并且也没什么不好用的',
          '在网页上看，因为跳转问题及Mark scheme方便',
          '在网页上看，因为切换到其他paper方便',
          '在网页上看，因为手机上不想下载pdf（内存不够/省流量）',
          '在网页上看，因为PDF下载很慢',
          '下载PDF，因为网页上加载很慢',
          '下载PDF，因为网页上翻页不方便（不考虑加载慢）',
          '下载PDF，因为网页上不能放大缩小（Mac好像有这个问题）',
          '下载PDF，因为网页上很卡（放大什么的时候有些浏览器可能会特别卡）',
          '下载PDF，因为很多时候我要一次看很多页',
          '下载PDF，因为网页上不能复制',
          '下载PDF，因为网页上显示不了（比如学校电脑上）',
          '两个都很慢\u{1F641}'
        ]
      },
      {
        mode: 'single',
        question: '最近一段时间，你觉得在网页上看时打开paper的速度…',
        answer: [
          '很快',
          '一般',
          '太慢了，无法忍受',
          '有时候很快，但是有时候很慢'
        ]
      },
      {
        mode: 'single',
        question: '你觉得下载PDF的速度…',
        answer: [
          '很快',
          '一般',
          '太慢了，无法忍受',
          '有时候很快，但是有时候特别慢'
        ]
      },
      {
        mode: 'single',
        question: '最近一段时间，你觉得全文搜索的速度…',
        answer: [
          '很快',
          '一般',
          '很慢，以至于我会尽量避免搜索',
          '有时候很快，但是有时候很慢'
        ]
      },
      {
        mode: 'single',
        question: '你的学校 / 工作单位是NCIC的吗？',
        answer: [
          '是',
          '不是',
          '不告诉你'
        ]
      },
      {
        mode: 'single',
        question: '你在NCIC的Wifi下使用Schsrch多吗？',
        answer: [
          '不是NCIC的 / 不告诉你',
          '我不用学校Wifi',
          '基本上都是在学校用的',
          '大部分时间是在学校用',
          '一半一半',
          '很少在学校用'
        ]
      },
      {
        mode: 'single',
        question: '最近一段时间，你觉得按题目全文搜索的精确度…',
        answer: [
          '很满意：每次都能在前几个找到我要的',
          '还可以：大部分时候都能找到我要找的',
          '有待提高：想要的paper经常被排在很后面',
          '有待提高：经常根本找不到'
        ]
      },
      {
        mode: 'open',
        optional: true,
        question: '（可选）列举一些不知道为什么搜不到但是明明在past paper里有的题目？（附上出现在哪个paper里）',
        placeholder: 'What did Clemenceau want to achieve from the peace settlement of 1919-20? / 0470 s07 paper 1'
      },
      {
        mode: 'single-orother',
        question: '如果你可以把一个科目所有的paper都缓存下来离线看，并且就算在线加载也会更快，但是这会用掉平均700M/科的存储，你会使用这个功能吗？',
        answer: [
          '会，这样很好',
          '不会，没那么多存储',
          '电脑上会，手机没那么多存储',
          '不会，我很少没网，而且感觉现在还挺快的'
        ]
      },
      {
        mode: 'single',
        question: '如果速度都一样，你更喜欢真正的App还是网页（Web App）？（网页也可以离线用的）',
        answer: [
          '网页',
          'App',
          '都OK'
        ]
      },
      {
        mode: 'select-orother',
        question: '你对Schsrch界面的满意度如何？',
        answer: [
          '好：简洁清晰',
          '好：配色不辣眼镜',
          '好：总体好看',
          '不好：不清晰，功能复杂 / 模糊，难以理解',
          '不好：配色风格奇怪',
          '不好：总体不好看'
        ]
      },
      {
        mode: 'select-orother',
        question: '你对Schsrch的总体满意度如何？',
        answer: [
          '没什么不满意的',
          '比其他的Past paper网站要好',
          '有些问题，但是总体还不错',
          '问题很多，有待改进',
          '不够稳定，经常用不了 / 出问题',
          '还没有其他的Past paper网站好'
        ]
      },
      {
        mode: 'single-orother',
        question: '你会把Schsrch推荐给别的需要找Past paper的人吗？',
        answer: [
          '肯定会',
          '也许会',
          '不会，因为Schsrch不够好',
          '不会，因为我不给别人推荐网站'
        ]
      },
      {
        mode: 'single-orother',
        question: '下列哪个选项最贴近你的身份？',
        answer: [
          '不告诉你',
          'IGCSE学生',
          'AS / A Level学生',
          'A Level 毕业学生',
          '老师'
        ]
      },
      {
        mode: 'open',
        optional: true,
        question: '（可选）这个网站可能会面临经济问题（i.e. 我没钱，服务器贵）。你有什么好的想法能帮我解决这个问题，或者有什么建议？',
        placeholder: '募捐、广告等，NCIC的人请尽量考虑我目前的实际情况，谢谢您的宝贵意见！'
      },
      {
        mode: 'open',
        optional: true,
        question: '（可选）有什么关于这个网站的其他意见（功能或者界面之类的）？'
      },
      {
        mode: 'select',
        question: '你知道我多少？',
        answer: [
          '不告诉你',
          '你是NCIC的',
          '你目前是IG1的',
          '你目前是IG2的',
          '你是3班的',
          '你是3班的Tim',
          '你是3班的Lynn',
          '并不知道'
        ]
      },
      {
        mode: 'input',
        question: '可选联系方式',
        optional: true,
        placeholder: 'm@maowtm.org'
      }
    ]
  },
  '__unit_test': {
    lang: 'en',
    desc: 'This survey is for testing porpuse. Ignore it.',
    q: [
      {
        question: 'single',
        mode: 'single',
        answer: ['H', 'E', 'L', 'l', 'O']
      },
      {
        question: 'select',
        mode: 'select',
        answer: ['H', 'E', 'L', 'l', 'O']
      },
      {
        question: 'single-orother',
        mode: 'single-orother',
        answer: ['H', 'E', 'L', 'l', 'O']
      },
      {
        question: 'select-orother',
        mode: 'select-orother',
        answer: ['H', 'E', 'L', 'l', 'O']
      },
      {
        question: 'input',
        mode: 'input',
        placeholder: 'ph'
      },
      {
        question: 'open',
        mode: 'open',
        placeholder: 'ph'
      }
    ]
  },
  'jose-proxy-purchasing': {
    lang: 'zh/en',
    title: '小调查 / Survey',
    desc: '小调查 / Survey',
    q: [
      {
        question: '你的年龄段？ / What is your age group?',
        answer: [
          '≤15', '16-24', '25-34', '35-49', '50-64', '≥65'
        ],
        mode: 'single'
      },
      {
        question: '你网上购物的频率是？ / How often do you buy items on the Internet?',
        mode: 'single',
        answer: ['一周一次 / Once per week', '几周一次 / Once per several week', '一年一次 / Once per year', '几乎不 / Hardly']
      },
      {
        mode: 'input',
        question: '你住在哪？ / Where are you living?',
        placeholder: '中国大陆 / Mainland China'
      },
      {
        mode: 'open',
        question: '你一般买什么东西？ / What kind of item?'
      },
      {
        mode: 'single-orother',
        question: '一般买哪的东西？ / Where are they from?',
        answer: ['国内 / China (including HK TW & MA)', '日本 / Japan', '欧洲 / Europe', '美国 / US']
      },
      {
        mode: 'single',
        question: '交税吗？ / Do you pay taxes on them?',
        answer: ['我交 / I explicitly pay taxes', '商家交 / Seller pays taxes', '都不交 / No one pays taxes']
      },
      {
        mode: 'single-orother',
        question: '你帮别人代购过吗？ / Had you previously purchased oversea items on behalf of others?',
        answer: [
          "没有，也并不想专门帮 / No, and I don't want to do this often.",
          '没有，但是可以考虑通过这个赚些钱 / Not yet, but I do want to do it for profit.',
          '有，但没有想赚钱 / Yes, but not for profit.',
          '很多次了，且也赚过一点钱 / Many times, and I did earned some money from it.',
          '我专门做代购 / I do it regularly (and professionally)'
        ]
      },
      {
        mode: 'single',
        question: '你出国或者回国的时候会带很多东西吗？ / When you go to a foreign country, do you bring a lot of items?',
        answer: ['会 / Yes', '没 / Not much']
      },
      {
        mode: 'single',
        question: '你出国旅游的频率？ / How often do you travel overseas?',
        answer: ['几乎不 / hardly', '一年一到两次 / Once or twice per year', '一个月一次 / One per month']
      }
    ]
  }
}
<|endoftext|>


<commit_before>/*
 * 	BBB v0.1
 * 		By Steven Weerdenburg and Kevin Lasconia
 * 		Last Modification: 11/08/2010
 */
var Mgr = (function(){
    var _chapters = []; // Array of Chapters/Bookmarks
    var _vid = 0, _toc = 0; // id to store the table of contents and video player
    var _hasMadeToc = false;
    var _hasTocChanged = false;

    var _curr = -1;
    var currChap = 0;
    var _playSeq = 0;

    var canVideo = !!document.createElement('video').play;

    return {
        // A Bookmark object for the manager to work with
        Bookmark: function(params) {
            var title = "";
            var description = "";
            var src = "";
            var startTime = 0;
            var endTime = 0;

            if (params) {
                title = params["title"];
                description = params["description"];
                src = params["src"];
                startTime = parseInt(params["startTime"]);
                endTime = parseInt(params["endTime"]);

                if (startTime < 0 || endTime < 0)
                    throw "Start and end times must be positive!";
                else if (startTime < endTime) {
                    startTime = startTime;
                    endTime = endTime;
                } else {
                    endTime = startTime;
                    startTime = endTime;
                }
            }

            return {
                getTitle: function() { return title; },
                getDescription: function() { return description; },
                getSrc: function() { return src; },
                getStartTime: function() { return startTime; },
                getEndTime: function() { return endTime; },
                toString: function(){
                    return "Source: " + src + "\nTitle: " + title + "\nDescription: " + description + "\nStart Time: " + startTime + "\nEnd Time: " + endTime;
                },
                toJSON: function(){
                    return '{ "src": "' + src + '", "title": "' + title + '", "description": "' + description + '", "startTime": ' + startTime + ', "endTime": ' + endTime + ' }';
                },
                equals: function(bkmrk) {
                    return src === bkmrk.getSrc() && title === bkmrk.getTitle() && description === bkmrk.getDescription() &&
                        startTime === bkmrk.getStartTime() && endTime === bkmrk.getEndTime();
                },
                fromJSON: function(str){
                    //var obj = jsonParse(str);

                    var currStart = -1;
                    var currEnd = 0;
                    var obj = {};

                    while ((currStart = str.indexOf('"', currEnd + 1)) !== -1 && (currEnd = str.indexOf('"', currStart + 1)) !== -1) {
                        // Has found another attribute

                        var attrName = str.substring(currStart + 1, currEnd);
                        var foundAttr = false;
                        var foundSemi = false;
                        var foundType = 0; // 0 = none, 1 = string, 2 = numeric, 3 = float
                        var currItem;

                        // Process value, eagerly assume comma follows when value found
                        while ((currItem = str[++currEnd]) !== '"' || !foundAttr) {
                            if (str[currEnd] === ':') {
                                foundSemi = true;
                            } else {
                                if (str[currEnd] === '"') { // Check for strings
                                    if (foundSemi && str[currEnd - 1] !== '\\') {
                                        if (!foundType) {
                                            foundType = 1;
                                            currStart = currEnd;
                                        } else {
                                            obj[attrName] = str.substring(currStart + 1, currEnd);
                                            foundAttr = true;
                                            break; // Go into outer loop to find next attribute
                                        }
                                    }
                                } else {
                                    if (str[currEnd] === '.') { // Check for decimal for numeric->float data
                                        if (foundType === 2)
                                            foundType = 3;
                                    } else {
                                        if (str[currEnd] === ' ') {
                                            if (foundType === 2 || foundType === 3) { // Check for end of numeric data
                                                if (foundType === 2) // Integer
                                                    obj[attrName] = parseInt(str.substring(currStart, currEnd));
                                                else
                                                    if (foundType === 3) // Float
                                                        obj[attrName] = parseFloat(str.substring(currStart, currEnd));

                                                foundAttr = true;
                                                break;
                                            }
                                        } else {
                                            if (!foundType) {
                                                if (!isNaN(str[currEnd])) {
                                                    currStart = str[currEnd - 1] === '-' ? currEnd - 1 : currEnd;
                                                    foundType = 2; // Numeric, may be upgraded to float later
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    return Mgr.Bookmark(obj);
                }
            }
        },
        fetchBookmarks: function() {
            // Stub code, will eventually get bookmarks from server call

            Mgr.addChapter({
                src: 'http://upload.wikimedia.org/wikipedia/commons/7/75/Big_Buck_Bunny_Trailer_400p.ogg',
                title: 'Big Buck Bunny',
                description: 'An animated video',
                startTime: 5,
                endTime: 14});

            Mgr.addChapter({
                src: 'http://www.archive.org/download/deadmandirewolffanclub/DireWolfFanClub.ogv',
                title: 'Dire Wolf Fan Club',
                description: 'An unusual video',
                startTime: 10,
                endTime: 29});

            Mgr.addChapter({
                src: 'http://jbuckley.ca/~hoops/elephant.ogv',
                title: 'Elephants Dream',
                description: 'Elephants',
                startTime: 145,
                endTime: 200});

            Mgr.addChapter({
                src: 'http://www.archive.org/download/Kinetic_Art_Demo_Video/nym.ogv',
                title: 'Kinetic Art',
                description: 'Domino fun',
                startTime: 60,
                endTime: 66});

            Mgr.addChapter({
                src: 'http://ftp.gnu.org/video/Stephen_Fry-Happy_Birthday_GNU-hq_600px_780kbit.ogv',
                title: 'Freedom Fry',
                description: 'Happy B-Day',
                startTime: 1,
                endTime: 60});
        },
        // (Re-)initialize all values except internal element pointers
        init: function(vidId, tocId, updateEvent, canPlayEvent){
            _chapters = [];
            _hasMadeToc = false;
            _hasTocChanged = true; // In event TOC has been output before calling init, this will redraw table
            _curr = -1;

            this.setVideoId(vidId, updateEvent, canPlayEvent);
            this.setTOCId(tocId);
            Mgr.fetchBookmarks();
        },
        // Add a chapter
        addChapter: function(_c){
            _chapters.push(Mgr.Bookmark(_c));
            _hasTocChanged = true;
        },
        // Add a chapter
        removeChapter: function(_idx){
            _chapters.splice(_idx, 1);
            _hasTocChanged = true;
        },

        // Set the table of contents (<table>) and player (<video>) elements based on id
        // Only set them if the currently stored element is null or has a differing id
        setTOCId: function(_id){
            if (_id && (!this._toc || this._toc.id !== _id)) { // Valid id given and No id supplied yet or different id supplied
                this._toc = document.getElementById(_id);
                _hasTocChanged = true;
            }
        },

        setVideoId: function(_id){
            if (canVideo) {
                if (_id && (!this._vid || this._vid.id !== _id)) { // valid id given and No id supplied yet or different id supplied
                    // Store locally for easy reference for event setup
                    this._vid = document.getElementById(_id);
                }
            }
        },

        // output the TOC
        printTOC: function(){
            if (canVideo) {
                if (this._toc) {
                    var tr = 0;
                    var srcElem = 0;
                    var th = 0;
                    if (!_hasMadeToc) {
                        tr = this._toc.insertRow(0);

                        // DOM approach for tables (IE doesn't like tr.innerHTML)
                        th = document.createElement('th');
                        th.innerHTML = "Chapter Title";
                        tr.appendChild(th);

                        th = document.createElement('th');
                        th.innerHTML = "Description";
                        tr.appendChild(th);

                        th = document.createElement('th');
                        th.innerHTML = "Start Time";
                        tr.appendChild(th);

                        th = document.createElement('th');
                        th.innerHTML = "End Time";
                        tr.appendChild(th);

                        th = document.createElement('th');
                        th.innerHTML = 'Delete';
                        tr.appendChild(th);

                        _hasMadeToc = true;
                    }

                    // Delete existing rows
                    for (var i = this._toc.rows.length - 1; i > 0; i--)
                        this._toc.deleteRow(i);

                    if (_hasTocChanged) {
                        for (var i = _chapters.length - 1; i >= 0; i--) {
                            tr = this._toc.insertRow(1);
                            srcElem = document.createElement('a');
                            var item = _chapters[i];

                            srcElem.href = 'javascript:Mgr.playChapter(' + i + ');';
                            srcElem.innerHTML = item.getTitle();
                            tr.insertCell(0).appendChild(srcElem);
                            tr.insertCell(1).appendChild(document.createTextNode(item.getDescription()));
                            tr.insertCell(2).appendChild(document.createTextNode(item.getStartTime()));
                            tr.insertCell(3).appendChild(document.createTextNode(item.getEndTime()));
                            tr.insertCell(4).innerHTML = '<input type="checkbox" onclick="Mgr.removeChapter('+i+'); Mgr.printTOC();" />';
                        }

                        tr = this._toc.insertRow(1);
                        tr.colspan = 4;

                        srcElem = document.createElement('a');
                        srcElem.href = 'javascript:Mgr.playChapter(0, 1);';
                        srcElem.innerHTML = 'Play All';
                        tr.insertCell(0).appendChild(srcElem);

                        _hasTocChanged = false;
                    }
                }
            }
        },

        playChapter: function(idx, sequential){
            if (canVideo) {
                if (idx !== _curr && idx >= 0 && idx < _chapters.length) {
                    var vid = this._vid;

                    _curr = idx;
                    currChap = _chapters[_curr];

                    vid.addEventListener('loadedmetadata', function(){
                        vid.currentTime = currChap.getStartTime();
                    }, true);

                    vid.addEventListener('canplay', function(){
                        vid.play();
                    }, true);

                    vid.addEventListener('timeupdate', function(){
                        if (vid.currentTime >= currChap.getEndTime()) {
                            if (sequential) {
                                Mgr.playChapter(idx+1, sequential);
                            }
                            else {
                                vid.pause();
                            }
                        }
                    }, true);

                    vid.src = currChap.getSrc();
                    vid.load();
                    vid.play();
                }
            }
        }
    };
})();
<commit_msg>Added statistics tracking function<commit_after>/*
 * 	BBB v0.1
 * 		By Steven Weerdenburg and Kevin Lasconia
 * 		Last Modification: 11/08/2010
 */
var Mgr = (function(){
    var _chapters = []; // Array of Chapters/Bookmarks
    var _vid = 0, _toc = 0; // id to store the table of contents and video player
    var _hasMadeToc = false;
    var _hasTocChanged = false;

    var _curr = -1;
    var currChap = 0;
    var _playSeq = 0;

    var canVideo = !!document.createElement('video').play;

    return {
        // A Bookmark object for the manager to work with
        Bookmark: function(params) {
            var title = "";
            var description = "";
            var src = "";
            var startTime = 0;
            var endTime = 0;

            if (params) {
                title = params["title"];
                description = params["description"];
                src = params["src"];
                startTime = parseInt(params["startTime"]);
                endTime = parseInt(params["endTime"]);

                if (startTime < 0 || endTime < 0)
                    throw "Start and end times must be positive!";
                else if (startTime < endTime) {
                    startTime = startTime;
                    endTime = endTime;
                } else {
                    endTime = startTime;
                    startTime = endTime;
                }
            }

            return {
                getTitle: function() { return title; },
                getDescription: function() { return description; },
                getSrc: function() { return src; },
                getStartTime: function() { return startTime; },
                getEndTime: function() { return endTime; },
                toString: function(){
                    return "Source: " + src + "\nTitle: " + title + "\nDescription: " + description + "\nStart Time: " + startTime + "\nEnd Time: " + endTime;
                },
                toJSON: function(){
                    return '{ "src": "' + src + '", "title": "' + title + '", "description": "' + description + '", "startTime": ' + startTime + ', "endTime": ' + endTime + ' }';
                },
                equals: function(bkmrk) {
                    return src === bkmrk.getSrc() && title === bkmrk.getTitle() && description === bkmrk.getDescription() &&
                        startTime === bkmrk.getStartTime() && endTime === bkmrk.getEndTime();
                },
                fromJSON: function(str){
                    //var obj = jsonParse(str);

                    var currStart = -1;
                    var currEnd = 0;
                    var obj = {};

                    while ((currStart = str.indexOf('"', currEnd + 1)) !== -1 && (currEnd = str.indexOf('"', currStart + 1)) !== -1) {
                        // Has found another attribute

                        var attrName = str.substring(currStart + 1, currEnd);
                        var foundAttr = false;
                        var foundSemi = false;
                        var foundType = 0; // 0 = none, 1 = string, 2 = numeric, 3 = float
                        var currItem;

                        // Process value, eagerly assume comma follows when value found
                        while ((currItem = str[++currEnd]) !== '"' || !foundAttr) {
                            if (str[currEnd] === ':') {
                                foundSemi = true;
                            } else {
                                if (str[currEnd] === '"') { // Check for strings
                                    if (foundSemi && str[currEnd - 1] !== '\\') {
                                        if (!foundType) {
                                            foundType = 1;
                                            currStart = currEnd;
                                        } else {
                                            obj[attrName] = str.substring(currStart + 1, currEnd);
                                            foundAttr = true;
                                            break; // Go into outer loop to find next attribute
                                        }
                                    }
                                } else {
                                    if (str[currEnd] === '.') { // Check for decimal for numeric->float data
                                        if (foundType === 2)
                                            foundType = 3;
                                    } else {
                                        if (str[currEnd] === ' ') {
                                            if (foundType === 2 || foundType === 3) { // Check for end of numeric data
                                                if (foundType === 2) // Integer
                                                    obj[attrName] = parseInt(str.substring(currStart, currEnd));
                                                else
                                                    if (foundType === 3) // Float
                                                        obj[attrName] = parseFloat(str.substring(currStart, currEnd));

                                                foundAttr = true;
                                                break;
                                            }
                                        } else {
                                            if (!foundType) {
                                                if (!isNaN(str[currEnd])) {
                                                    currStart = str[currEnd - 1] === '-' ? currEnd - 1 : currEnd;
                                                    foundType = 2; // Numeric, may be upgraded to float later
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    return Mgr.Bookmark(obj);
                }
            }
        },
        // A Statistics object for the manager to work with
		Statistics: function() {
			var a = "";

			return {

			}
		},
        fetchBookmarks: function() {
            // Stub code, will eventually get bookmarks from server call

            Mgr.addChapter({
                src: 'http://upload.wikimedia.org/wikipedia/commons/7/75/Big_Buck_Bunny_Trailer_400p.ogg',
                title: 'Big Buck Bunny',
                description: 'An animated video',
                startTime: 5,
                endTime: 14});

            Mgr.addChapter({
                src: 'http://www.archive.org/download/deadmandirewolffanclub/DireWolfFanClub.ogv',
                title: 'Dire Wolf Fan Club',
                description: 'An unusual video',
                startTime: 10,
                endTime: 29});

            Mgr.addChapter({
                src: 'http://jbuckley.ca/~hoops/elephant.ogv',
                title: 'Elephants Dream',
                description: 'Elephants',
                startTime: 145,
                endTime: 200});

            Mgr.addChapter({
                src: 'http://www.archive.org/download/Kinetic_Art_Demo_Video/nym.ogv',
                title: 'Kinetic Art',
                description: 'Domino fun',
                startTime: 60,
                endTime: 66});

            Mgr.addChapter({
                src: 'http://ftp.gnu.org/video/Stephen_Fry-Happy_Birthday_GNU-hq_600px_780kbit.ogv',
                title: 'Freedom Fry',
                description: 'Happy B-Day',
                startTime: 1,
                endTime: 60});
        },
        // (Re-)initialize all values except internal element pointers
        init: function(vidId, tocId, updateEvent, canPlayEvent, ip){
            _chapters = [];
            _hasMadeToc = false;
            _hasTocChanged = true; // In event TOC has been output before calling init, this will redraw table
            _curr = -1;

            this.setVideoId(vidId, updateEvent, canPlayEvent);
            this.setTOCId(tocId);
            Mgr.fetchBookmarks();
			//Mgr.trackStatistics();
        },
        // Add a chapter
        addChapter: function(_c){
            _chapters.push(Mgr.Bookmark(_c));
            _hasTocChanged = true;
        },
        // Add a chapter
        removeChapter: function(_idx){
            _chapters.splice(_idx, 1);
            _hasTocChanged = true;
        },

        // Set the table of contents (<table>) and player (<video>) elements based on id
        // Only set them if the currently stored element is null or has a differing id
        setTOCId: function(_id){
            if (_id && (!this._toc || this._toc.id !== _id)) { // Valid id given and No id supplied yet or different id supplied
                this._toc = document.getElementById(_id);
                _hasTocChanged = true;
            }
        },

        setVideoId: function(_id){
            if (canVideo) {
                if (_id && (!this._vid || this._vid.id !== _id)) { // valid id given and No id supplied yet or different id supplied
                    // Store locally for easy reference for event setup
                    this._vid = document.getElementById(_id);
                }
            }
        },

        // output the TOC
        printTOC: function(){
            if (canVideo) {
                if (this._toc) {
                    var tr = 0;
                    var srcElem = 0;
                    var th = 0;
                    if (!_hasMadeToc) {
                        tr = this._toc.insertRow(0);

                        // DOM approach for tables (IE doesn't like tr.innerHTML)
                        th = document.createElement('th');
                        th.innerHTML = "Chapter Title";
                        tr.appendChild(th);

                        th = document.createElement('th');
                        th.innerHTML = "Description";
                        tr.appendChild(th);

                        th = document.createElement('th');
                        th.innerHTML = "Start Time";
                        tr.appendChild(th);

                        th = document.createElement('th');
                        th.innerHTML = "End Time";
                        tr.appendChild(th);

                        th = document.createElement('th');
                        th.innerHTML = 'Delete';
                        tr.appendChild(th);

                        _hasMadeToc = true;
                    }

                    // Delete existing rows
                    for (var i = this._toc.rows.length - 1; i > 0; i--)
                        this._toc.deleteRow(i);

                    if (_hasTocChanged) {
                        for (var i = _chapters.length - 1; i >= 0; i--) {
                            tr = this._toc.insertRow(1);
                            srcElem = document.createElement('a');
                            var item = _chapters[i];

                            srcElem.href = 'javascript:Mgr.playChapter(' + i + ');';
                            srcElem.innerHTML = item.getTitle();
                            tr.insertCell(0).appendChild(srcElem);
                            tr.insertCell(1).appendChild(document.createTextNode(item.getDescription()));
                            tr.insertCell(2).appendChild(document.createTextNode(item.getStartTime()));
                            tr.insertCell(3).appendChild(document.createTextNode(item.getEndTime()));
                            tr.insertCell(4).innerHTML = '<input type="checkbox" onclick="Mgr.removeChapter('+i+'); Mgr.printTOC();" />';
                        }

                        tr = this._toc.insertRow(1);
                        tr.colspan = 4;

                        srcElem = document.createElement('a');
                        srcElem.href = 'javascript:Mgr.playChapter(0, 1);';
                        srcElem.innerHTML = 'Play All';
                        tr.insertCell(0).appendChild(srcElem);

                        _hasTocChanged = false;
                    }
                }
            }
        },

        playChapter: function(idx, sequential){
            if (canVideo) {
                if (idx !== _curr && idx >= 0 && idx < _chapters.length) {
                    var vid = this._vid;

                    _curr = idx;
                    currChap = _chapters[_curr];

                    vid.addEventListener('loadedmetadata', function(){
                        vid.currentTime = currChap.getStartTime();
                    }, true);

                    vid.addEventListener('canplay', function(){
                        vid.play();
                    }, true);

                    vid.addEventListener('timeupdate', function(){
                        if (vid.currentTime >= currChap.getEndTime()) {
                            if (sequential) {
                                Mgr.playChapter(idx+1, sequential);
                            }
                            else {
                                vid.pause();
                            }
                        }
                    }, true);

                    vid.src = currChap.getSrc();
                    vid.load();
                    vid.play();
                }
            }
        },

        trackStatistics: function(ip) {
			var stats = {ip : 0, onLoad : false, _25 : false, _50 : false, _75 : false, _90 : false, _100 : false, cc_on : false, cc_off : false, ad_on : false, ad_off : false};
			var vid = this._vid;
            var duration = vid.duration;

			stats.ip = ip;

            var durationListener = function() {
                if (parseInt(vid.currentTime, 10) === parseInt(duration * 0.25, 10)) {
                    vid.removeEventListener('timeupdate', durationListener, false);
					stats._25 = true;
                }
                else if (parseInt(vid.currentTime, 10) === parseInt(duration * 0.50, 10)) {
                	vid.removeEventListener('timeupdate', durationListener, false);
                    stats._50 = true;
                }
                else if (parseInt(vid.currentTime, 10) === parseInt(duration * 0.75, 10)) {
                	vid.removeEventListener('timeupdate', durationListener, false);
                    stats._75 = true;
                }
                else if (parseInt(vid.currentTime, 10) === parseInt(duration * 0.90, 10)) {
                	vid.removeEventListener('timeupdate', durationListener, false);
                    stats._90 = true;
                }
                vid.addEventListener('timeupdate', durationListener, false);
            }

            var endListener = function(){
                stats._100 = true;
				alert(stats._25 + ' ' + stats._50 + ' ' + stats._75 + ' ' + stats._90 + ' ' + stats._100);
            }

            vid.addEventListener('timeupdate', durationListener, false);
            vid.addEventListener('ended', endListener, false);
        }
    };
})();
<|endoftext|>