<commit_before>/*
 * Licensed to the Sakai Foundation (SF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The SF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

define(['jquery', 'oae.core', 'jquery.timeago'], function($, oae) {

    return function(uid, showSettings) {

        // Cache the widget container
        var $rootel = $('#' + uid);

        // Variable used to keep track of current content item
        // TODO: Use the getContext functionality once the upload branch has been merged
        var contentProfile = null;

        // Variable used to keep track of the current infinite scroll
        var infinityScroll = null;

        /**
         * When a reply or comment is made, the comment is added into the comments list.
         *
         * @param  {Object}     err        Error object containing error code and message
         * @param  {Comment}    comment    The Comment object representing the comment/reply that has been made
         */
        var renderComment = function(err, comment) {
            // Top level comment
            if (!comment.replyTo) {
                // Insert the comment at the beginning of the list after the new comment box
                $('#contentcomments-content-container li:first-child', $rootel).after(
                    oae.api.util.template().render('#contentcomments-comment-template', {
                        'results': [comment],
                        'canManage': contentProfile.isManager
                    })
                );
            // Reply on an existing comment
            } else {
                // Insert the reply after the comment it is a reply to
                $('li.media[data-id="' + comment.replyTo + '"]', $rootel).after(
                    oae.api.util.template().render('#contentcomments-comment-template', {
                        'results': [comment],
                        'canManage': contentProfile.isManager
                    })
                );
            }
            setUpValidation();
        };

        /**
         * Marks a comment in the list as deleted without removing it from the list. This is done when
         * the comment has at least one reply.
         *
         * @param  {Comment}    comment    The comment that was deleted
         */
        var markCommentAsDeleted = function(comment) {
            // Replace the deleted comment with a dummy placeholder that indicates there used to be a comment
            $('li.media[data-id="' + comment.commentId + '"]').replaceWith(
                oae.api.util.template().render('#contentcomments-comment-template', {
                    'results': [comment],
                    'canManage': contentProfile.isManager
                })
            );
        };

        /**
         * Bind all functionality related to creating a new top-level comment on the content item.
         *
         * @param  {Object}    form    The form DOM element passed in by the validation plugin
         */
         var createComment = function(form) {
            var $form = $(form);
            var comment = $.trim($form.find('textarea').val());
            // Post the comment and re-render the results
            oae.api.content.createComment(contentProfile.id, comment, null, renderComment);
            // Reset the form
            $form[0].reset();
            // Return false to prevent the default browser behavior
            return false;
        };

        /**
         * Reply to a comment. This will also reset and hide the reply form.
         *
         * @param  {Object}    form    The form DOM element passed in by the validation plugin
         */
        var createReply = function(form) {
            var $form = $(form);
            var replyTo = $form.attr('data-replyTo');
            var comment = $.trim($form.find('textarea').val());
            // Post the comment and re-render the results
            oae.api.content.createComment(contentProfile.id, comment, replyTo, renderComment);
            // Reset the form
            $form[0].reset();
            $form.parents('.contentcomments-reply-container').hide();
            // Return false to prevent the default browser behavior
            return false;
        };

        /**
         * Set up the validation on the comment and reply forms. We only initialize validation on the forms that haven't
         * been initialized yet. As jQuery.validate sets `novalidate="novalidate"` once a form has been initialized for
         * validation, we use this to find the forms that haven't been initialized.
         */
        var setUpValidation = function() {
            oae.api.util.validation().validate($('.contentcomments-new-comment-form[novalidate!="novalidate"]', $rootel), {
                'submitHandler': createComment
            });

            $('.contentcomments-new-reply-form[novalidate!="novalidate"]', $rootel).each(function(i, form) {
                oae.api.util.validation().validate($(form), {
                    'submitHandler': createReply
                });
            });
        };

        /**
         * Bind all reply related functionality.
         */
        var setUpReplyComment = function() {
            $rootel.on('click', '.contentcomments-reply-button', function() {
                // Show the reply container
                var $replyContainer = $(this).parent().siblings('.contentcomments-reply-container');
                $replyContainer.toggle();
                $replyContainer.find('textarea').focus();
            });
        };

        /**
         * Deletes a comment from the content item. An item that has been properly deleted, because it had no replies,
         * will be removed from the list. A deleted item that does have replies will remain available as `This comment
         * has been deleted`.
         */
        var setUpDeleteComment = function() {
            $rootel.on('click', '.contentcomments-delete-button', function() {
                var commentId = $(this).attr('data-id');
                oae.api.content.deleteComment(contentProfile.id, commentId, function(err, softDeleted) {
                    if (err) {
                        throw new Error('Comment could not be deleted.');
                    }

                    if (softDeleted) {
                        markCommentAsDeleted(softDeleted);
                    } else {
                        infinityScroll.removeItems(commentId);
                    }
                });
            });
        };

        /**
         * Prepends the textarea that allows creation of new top level comments to the list of comments if
         * the current user is logged in
         */
        var renderCreateNewComment = function() {
            if (!oae.data.me.anon) {
                $('#contentcomments-content-container').prepend(oae.api.util.template().render('#contentcomments-new-comment-template'));

                // Focuses the new comment field when the comment clip is clicked
                $(document).on('click', '.contentcomments-focus-new-comment', function() {
                    $('.contentcomments-new-comment-form textarea').focus();
                });
            }
        };

        /**
         * Initialize a new infinite scroll container that fetches the content comments.
         */
        var setUpInfiniteScroll = function() {
            infinityScroll = $('#contentcomments-content-container', $rootel).infiniteScroll('/api/content/' + contentProfile.id + '/comments', null, $('#contentcomments-comment-template'), {
                'postProcessor': function(data) {
                    data.canManage = contentProfile.isManager;
                    return data;
                },
                'postRenderer': setUpValidation
            });

            renderCreateNewComment();
            setUpReplyComment();
            setUpDeleteComment();
        };

        // Receive the content profile information and set up the infinite scroll for comments
        $(document).on('oae.context.send', function(ev, contentData) {
            contentProfile = contentData;
            setUpInfiniteScroll();
        });

        // Request the content profile information
        $(document).trigger('oae.context.get');

    };
});
<commit_msg>Removed TODO statement<commit_after>/*
 * Licensed to the Sakai Foundation (SF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The SF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

define(['jquery', 'oae.core', 'jquery.timeago'], function($, oae) {

    return function(uid, showSettings) {

        // Cache the widget container
        var $rootel = $('#' + uid);

        // Variable used to keep track of current content item
        var contentProfile = null;

        // Variable used to keep track of the current infinite scroll
        var infinityScroll = null;

        /**
         * When a reply or comment is made, the comment is added into the comments list.
         *
         * @param  {Object}     err        Error object containing error code and message
         * @param  {Comment}    comment    The Comment object representing the comment/reply that has been made
         */
        var renderComment = function(err, comment) {
            // Top level comment
            if (!comment.replyTo) {
                // Insert the comment at the beginning of the list after the new comment box
                $('#contentcomments-content-container li:first-child', $rootel).after(
                    oae.api.util.template().render('#contentcomments-comment-template', {
                        'results': [comment],
                        'canManage': contentProfile.isManager
                    })
                );
            // Reply on an existing comment
            } else {
                // Insert the reply after the comment it is a reply to
                $('li.media[data-id="' + comment.replyTo + '"]', $rootel).after(
                    oae.api.util.template().render('#contentcomments-comment-template', {
                        'results': [comment],
                        'canManage': contentProfile.isManager
                    })
                );
            }
            setUpValidation();
        };

        /**
         * Marks a comment in the list as deleted without removing it from the list. This is done when
         * the comment has at least one reply.
         *
         * @param  {Comment}    comment    The comment that was deleted
         */
        var markCommentAsDeleted = function(comment) {
            // Replace the deleted comment with a dummy placeholder that indicates there used to be a comment
            $('li.media[data-id="' + comment.commentId + '"]').replaceWith(
                oae.api.util.template().render('#contentcomments-comment-template', {
                    'results': [comment],
                    'canManage': contentProfile.isManager
                })
            );
        };

        /**
         * Bind all functionality related to creating a new top-level comment on the content item.
         *
         * @param  {Object}    form    The form DOM element passed in by the validation plugin
         */
         var createComment = function(form) {
            var $form = $(form);
            var comment = $.trim($form.find('textarea').val());
            // Post the comment and re-render the results
            oae.api.content.createComment(contentProfile.id, comment, null, renderComment);
            // Reset the form
            $form[0].reset();
            // Return false to prevent the default browser behavior
            return false;
        };

        /**
         * Reply to a comment. This will also reset and hide the reply form.
         *
         * @param  {Object}    form    The form DOM element passed in by the validation plugin
         */
        var createReply = function(form) {
            var $form = $(form);
            var replyTo = $form.attr('data-replyTo');
            var comment = $.trim($form.find('textarea').val());
            // Post the comment and re-render the results
            oae.api.content.createComment(contentProfile.id, comment, replyTo, renderComment);
            // Reset the form
            $form[0].reset();
            $form.parents('.contentcomments-reply-container').hide();
            // Return false to prevent the default browser behavior
            return false;
        };

        /**
         * Set up the validation on the comment and reply forms. We only initialize validation on the forms that haven't
         * been initialized yet. As jQuery.validate sets `novalidate="novalidate"` once a form has been initialized for
         * validation, we use this to find the forms that haven't been initialized.
         */
        var setUpValidation = function() {
            oae.api.util.validation().validate($('.contentcomments-new-comment-form[novalidate!="novalidate"]', $rootel), {
                'submitHandler': createComment
            });

            $('.contentcomments-new-reply-form[novalidate!="novalidate"]', $rootel).each(function(i, form) {
                oae.api.util.validation().validate($(form), {
                    'submitHandler': createReply
                });
            });
        };

        /**
         * Bind all reply related functionality.
         */
        var setUpReplyComment = function() {
            $rootel.on('click', '.contentcomments-reply-button', function() {
                // Show the reply container
                var $replyContainer = $(this).parent().siblings('.contentcomments-reply-container');
                $replyContainer.toggle();
                $replyContainer.find('textarea').focus();
            });
        };

        /**
         * Deletes a comment from the content item. An item that has been properly deleted, because it had no replies,
         * will be removed from the list. A deleted item that does have replies will remain available as `This comment
         * has been deleted`.
         */
        var setUpDeleteComment = function() {
            $rootel.on('click', '.contentcomments-delete-button', function() {
                var commentId = $(this).attr('data-id');
                oae.api.content.deleteComment(contentProfile.id, commentId, function(err, softDeleted) {
                    if (err) {
                        throw new Error('Comment could not be deleted.');
                    }

                    if (softDeleted) {
                        markCommentAsDeleted(softDeleted);
                    } else {
                        infinityScroll.removeItems(commentId);
                    }
                });
            });
        };

        /**
         * Prepends the textarea that allows creation of new top level comments to the list of comments if
         * the current user is logged in
         */
        var renderCreateNewComment = function() {
            if (!oae.data.me.anon) {
                $('#contentcomments-content-container').prepend(oae.api.util.template().render('#contentcomments-new-comment-template'));

                // Focuses the new comment field when the comment clip is clicked
                $(document).on('click', '.contentcomments-focus-new-comment', function() {
                    $('.contentcomments-new-comment-form textarea').focus();
                });
            }
        };

        /**
         * Initialize a new infinite scroll container that fetches the content comments.
         */
        var setUpInfiniteScroll = function() {
            infinityScroll = $('#contentcomments-content-container', $rootel).infiniteScroll('/api/content/' + contentProfile.id + '/comments', null, $('#contentcomments-comment-template'), {
                'postProcessor': function(data) {
                    data.canManage = contentProfile.isManager;
                    return data;
                },
                'postRenderer': setUpValidation
            });

            renderCreateNewComment();
            setUpReplyComment();
            setUpDeleteComment();
        };

        // Receive the content profile information and set up the infinite scroll for comments
        $(document).on('oae.context.send', function(ev, contentData) {
            contentProfile = contentData;
            setUpInfiniteScroll();
        });
        // Request the content profile information
        $(document).trigger('oae.context.get');

    };
});
<|endoftext|>


<commit_before>function hex(number, leading, usePrefix) {
	if (typeof(usePrefix) === 'undefined') {
		usePrefix = true;
	}
	if (typeof(leading) === 'undefined') {
		leading = 8;
	}
	var string = (number >>> 0).toString(16).toUpperCase();
	leading -= string.length;
	return (usePrefix ? '0x' : '')  + new Array(leading + 1).join('0') + string;
}

Console = function(cpu) {
	this.cpu = cpu;
	this.ul = document.getElementById('console');
	this.gprs = document.getElementById('gprs');
	this.memory = new Memory(cpu.mmu);
	this.updateGPRs();
	this.updateCPSR();
	this.breakpoints = [];
	this.memory.refreshAll();
	this.logQueue = [];
	var self = this;
	cpu.setLogger(function (message) { self.log(message) });
}

Console.prototype.updateGPRs = function() {
	for (var i = 0; i < 16; ++i) {
		this.gprs.children[i].textContent = hex(this.cpu.gprs[i]);
	}
}

Console.prototype.updateCPSR = function() {
	var cpu = this.cpu;
	var bit = function(psr, member) {
		var element = document.getElementById(psr);
		if (cpu[member]) {
			element.removeAttribute('class');
		} else {
			element.setAttribute('class', 'disabled');
		}
	}
	bit('cpsrN', 'cpsrN');
	bit('cpsrZ', 'cpsrZ');
	bit('cpsrC', 'cpsrC');
	bit('cpsrV', 'cpsrV');
	bit('cpsrI', 'cpsrI');
	bit('cpsrT', 'execMode');

	var mode = document.getElementById('mode');
	switch (cpu.mode) {
	case cpu.MODE_USER:
		mode.textContent = 'USER';
		break;
	case cpu.MODE_IRQ:
		mode.textContent = 'IRQ';
		break;
	case cpu.MODE_ABORT:
		mode.textContent = 'ABORT';
		break;
	case cpu.MODE_UNDEFINED:
		mode.textContent = 'UNDEFINED';
		break;
	case cpu.MODE_SYSTEM:
		mode.textContent = 'SYSTEM';
		break;
	default:
		mode.textContent = '???';
		break;
	}
}

Console.prototype.log = function(message) {
	this.logQueue.push(message);
	if (!this.stillRunning) {
		this.flushLog();
	}
}

Console.prototype.flushLog = function() {
	var doScroll = this.ul.scrollTop == this.ul.scrollHeight - this.ul.offsetHeight;
	while (this.logQueue.length) {
		var entry = document.createElement('li');
		entry.textContent = this.logQueue.shift();
		this.ul.appendChild(entry);
	}
	if (doScroll) {
		this.ul.scrollTop = this.ul.scrollHeight - this.ul.offsetHeight;
	}

}

Console.prototype.step = function() {
	try {
		this.cpu.step();
		this.updateGPRs();
		this.updateCPSR();
		this.memory.refreshAll();
	} catch (exception) {
		this.log(exception);
		throw exception;
	}
}

Console.prototype.runVisible = function() {
	if (this.stillRunning) {
		return;
	}

	this.stillRunning = true;
	var self = this;
	run = function() {
		if (self.stillRunning) {
			try {
				self.step();
				if (self.breakpoints.length && self.breakpoints[self.cpu.gprs[self.cpu.PC]]) {
					self.breakpointHit();
					return;
				}
				self.flushLog();
				setTimeout(run, 0);
			} catch (exception) {
				self.pause();
				throw exception;
			}
		}
	}
	run();
}

Console.prototype.run = function() {
	if (this.stillRunning) {
		return;
	}

	this.stillRunning = true;
	var regs = document.getElementById('registers');
	var mem = document.getElementById('memory');
	var start = new Date().getTime();
	regs.setAttribute('class', 'disabled');
	mem.setAttribute('class', 'disabled');
	var self = this;
	var instructions = 0;
	run = function() {
		if (self.stillRunning) {
			try {
				if (self.breakpoints.length) {
					var base = self.cpu.cycles;
					while (self.cpu.cycles - base < 280896) {
						++instructions;
						self.cpu.step();
						if (self.breakpoints[self.cpu.gprs[self.cpu.PC]]) {
							self.breakpointHit();
							return;
						}
					}
				} else {
					for (var i = 0; i < 281590; ++i) {
						++instructions;
						self.cpu.step();
					}
				}
				setTimeout(run, 0);
			} catch (exception) {
				self.log("Exception hit after " + instructions + " instructions in " + (new Date().getTime() - start) + " milliseconds!");
				self.log(exception);
				self.pause();
				throw exception;
			}
		}
	}
	run();
}

Console.prototype.pause = function() {
	this.stillRunning = false;
	var regs = document.getElementById('registers');
	var mem = document.getElementById('memory');
	mem.removeAttribute('class');
	regs.removeAttribute('class');
	this.updateGPRs();
	this.updateCPSR();
	this.memory.refreshAll();
	this.flushLog();
}

Console.prototype.breakpointHit = function() {
	this.pause();
	this.log('Hit breakpoint at ' + hex(this.cpu.gprs[this.cpu.PC]));
}

Console.prototype.addBreakpoint = function(addr) {
	this.breakpoints[addr] = true;
	var bpLi = document.getElementById('bp' + addr);
	if (!bpLi) {
		bpLi = document.createElement('li');
		bpLi.address = addr;
		var cb = document.createElement('input');
		cb.setAttribute('type', 'checkbox');
		cb.setAttribute('checked', 'checked');
		bpLi.appendChild(cb);
		bpLi.appendChild(document.createTextNode(hex(addr)));
		document.getElementById('breakpointView').appendChild(bpLi);
	}
}

Memory = function(mmu) {
	this.mmu = mmu;
	this.ul = document.getElementById('memoryView');
	row = this.createRow(0);
	this.ul.appendChild(row);
	this.rowHeight = row.offsetHeight;
	this.numberRows = this.ul.offsetHeight / this.rowHeight + 2;
	this.ul.removeChild(row);

	for (var i = 0; i < this.numberRows; ++i) {
		this.ul.appendChild(this.createRow(i << 4));
	}
	this.ul.scrollTop = 100;

	var self = this;
	this.ul.addEventListener('scroll', function(e) { self.scroll() }, true);
	window.addEventListener('resize', function(e) { self.resize() }, true);
}

Memory.prototype.scroll = function() {
	while (this.ul.scrollTop - 100 < this.rowHeight) {
		if (this.ul.firstChild.offset == 0) {
			break;
		}
		var victim = this.ul.lastChild;
		this.ul.removeChild(victim);
		victim.offset = this.ul.firstChild.offset - 16;
		this.refresh(victim);
		this.ul.insertBefore(victim, this.ul.firstChild);
		this.ul.scrollTop += this.rowHeight;
	}
	while (this.ul.scrollTop - 100 > this.rowHeight * 2) {
		var victim = this.ul.firstChild;
		this.ul.removeChild(victim);
		victim.offset = this.ul.lastChild.offset + 16;
		this.refresh(victim);
		this.ul.appendChild(victim);
		this.ul.scrollTop -= this.rowHeight;
	}
	if (this.ul.scrollTop < 100) {
		this.ul.scrollTop = 100;
	}
}

Memory.prototype.resize = function() {
	this.numberRows = this.ul.offsetHeight / this.rowHeight + 2;
	if (this.numberRows > this.ul.children.length) {
		var offset = this.ul.lastChild.offset + 16;
		for (var i = 0; i < this.numberRows - this.ul.children.length; ++i) {
			var row = this.createRow(offset);
			this.refresh(row);
			this.ul.appendChild(row);
			offset += 16;
		}
	} else {
		for (var i = 0; i < this.ul.children.length - this.numberRows; ++i) {
			this.ul.removeChild(this.ul.lastChild);
		}
	}
}

Memory.prototype.refresh = function(row) {
	row.firstChild.textContent = hex(row.offset);
	for (var i = 0; i < 16; ++i) {
		try {
			row.children[i + 1].textContent = hex(this.mmu.freeLoadU8(row.offset + i), 2, false);
		} catch (exception) {
			row.children[i + 1].textContent = '??';
		}
	}
}

Memory.prototype.refreshAll = function() {
	for (var i = 0; i < this.ul.children.length; ++i) {
		this.refresh(this.ul.children[i]);
	}
}

Memory.prototype.createRow = function(startOffset) {
	var li = document.createElement('li');
	var offset = document.createElement('span');
	offset.setAttribute('class', 'memoryOffset');
	offset.textContent = hex(startOffset);
	li.appendChild(offset);

	for (var i = 0; i < 16; ++i) {
		var b = document.createElement('span');
		b.textContent = '00';
		b.setAttribute('class', 'memoryCell');
		li.appendChild(b);
	}
	li.offset = startOffset;
	return li;
}

Memory.prototype.scrollTo = function(offset) {
	offset &= 0xFFFFFFF0;
	if (offset) {
		for (var i = 0; i < this.ul.children.length; ++i) {
			var child = this.ul.children[i];
			child.offset = offset + (i - 1) * 16;
			this.refresh(child);
		}
		this.ul.scrollTop = 100+ this.rowHeight;
	} else {
		for (var i = 0; i < this.ul.children.length; ++i) {
			var child = this.ul.children[i];
			child.offset = offset + i * 16;
			this.refresh(child);
		}
		this.ul.scrollTop = 100;
	}
}
<commit_msg>Run a few console tasks asynchronously to let other parts catch up<commit_after>function hex(number, leading, usePrefix) {
	if (typeof(usePrefix) === 'undefined') {
		usePrefix = true;
	}
	if (typeof(leading) === 'undefined') {
		leading = 8;
	}
	var string = (number >>> 0).toString(16).toUpperCase();
	leading -= string.length;
	return (usePrefix ? '0x' : '')  + new Array(leading + 1).join('0') + string;
}

Console = function(cpu) {
	this.cpu = cpu;
	this.ul = document.getElementById('console');
	this.gprs = document.getElementById('gprs');
	this.memory = new Memory(cpu.mmu);
	this.updateGPRs();
	this.updateCPSR();
	this.breakpoints = [];
	this.memory.refreshAll();
	this.logQueue = [];
	var self = this;
	cpu.setLogger(function (message) { self.log(message) });
}

Console.prototype.updateGPRs = function() {
	for (var i = 0; i < 16; ++i) {
		this.gprs.children[i].textContent = hex(this.cpu.gprs[i]);
	}
}

Console.prototype.updateCPSR = function() {
	var cpu = this.cpu;
	var bit = function(psr, member) {
		var element = document.getElementById(psr);
		if (cpu[member]) {
			element.removeAttribute('class');
		} else {
			element.setAttribute('class', 'disabled');
		}
	}
	bit('cpsrN', 'cpsrN');
	bit('cpsrZ', 'cpsrZ');
	bit('cpsrC', 'cpsrC');
	bit('cpsrV', 'cpsrV');
	bit('cpsrI', 'cpsrI');
	bit('cpsrT', 'execMode');

	var mode = document.getElementById('mode');
	switch (cpu.mode) {
	case cpu.MODE_USER:
		mode.textContent = 'USER';
		break;
	case cpu.MODE_IRQ:
		mode.textContent = 'IRQ';
		break;
	case cpu.MODE_ABORT:
		mode.textContent = 'ABORT';
		break;
	case cpu.MODE_UNDEFINED:
		mode.textContent = 'UNDEFINED';
		break;
	case cpu.MODE_SYSTEM:
		mode.textContent = 'SYSTEM';
		break;
	default:
		mode.textContent = '???';
		break;
	}
}

Console.prototype.log = function(message) {
	this.logQueue.push(message);
	if (!this.stillRunning) {
		this.flushLog();
	}
}

Console.prototype.flushLog = function() {
	var doScroll = this.ul.scrollTop == this.ul.scrollHeight - this.ul.offsetHeight;
	while (this.logQueue.length) {
		var entry = document.createElement('li');
		entry.textContent = this.logQueue.shift();
		this.ul.appendChild(entry);
	}
	if (doScroll) {
		var ul = this.ul;
		setTimeout(function() { ul.scrollTop = ul.scrollHeight - ul.offsetHeight }, 0);
	}

}

Console.prototype.step = function() {
	try {
		this.cpu.step();
		this.updateGPRs();
		this.updateCPSR();
		this.memory.refreshAll();
	} catch (exception) {
		this.log(exception);
		throw exception;
	}
}

Console.prototype.runVisible = function() {
	if (this.stillRunning) {
		return;
	}

	this.stillRunning = true;
	var self = this;
	run = function() {
		if (self.stillRunning) {
			try {
				self.step();
				if (self.breakpoints.length && self.breakpoints[self.cpu.gprs[self.cpu.PC]]) {
					self.breakpointHit();
					return;
				}
				self.flushLog();
				setTimeout(run, 0);
			} catch (exception) {
				self.pause();
				throw exception;
			}
		}
	}
	setTimeout(run, 0);
}

Console.prototype.run = function() {
	if (this.stillRunning) {
		return;
	}

	this.stillRunning = true;
	var regs = document.getElementById('registers');
	var mem = document.getElementById('memory');
	var start = new Date().getTime();
	regs.setAttribute('class', 'disabled');
	mem.setAttribute('class', 'disabled');
	var self = this;
	var instructions = 0;
	run = function() {
		if (self.stillRunning) {
			try {
				if (self.breakpoints.length) {
					var base = self.cpu.cycles;
					while (self.cpu.cycles - base < 280896) {
						++instructions;
						self.cpu.step();
						if (self.breakpoints[self.cpu.gprs[self.cpu.PC]]) {
							self.breakpointHit();
							return;
						}
					}
				} else {
					for (var i = 0; i < 281590; ++i) {
						++instructions;
						self.cpu.step();
					}
				}
				setTimeout(run, 0);
			} catch (exception) {
				self.log("Exception hit after " + instructions + " instructions in " + (new Date().getTime() - start) + " milliseconds!");
				self.log(exception);
				self.pause();
				throw exception;
			}
		}
	}
	setTimeout(run, 0);
}

Console.prototype.pause = function() {
	this.stillRunning = false;
	var regs = document.getElementById('registers');
	var mem = document.getElementById('memory');
	mem.removeAttribute('class');
	regs.removeAttribute('class');
	this.updateGPRs();
	this.updateCPSR();
	this.memory.refreshAll();
	this.flushLog();
}

Console.prototype.breakpointHit = function() {
	this.pause();
	this.log('Hit breakpoint at ' + hex(this.cpu.gprs[this.cpu.PC]));
}

Console.prototype.addBreakpoint = function(addr) {
	this.breakpoints[addr] = true;
	var bpLi = document.getElementById('bp' + addr);
	if (!bpLi) {
		bpLi = document.createElement('li');
		bpLi.address = addr;
		var cb = document.createElement('input');
		cb.setAttribute('type', 'checkbox');
		cb.setAttribute('checked', 'checked');
		bpLi.appendChild(cb);
		bpLi.appendChild(document.createTextNode(hex(addr)));
		document.getElementById('breakpointView').appendChild(bpLi);
	}
}

Memory = function(mmu) {
	this.mmu = mmu;
	this.ul = document.getElementById('memoryView');
	row = this.createRow(0);
	this.ul.appendChild(row);
	this.rowHeight = row.offsetHeight;
	this.numberRows = this.ul.offsetHeight / this.rowHeight + 2;
	this.ul.removeChild(row);

	for (var i = 0; i < this.numberRows; ++i) {
		this.ul.appendChild(this.createRow(i << 4));
	}
	this.ul.scrollTop = 100;

	var self = this;
	this.ul.addEventListener('scroll', function(e) { self.scroll() }, true);
	window.addEventListener('resize', function(e) { self.resize() }, true);
}

Memory.prototype.scroll = function() {
	while (this.ul.scrollTop - 100 < this.rowHeight) {
		if (this.ul.firstChild.offset == 0) {
			break;
		}
		var victim = this.ul.lastChild;
		this.ul.removeChild(victim);
		victim.offset = this.ul.firstChild.offset - 16;
		this.refresh(victim);
		this.ul.insertBefore(victim, this.ul.firstChild);
		this.ul.scrollTop += this.rowHeight;
	}
	while (this.ul.scrollTop - 100 > this.rowHeight * 2) {
		var victim = this.ul.firstChild;
		this.ul.removeChild(victim);
		victim.offset = this.ul.lastChild.offset + 16;
		this.refresh(victim);
		this.ul.appendChild(victim);
		this.ul.scrollTop -= this.rowHeight;
	}
	if (this.ul.scrollTop < 100) {
		this.ul.scrollTop = 100;
	}
}

Memory.prototype.resize = function() {
	this.numberRows = this.ul.offsetHeight / this.rowHeight + 2;
	if (this.numberRows > this.ul.children.length) {
		var offset = this.ul.lastChild.offset + 16;
		for (var i = 0; i < this.numberRows - this.ul.children.length; ++i) {
			var row = this.createRow(offset);
			this.refresh(row);
			this.ul.appendChild(row);
			offset += 16;
		}
	} else {
		for (var i = 0; i < this.ul.children.length - this.numberRows; ++i) {
			this.ul.removeChild(this.ul.lastChild);
		}
	}
}

Memory.prototype.refresh = function(row) {
	row.firstChild.textContent = hex(row.offset);
	for (var i = 0; i < 16; ++i) {
		try {
			row.children[i + 1].textContent = hex(this.mmu.freeLoadU8(row.offset + i), 2, false);
		} catch (exception) {
			row.children[i + 1].textContent = '??';
		}
	}
}

Memory.prototype.refreshAll = function() {
	for (var i = 0; i < this.ul.children.length; ++i) {
		this.refresh(this.ul.children[i]);
	}
}

Memory.prototype.createRow = function(startOffset) {
	var li = document.createElement('li');
	var offset = document.createElement('span');
	offset.setAttribute('class', 'memoryOffset');
	offset.textContent = hex(startOffset);
	li.appendChild(offset);

	for (var i = 0; i < 16; ++i) {
		var b = document.createElement('span');
		b.textContent = '00';
		b.setAttribute('class', 'memoryCell');
		li.appendChild(b);
	}
	li.offset = startOffset;
	return li;
}

Memory.prototype.scrollTo = function(offset) {
	offset &= 0xFFFFFFF0;
	if (offset) {
		for (var i = 0; i < this.ul.children.length; ++i) {
			var child = this.ul.children[i];
			child.offset = offset + (i - 1) * 16;
			this.refresh(child);
		}
		this.ul.scrollTop = 100+ this.rowHeight;
	} else {
		for (var i = 0; i < this.ul.children.length; ++i) {
			var child = this.ul.children[i];
			child.offset = offset + i * 16;
			this.refresh(child);
		}
		this.ul.scrollTop = 100;
	}
}
<|endoftext|>


<commit_before>;(function () {
  'use strict'

  // -----------------------------------------------------------------------------
  // Show outdated diffs by default

  let outdatedDiffs = document.querySelectorAll('.outdated-diff-comment-container')

  for(let i = 0; i < outdatedDiffs.length; i++) {
    outdatedDiffs[i].classList.add('open')
  }
})()
<commit_msg>Toggle diffs<commit_after>;(function () {
  'use strict'

  var urlObserver = new window.MutationObserver(function(mutations, observer) {
    setTimeout(main)
  })

  urlObserver.observe(document.getElementById('js-pjax-loader-bar'), {
    attributes: true,
    attributeFilter: ['class']
  })

  main()

  function main() {
    // -----------------------------------------------------------------------------
    // Show outdated diffs by default

    let outdatedDiffs = document.querySelectorAll('.outdated-diff-comment-container')

    for(let i = 0; i < outdatedDiffs.length; i++) {
      outdatedDiffs[i].classList.add('open')
    }

    // -----------------------------------------------------------------------------
    // Collapse diffs

    let headers = document.querySelectorAll('.file-header')

    for(let i = 0; i < headers.length; i++) {
      headers[i].addEventListener('click', togglePanel)
      headers[i].style.cursor = 'pointer'
    }

    function togglePanel() {
      let code = nextByClass(this, 'blob-wrapper')
      if (code) {
        code.classList.toggle('hidden')
      }
    }
  }

  // -----------------------------------------------------------------------------
  // Utils

  function nextByClass(node, className) {
    while (node = node.nextSibling) {
      if (node.classList && node.classList.contains(className)) {
        return node
      }
    }
  }

})()
<|endoftext|>


<commit_before>var conf = {
  // Scroll screen interval
  SCR_ITV: 1000,

  // Reposition download button interval
  REPOSITION_ITV: 250,

  // Hide download button after finish timeout
  HIDE_TO: 2500,

  // Get photo data interval
  GET_PHOTO_ITV_H: 1500,
  GET_PHOTO_ITV_L: 250,
  GET_PHOTO_ITV: 250,

  // Get photo data timeout
  GET_PHOTO_TO: 60000
};

var options = {

};

var util = (function() {
  var obj = {};

  obj.processName = function(name) {
    return name.replace(/[\/\\:\*\?<>|"]/g, '');
  };

  return obj;
})();

var view = (function() {
  var obj = {};

  var
    $body,
    $textWrapper,
    $icon,
    $hint,
    $info,
    $btn,
    $progressBar,
    $progressBarText,
    $progressBarWrapper;

  var state = '';

  var disabled = false;

  obj.init = function() {
    state = 'init';
    $body = $('body');

    $('<link />')
      .attr({
        rel: 'stylesheet',
        type: 'text/css',
        href: chrome.extension.getURL('style.css')
      })
      .appendTo('head');

    $btn = $('<div />')
      .attr('id', 'renren_album_downloader_btn');
    $info = $('<div />')
      .attr('id', 'renren_album_downloader_btn_info')
      .appendTo($btn);
    $hint = $('<div />')
      .attr('id', 'renren_album_downloader_btn_hint')
      .addClass('clearFloat')
      .appendTo($btn);
    $icon = $('<div />')
      .attr('id', 'renren_album_downloader_btn_icon')
      .addClass('default')
      .appendTo($hint);
    $textWrapper = $('<div />')
      .attr('id', 'renren_album_downloader_btn_text')
      .html(chrome.i18n.getMessage('hint'))
      .appendTo($hint);
    $btn.appendTo($body);

    $btn.click(function() {
      if (disabled) {
        return;
      }
      disabled = true;
      $btn.addClass('disabled');

      chrome.extension.sendRequest({
        e: 'clickDownload'
      });

      view.start();

      // Switch to thumb view if in comment view
      var $commentViewBtn = $('#tabview_3_3');
      if ($commentViewBtn.hasClass('select-btn')) {
        var $thumbViewBtn = $('#tabview_3_1');
        // Fire click on thumb view button
        var evt = document.createEvent("HTMLEvents");
        evt.initEvent('click', true, true);
        $thumbViewBtn[0].dispatchEvent(evt);
      }

      view.scrollToBottom(function() {
        // Start getting photos
        album.start();
      });
    });

    (function() {
      var oriRight = 24;  // window.parseInt($btn.css('right'));
      var repositionBtn = function() {
        var $friendsPanel = $('#friends-panel');
        var $sidebar = $friendsPanel.children('div');
        if ($friendsPanel.hasClass('side-panel') && $sidebar.hasClass('actived')) {
          // Sidebar is here, watch out
          var newRight = $sidebar.width() + oriRight;
          $btn.css('right', newRight);
        } else {
          $btn.css('right', oriRight);
        }
        window.setTimeout(repositionBtn, conf.REPOSITION_ITV);
      };
      repositionBtn();
    })();
  };

  obj.getBody = function() {
    return $body;
  };

  obj.scrollToBottom = function(callback) {
    state = 'downloading';

    // Scroll to bottom to load all the photo links
    var $window = $(window);
    var
      oriScrollTop = $window.scrollTop(),
      curScrollTop = 0;
    var scrollDown = function() {
      curScrollTop += $window.height();
      if (curScrollTop < $(document).height()) {
        $window.scrollTop(curScrollTop);
        // Continue loop
        window.setTimeout(scrollDown, conf.SCR_ITV);
        return;
      }
      // Loop finished
      // Restore original scroll position
      $window.scrollTop(oriScrollTop);
      callback && callback();
    };
    scrollDown();
  };

  obj.start = function() {
    state = 'analyzing';
    $btn.addClass('expanded');
    $info.html(chrome.i18n.getMessage('msgAnalyzing'));
    for (var i = 0; i < 8; i++) {
      $('<div />').appendTo($icon);
    }
    $icon
      .removeClass('default')
      .removeClass('finished')
      .addClass('spinning');
  };

  var createProgressBar = function() {
    $progressBarWrapper = $('<div />')
      .attr('id', 'renren_album_downloader_progress_bar_wrapper');
    $progressBar = $('<div />')
      .attr('id', 'renren_album_downloader_progress_bar')
      .appendTo($progressBarWrapper);
    $progressBarText = $('<div />')
      .attr('id', 'renren_album_downloader_progress_bar_text')
      .appendTo($progressBarWrapper);
    $progressBarWrapper
      .prependTo($btn)
      .slideDown();
  };

  obj.startDownload = function(ttl) {
    state = 'downloading';
    $info.html(chrome.i18n.getMessage('msgDownloading'));
    createProgressBar();
    this.updateDownloadProgress(0, ttl);
  };

  obj.updateDownloadProgress = function(cur, ttl) {
    $progressBarText.html(chrome.i18n.getMessage('dldProgress', [cur.toString(), ttl.toString()]));
    $progressBar.width((cur / ttl * 100) + '%');
  };

  obj.startZipping = function(callback) {
    state = 'zipping';
    $info.html(chrome.i18n.getMessage('msgZipping'));
    $progressBarWrapper.slideUp(function() {
      $progressBarWrapper.remove();
      callback && callback();
    });
  };

  obj.finish = function() {
    state = 'finished';
    $info.html(chrome.i18n.getMessage('msgFinished'));
    disabled = false;
    $btn.removeClass('disabled');
    $icon
      .removeClass('spinning')
      .addClass('finished')
      .empty();
    window.setTimeout(function() {
      $btn.removeClass('expanded');
    }, conf.HIDE_TO);
  };

  return obj;
})();

var downloader = (function() {
  var obj = {};

  var
    zip = null,
    folder = null,
    zipName = '',
    folderName = '',
    cnt = 0,
    len = 0,
    errList = [];

  var dataURI2Blob = function(dataURI) {
    // by @Stoive from StackOverflow

    // convert base64 to raw binary data held in a string
    // doesn't handle URLEncoded DataURIs
    var byteString = atob(dataURI.split(',')[1]);

    // separate out the mime component
    var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];

    // write the bytes of the string to an ArrayBuffer
    var ab = new ArrayBuffer(byteString.length);
    var ia = new Uint8Array(ab);
    for (var i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
    }

    // write the ArrayBuffer to a blob, and you're done
    var bb = new (window.BlobBuilder || window.WebKitBlobBuilder);
    bb.append(ab);
    return bb.getBlob(mimeString);
  };

  var triggerDownload = function(uri, filename) {
    saveAs(dataURI2Blob(uri), filename);
  };

  var createZip = function(info) {
    zip = new JSZip;
    // Create folder to put picture into
    folder = zip.folder(folderName);
    if (info) {

      $.ajax({
        async: false,
        url: chrome.extension.getURL('info.tmpl.html'),
        success: function(template) {
          var $infoHTML = $.tmpl(template, info);
          folder.file('info.html', $('<div />').append($infoHTML).remove().html());
        }
      });

    }
  };

  var startZipping = function() {
    var errLen = errList.length;
    if (errLen > 0) {
      var errorsTxt = '';
      errorsTxt += chrome.i18n.getMessage('errorTxtDesc');
      errorsTxt += '\r\n\r\n';
      for (var i = 0; i < errLen; i++) {
        errorsTxt += errList[i] + '\r\n';
      }
      folder.file('errors.txt', errorsTxt);
    }
    view.startZipping(function() {
      var uri = 'data:application/zip;base64,' + zip.generate();
      triggerDownload(uri, zipName);
      chrome.extension.sendRequest({
        e: 'finishDownload'
      });
      view.finish();
    });
  };

  obj.onError = function(url) {
    len--;
    // errList.push(url);
    view.updateDownloadProgress(cnt, len);
    if (len === cnt) {
      startZipping();
    }
  };

  obj.add = function(data, photo) {
    cnt++;

    var base64Data = base64ArrayBuffer(data);
    folder.file(photo.filename, base64Data, {base64: true});

    view.updateDownloadProgress(cnt, len);
    if (cnt === len) {
      startZipping();
    }
  };

  obj.init = function(info, folderName_, len_, zipName_) {
    folderName = folderName_;
    len = len_;
    zipName = zipName_;
    cnt = 0;
    zip = null,
    folder = null,
    errList = [];

    // Create zip and folder
    createZip(info);
  };

  return obj;
})();

var album = (function() {
  var obj = {};

  // Array of photo sources
  var
    albumName = '',
    albumDesc = '',  // Album description
    folderName = '',
    photos = [];

  var createInfo = function () {
    var ret = {
      extName: chrome.i18n.getMessage('extName'),
      title: albumName,
      desc: albumDesc,
      url: window.location.href,
      urlText: chrome.i18n.getMessage('infoAlbumLinkText'),
      photos: []
    }
    var len = photos.length;
    for (var idx = 1; idx <= len; idx++) {
      for (var i = 0; i < len; i++) {
        // Double loop to make sure photos are pushed in order
        if (photos[i].idx === idx) {
          ret.photos.push({
            idx: idx,
            title: photos[i].title,
            filename: photos[i].filename,
            pageUrl: photos[i].pageUrl
          });
          break;
        }
      }
    }
    return ret;
  };

  var downloadPhotos = function() {
    var len = photos.length;  // Number of photos
    view.startDownload(len);

    chrome.extension.sendRequest({
      e: 'startDownload',
      opt: {
        num: len
      }
    });

    downloader.init(createInfo(), folderName, len, albumName + '.zip');

    // Get the image data of each photo and send to downloader
    var cnt = 0;  // Counts downloaded photos
    var addToQueue = function(idx) {
      if (idx >= len) {
        return;
      }
      (function() {
        var photo = photos[idx];
        if (options.originalSize === 'true') {
          var urlArr = [photo.src.original, photo.src.xlarge, photo.src.large];
        } else {
          var urlArr = [photo.src.large];
        }

        var ajaxPhoto = function(urlArr) {
          $.ajax({
            url: urlArr[0],
            type: 'GET',
            error: function(jqXHR) {
              if (jqXHR.status === 404 && urlArr.length > 1) {
                urlArr.shift();
                ajaxPhoto(urlArr);
                return;
              }
              downloader.onError();
            },
            success: function(data) {
              cnt++;
              downloader.add(data, photo);

              // Adjust GET_PHOTO_ITV
              conf.GET_PHOTO_ITV = data.byteLength > 1048576 ? conf.GET_PHOTO_ITV_H : conf.GET_PHOTO_ITV_L;
              data = null;
            },
            dataType: 'binary',
            timeout: conf.GET_PHOTO_TO
          });
        };

        ajaxPhoto(urlArr);
      })();
      window.setTimeout(function() {
        addToQueue(idx + 1);
      }, conf.GET_PHOTO_ITV);
    };
    addToQueue(0);
  };

  obj.start = function() {
    // Parse album id, name and description

    if (window.location.pathname.indexOf('getalbumprofile.do') !== -1){
      // profile album
      var userId = window.location.search.match(/owner=\d+/)[0].match(/\d+/)[0];
      folderName = 'renren-album-profile-' + userId;
    } else {
      var albumId = window.location.pathname.match(/album-\d+/)[0].match(/\d+/)[0];
      folderName = 'renren-album-' + albumId;
    }
    var $albumInfo = $('div.ablum-infor');
    albumName = $albumInfo.children('h1').contents()[0].data;
    albumDesc = $.trim($('#describeAlbum').contents()[0].data);
    (albumDesc === '还没有相册描述...') && (albumDesc = '');

    // Get all the sources and put in photos array
    photos = [];
    var cnt = 0;
    var $photoItems = $('div.photo-list li');
    if ($photoItems.length === 0) {
      // No photos to download
      // TODO
      return;
    }

    $photoItems.each(function(idx, ele) {
      var $ele = $(ele);
      var $a = $ele.children('a.picture');
      var pageUrl = $a.attr('href');

      var $img = $a.children('img');
      var src = (function() {
        eval('var obj = ' + $img.attr('data-photo'));
        var large = obj.large;

        // replace '/large' with '/original' or '/xlarge' to get larger img
        var original = large.replace('/large', '/original');
        var xlarge = large.replace('/large', '/xlarge');
        return {
          large: large,
          xlarge: xlarge,
          original: original
        };
      })();
      var ext = src.large.match(/.\w{3,4}$/)[0];

      var $desc = $ele.find('span.descript');
      var title = $desc.length ? $desc.text() : '';

      photos.push({
        src: src,
        title: title,
        filename: (idx + 1) + ext,
        idx: idx + 1,
        pageUrl: pageUrl
      });
    });

    downloadPhotos();
  };

  return obj;
})();

chrome.extension.sendRequest({
  e: 'visitAlbum'
});

// get options from local storage
chrome.extension.sendRequest({
  e: 'getOption',
  name: 'originalSize'
}, function(response) {
  options.originalSize = response.value;
});

view.init();<commit_msg>fixed float button position with side panel<commit_after>var conf = {
  // Scroll screen interval
  SCR_ITV: 1000,

  // Reposition download button interval
  REPOSITION_ITV: 250,

  // Hide download button after finish timeout
  HIDE_TO: 2500,

  // Get photo data interval
  GET_PHOTO_ITV_H: 1500,
  GET_PHOTO_ITV_L: 250,
  GET_PHOTO_ITV: 250,

  // Get photo data timeout
  GET_PHOTO_TO: 60000
};

var options = {

};

var util = (function() {
  var obj = {};

  obj.processName = function(name) {
    return name.replace(/[\/\\:\*\?<>|"]/g, '');
  };

  return obj;
})();

var view = (function() {
  var obj = {};

  var
    $body,
    $textWrapper,
    $icon,
    $hint,
    $info,
    $btn,
    $progressBar,
    $progressBarText,
    $progressBarWrapper;

  var state = '';

  var disabled = false;

  obj.init = function() {
    state = 'init';
    $body = $('body');

    $('<link />')
      .attr({
        rel: 'stylesheet',
        type: 'text/css',
        href: chrome.extension.getURL('style.css')
      })
      .appendTo('head');

    $btn = $('<div />')
      .attr('id', 'renren_album_downloader_btn');
    $info = $('<div />')
      .attr('id', 'renren_album_downloader_btn_info')
      .appendTo($btn);
    $hint = $('<div />')
      .attr('id', 'renren_album_downloader_btn_hint')
      .addClass('clearFloat')
      .appendTo($btn);
    $icon = $('<div />')
      .attr('id', 'renren_album_downloader_btn_icon')
      .addClass('default')
      .appendTo($hint);
    $textWrapper = $('<div />')
      .attr('id', 'renren_album_downloader_btn_text')
      .html(chrome.i18n.getMessage('hint'))
      .appendTo($hint);
    $btn.appendTo($body);

    $btn.click(function() {
      if (disabled) {
        return;
      }
      disabled = true;
      $btn.addClass('disabled');

      chrome.extension.sendRequest({
        e: 'clickDownload'
      });

      view.start();

      // Switch to thumb view if in comment view
      var $commentViewBtn = $('#tabview_3_3');
      if ($commentViewBtn.hasClass('select-btn')) {
        var $thumbViewBtn = $('#tabview_3_1');
        // Fire click on thumb view button
        var evt = document.createEvent("HTMLEvents");
        evt.initEvent('click', true, true);
        $thumbViewBtn[0].dispatchEvent(evt);
      }

      view.scrollToBottom(function() {
        // Start getting photos
        album.start();
      });
    });

    (function() {
      var oriRight = 24;  // window.parseInt($btn.css('right'));
      var repositionBtn = function() {
        var $friendsPanel = $('#friends-panel');
        var $sidebar = $friendsPanel.children('div');
        if ($friendsPanel.hasClass('side-panel') && $sidebar.hasClass('actived')) {
          // Sidebar is here, watch out
          var newRight = $sidebar.filter('.actived').width() + oriRight;
          $btn.css('right', newRight);
        } else {
          $btn.css('right', oriRight);
        }
        window.setTimeout(repositionBtn, conf.REPOSITION_ITV);
      };
      repositionBtn();
    })();
  };

  obj.getBody = function() {
    return $body;
  };

  obj.scrollToBottom = function(callback) {
    state = 'downloading';

    // Scroll to bottom to load all the photo links
    var $window = $(window);
    var
      oriScrollTop = $window.scrollTop(),
      curScrollTop = 0;
    var scrollDown = function() {
      curScrollTop += $window.height();
      if (curScrollTop < $(document).height()) {
        $window.scrollTop(curScrollTop);
        // Continue loop
        window.setTimeout(scrollDown, conf.SCR_ITV);
        return;
      }
      // Loop finished
      // Restore original scroll position
      $window.scrollTop(oriScrollTop);
      callback && callback();
    };
    scrollDown();
  };

  obj.start = function() {
    state = 'analyzing';
    $btn.addClass('expanded');
    $info.html(chrome.i18n.getMessage('msgAnalyzing'));
    for (var i = 0; i < 8; i++) {
      $('<div />').appendTo($icon);
    }
    $icon
      .removeClass('default')
      .removeClass('finished')
      .addClass('spinning');
  };

  var createProgressBar = function() {
    $progressBarWrapper = $('<div />')
      .attr('id', 'renren_album_downloader_progress_bar_wrapper');
    $progressBar = $('<div />')
      .attr('id', 'renren_album_downloader_progress_bar')
      .appendTo($progressBarWrapper);
    $progressBarText = $('<div />')
      .attr('id', 'renren_album_downloader_progress_bar_text')
      .appendTo($progressBarWrapper);
    $progressBarWrapper
      .prependTo($btn)
      .slideDown();
  };

  obj.startDownload = function(ttl) {
    state = 'downloading';
    $info.html(chrome.i18n.getMessage('msgDownloading'));
    createProgressBar();
    this.updateDownloadProgress(0, ttl);
  };

  obj.updateDownloadProgress = function(cur, ttl) {
    $progressBarText.html(chrome.i18n.getMessage('dldProgress', [cur.toString(), ttl.toString()]));
    $progressBar.width((cur / ttl * 100) + '%');
  };

  obj.startZipping = function(callback) {
    state = 'zipping';
    $info.html(chrome.i18n.getMessage('msgZipping'));
    $progressBarWrapper.slideUp(function() {
      $progressBarWrapper.remove();
      callback && callback();
    });
  };

  obj.finish = function() {
    state = 'finished';
    $info.html(chrome.i18n.getMessage('msgFinished'));
    disabled = false;
    $btn.removeClass('disabled');
    $icon
      .removeClass('spinning')
      .addClass('finished')
      .empty();
    window.setTimeout(function() {
      $btn.removeClass('expanded');
    }, conf.HIDE_TO);
  };

  return obj;
})();

var downloader = (function() {
  var obj = {};

  var
    zip = null,
    folder = null,
    zipName = '',
    folderName = '',
    cnt = 0,
    len = 0,
    errList = [];

  var dataURI2Blob = function(dataURI) {
    // by @Stoive from StackOverflow

    // convert base64 to raw binary data held in a string
    // doesn't handle URLEncoded DataURIs
    var byteString = atob(dataURI.split(',')[1]);

    // separate out the mime component
    var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];

    // write the bytes of the string to an ArrayBuffer
    var ab = new ArrayBuffer(byteString.length);
    var ia = new Uint8Array(ab);
    for (var i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
    }

    // write the ArrayBuffer to a blob, and you're done
    var bb = new (window.BlobBuilder || window.WebKitBlobBuilder);
    bb.append(ab);
    return bb.getBlob(mimeString);
  };

  var triggerDownload = function(uri, filename) {
    saveAs(dataURI2Blob(uri), filename);
  };

  var createZip = function(info) {
    zip = new JSZip;
    // Create folder to put picture into
    folder = zip.folder(folderName);
    if (info) {

      $.ajax({
        async: false,
        url: chrome.extension.getURL('info.tmpl.html'),
        success: function(template) {
          var $infoHTML = $.tmpl(template, info);
          folder.file('info.html', $('<div />').append($infoHTML).remove().html());
        }
      });

    }
  };

  var startZipping = function() {
    var errLen = errList.length;
    if (errLen > 0) {
      var errorsTxt = '';
      errorsTxt += chrome.i18n.getMessage('errorTxtDesc');
      errorsTxt += '\r\n\r\n';
      for (var i = 0; i < errLen; i++) {
        errorsTxt += errList[i] + '\r\n';
      }
      folder.file('errors.txt', errorsTxt);
    }
    view.startZipping(function() {
      var uri = 'data:application/zip;base64,' + zip.generate();
      triggerDownload(uri, zipName);
      chrome.extension.sendRequest({
        e: 'finishDownload'
      });
      view.finish();
    });
  };

  obj.onError = function(url) {
    len--;
    // errList.push(url);
    view.updateDownloadProgress(cnt, len);
    if (len === cnt) {
      startZipping();
    }
  };

  obj.add = function(data, photo) {
    cnt++;

    var base64Data = base64ArrayBuffer(data);
    folder.file(photo.filename, base64Data, {base64: true});

    view.updateDownloadProgress(cnt, len);
    if (cnt === len) {
      startZipping();
    }
  };

  obj.init = function(info, folderName_, len_, zipName_) {
    folderName = folderName_;
    len = len_;
    zipName = zipName_;
    cnt = 0;
    zip = null,
    folder = null,
    errList = [];

    // Create zip and folder
    createZip(info);
  };

  return obj;
})();

var album = (function() {
  var obj = {};

  // Array of photo sources
  var
    albumName = '',
    albumDesc = '',  // Album description
    folderName = '',
    photos = [];

  var createInfo = function () {
    var ret = {
      extName: chrome.i18n.getMessage('extName'),
      title: albumName,
      desc: albumDesc,
      url: window.location.href,
      urlText: chrome.i18n.getMessage('infoAlbumLinkText'),
      photos: []
    }
    var len = photos.length;
    for (var idx = 1; idx <= len; idx++) {
      for (var i = 0; i < len; i++) {
        // Double loop to make sure photos are pushed in order
        if (photos[i].idx === idx) {
          ret.photos.push({
            idx: idx,
            title: photos[i].title,
            filename: photos[i].filename,
            pageUrl: photos[i].pageUrl
          });
          break;
        }
      }
    }
    return ret;
  };

  var downloadPhotos = function() {
    var len = photos.length;  // Number of photos
    view.startDownload(len);

    chrome.extension.sendRequest({
      e: 'startDownload',
      opt: {
        num: len
      }
    });

    downloader.init(createInfo(), folderName, len, albumName + '.zip');

    // Get the image data of each photo and send to downloader
    var cnt = 0;  // Counts downloaded photos
    var addToQueue = function(idx) {
      if (idx >= len) {
        return;
      }
      (function() {
        var photo = photos[idx];
        if (options.originalSize === 'true') {
          var urlArr = [photo.src.original, photo.src.xlarge, photo.src.large];
        } else {
          var urlArr = [photo.src.large];
        }

        var ajaxPhoto = function(urlArr) {
          $.ajax({
            url: urlArr[0],
            type: 'GET',
            error: function(jqXHR) {
              if (jqXHR.status === 404 && urlArr.length > 1) {
                urlArr.shift();
                ajaxPhoto(urlArr);
                return;
              }
              downloader.onError();
            },
            success: function(data) {
              cnt++;
              downloader.add(data, photo);

              // Adjust GET_PHOTO_ITV
              conf.GET_PHOTO_ITV = data.byteLength > 1048576 ? conf.GET_PHOTO_ITV_H : conf.GET_PHOTO_ITV_L;
              data = null;
            },
            dataType: 'binary',
            timeout: conf.GET_PHOTO_TO
          });
        };

        ajaxPhoto(urlArr);
      })();
      window.setTimeout(function() {
        addToQueue(idx + 1);
      }, conf.GET_PHOTO_ITV);
    };
    addToQueue(0);
  };

  obj.start = function() {
    // Parse album id, name and description

    if (window.location.pathname.indexOf('getalbumprofile.do') !== -1){
      // profile album
      var userId = window.location.search.match(/owner=\d+/)[0].match(/\d+/)[0];
      folderName = 'renren-album-profile-' + userId;
    } else {
      var albumId = window.location.pathname.match(/album-\d+/)[0].match(/\d+/)[0];
      folderName = 'renren-album-' + albumId;
    }
    var $albumInfo = $('div.ablum-infor');
    albumName = $albumInfo.children('h1').contents()[0].data;
    albumDesc = $.trim($('#describeAlbum').contents()[0].data);
    (albumDesc === '还没有相册描述...') && (albumDesc = '');

    // Get all the sources and put in photos array
    photos = [];
    var cnt = 0;
    var $photoItems = $('div.photo-list li');
    if ($photoItems.length === 0) {
      // No photos to download
      // TODO
      return;
    }

    $photoItems.each(function(idx, ele) {
      var $ele = $(ele);
      var $a = $ele.children('a.picture');
      var pageUrl = $a.attr('href');

      var $img = $a.children('img');
      var src = (function() {
        eval('var obj = ' + $img.attr('data-photo'));
        var large = obj.large;

        // replace '/large' with '/original' or '/xlarge' to get larger img
        var original = large.replace('/large', '/original');
        var xlarge = large.replace('/large', '/xlarge');
        return {
          large: large,
          xlarge: xlarge,
          original: original
        };
      })();
      var ext = src.large.match(/.\w{3,4}$/)[0];

      var $desc = $ele.find('span.descript');
      var title = $desc.length ? $desc.text() : '';

      photos.push({
        src: src,
        title: title,
        filename: (idx + 1) + ext,
        idx: idx + 1,
        pageUrl: pageUrl
      });
    });

    downloadPhotos();
  };

  return obj;
})();

chrome.extension.sendRequest({
  e: 'visitAlbum'
});

// get options from local storage
chrome.extension.sendRequest({
  e: 'getOption',
  name: 'originalSize'
}, function(response) {
  options.originalSize = response.value;
});

view.init();<|endoftext|>


<commit_before>$(document).ready(function() {
  // get card name from page text
  var name = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_nameRow > .value");

  // get card set from page text
  var set = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_setRow > .value");

  // Handle double-sided cards and split cards
  var second_name;
  if (name.text().length == 0) {
    name = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl07_nameRow > .value");
    set = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl07_setRow > .value");

    // Set up Split card names in case this is a Split card
    second_name = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl08_nameRow > .value");

    // Sometimes split cards use ctl09 and ctl10
    if (name.text().length == 0) {
      name = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl09_nameRow > .value");
      set = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl09_setRow > .value");
      second_name = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl10_nameRow > .value");
    }

    // Sometimes split cards use ctl02 and ctl03
    if (name.text().length == 0) {
      name = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl02_nameRow > .value");
      set = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl02_setRow > .value");
      second_name = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl03_nameRow > .value");
    }

    // Sometimes split cards use ctl03 and ctl04
    if (name.text().length == 0) {
      name = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl03_nameRow > .value");
      set = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl03_setRow > .value");
      second_name = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl04_nameRow > .value");
    }
  }

  // trim spaces and handle AE characters
  set = $.trim(set.text());
  name = escape($.trim(name.text())).replace('%C6', 'AE');
  if (second_name) {
    second_name = escape($.trim(second_name.text())).replace('%C6', 'AE');
  }

  var split_name_1 = name + '+%2f%2f+' + second_name
  var split_name_2 = second_name + '+%2f%2f+' + name

  // set null variables
  var hiprice = null;
  var lowprice = null;
  var avgprice = null;
  var foilavgprice = null;
  var storelink = null;

  // Transform bad set names into applicable set names
  var set_map = {};
  set_map['Limited Edition Alpha'] = 'Alpha Edition';
  set_map['Limited Edition Beta'] = 'Beta Edition';
  set_map['Seventh Edition'] = '7th Edition';
  set_map['Eighth Edition'] = '8th Edition';
  set_map['Ninth Edition'] = '9th Edition';
  set_map['Tenth Edition'] = '10th Edition';
  set_map['Planechase 2012 Edition'] = 'Planechase 2012';
  set_map['Commander 2013 Edition'] = 'Commander 2013';
  set_map['Ravnica: City of Guilds'] = 'Ravnica';
  set_map['Time Spiral "Timeshifted"'] = 'Timeshifted';
  set_map['Promo set for Gatherer'] = 'Media Promos';

  if (set_map[set] != undefined) { set = set_map[set] };

  set = set.replace(/Magic: The Gathering\b\S\b/, '');
  set = set.replace(' vs. ', ' vs ');

  m = set.match(/Magic 20(\d\d)/);
  if (m != null) {
    year = m[1];
    if (typeof(year) == "string") { set = "Magic 20" + year + " (M" + year + ")";};
  };

  // Append the price div to the left column
  var price_div = $('

')
  $(".leftCol").append(price_div);

  // Prepare variables needed for API query
  var url = generateTCGPlayerUrl(set, name);

  // Query TCGplayer's Hi-Mid-Low API
  $.get(url, function(xml) {
    if ($(xml).find("error").text() == "") {
      displayPrices(xml);
    } else {
      // If failed, try again, but without Set name (gives average for all sets)
      url = generateTCGPlayerUrl("", name);
      $.get(url, function(xml) {
        if ($(xml).find("error").text() == "") {
          displayAvgPricesForAllSets(xml);
        } else {
          // If failed, maybe it's a Split card
          url = generateTCGPlayerUrl(set, split_name_1);
          $.get(url, function(xml) {
            if ($(xml).find("error").text() == "") {
              displayPrices(xml);
            } else {
              // If failed, maybe the split card names are backwards
              url = generateTCGPlayerUrl(set, split_name_2);
              $.get(url, function(xml) {
                if ($(xml).find("error").text() == "") {
                  displayPrices(xml);
                } else {
                  // If still failed, give up and print an error
                  $(".leftCol").append('
Sorry, an error occured fetching price data
');
                }
              });
            }
          });
        }
      });
    }
  });

  // send message to the extension containing the card ID and Name
  chrome.runtime.sendMessage(
  {
    cardinfo:
    {
      cardname: name,
      cardset:  set,
    }
  }, function(response) {
    // do stuff?
  });

})

function generateTCGPlayerUrl(set, cardName) {
  return "http://partner.tcgplayer.com/x3/phl.asmx/p?pk=GATHPRICE&s=" + set + "&p=" + cardName;
}

function displayPrices(xml) {
  hiprice = "$" + $(xml).find("hiprice").text();
  lowprice = "$" + $(xml).find("lowprice").text();
  avgprice = "$" + $(xml).find("avgprice").text();
  foilavgprice = "$" + $(xml).find("foilavgprice").text();
  storelink = $(xml).find("link").text();

  if (hiprice == "$0") { hiprice = "Unavailable" };
  if (lowprice == "$0") { lowprice = "Unavailable" };
  if (avgprice == "$0") { avgprice = "Unavailable" };
  if (foilavgprice == "$0") { foilavgprice = "N/A" };

  // Add the price data to the price div on the page
  $('.price').append(
    '
' +
      '
H: ' + hiprice + '
' +
      '
M: ' + avgprice + '
' +
      '
L: ' + lowprice + '
' +
    '
' +
    '
Foil M: ' + foilavgprice + '
'
  );

  // Set the widths for the price elements based on the price div
  stylePrices();
}

function displayAvgPricesForAllSets(xml) {
  displayPrices(xml);
  $('.price').css('font-style', 'italic')
  var footnote_msg = 'These prices are aggregated over all available printings of this card, because the printing you selected does not have any available pricing data.';
  var footnote = $('
Why are the prices in italics?
');
  $('.leftCol').append(footnote);
  $(footnote).click( function() { alert(footnote_msg) } );
};

function splitCSS() {
  $('.hiprice').css('width', 107);
  $('.avgprice').css('width', 106);
  $('.lowprice').css('width', 107);
}

function stylePrices() {
  var width = $('.price').width() / 3
  var fl = Math.floor(width)
  var cl = Math.ceil(width)
  var rnd = Math.round(width)

  $('.hiprice').css('width', rnd);
  $('.lowprice').css('width', rnd);

  if (rnd == cl) { $('.avgprice').css('width', fl) };
  if (rnd == fl) { $('.avgprice').css('width', cl) };

  // The new Gatherer layout has weird font color handling, so we need to do this here
  $('.price a').css('color', 'black');
}
<commit_msg>Refactor the code to be slightly less disgusting<commit_after>$(document).ready(function() {
  // get card name from page text
  var name = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_nameRow > .value");

  // get card set from page text
  var set = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_setRow > .value");

  // Handle double-sided cards and split cards
  var second_name;
  if (name.text().length == 0) {
    name = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl07_nameRow > .value");
    set = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl07_setRow > .value");

    // Set up Split card names in case this is a Split card
    second_name = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl08_nameRow > .value");

    // Sometimes split cards use ctl09 and ctl10
    if (name.text().length == 0) {
      name = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl09_nameRow > .value");
      set = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl09_setRow > .value");
      second_name = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl10_nameRow > .value");
    }

    // Sometimes split cards use ctl02 and ctl03
    if (name.text().length == 0) {
      name = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl02_nameRow > .value");
      set = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl02_setRow > .value");
      second_name = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl03_nameRow > .value");
    }

    // Sometimes split cards use ctl03 and ctl04
    if (name.text().length == 0) {
      name = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl03_nameRow > .value");
      set = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl03_setRow > .value");
      second_name = $("#ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl04_nameRow > .value");
    }
  }

  // trim spaces and handle AE characters
  set = $.trim(set.text());
  name = escape($.trim(name.text())).replace('%C6', 'AE');
  if (second_name) {
    second_name = escape($.trim(second_name.text())).replace('%C6', 'AE');
  }

  var split_name_1 = name + '+%2f%2f+' + second_name
  var split_name_2 = second_name + '+%2f%2f+' + name

  // set null variables
  var hiprice = null;
  var lowprice = null;
  var avgprice = null;
  var foilavgprice = null;
  var storelink = null;

  // Transform bad set names into applicable set names
  var set_map = {};
  set_map['Limited Edition Alpha'] = 'Alpha Edition';
  set_map['Limited Edition Beta'] = 'Beta Edition';
  set_map['Seventh Edition'] = '7th Edition';
  set_map['Eighth Edition'] = '8th Edition';
  set_map['Ninth Edition'] = '9th Edition';
  set_map['Tenth Edition'] = '10th Edition';
  set_map['Planechase 2012 Edition'] = 'Planechase 2012';
  set_map['Commander 2013 Edition'] = 'Commander 2013';
  set_map['Ravnica: City of Guilds'] = 'Ravnica';
  set_map['Time Spiral "Timeshifted"'] = 'Timeshifted';
  set_map['Promo set for Gatherer'] = 'Media Promos';

  if (set_map[set] != undefined) { set = set_map[set] };

  set = set.replace(/Magic: The Gathering\b\S\b/, '');
  set = set.replace(' vs. ', ' vs ');

  m = set.match(/Magic 20(\d\d)/);
  if (m != null) {
    year = m[1];
    if (typeof(year) == "string") { set = "Magic 20" + year + " (M" + year + ")";};
  };

  // Append the price div to the left column
  var price_div = $('

')
  $(".leftCol").append(price_div);

  // Prepare variables needed for API query
  var url = generateTCGPlayerUrl(set, name);

  // Query TCGplayer's Hi-Mid-Low API
  $.get(url).done(function(xml) {
    handleApiResponse(xml, displayPrices, function() {
      // If failed, try again, but without Set name (gives average for all sets)
      url = generateTCGPlayerUrl("", name);
      $.get(url).done(function(xml) {
        handleApiResponse(xml, displayAvgPricesForAllSets, function() {
          // If failed, maybe it's a Split card
          url = generateTCGPlayerUrl(set, split_name_1);
          $.get(url).done(function(xml) {
            handleApiResponse(xml, displayPrices, function() {
              // If failed, maybe the split card names are backwards
              url = generateTCGPlayerUrl(set, split_name_2);
              $.get(url).done(function(xml) {
                handleApiResponse(xml, displayPrices, function() {
                  // If still failed, give up and print an error
                  $(".leftCol").append('
Sorry, an error occured fetching price data
');
                });
              });
            });
          });
        });
      });
    });
  });

  // send message to the extension containing the card ID and Name
  chrome.runtime.sendMessage(
  {
    cardinfo:
    {
      cardname: name,
      cardset:  set,
    }
  }, function(response) {
    // do stuff?
  });

})

function generateTCGPlayerUrl(set, cardName) {
  return "http://partner.tcgplayer.com/x3/phl.asmx/p?pk=GATHPRICE&s=" + set + "&p=" + cardName;
}

function handleApiResponse(xml, successFn, failFn) {
  if ($(xml).find("error").text() == "") {
    successFn(xml);
  } else {
    failFn();
  }
}

function displayPrices(xml) {
  hiprice = "$" + $(xml).find("hiprice").text();
  lowprice = "$" + $(xml).find("lowprice").text();
  avgprice = "$" + $(xml).find("avgprice").text();
  foilavgprice = "$" + $(xml).find("foilavgprice").text();
  storelink = $(xml).find("link").text();

  if (hiprice == "$0") { hiprice = "Unavailable" };
  if (lowprice == "$0") { lowprice = "Unavailable" };
  if (avgprice == "$0") { avgprice = "Unavailable" };
  if (foilavgprice == "$0") { foilavgprice = "N/A" };

  // Add the price data to the price div on the page
  $('.price').append(
    '
' +
      '
H: ' + hiprice + '
' +
      '
M: ' + avgprice + '
' +
      '
L: ' + lowprice + '
' +
    '
' +
    '
Foil M: ' + foilavgprice + '
'
  );

  // Set the widths for the price elements based on the price div
  stylePrices();
}

function displayAvgPricesForAllSets(xml) {
  displayPrices(xml);
  $('.price').css('font-style', 'italic')
  var footnote_msg = 'These prices are aggregated over all available printings of this card, because the printing you selected does not have any available pricing data.';
  var footnote = $('
Why are the prices in italics?
');
  $('.leftCol').append(footnote);
  $(footnote).click( function() { alert(footnote_msg) } );
};

function splitCSS() {
  $('.hiprice').css('width', 107);
  $('.avgprice').css('width', 106);
  $('.lowprice').css('width', 107);
}

function stylePrices() {
  var width = $('.price').width() / 3
  var fl = Math.floor(width)
  var cl = Math.ceil(width)
  var rnd = Math.round(width)

  $('.hiprice').css('width', rnd);
  $('.lowprice').css('width', rnd);

  if (rnd == cl) { $('.avgprice').css('width', fl) };
  if (rnd == fl) { $('.avgprice').css('width', cl) };

  // The new Gatherer layout has weird font color handling, so we need to do this here
  $('.price a').css('color', 'black');
}
<|endoftext|>


<commit_before>/*! quark 2.1.2 (https://github.com/pyrsmk/quark) */

/*
	Retrieve only one node

	Parameters
		String, Object, Function spec

	Return
		Object
*/
var $ = function(spec) {
	var quark;
	// Readiness
	if(typeof spec == 'function') {
		return $._whenReady(spec);
	}
	else if(typeof spec == 'string') {
		// Create new node
		if(/</.test(spec)) {
			quark = node2quark($._createNode(spec)[0]);
		}
		// Get node
		else {
			quark = node2quark($._selectNode(spec));
		}
	}
	else if (typeof spec == 'object' && spec !== null && 'length' in spec) {
		quark = node2quark(spec[0]);
	}
	else {
		quark = node2quark(spec);
	}
	// Convert and return node
	return quark;
},

/*
	Retrieve a list of nodes

	Parameters
		String, Array spec
		Boolean raw

	Return
		Object
*/
$$ = function(spec, raw) {
	var quarks = [],
		i, j;
	raw = (typeof raw == 'undefined' ? false : !!raw);
	quarks.quarked = true;
	if(typeof spec == 'string') {
		// Create new nodes
		if(/</.test(spec)) {
			spec = $._createNodes(spec);
		}
		// Get nodes
		else{
			spec = $._selectNodes(spec);
		}
	}
	// Convert nodes
	if(typeof spec == 'object' && spec !== null && 'length' in spec) {
		for(i = 0, j = spec.length; i < j; ++i) {
			quarks.push(!raw ? node2quark(spec[i]) : spec[i]);
		}
	}
	// Quarked node
	else if (typeof spec == 'object' && 'quarked' in spec) {
		quarks.push(spec);
	}
	// Add global methods
	for(i in $._nodeMethods) {
		quarks[i] = function(quarks, method) {
			return function() {
				var results = [], results2, i, j, k, l;
				for(i = 0, j = quarks.length; i < j; ++i) {
					results.push(method.apply(quarks[i], arguments));
				}
				if(results.length) {
					// Quark nodes detected, return them
					if(
						typeof results[0] == 'object' &&
						spec !== null &&
						'length' in results[0] &&
						results[0].length
					) {
						if('quarked' in results[0][0]) {
							results2 = [];
							for(i = 0, j = results.length; i < j; ++i) {
								for(k = 0, l = results[i].length; k < l; ++k) {
									results2.push(results[i][k]);
								}
							}
							return $$(results2);
						}
					}
					else if((typeof results[0] == 'object') && ('quarked' in results[0])) {
						results2 = [];
						for(i = 0, j = results.length; i < j; ++i) {
							results2.push(results[i]);
						}
						return $$(results2);
					}
					// Return the first result
					return results[0];
				}
				// No returned value, return $$()
				return quarks;
			};
		}(quarks, $._nodeMethods[i]);
	}
	// Add the 'forEach' method
	quarks.forEach = function(quarks) {
		return function(func) {
			var i = -1;
			while(quarks[++i]) {
				func.apply(quarks[i], [i]);
			}
			return quarks;
		};
	}(quarks);
	// Return nodes
	return quarks;
},

/*
	Convert regular node to quark

	Parameters
		Object node

	Return
		Object
*/
node2quark = function(node) {
	var quark = {node: null, quarked: true}, i;
	// Create a dummy node
	if((typeof node != 'object') || (node === null)) {
		var func = function(){};
		for(i in $._nodeMethods){
			quark[i] = func;
		}
	}
	// Create quark node
	else if(!('quarked' in node)) {
		quark.node = node;
		for(i in $._nodeMethods) {
			quark[i] = function(quark, method) {
				return function() {
					return method.apply(quark, arguments);
				};
			}(quark, $._nodeMethods[i]);
		}
	}
	else {
		quark = node;
	}
	return quark;
};

// Define default methods

$._whenReady = function(func) {
	if(document.readyState == 'complete') {
		func();
	}
	else {
		document.addEventListener('DOMContentLoaded', func);
	}
};

$._selectNode = function(selector) {
	return document.querySelector(selector);
};

$._selectNodes = function(selector) {
	return document.querySelectorAll(selector);
};

$._createNode = function(html) {
	var node = document.createElement('div'),
		nodelist = [];
	node.innerHTML = html;
	return node.firstChild;
};

$._createNodes = function(html) {
	var node = document.createElement('div'),
		nodelist = [];
	node.innerHTML = html;
	node = node.firstChild;
	nodelist.push(node);
	while(node = node.nextSibling) {
		nodelist.push(node);
	}
	return nodelist;
};

$._nodeMethods = {
	findOne: function(selector) {
		if('querySelector' in this.node) {
			return $(this.node.querySelector(selector));
		}
		else {
			return $();
		}
	},
	findAll: function(selector) {
		if('querySelectorAll' in this.node) {
			return $$(this.node.querySelectorAll(selector));
		}
		else {
			return $$([]);
		}
	}
};

// Export
return {
	$ : $,
	$$ : $$
};
<commit_msg>Fix window handling<commit_after>/*! quark 2.1.2 (https://github.com/pyrsmk/quark) */

/*
	Retrieve only one node

	Parameters
		String, Object, Function spec

	Return
		Object
*/
var $ = function(spec) {
	var quark;
	// Readiness
	if(typeof spec == 'function') {
		return $._whenReady(spec);
	}
	else if(typeof spec == 'string') {
		// Create new node
		if(/</.test(spec)) {
			quark = node2quark($._createNode(spec)[0]);
		}
		// Get node
		else {
			quark = node2quark($._selectNode(spec));
		}
	}
	else if (typeof spec == 'object' && spec !== null && spec !== window && 'length' in spec) {
		quark = node2quark(spec[0]);
	}
	else {
		quark = node2quark(spec);
	}
	// Convert and return node
	return quark;
},

/*
	Retrieve a list of nodes

	Parameters
		String, Array spec
		Boolean raw

	Return
		Object
*/
$$ = function(spec, raw) {
	var quarks = [],
		i, j;
	raw = (typeof raw == 'undefined' ? false : !!raw);
	quarks.quarked = true;
	if(typeof spec == 'string') {
		// Create new nodes
		if(/</.test(spec)) {
			spec = $._createNodes(spec);
		}
		// Get nodes
		else{
			spec = $._selectNodes(spec);
		}
	}
	// Convert nodes
	if(typeof spec == 'object' && spec !== null && 'length' in spec) {
		for(i = 0, j = spec.length; i < j; ++i) {
			quarks.push(!raw ? node2quark(spec[i]) : spec[i]);
		}
	}
	// Quarked node
	else if (typeof spec == 'object' && 'quarked' in spec) {
		quarks.push(spec);
	}
	// Add global methods
	for(i in $._nodeMethods) {
		quarks[i] = function(quarks, method) {
			return function() {
				var results = [], results2, i, j, k, l;
				for(i = 0, j = quarks.length; i < j; ++i) {
					results.push(method.apply(quarks[i], arguments));
				}
				if(results.length) {
					// Quark nodes detected, return them
					if(
						typeof results[0] == 'object' &&
						spec !== null &&
						'length' in results[0] &&
						results[0].length
					) {
						if('quarked' in results[0][0]) {
							results2 = [];
							for(i = 0, j = results.length; i < j; ++i) {
								for(k = 0, l = results[i].length; k < l; ++k) {
									results2.push(results[i][k]);
								}
							}
							return $$(results2);
						}
					}
					else if((typeof results[0] == 'object') && ('quarked' in results[0])) {
						results2 = [];
						for(i = 0, j = results.length; i < j; ++i) {
							results2.push(results[i]);
						}
						return $$(results2);
					}
					// Return the first result
					return results[0];
				}
				// No returned value, return $$()
				return quarks;
			};
		}(quarks, $._nodeMethods[i]);
	}
	// Add the 'forEach' method
	quarks.forEach = function(quarks) {
		return function(func) {
			var i = -1;
			while(quarks[++i]) {
				func.apply(quarks[i], [i]);
			}
			return quarks;
		};
	}(quarks);
	// Return nodes
	return quarks;
},

/*
	Convert regular node to quark

	Parameters
		Object node

	Return
		Object
*/
node2quark = function(node) {
	var quark = {node: null, quarked: true}, i;
	// Create a dummy node
	if((typeof node != 'object') || (node === null)) {
		var func = function(){};
		for(i in $._nodeMethods){
			quark[i] = func;
		}
	}
	// Create quark node
	else if(!('quarked' in node)) {
		quark.node = node;
		for(i in $._nodeMethods) {
			quark[i] = function(quark, method) {
				return function() {
					return method.apply(quark, arguments);
				};
			}(quark, $._nodeMethods[i]);
		}
	}
	else {
		quark = node;
	}
	return quark;
};

// Define default methods

$._whenReady = function(func) {
	if(document.readyState == 'complete') {
		func();
	}
	else {
		document.addEventListener('DOMContentLoaded', func);
	}
};

$._selectNode = function(selector) {
	return document.querySelector(selector);
};

$._selectNodes = function(selector) {
	return document.querySelectorAll(selector);
};

$._createNode = function(html) {
	var node = document.createElement('div'),
		nodelist = [];
	node.innerHTML = html;
	return node.firstChild;
};

$._createNodes = function(html) {
	var node = document.createElement('div'),
		nodelist = [];
	node.innerHTML = html;
	node = node.firstChild;
	nodelist.push(node);
	while(node = node.nextSibling) {
		nodelist.push(node);
	}
	return nodelist;
};

$._nodeMethods = {
	findOne: function(selector) {
		if('querySelector' in this.node) {
			return $(this.node.querySelector(selector));
		}
		else {
			return $();
		}
	},
	findAll: function(selector) {
		if('querySelectorAll' in this.node) {
			return $$(this.node.querySelectorAll(selector));
		}
		else {
			return $$([]);
		}
	}
};

// Export
return {
	$ : $,
	$$ : $$
};
<|endoftext|>


<commit_before>var fs = require('fs');
var sax = require("sax");
var AdmZip = require('adm-zip');

var argv = require('minimist')(process.argv.slice(2));

if (!argv["f"]) {
	console.log("no file, use -f argument");
	process.exit(1);
}

var filePath =argv["f"];

if (!fs.existsSync(filePath)) {
	console.log("file not found", filePath);
	process.exit(1);
}

var zip = new AdmZip(filePath);
var zipEntries = zip.getEntries();
zipEntries.forEach(function(val) {
	if (val.entryName.indexOf("content.xml") >= 0) {
		console.log(val.entryName);
		zip.extractEntryTo(val, "target/", true, true);
	}
	if (val.entryName.indexOf("Pictures") >=0 ) {
		console.log(val.entryName);
		zip.extractEntryTo(val, "target/ressources/images/", false, true);
	}
})

function MDWriter() {
	this.text = "# TITRE\n\n<!-- .slide: data-background=\"reveal/theme-zenika/images/title-background.png\" -->";

	this.addPage = function() {
		this.text+= "\n\n\n\n## ";
	}

	this.addParagraph = function() {
		this.text+= "\n\n";
	}

	this.addText = function(text) {
		this.text+=text;
	}

	this.addImage = function(path) {
		this.text+="\n\n![](ressources/images/"+path.replace("Pictures/", "")+")\n";
	}

	this.addBullet = function() {
		this.text+="\n - ";
	}

	this.addEnd = function() {
		this.text+="\n\n\n\n<!-- .slide: data-background=\"reveal/theme-zenika/images/tp1.png\" -->\n\n\n\n<!-- .slide: data-background=\"reveal/theme-zenika/images/tp1.png\" -->\n<!-- .slide: data-background-size=\"30%\" -->";
	}

}

var mdWriter = new MDWriter();

var saxStream = sax.createStream(true, {
            trim: true,
            normalize: true,
            xmlns: false,
            lowercase: true
        });

saxStream.on("opentag", function(node) {
	//console.log(node.name);

	if (node.name === "draw:page") {
		mdWriter.addPage();
	} else if (node.name ==="draw:image") {
		mdWriter.addImage(node.attributes["xlink:href"]);
	} else if (node.name === "text:list-item") {
		mdWriter.addBullet();
	}
});

saxStream.on("end", function() {
	//console.log(mdWriter.text);
	mdWriter.addEnd();
	fs.writeFile("target/content.md", mdWriter.text);
});

saxStream.on("text", function(t) {
    mdWriter.addText(t);
});

fs.createReadStream("target/content.xml").pipe(saxStream);

<commit_msg>use css class instead of images<commit_after>var fs = require('fs');
var sax = require("sax");
var AdmZip = require('adm-zip');

var argv = require('minimist')(process.argv.slice(2));

if (!argv["f"]) {
	console.log("no file, use -f argument");
	process.exit(1);
}

var filePath =argv["f"];

if (!fs.existsSync(filePath)) {
	console.log("file not found", filePath);
	process.exit(1);
}

var zip = new AdmZip(filePath);
var zipEntries = zip.getEntries();
zipEntries.forEach(function(val) {
	if (val.entryName.indexOf("content.xml") >= 0) {
		console.log(val.entryName);
		zip.extractEntryTo(val, "target/", true, true);
	}
	if (val.entryName.indexOf("Pictures") >=0 ) {
		console.log(val.entryName);
		zip.extractEntryTo(val, "target/ressources/images/", false, true);
	}
})

function MDWriter() {
	this.text = "# TITRE\n\n<!-- .slide: class=\"page-title\" -->";

	this.addPage = function() {
		this.text+= "\n\n\n\n## ";
	}

	this.addParagraph = function() {
		this.text+= "\n\n";
	}

	this.addText = function(text) {
		this.text+=text;
	}

	this.addImage = function(path) {
		this.text+="\n\n![](ressources/images/"+path.replace("Pictures/", "")+")\n";
	}

	this.addBullet = function() {
		this.text+="\n - ";
	}

	this.addEnd = function() {
		this.text+="\n\n\n\n<!-- .slide: class=\"page-questions\" -->\n\n\n\n<!-- .slide: class=\"page-tp1\" -->";
	}

}

var mdWriter = new MDWriter();

var saxStream = sax.createStream(true, {
            trim: true,
            normalize: true,
            xmlns: false,
            lowercase: true
        });

saxStream.on("opentag", function(node) {
	//console.log(node.name);

	if (node.name === "draw:page") {
		mdWriter.addPage();
	} else if (node.name ==="draw:image") {
		mdWriter.addImage(node.attributes["xlink:href"]);
	} else if (node.name === "text:list-item") {
		mdWriter.addBullet();
	}
});

saxStream.on("end", function() {
	//console.log(mdWriter.text);
	mdWriter.addEnd();
	fs.writeFile("target/content.md", mdWriter.text);
});

saxStream.on("text", function(t) {
    mdWriter.addText(t);
});

fs.createReadStream("target/content.xml").pipe(saxStream);

<|endoftext|>