<commit_before>var igv = (function (igv) {

    igv.createCursorBrowser = function () {

        var browser = new igv.Browser("CURSOR"),
            contentHeader = $('

')[0],
            contentHeaderDiv = $('

')[0],
            trackContainer = $('
')[0];

        browser.div = $('
')[0];
        $(browser.div).append(contentHeader);
        $(contentHeader).append(contentHeaderDiv);
        $(browser.div).append(trackContainer);
        document.getElementById('igvContainerDiv').appendChild(browser.div);

        browser.horizontalScrollbar = new cursor.HorizontalScrollbar(browser, $(trackContainer));

        // Append event handlers to DOM elements
        document.getElementById('zoomOut').onclick = function (e) {
            browser.zoomOut()
        };
        document.getElementById('zoomIn').onclick = function () {
            browser.zoomIn()
        };
        document.getElementById('fitToScreen').onclick = function () {
            browser.fitToScreen();
        };
        document.getElementById('frameWidthInput').onchange = function (e) {

            var value = $("#frameWidthInput").val();
            if (!igv.isNumber(value)) {
                console.log("bogus " + value);
                return;
            }

            browser.setFrameWidth(parseFloat(value, 10));

        };
        document.getElementById('regionSizeInput').onchange = function (e) {

            var value = $("#regionSizeInput").val();
            if (!igv.isNumber(value)) {
                console.log("bogus " + value);
                return;
            }

            browser.setRegionSize(parseFloat(value, 10));
        };
        document.getElementById('trackHeightInput').onchange = function (e) {

            var value = $("#trackHeightInput").val();
            if (!igv.isNumber(value)) {
                console.log("bogus " + value);
                return;
            }

            browser.setTrackHeight(Math.round(parseFloat(value, 10)));
        };

        // export regions
        document.getElementById('igvExportRegionsButton').onclick = function (e) {
            browser.cursorModel.exportRegions();
        };

        // session save/load
        document.getElementById('igvSessionSaveButton').onclick = function (e) {
//            window.alert("igvSessionSaveButton");
            browser.saveSession();
        };
        document.getElementById('igvSessionLoadButton').onclick = function (e) {
            window.alert("igvSessionSaveButton");
        };

        var fileInput = document.getElementById('fileInput');
        fileInput.addEventListener('change', function (e) {

            var localFile,
                localFiles = fileInput.files,
                featureSource,
                cursorTrack;

            for (var i = 0; i < localFiles.length; i++) {

                localFile = localFiles[ i ];

                featureSource = new igv.BedFeatureSource(localFile);

                cursorTrack = new cursor.CursorTrack(featureSource, browser.cursorModel, browser.referenceFrame, localFile.name, browser.trackHeight);
                browser.addTrack(cursorTrack);

            }

        });

        // Load ENCODE DataTables data and build markup for modal dialog.
        encode.createEncodeDataTablesDataSet("resources/peaks.hg19.txt", function (dataSet) {

            var encodeModalTable = $('#encodeModalTable'),
                myDataTable = encodeModalTable.dataTable({

                    "data": dataSet,
                    "scrollY": "400px",
                    "scrollCollapse": true,
                    "paging": false,

                    "columns": [

                        { "title": "cell" },
                        { "title": "dataType" },

                        { "title": "antibody" },
                        { "title": "view" },

                        { "title": "replicate" },
                        { "title": "type" },

                        { "title": "lab" },
                        { "title": "path" }
                    ]

                });

            encodeModalTable.find('tbody').on('click', 'tr', function () {

                if ($(this).hasClass('selected')) {

                    $(this).removeClass('selected');
                }
                else {

                    // Commenting this out enables multi-selection
//                    myDataTable.$('tr.selected').removeClass('selected');
                    $(this).addClass('selected');
                }

            });

            $('#encodeModalTopCloseButton').on('click', function () {
                myDataTable.$('tr.selected').removeClass('selected');

            });

            $('#encodeModalBottomCloseButton').on('click', function () {
                myDataTable.$('tr.selected').removeClass('selected');
            });

            $('#encodeModalGoButton').on('click', function () {

                var featureSource,
                    cursorTrack,
                    tableRow,
                    tableRows,
                    tableCell,
                    tableCells,
                    record = {};

                tableRows = myDataTable.$('tr.selected');

                if (0 < tableRows.length) {

                    tableRows.removeClass('selected');

                    for (var i = 0; i < tableRows.length; i++) {

                        tableRow = tableRows[ i ];
                        tableCells = $('td', tableRow);

                        tableCells.each(function () {

                            tableCell = $(this)[0];
                            record[ encode.dataTableRowLabels[ tableCell.cellIndex ] ] = tableCell.innerText;

                        });

                        featureSource = new igv.BedFeatureSource(record.path);

                        cursorTrack = new cursor.CursorTrack(featureSource, browser.cursorModel, browser.referenceFrame, encode.encodeTrackLabel(record), browser.trackHeight);
                        cursorTrack.color = encode.encodeAntibodyColor(record.antibody);

                        browser.addTrack(cursorTrack);

                    }

                }

            });

        });

        // Append resultant ENCODE DataTables markup
        $('#encodeModalBody').html('

');

        browser.startup = function () {

            browser.genome = null;

            browser.referenceFrame = null;

            browser.controlPanelWidth = 50;

            browser.trackContainerDiv = trackContainer;

            browser.trackPanels = [];

            initCursor();

            window.onresize = igv.throttle(function () {

                var percent;

                if (browser.ideoPanel) {
                    browser.ideoPanel.resize();
                }

                browser.trackPanels.forEach(function (panel) {
                    panel.resize();
                });

                if (browser.cursorModel) {

                    percent = 100.0 * ($(".igv-viewport-div").first().width() / $(".igv-track-div").first().width());
//                    console.log("percent " + percent);
                    $(".igv-horizontal-scrollbar-div").css({
                        "width": percent + "%"
                    });

                }

            }, 10);
        };

        function initCursor() {

            var regionDisplayJQueryObject = $('#igvHeaderRegionDisplaySpan');

            browser.cursorModel = new cursor.CursorModel(browser, regionDisplayJQueryObject);
            browser.referenceFrame = new igv.ReferenceFrame("", 0, 1 / browser.cursorModel.framePixelWidth);

            browser.setFrameWidth = function (frameWidthString) {

                var frameWidth = parseFloat(frameWidthString);
                if (frameWidth > 0) {

                    browser.cursorModel.framePixelWidth = frameWidth;
                    $("input[id='frameWidthInput']").val(browser.cursorModel.framePixelWidth);

                    browser.referenceFrame.bpPerPixel = 1 / frameWidth;
                    browser.update();
                }
            };

            browser.setRegionSize = function (regionSizeString) {

                var regionSize = parseFloat(regionSizeString);
                if (regionSize > 0) {

                    browser.cursorModel.regionWidth = regionSize;
                    browser.update();
                }

            };

            browser.zoomIn = function () {

                browser.cursorModel.framePixelWidth *= 2;
                $("input[id='frameWidthInput']").val(browser.cursorModel.framePixelWidth);

                browser.update();
            };

            browser.zoomOut = function () {

                var thresholdFramePixelWidth = $(".igv-viewport-div").first().width() / browser.cursorModel.regionsToRender().length;

                browser.cursorModel.framePixelWidth = Math.max(thresholdFramePixelWidth, browser.cursorModel.framePixelWidth / 2.0);

//                    console.log("candidate " + browser.cursorModel.framePixelWidth + " threshold " + thresholdFramePixelWidth);

                $("input[id='frameWidthInput']").val(browser.cursorModel.framePixelWidth);

                browser.update();
            };

            browser.fitToScreen = function () {

                var regionCount,
                    frameWidth;

                if (!(browser.cursorModel && browser.cursorModel.regions)) {
                    return;
                }

                regionCount = browser.cursorModel.regionsToRender().length;

                if (regionCount > 0) {
//                        frameWidth = (browser.trackContainerDiv.clientWidth - browser.controlPanelWidth) / regionCount;
                    frameWidth = $(".igv-viewport-div").first().width() / regionCount;
                    browser.referenceFrame.start = 0;
                    browser.setFrameWidth(frameWidth);
                    $('frameWidthBox').value = frameWidth;
                }
            };

            var tssUrl = "test/data/cursor/hg19.tss.bed.gz";
            var peakURL = "test/data/cursor/wgEncodeBroadHistoneH1hescH3k4me3StdPk.broadPeak.gz";
            var peak2URL = "test/data/cursor/wgEncodeBroadHistoneH1hescH3k27me3StdPk.broadPeak.gz";

            var peakDataSource = new igv.BedFeatureSource(peakURL);
            var peak2DataSource = new igv.BedFeatureSource(peak2URL);
            var tssDataSource = new igv.BedFeatureSource(tssUrl);

            var tssTrack = new cursor.CursorTrack(tssDataSource, browser.cursorModel, browser.referenceFrame, "TSS", 40);

            var track1 = new cursor.CursorTrack(peakDataSource, browser.cursorModel, browser.referenceFrame, "H3k4me3 H1hesc", browser.trackHeight);
            track1.color = "rgb(0,150,0)";

            var track2 = new cursor.CursorTrack(peak2DataSource, browser.cursorModel, browser.referenceFrame, "H3k27me3 H1hesc", browser.trackHeight);
            track2.color = "rgb(150,0,0)";

            // Set the TSS track as the inital "selected" track (i.e. defines the regions)
            tssDataSource.allFeatures(function (featureList) {

                browser.cursorModel.setRegions(featureList);

                browser.addTrack(tssTrack);

                browser.addTrack(track1);

                browser.addTrack(track2);

                tssTrack.labelButton.className = "btn btn-xs btn-cursor-selected";

                browser.horizontalScrollbar.update(browser.cursorModel, browser.referenceFrame);
            });

        }

        // Augment standard behavior
        browser.removeTrack = function (track) {

            this.__proto__.removeTrack.call(this, track);
            this.cursorModel.filterRegions();

        }

        browser.saveSession = function () {

            var session,
                form,
                hiddenFilenameInput,
                hiddenDownloadContent;

            form = document.createElement("form");
            document.body.appendChild(form);
            form.setAttribute("method", "post");
            form.setAttribute("action", "php/exportregions.php");

            // file name
            hiddenFilenameInput = document.createElement("input");
            form.appendChild(hiddenFilenameInput);
            hiddenFilenameInput.setAttribute("type", "hidden");
            hiddenFilenameInput.setAttribute("name", "filename");
            hiddenFilenameInput.setAttribute("value", "igv-session-save.json");

            // For attribute named downloadContent, stuff exportedRegions var into it's value
            hiddenDownloadContent = document.createElement("input");
            form.appendChild(hiddenDownloadContent);
            hiddenDownloadContent.setAttribute("type", "hidden");
            hiddenDownloadContent.setAttribute("name", "downloadContent");

            session = { tracks : [] };

            browser.trackPanels.forEach(function (trackView) {

                session.tracks.push( trackView.track.jsonRepresentation());

            });

            hiddenDownloadContent.setAttribute("value", JSON.stringify(session));

            // submit and self-destruct
            form.submit();
            form.detach();

        };

        return browser;
    };

    igv.cursorAddTrackControlButtons = function (trackView, browser, controlDiv) {

        var sortButton = document.createElement("i"),
            track = trackView.track,
            nextButtonTop = 5;

        controlDiv.appendChild(sortButton);
        sortButton.className = "fa fa-bar-chart-o";
        sortButton.style.color = "black";
        sortButton.style.position = "absolute";
        sortButton.style.top = nextButtonTop + "px";
        sortButton.style.left = "5px";
        sortButton.style.cursor = "pointer";
        nextButtonTop += 18;

        track.sortButton = sortButton;
        sortButton.onclick = function () {

            browser.cursorModel.sortRegions(track.featureSource, track.sortDirection, function (regions) {
                browser.update();
                track.sortDirection *= -1;

            });

            browser.trackPanels.forEach(function (trackView) {
                if (track !== trackView.track) {
                    trackView.track.sortButton.className = "fa fa-bar-chart-o";
                    trackView.track.sortButton.style.color = "black";
                }
            });

            sortButton.className = "fa fa-signal";
            sortButton.style.color = "red";

        };

        //
        trackFilterButtonDiv = document.createElement("div");
        controlDiv.appendChild(trackFilterButtonDiv);

        trackFilterButtonDiv.id = "filterButtonDiv_" + igv.guid();
        trackFilterButtonDiv.className = "igv-filter-histogram-button-div";
        trackFilterButtonDiv.style.top = nextButtonTop + "px";
        trackFilterButtonDiv.style.left = "5px";

        trackView.track.trackFilter = new igv.TrackFilter(trackView);
        trackView.track.trackFilter.createTrackFilterWidgetWithParentElement(trackFilterButtonDiv);

        nextButtonTop += 18;

    }

    return igv;

})(igv || {});<commit_msg>Session save happening. Just tracks for now.<commit_after>var igv = (function (igv) {

    igv.createCursorBrowser = function () {

        var browser = new igv.Browser("CURSOR"),
            contentHeader = $('

')[0],
            contentHeaderDiv = $('

')[0],
            trackContainer = $('
')[0];

        browser.div = $('
')[0];
        $(browser.div).append(contentHeader);
        $(contentHeader).append(contentHeaderDiv);
        $(browser.div).append(trackContainer);
        document.getElementById('igvContainerDiv').appendChild(browser.div);

        browser.horizontalScrollbar = new cursor.HorizontalScrollbar(browser, $(trackContainer));

        // Append event handlers to DOM elements
        document.getElementById('zoomOut').onclick = function (e) {
            browser.zoomOut()
        };
        document.getElementById('zoomIn').onclick = function () {
            browser.zoomIn()
        };
        document.getElementById('fitToScreen').onclick = function () {
            browser.fitToScreen();
        };
        document.getElementById('frameWidthInput').onchange = function (e) {

            var value = $("#frameWidthInput").val();
            if (!igv.isNumber(value)) {
                console.log("bogus " + value);
                return;
            }

            browser.setFrameWidth(parseFloat(value, 10));

        };
        document.getElementById('regionSizeInput').onchange = function (e) {

            var value = $("#regionSizeInput").val();
            if (!igv.isNumber(value)) {
                console.log("bogus " + value);
                return;
            }

            browser.setRegionSize(parseFloat(value, 10));
        };
        document.getElementById('trackHeightInput').onchange = function (e) {

            var value = $("#trackHeightInput").val();
            if (!igv.isNumber(value)) {
                console.log("bogus " + value);
                return;
            }

            browser.setTrackHeight(Math.round(parseFloat(value, 10)));
        };

        // export regions
        document.getElementById('igvExportRegionsButton').onclick = function (e) {
            browser.cursorModel.exportRegions();
        };

        // session save/load
        document.getElementById('igvSessionSaveButton').onclick = function (e) {
//            window.alert("igvSessionSaveButton");
            browser.saveSession();
        };
        document.getElementById('igvSessionLoadButton').onclick = function (e) {
            window.alert("igvSessionSaveButton");
        };

        var fileInput = document.getElementById('fileInput');
        fileInput.addEventListener('change', function (e) {

            var localFile,
                localFiles = fileInput.files,
                featureSource,
                cursorTrack;

            for (var i = 0; i < localFiles.length; i++) {

                localFile = localFiles[ i ];

                featureSource = new igv.BedFeatureSource(localFile);

                cursorTrack = new cursor.CursorTrack(featureSource, browser.cursorModel, browser.referenceFrame, localFile.name, browser.trackHeight);
                browser.addTrack(cursorTrack);

            }

        });

        // Load ENCODE DataTables data and build markup for modal dialog.
        encode.createEncodeDataTablesDataSet("resources/peaks.hg19.txt", function (dataSet) {

            var encodeModalTable = $('#encodeModalTable'),
                myDataTable = encodeModalTable.dataTable({

                    "data": dataSet,
                    "scrollY": "400px",
                    "scrollCollapse": true,
                    "paging": false,

                    "columns": [

                        { "title": "cell" },
                        { "title": "dataType" },

                        { "title": "antibody" },
                        { "title": "view" },

                        { "title": "replicate" },
                        { "title": "type" },

                        { "title": "lab" },
                        { "title": "path" }
                    ]

                });

            encodeModalTable.find('tbody').on('click', 'tr', function () {

                if ($(this).hasClass('selected')) {

                    $(this).removeClass('selected');
                }
                else {

                    // Commenting this out enables multi-selection
//                    myDataTable.$('tr.selected').removeClass('selected');
                    $(this).addClass('selected');
                }

            });

            $('#encodeModalTopCloseButton').on('click', function () {
                myDataTable.$('tr.selected').removeClass('selected');

            });

            $('#encodeModalBottomCloseButton').on('click', function () {
                myDataTable.$('tr.selected').removeClass('selected');
            });

            $('#encodeModalGoButton').on('click', function () {

                var featureSource,
                    cursorTrack,
                    tableRow,
                    tableRows,
                    tableCell,
                    tableCells,
                    record = {};

                tableRows = myDataTable.$('tr.selected');

                if (0 < tableRows.length) {

                    tableRows.removeClass('selected');

                    for (var i = 0; i < tableRows.length; i++) {

                        tableRow = tableRows[ i ];
                        tableCells = $('td', tableRow);

                        tableCells.each(function () {

                            tableCell = $(this)[0];
                            record[ encode.dataTableRowLabels[ tableCell.cellIndex ] ] = tableCell.innerText;

                        });

                        featureSource = new igv.BedFeatureSource(record.path);

                        cursorTrack = new cursor.CursorTrack(featureSource, browser.cursorModel, browser.referenceFrame, encode.encodeTrackLabel(record), browser.trackHeight);
                        cursorTrack.color = encode.encodeAntibodyColor(record.antibody);

                        browser.addTrack(cursorTrack);

                    }

                }

            });

        });

        // Append resultant ENCODE DataTables markup
        $('#encodeModalBody').html('

');

        browser.startup = function () {

            browser.genome = null;

            browser.referenceFrame = null;

            browser.controlPanelWidth = 50;

            browser.trackContainerDiv = trackContainer;

            browser.trackPanels = [];

            initCursor();

            window.onresize = igv.throttle(function () {

                var percent;

                if (browser.ideoPanel) {
                    browser.ideoPanel.resize();
                }

                browser.trackPanels.forEach(function (panel) {
                    panel.resize();
                });

                if (browser.cursorModel) {

                    percent = 100.0 * ($(".igv-viewport-div").first().width() / $(".igv-track-div").first().width());
//                    console.log("percent " + percent);
                    $(".igv-horizontal-scrollbar-div").css({
                        "width": percent + "%"
                    });

                }

            }, 10);
        };

        function initCursor() {

            var regionDisplayJQueryObject = $('#igvHeaderRegionDisplaySpan');

            browser.cursorModel = new cursor.CursorModel(browser, regionDisplayJQueryObject);
            browser.referenceFrame = new igv.ReferenceFrame("", 0, 1 / browser.cursorModel.framePixelWidth);

            browser.setFrameWidth = function (frameWidthString) {

                var frameWidth = parseFloat(frameWidthString);
                if (frameWidth > 0) {

                    browser.cursorModel.framePixelWidth = frameWidth;
                    $("input[id='frameWidthInput']").val(browser.cursorModel.framePixelWidth);

                    browser.referenceFrame.bpPerPixel = 1 / frameWidth;
                    browser.update();
                }
            };

            browser.setRegionSize = function (regionSizeString) {

                var regionSize = parseFloat(regionSizeString);
                if (regionSize > 0) {

                    browser.cursorModel.regionWidth = regionSize;
                    browser.update();
                }

            };

            browser.zoomIn = function () {

                browser.cursorModel.framePixelWidth *= 2;
                $("input[id='frameWidthInput']").val(browser.cursorModel.framePixelWidth);

                browser.update();
            };

            browser.zoomOut = function () {

                var thresholdFramePixelWidth = $(".igv-viewport-div").first().width() / browser.cursorModel.regionsToRender().length;

                browser.cursorModel.framePixelWidth = Math.max(thresholdFramePixelWidth, browser.cursorModel.framePixelWidth / 2.0);

//                    console.log("candidate " + browser.cursorModel.framePixelWidth + " threshold " + thresholdFramePixelWidth);

                $("input[id='frameWidthInput']").val(browser.cursorModel.framePixelWidth);

                browser.update();
            };

            browser.fitToScreen = function () {

                var regionCount,
                    frameWidth;

                if (!(browser.cursorModel && browser.cursorModel.regions)) {
                    return;
                }

                regionCount = browser.cursorModel.regionsToRender().length;

                if (regionCount > 0) {
//                        frameWidth = (browser.trackContainerDiv.clientWidth - browser.controlPanelWidth) / regionCount;
                    frameWidth = $(".igv-viewport-div").first().width() / regionCount;
                    browser.referenceFrame.start = 0;
                    browser.setFrameWidth(frameWidth);
                    $('frameWidthBox').value = frameWidth;
                }
            };

            var tssUrl = "test/data/cursor/hg19.tss.bed.gz";
            var peakURL = "test/data/cursor/wgEncodeBroadHistoneH1hescH3k4me3StdPk.broadPeak.gz";
            var peak2URL = "test/data/cursor/wgEncodeBroadHistoneH1hescH3k27me3StdPk.broadPeak.gz";

            var peakDataSource = new igv.BedFeatureSource(peakURL);
            var peak2DataSource = new igv.BedFeatureSource(peak2URL);
            var tssDataSource = new igv.BedFeatureSource(tssUrl);

            var tssTrack = new cursor.CursorTrack(tssDataSource, browser.cursorModel, browser.referenceFrame, "TSS", 40);

            var track1 = new cursor.CursorTrack(peakDataSource, browser.cursorModel, browser.referenceFrame, "H3k4me3 H1hesc", browser.trackHeight);
            track1.color = "rgb(0,150,0)";

            var track2 = new cursor.CursorTrack(peak2DataSource, browser.cursorModel, browser.referenceFrame, "H3k27me3 H1hesc", browser.trackHeight);
            track2.color = "rgb(150,0,0)";

            // Set the TSS track as the inital "selected" track (i.e. defines the regions)
            tssDataSource.allFeatures(function (featureList) {

                browser.cursorModel.setRegions(featureList);

                browser.addTrack(tssTrack);

                browser.addTrack(track1);

                browser.addTrack(track2);

                tssTrack.labelButton.className = "btn btn-xs btn-cursor-selected";

                browser.horizontalScrollbar.update(browser.cursorModel, browser.referenceFrame);
            });

        }

        // Augment standard behavior
        browser.removeTrack = function (track) {

            this.__proto__.removeTrack.call(this, track);
            this.cursorModel.filterRegions();

        }

        browser.saveSession = function () {

            var session,
                restoredSession,
                form,
                hiddenFilenameInput,
                hiddenDownloadContent,
                stringified;

            form = document.createElement("form");
            document.body.appendChild(form);
            form.setAttribute("method", "post");
            form.setAttribute("action", "php/exportregions.php");

            // file name
            hiddenFilenameInput = document.createElement("input");
            form.appendChild(hiddenFilenameInput);
            hiddenFilenameInput.setAttribute("type", "hidden");
            hiddenFilenameInput.setAttribute("name", "filename");
            hiddenFilenameInput.setAttribute("value", "igv-session-save.json");

            // For attribute named downloadContent, stuff exportedRegions var into it's value
            hiddenDownloadContent = document.createElement("input");
            form.appendChild(hiddenDownloadContent);
            hiddenDownloadContent.setAttribute("type", "hidden");
            hiddenDownloadContent.setAttribute("name", "downloadContent");

            session = { tracks : [] };

            browser.trackPanels.forEach(function (trackView) {

                session.tracks.push( trackView.track.jsonRepresentation());

            });

            stringified = JSON.stringify(session);
            hiddenDownloadContent.setAttribute("value", JSON.stringify(session));

            restoredSession = JSON.parse(stringified);

            // submit and self-destruct
            form.submit();
            form.detach();

        };

        return browser;
    };

    igv.cursorAddTrackControlButtons = function (trackView, browser, controlDiv) {

        var sortButton = document.createElement("i"),
            track = trackView.track,
            nextButtonTop = 5;

        controlDiv.appendChild(sortButton);
        sortButton.className = "fa fa-bar-chart-o";
        sortButton.style.color = "black";
        sortButton.style.position = "absolute";
        sortButton.style.top = nextButtonTop + "px";
        sortButton.style.left = "5px";
        sortButton.style.cursor = "pointer";
        nextButtonTop += 18;

        track.sortButton = sortButton;
        sortButton.onclick = function () {

            browser.cursorModel.sortRegions(track.featureSource, track.sortDirection, function (regions) {
                browser.update();
                track.sortDirection *= -1;

            });

            browser.trackPanels.forEach(function (trackView) {
                if (track !== trackView.track) {
                    trackView.track.sortButton.className = "fa fa-bar-chart-o";
                    trackView.track.sortButton.style.color = "black";
                }
            });

            sortButton.className = "fa fa-signal";
            sortButton.style.color = "red";

        };

        //
        trackFilterButtonDiv = document.createElement("div");
        controlDiv.appendChild(trackFilterButtonDiv);

        trackFilterButtonDiv.id = "filterButtonDiv_" + igv.guid();
        trackFilterButtonDiv.className = "igv-filter-histogram-button-div";
        trackFilterButtonDiv.style.top = nextButtonTop + "px";
        trackFilterButtonDiv.style.left = "5px";

        trackView.track.trackFilter = new igv.TrackFilter(trackView);
        trackView.track.trackFilter.createTrackFilterWidgetWithParentElement(trackFilterButtonDiv);

        nextButtonTop += 18;

    }

    return igv;

})(igv || {});<|endoftext|>


<commit_before>// Try to gracefully parse as many decks as possible
// Parsing data is like the worst
function parseDecklist() {
	deckmain = $("#deckmain").val()
	deckside = $("#deckside").val()

	// Let's store the lists in a tidy little array
	maindeck = [];
	sideboard = [];

	// And let's store their counts for future reference
	maindeck_count = 0;
	sideboard_count = 0;

	// Track unrecognized cards and lines that can't be parsed.
	// (encoded to prevent XSS)
	unrecognized = {};
	unparseable = [];

	// Stop processing the function if there's no main deck
	if (deckmain == "") { return(null, null); }

	// Split main deck and sideboard by newlines
	deckmain = deckmain.split('\n');
	deckside = deckside.split('\n');

	mtgo_re = /^(\d+)x*\s(.+)/;             // MTGO deck format (4 Brainstorm) also TCG (4x Brainstorm)
	mtgosb_re = /^SB:\s+(\d+)\s(.+)/;       // Sideboard lines begin with SB:
	mws_re = /^\s*(\d+)\s+\[.*\]\s+(.+)/;       // MWS, what an ugly format
	mwssb_re = /^SB:\s*(\d+)\s+\[.*\]\s(.+)/;  // MWS, what an ugly format
	tosb_re = /^Sideboard/;                 // Tappedout looks like MTGO, except sideboard begins with Sideboard:  Salvation, same, but no colon

	// Loop through all the cards in the main deck field
	in_sb = false;
	for (i = 0; i < deckmain.length; i++) {
		// Parse for Magic Workstation style deck
		if (mws_re.exec(deckmain[i]) != null) {
			quantity = mws_re.exec(deckmain[i])[1];
			card = mws_re.exec(deckmain[i])[2];

			recognizeCard(card, quantity);
		}

		// Parse for Magic Workstation sideboards
		else if (mwssb_re.exec(deckmain[i]) != null) {
			quantity = mwssb_re.exec(deckmain[i])[1];
			card = mwssb_re.exec(deckmain[i])[2];

			recognizeCard(card, quantity, "side");
		}

		// Parse for MTGO/TappedOut style decks
		else if (mtgo_re.exec(deckmain[i]) != null) {
			quantity = mtgo_re.exec(deckmain[i])[1];
			card = mtgo_re.exec(deckmain[i])[2];

			if (in_sb) {	// TappedOut style Sideboard listing
				recognizeCard(card, quantity, "side");
			} else {
				recognizeCard(card, quantity);
			}
		}

		// Parse for MTGO style sideboard cards
		else if (mtgosb_re.exec(deckmain[i]) != null) {
			quantity = mtgosb_re.exec(deckmain[i])[1];
			card = mtgosb_re.exec(deckmain[i])[2];

			recognizeCard(card, quantity, "side");
		}

		// If we see "Sideboard:", then we're in the TappedOut style sideboard entries from now on
		else if (tosb_re.test(deckmain[i])) { in_sb = true; }

		// Could not be parsed, store in appropriate array
		else {
			addUnparseable(deckmain[i]);
		}
	}

	// Now we get to do the same for the sideboard, but we only have to worry about TCG/MTGO style entries
	for (i = 0; i < deckside.length; i++) {
		// Parse for MTGO/TappedOut style decks
		if (mtgo_re.exec(deckside[i]) != null) {
			quantity = mtgo_re.exec(deckside[i])[1];
			card = mtgo_re.exec(deckside[i])[2];

			recognizeCard(card, quantity, "side");
		} else {
			// Could not be parsed, store in appropriate array
			addUnparseable(deckside[i]);
		}
	}

	// Now we need to sort the deck lists, with the sideboard always being sorted alphabetically
	if ( $("#sortorderfloat input[name=sortorder]:checked").prop("id") == "sortorder1" ) { // alpabetical
		maindeck = sortDecklist(maindeck, 'alphabetically');
		sideboard = sortDecklist(sideboard, 'alphabetically');
	}
	else if ( $("#sortorderfloat input[name=sortorder]:checked").prop("id") == "sortorder2" ) { // CMC
		maindeck = sortDecklist(maindeck, 'cmc');
		sideboard = sortDecklist(sideboard, 'alphabetically');
	}
	else if ( $("#sortorderfloat input[name=sortorder]:checked").prop("id") == "sortorder3" ) { // color
		maindeck = sortDecklist(maindeck, 'color');
		sideboard = sortDecklist(sideboard, 'alphabetically');
	}
	else if ( $("#sortorderfloat input[name=sortorder]:checked").prop("id") == "sortorder4" ) { // numeric
		maindeck = sortDecklist(maindeck, 'numerically');
		sideboard = sortDecklist(sideboard, 'alphabetically');
	}

	// Check the card name against the card database. If it exists, add it to the
	// appropriate list (main or side), otherwise add it to the unrecognized map.
	function recognizeCard (card, quantity, list) {
		list = list || "main";
		recognized = objectHasPropertyCI(cards, card);
		if (recognized) {
			list_add(list, recognized, quantity);
		} else {
			// if the card name starts with "ae", try using the æ character instead
			if (card.slice(0,2).toLowerCase() === "ae") {
				recognized = objectHasPropertyCI(cards, "\u00e6"+card.slice(2));
				if (recognized) {
					list_add(list, recognized, quantity);
					return;
				}
			}
			unrecognized[htmlEncode(card)] = 1;
		}
	}

	// add the passed string to the unparseable array if it isn't empty or entirely whitespace
	function addUnparseable(line) {
		// only store if it's not a falsey value (empty string, etc.)
		// or entirely composed of whitespace
		if (htmlEncode(line) && !htmlEncode(line).match(/^\s+$/)) {
			unparseable.push(htmlEncode(line));
		}
	}

	// Case-insensitive property search, modified from:
	// http://stackoverflow.com/a/12484507/540162
	// Returns property value (properly-capitalized card name) if found, false otherwise
	function objectHasPropertyCI(obj, val) {
		for (var p in obj) {
			if (obj.hasOwnProperty(p) && p.toLowerCase() === val.toLowerCase()) {
				return obj[p].n;
			}
		}
		return false;
	}
}

function sortDecklist(deck, sortorder) {

	// Sort the decklist alphabetically, if chosen
	if ( sortorder == 'alphabetically' ) {

		// Add a case insensitive field to sort by
		for (i = 0; i < deck.length; i++) { deck[i] = [ deck[i][0].toLowerCase(), deck[i][0], deck[i][1] ]; }

		deck.sort();

		// After sorting is done, we can remove the lower case index
		for (i = 0; i < deck.length; i++) { deck[i] = deck[i].splice(1, 2); }
	}

	// Sort the decklist by color, if chosen
	// White = A, Blue = B, Black = C, Red = D, Green = E, Gold = F, Artifact = G , Unknown = X, Land = Z
	else if ( sortorder == 'color' ) {
		var color_to_cards = {}

		for (i = 0; i < deck.length; i++) {

			// We're going to search by lower case
			var lcard = deck[i][0].toLowerCase();

			// Grab the card's color
			if (lcard in cards) { color = cards[ lcard ]['c']; }
			else { color = "X"; } // Unknown

			// Create the color subarray
			if ( !(color in color_to_cards ) ) { color_to_cards[color] = []; }

			// Fix the Aetherling issue until the PDF things supports it
			lcard = lcard.replace("\u00c6", "Ae").replace("\u00e6", "ae");
			deck[i][0] = deck[i][0].replace("\u00c6", "Ae").replace("\u00e6", "ae");

			// Add the card to that array, including lower-case (only used for sorting)
			color_to_cards[color].push( [ lcard, deck[i][0], deck[i][1] ] );

		}

		// Get the list of colors in the deck
		color_to_cards_keys = Object.keys(color_to_cards).sort();

		// Sort each subcolor, then append them to the final array
		deck = []
		for (i = 0; i < color_to_cards_keys.length; i++) {
			color = color_to_cards_keys[i];

			color_to_cards[ color ].sort();   // color_to_cards['A']

			for (j = 0; j < color_to_cards[color].length; j++) {
				card = color_to_cards[color][j][1];
				quantity = color_to_cards[color][j][2];

				deck.push([card, quantity]);
			}

			// Push a blank entry onto deck (to separate colors)
			deck.push(['', 0]);

		}

		// We must clear out the 32nd entry, if it's blank, as it's at the top of the 2nd column
		if (deck.length > 31) {
			if (deck[31][1] == 0) {
				deck.splice(31, 1);
			}
		}
	}

	// Sort the decklist by CMC, if chosen
	else if ( sortorder == 'cmc' ) {
		var cmc_to_cards = {}

		for (i = 0; i < deck.length; i++) {

			// We're going to search by lower case
			var lcard = deck[i][0].toLowerCase();

			// Grab the card's cmc
			if (lcard in cards) { cmc = cards[ lcard ]['m']; }
			else { cmc = 100; } // Unknown

			// Convert the CMC to a string, and pad zeroes (grr Javascript)
			cmc = cmc.toString();
			if ( cmc.length == 1 ) { cmc = "00" + cmc; }
			if ( cmc.length == 2 ) { cmc = "0" + cmc; }

			// Create the cmc subarray
			if ( !(cmc in cmc_to_cards ) ) { cmc_to_cards[cmc] = []; }

			// Fix the Aetherling issue until the PDF things supports it
			lcard = lcard.replace("\u00c6", "Ae").replace("\u00e6", "ae");
			deck[i][0] = deck[i][0].replace("\u00c6", "Ae").replace("\u00e6", "ae");

			// Add the card to that array, including lower-case (only used for sorting)
			cmc_to_cards[cmc].push( [ lcard, deck[i][0], deck[i][1] ] );

		}

		// Get the list of CMCs in the deck
		cmc_to_cards_keys = Object.keys(cmc_to_cards).sort();

		// Sort each CMC, then append them to the final array
		deck = []
		for (i = 0; i < cmc_to_cards_keys.length; i++) {
			cmc = cmc_to_cards_keys[i];

			cmc_to_cards[ cmc ].sort();   // cmc_to_cards[3]

			for (j = 0; j < cmc_to_cards[cmc].length; j++) {
				card = cmc_to_cards[cmc][j][1];
				quantity = cmc_to_cards[cmc][j][2];

				deck.push([card, quantity]);
			}

			// Push a blank entry onto deck (to separate CMCs)
			deck.push(['', 0]);

		}

		// We must clear out the 32nd entry, if it's blank, as it's at the top of the 2nd column
		if (deck.length > 31) {
			if (deck[31][1] == 0) {
				deck.splice(31, 1);
			}
		}
	}

	// Sort the decklist numerically, if chosen
	else if ( sortorder == 'numerically' ) {

		// Add a case insensitive field, swap order around
		for (i = 0; i < deck.length; i++) {
			deck[i] = [ deck[i][1], deck[i][0].toLowerCase(), deck[i][0] ]
		}

		deck.sort();

		// After sorting is done, we can remove the lower case index
		for (i = 0; i < deck.length; i++) { deck[i] = [ deck[i][2], deck[i][0] ] }
	}

	// Get the card's true English name (ignoring any particular capitalization that someone may have done)
	for (i = 0; i < deck.length; i++) {
		var lcard = deck[i][0].toLowerCase()
		if (cards[ lcard ] != undefined) {
			deck[i][0] = cards[ lcard ]['n']
		}
	}

	// Return the deck
	return(deck);

}

// Stub to simplify updating deck and sideboard counts
// Adds a new entry for unique entries, increments existing entries for duplicates
function list_add(type, card, quantity) {
	if (type === "main") {
		cardIndex = listContainsCard(maindeck,card);
		if (cardIndex !== -1) {
			// arggh, strings!
			maindeck[cardIndex][1] = parseInt(maindeck[cardIndex][1]) + parseInt(quantity) + "";
		} else {
			maindeck.push([card, quantity]);
			maindeck_count += parseInt(quantity);
		}
	} else if (type === "side") {
		cardIndex = listContainsCard(sideboard,card);
		if (cardIndex !== -1) {
			// arggh, strings!
			sideboard[cardIndex][1] = parseInt(sideboard[cardIndex][1]) + parseInt(quantity) + "";
		} else {
			sideboard.push([card, quantity]);
			sideboard_count += parseInt(quantity);
		}
	}

	// Returns the index of the card:quantity pair within the given list, or -1 if not found
	function listContainsCard(list, card) {
		for (j=0; j < list.length; j++) {
			if (list[j][0] === card) {
				return j;
			}
		}
		return -1;
	}
}

function htmlEncode(string) {
	return string.replace(/&/g, '&').replace(/"/g, '"').replace(/'/g, ''').replace(/</g, '<').replace(/>/g, '>');
}
<commit_msg>fixed main/side quantity bug<commit_after>// Try to gracefully parse as many decks as possible
// Parsing data is like the worst
function parseDecklist() {
	deckmain = $("#deckmain").val()
	deckside = $("#deckside").val()

	// Let's store the lists in a tidy little array
	maindeck = [];
	sideboard = [];

	// And let's store their counts for future reference
	maindeck_count = 0;
	sideboard_count = 0;

	// Track unrecognized cards and lines that can't be parsed.
	// (encoded to prevent XSS)
	unrecognized = {};
	unparseable = [];

	// Stop processing the function if there's no main deck
	if (deckmain == "") { return(null, null); }

	// Split main deck and sideboard by newlines
	deckmain = deckmain.split('\n');
	deckside = deckside.split('\n');

	mtgo_re = /^(\d+)x*\s(.+)/;             // MTGO deck format (4 Brainstorm) also TCG (4x Brainstorm)
	mtgosb_re = /^SB:\s+(\d+)\s(.+)/;       // Sideboard lines begin with SB:
	mws_re = /^\s*(\d+)\s+\[.*\]\s+(.+)/;       // MWS, what an ugly format
	mwssb_re = /^SB:\s*(\d+)\s+\[.*\]\s(.+)/;  // MWS, what an ugly format
	tosb_re = /^Sideboard/;                 // Tappedout looks like MTGO, except sideboard begins with Sideboard:  Salvation, same, but no colon

	// Loop through all the cards in the main deck field
	in_sb = false;
	for (i = 0; i < deckmain.length; i++) {
		// Parse for Magic Workstation style deck
		if (mws_re.exec(deckmain[i]) != null) {
			quantity = mws_re.exec(deckmain[i])[1];
			card = mws_re.exec(deckmain[i])[2];

			recognizeCard(card, quantity);
		}

		// Parse for Magic Workstation sideboards
		else if (mwssb_re.exec(deckmain[i]) != null) {
			quantity = mwssb_re.exec(deckmain[i])[1];
			card = mwssb_re.exec(deckmain[i])[2];

			recognizeCard(card, quantity, "side");
		}

		// Parse for MTGO/TappedOut style decks
		else if (mtgo_re.exec(deckmain[i]) != null) {
			quantity = mtgo_re.exec(deckmain[i])[1];
			card = mtgo_re.exec(deckmain[i])[2];

			if (in_sb) {	// TappedOut style Sideboard listing
				recognizeCard(card, quantity, "side");
			} else {
				recognizeCard(card, quantity);
			}
		}

		// Parse for MTGO style sideboard cards
		else if (mtgosb_re.exec(deckmain[i]) != null) {
			quantity = mtgosb_re.exec(deckmain[i])[1];
			card = mtgosb_re.exec(deckmain[i])[2];

			recognizeCard(card, quantity, "side");
		}

		// If we see "Sideboard:", then we're in the TappedOut style sideboard entries from now on
		else if (tosb_re.test(deckmain[i])) { in_sb = true; }

		// Could not be parsed, store in appropriate array
		else {
			addUnparseable(deckmain[i]);
		}
	}

	// Now we get to do the same for the sideboard, but we only have to worry about TCG/MTGO style entries
	for (i = 0; i < deckside.length; i++) {
		// Parse for MTGO/TappedOut style decks
		if (mtgo_re.exec(deckside[i]) != null) {
			quantity = mtgo_re.exec(deckside[i])[1];
			card = mtgo_re.exec(deckside[i])[2];

			recognizeCard(card, quantity, "side");
		} else {
			// Could not be parsed, store in appropriate array
			addUnparseable(deckside[i]);
		}
	}

	// Now we need to sort the deck lists, with the sideboard always being sorted alphabetically
	if ( $("#sortorderfloat input[name=sortorder]:checked").prop("id") == "sortorder1" ) { // alpabetical
		maindeck = sortDecklist(maindeck, 'alphabetically');
		sideboard = sortDecklist(sideboard, 'alphabetically');
	}
	else if ( $("#sortorderfloat input[name=sortorder]:checked").prop("id") == "sortorder2" ) { // CMC
		maindeck = sortDecklist(maindeck, 'cmc');
		sideboard = sortDecklist(sideboard, 'alphabetically');
	}
	else if ( $("#sortorderfloat input[name=sortorder]:checked").prop("id") == "sortorder3" ) { // color
		maindeck = sortDecklist(maindeck, 'color');
		sideboard = sortDecklist(sideboard, 'alphabetically');
	}
	else if ( $("#sortorderfloat input[name=sortorder]:checked").prop("id") == "sortorder4" ) { // numeric
		maindeck = sortDecklist(maindeck, 'numerically');
		sideboard = sortDecklist(sideboard, 'alphabetically');
	}

	// Check the card name against the card database. If it exists, add it to the
	// appropriate list (main or side), otherwise add it to the unrecognized map.
	function recognizeCard (card, quantity, list) {
		list = list || "main";
		recognized = objectHasPropertyCI(cards, card);
		if (recognized) {
			list_add(list, recognized, quantity);
		} else {
			// if the card name starts with "ae", try using the æ character instead
			if (card.slice(0,2).toLowerCase() === "ae") {
				recognized = objectHasPropertyCI(cards, "\u00e6"+card.slice(2));
				if (recognized) {
					list_add(list, recognized, quantity);
					return;
				}
			}
			unrecognized[htmlEncode(card)] = 1;
		}
	}

	// add the passed string to the unparseable array if it isn't empty or entirely whitespace
	function addUnparseable(line) {
		// only store if it's not a falsey value (empty string, etc.)
		// or entirely composed of whitespace
		if (htmlEncode(line) && !htmlEncode(line).match(/^\s+$/)) {
			unparseable.push(htmlEncode(line));
		}
	}

	// Case-insensitive property search, modified from:
	// http://stackoverflow.com/a/12484507/540162
	// Returns property value (properly-capitalized card name) if found, false otherwise
	function objectHasPropertyCI(obj, val) {
		for (var p in obj) {
			if (obj.hasOwnProperty(p) && p.toLowerCase() === val.toLowerCase()) {
				return obj[p].n;
			}
		}
		return false;
	}
}

function sortDecklist(deck, sortorder) {

	// Sort the decklist alphabetically, if chosen
	if ( sortorder == 'alphabetically' ) {

		// Add a case insensitive field to sort by
		for (i = 0; i < deck.length; i++) { deck[i] = [ deck[i][0].toLowerCase(), deck[i][0], deck[i][1] ]; }

		deck.sort();

		// After sorting is done, we can remove the lower case index
		for (i = 0; i < deck.length; i++) { deck[i] = deck[i].splice(1, 2); }
	}

	// Sort the decklist by color, if chosen
	// White = A, Blue = B, Black = C, Red = D, Green = E, Gold = F, Artifact = G , Unknown = X, Land = Z
	else if ( sortorder == 'color' ) {
		var color_to_cards = {}

		for (i = 0; i < deck.length; i++) {

			// We're going to search by lower case
			var lcard = deck[i][0].toLowerCase();

			// Grab the card's color
			if (lcard in cards) { color = cards[ lcard ]['c']; }
			else { color = "X"; } // Unknown

			// Create the color subarray
			if ( !(color in color_to_cards ) ) { color_to_cards[color] = []; }

			// Fix the Aetherling issue until the PDF things supports it
			lcard = lcard.replace("\u00c6", "Ae").replace("\u00e6", "ae");
			deck[i][0] = deck[i][0].replace("\u00c6", "Ae").replace("\u00e6", "ae");

			// Add the card to that array, including lower-case (only used for sorting)
			color_to_cards[color].push( [ lcard, deck[i][0], deck[i][1] ] );

		}

		// Get the list of colors in the deck
		color_to_cards_keys = Object.keys(color_to_cards).sort();

		// Sort each subcolor, then append them to the final array
		deck = []
		for (i = 0; i < color_to_cards_keys.length; i++) {
			color = color_to_cards_keys[i];

			color_to_cards[ color ].sort();   // color_to_cards['A']

			for (j = 0; j < color_to_cards[color].length; j++) {
				card = color_to_cards[color][j][1];
				quantity = color_to_cards[color][j][2];

				deck.push([card, quantity]);
			}

			// Push a blank entry onto deck (to separate colors)
			deck.push(['', 0]);

		}

		// We must clear out the 32nd entry, if it's blank, as it's at the top of the 2nd column
		if (deck.length > 31) {
			if (deck[31][1] == 0) {
				deck.splice(31, 1);
			}
		}
	}

	// Sort the decklist by CMC, if chosen
	else if ( sortorder == 'cmc' ) {
		var cmc_to_cards = {}

		for (i = 0; i < deck.length; i++) {

			// We're going to search by lower case
			var lcard = deck[i][0].toLowerCase();

			// Grab the card's cmc
			if (lcard in cards) { cmc = cards[ lcard ]['m']; }
			else { cmc = 100; } // Unknown

			// Convert the CMC to a string, and pad zeroes (grr Javascript)
			cmc = cmc.toString();
			if ( cmc.length == 1 ) { cmc = "00" + cmc; }
			if ( cmc.length == 2 ) { cmc = "0" + cmc; }

			// Create the cmc subarray
			if ( !(cmc in cmc_to_cards ) ) { cmc_to_cards[cmc] = []; }

			// Fix the Aetherling issue until the PDF things supports it
			lcard = lcard.replace("\u00c6", "Ae").replace("\u00e6", "ae");
			deck[i][0] = deck[i][0].replace("\u00c6", "Ae").replace("\u00e6", "ae");

			// Add the card to that array, including lower-case (only used for sorting)
			cmc_to_cards[cmc].push( [ lcard, deck[i][0], deck[i][1] ] );

		}

		// Get the list of CMCs in the deck
		cmc_to_cards_keys = Object.keys(cmc_to_cards).sort();

		// Sort each CMC, then append them to the final array
		deck = []
		for (i = 0; i < cmc_to_cards_keys.length; i++) {
			cmc = cmc_to_cards_keys[i];

			cmc_to_cards[ cmc ].sort();   // cmc_to_cards[3]

			for (j = 0; j < cmc_to_cards[cmc].length; j++) {
				card = cmc_to_cards[cmc][j][1];
				quantity = cmc_to_cards[cmc][j][2];

				deck.push([card, quantity]);
			}

			// Push a blank entry onto deck (to separate CMCs)
			deck.push(['', 0]);

		}

		// We must clear out the 32nd entry, if it's blank, as it's at the top of the 2nd column
		if (deck.length > 31) {
			if (deck[31][1] == 0) {
				deck.splice(31, 1);
			}
		}
	}

	// Sort the decklist numerically, if chosen
	else if ( sortorder == 'numerically' ) {

		// Add a case insensitive field, swap order around
		for (i = 0; i < deck.length; i++) {
			deck[i] = [ deck[i][1], deck[i][0].toLowerCase(), deck[i][0] ]
		}

		deck.sort();

		// After sorting is done, we can remove the lower case index
		for (i = 0; i < deck.length; i++) { deck[i] = [ deck[i][2], deck[i][0] ] }
	}

	// Get the card's true English name (ignoring any particular capitalization that someone may have done)
	for (i = 0; i < deck.length; i++) {
		var lcard = deck[i][0].toLowerCase()
		if (cards[ lcard ] != undefined) {
			deck[i][0] = cards[ lcard ]['n']
		}
	}

	// Return the deck
	return(deck);

}

// Stub to simplify updating deck and sideboard counts
// Adds a new entry for unique entries, increments existing entries for duplicates
function list_add(type, card, quantity) {
	if (type === "main") {
		cardIndex = listContainsCard(maindeck,card);
		if (cardIndex !== -1) {
			// arggh, strings!
			maindeck[cardIndex][1] = parseInt(maindeck[cardIndex][1]) + parseInt(quantity) + "";
		} else {
			maindeck.push([card, quantity]);
		}
		maindeck_count += parseInt(quantity);
	} else if (type === "side") {
		cardIndex = listContainsCard(sideboard,card);
		if (cardIndex !== -1) {
			// arggh, strings!
			sideboard[cardIndex][1] = parseInt(sideboard[cardIndex][1]) + parseInt(quantity) + "";
		} else {
			sideboard.push([card, quantity]);
		}
		sideboard_count += parseInt(quantity);
	}

	// Returns the index of the card:quantity pair within the given list, or -1 if not found
	function listContainsCard(list, card) {
		for (j=0; j < list.length; j++) {
			if (list[j][0] === card) {
				return j;
			}
		}
		return -1;
	}
}

function htmlEncode(string) {
	return string.replace(/&/g, '&').replace(/"/g, '"').replace(/'/g, ''').replace(/</g, '<').replace(/>/g, '>');
}
<|endoftext|>


<commit_before>//= require "../chrome/storage"

// shortcut method
var push = Array.prototype.push;

var Libraries = function () {
  this.init();

  this.userSpecified = JSON.parse(localStorage.getItem('libraries') || "[]");

  // read from storage
  for (i = 0; i < this.userSpecified.length; i++) {
    push.call(this, this.userSpecified[i]);
  }
};

Libraries.prototype.init = function () {
  var libs = {
    yui: {
      text: 'YUI',
      scripts: [
        { text: 'YUI 3.3.0', url: 'http://ajax.googleapis.com/ajax/libs/yui/3.3.0/build/yuiloader/yuiloader-min.js' },
        { text: 'YUI 2.8.2', url: 'http://ajax.googleapis.com/ajax/libs/yui/2.8.2/build/yuiloader/yuiloader-min.js'}
      ]
    },
    mootools: {
      text: 'MooTools',
      scripts: [
        { text: 'Mootools 1.3.0', url: 'http://ajax.googleapis.com/ajax/libs/mootools/1.3.0/mootools-yui-compressed.js'},
        { text: 'Mootools 1.2.4', url: 'http://ajax.googleapis.com/ajax/libs/mootools/1.2.4/mootools-yui-compressed.js' }
      ]
    },
    prototype: {
      text: 'Prototype',
      scripts: [
        { text: 'Prototype latest', url: 'http://ajax.googleapis.com/ajax/libs/prototype/1/prototype.js' },
        { text: 'Prototype 1.7.0.0', url: 'http://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js'},
        { text: 'Prototype 1.6.1.0', url: 'http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js' }
      ]
    },
    jquery: {
      text: 'jQuery',
      scripts: [
        { text: 'jQuery latest', url: 'http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js' },
        { text: 'jQuery WIP (via git)', url: 'http://code.jquery.com/jquery-git.js' },
        { text: 'jQuery 1.5', url: 'http://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js' },
        { text: 'jQuery 1.4.4', url: 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js' }
      ]
    },
    jqueryui : {
      text: 'jQuery UI',
      requires: 'http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js',
      style: 'http://ajax.googleapis.com/ajax/libs/jqueryui/1/themes/base/jquery-ui.css',
      scripts: [
        { text: 'jQuery UI 1.8.9', url: 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/jquery-ui.min.js' }
      ]
    },
    jquerymobile : {
      text: 'jQuery Mobile',
      requires: 'http://code.jquery.com/jquery-1.5.min.js',
      style: 'http://code.jquery.com/mobile/1.0a3/jquery.mobile-1.0a3.min.css',
      scripts: [
        { text: 'jQuery Mobile 1.0a3', url: 'http://code.jquery.com/mobile/1.0a3/jquery.mobile-1.0a3.min.js' }
      ]
    },
    others: {
      text: 'Others',
      scripts: [
        { text: 'underscore', url: 'http://documentcloud.github.com/underscore/underscore-min.js'},
        { text: 'Raphaël', url: 'https://github.com/DmitryBaranovskiy/raphael/raw/master/raphael-min.js'}
      ]
    },
    scriptaculous: {
      text: 'script.aculo.us',
      requires: 'http://ajax.googleapis.com/ajax/libs/prototype/1/prototype.js',
      scripts: [
        { text: 'script.aculo.us 1.8.3', url: 'http://ajax.googleapis.com/ajax/libs/scriptaculous/1.8.3/scriptaculous.js' }
      ]
    },
    dojo : {
      text: 'Dojo',
      scripts: [
        { text: 'Dojo 1.4.1', url: 'http://ajax.googleapis.com/ajax/libs/dojo/1.4.1/dojo/dojo.xd.js' },
        { text: 'Dojo 1.3.2', url: 'http://ajax.googleapis.com/ajax/libs/dojo/1.3.2/dojo/dojo.xd.js' }
      ]
    }
    // ext : {
    //   text: 'Ext Core',
    //   style: 'http://extjs.cachefly.net/ext-2.2/resources/css/ext-all.css',
    //   scripts: [
    //     { text: 'Ext Core 3.1', url: 'http://ajax.googleapis.com/ajax/libs/ext-core/3.1.0/ext-core.js' }
    //   ]
    // }
  },
  // NOTE if a new library category is added, you need to add it here
  order = 'jquery jqueryui jquerymobile prototype scriptaculous yui mootools dojo others'.split(' '),
  i = 0;

  this.length = 0; // triggers support for length prop
  for (i = 0; i < order.length; i++) {
    push.call(this, libs[order[i]]);
  }
};

Libraries.prototype.add = function (lib) {
  // save to localStorage
  this.userSpecified.push(lib);
  try {
    localStorage.setItem('libraries', JSON.stringify(this.userSpecified));
  } catch (e) {} // just in case of DOM_22 error, makes me so sad to use this :(
  push.call(this, lib);
  $('#library').trigger('init');
};

Libraries.prototype.clear = function () {
  this.userSpecified = [];
  localStorage.removeItem('libraries');
  this.init();
  $('#library').trigger('init');
};

// OO based to all me to fiddle the object to resemble an array
var libraries = new Libraries();
window.libraries = libraries; // expose a command line API<commit_msg>jQuery 1.5.1<commit_after>//= require "../chrome/storage"

// shortcut method
var push = Array.prototype.push;

var Libraries = function () {
  this.init();

  this.userSpecified = JSON.parse(localStorage.getItem('libraries') || "[]");

  // read from storage
  for (i = 0; i < this.userSpecified.length; i++) {
    push.call(this, this.userSpecified[i]);
  }
};

Libraries.prototype.init = function () {
  var libs = {
    yui: {
      text: 'YUI',
      scripts: [
        { text: 'YUI 3.3.0', url: 'http://ajax.googleapis.com/ajax/libs/yui/3.3.0/build/yuiloader/yuiloader-min.js' },
        { text: 'YUI 2.8.2', url: 'http://ajax.googleapis.com/ajax/libs/yui/2.8.2/build/yuiloader/yuiloader-min.js'}
      ]
    },
    mootools: {
      text: 'MooTools',
      scripts: [
        { text: 'Mootools 1.3.0', url: 'http://ajax.googleapis.com/ajax/libs/mootools/1.3.0/mootools-yui-compressed.js'},
        { text: 'Mootools 1.2.4', url: 'http://ajax.googleapis.com/ajax/libs/mootools/1.2.4/mootools-yui-compressed.js' }
      ]
    },
    prototype: {
      text: 'Prototype',
      scripts: [
        { text: 'Prototype latest', url: 'http://ajax.googleapis.com/ajax/libs/prototype/1/prototype.js' },
        { text: 'Prototype 1.7.0.0', url: 'http://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js'},
        { text: 'Prototype 1.6.1.0', url: 'http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js' }
      ]
    },
    jquery: {
      text: 'jQuery',
      scripts: [
        { text: 'jQuery latest', url: 'http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js' },
        { text: 'jQuery WIP (via git)', url: 'http://code.jquery.com/jquery-git.js' },
        { text: 'jQuery 1.5.1', url: 'http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js' },
        { text: 'jQuery 1.4.4', url: 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js' }
      ]
    },
    jqueryui : {
      text: 'jQuery UI',
      requires: 'http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js',
      style: 'http://ajax.googleapis.com/ajax/libs/jqueryui/1/themes/base/jquery-ui.css',
      scripts: [
        { text: 'jQuery UI 1.8.9', url: 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/jquery-ui.min.js' }
      ]
    },
    jquerymobile : {
      text: 'jQuery Mobile',
      requires: 'http://code.jquery.com/jquery-1.5.min.js',
      style: 'http://code.jquery.com/mobile/1.0a3/jquery.mobile-1.0a3.min.css',
      scripts: [
        { text: 'jQuery Mobile 1.0a3', url: 'http://code.jquery.com/mobile/1.0a3/jquery.mobile-1.0a3.min.js' }
      ]
    },
    others: {
      text: 'Others',
      scripts: [
        { text: 'underscore', url: 'http://documentcloud.github.com/underscore/underscore-min.js'},
        { text: 'Raphaël', url: 'https://github.com/DmitryBaranovskiy/raphael/raw/master/raphael-min.js'}
      ]
    },
    scriptaculous: {
      text: 'script.aculo.us',
      requires: 'http://ajax.googleapis.com/ajax/libs/prototype/1/prototype.js',
      scripts: [
        { text: 'script.aculo.us 1.8.3', url: 'http://ajax.googleapis.com/ajax/libs/scriptaculous/1.8.3/scriptaculous.js' }
      ]
    },
    dojo : {
      text: 'Dojo',
      scripts: [
        { text: 'Dojo 1.4.1', url: 'http://ajax.googleapis.com/ajax/libs/dojo/1.4.1/dojo/dojo.xd.js' },
        { text: 'Dojo 1.3.2', url: 'http://ajax.googleapis.com/ajax/libs/dojo/1.3.2/dojo/dojo.xd.js' }
      ]
    }
    // ext : {
    //   text: 'Ext Core',
    //   style: 'http://extjs.cachefly.net/ext-2.2/resources/css/ext-all.css',
    //   scripts: [
    //     { text: 'Ext Core 3.1', url: 'http://ajax.googleapis.com/ajax/libs/ext-core/3.1.0/ext-core.js' }
    //   ]
    // }
  },
  // NOTE if a new library category is added, you need to add it here
  order = 'jquery jqueryui jquerymobile prototype scriptaculous yui mootools dojo others'.split(' '),
  i = 0;

  this.length = 0; // triggers support for length prop
  for (i = 0; i < order.length; i++) {
    push.call(this, libs[order[i]]);
  }
};

Libraries.prototype.add = function (lib) {
  // save to localStorage
  this.userSpecified.push(lib);
  try {
    localStorage.setItem('libraries', JSON.stringify(this.userSpecified));
  } catch (e) {} // just in case of DOM_22 error, makes me so sad to use this :(
  push.call(this, lib);
  $('#library').trigger('init');
};

Libraries.prototype.clear = function () {
  this.userSpecified = [];
  localStorage.removeItem('libraries');
  this.init();
  $('#library').trigger('init');
};

// OO based to all me to fiddle the object to resemble an array
var libraries = new Libraries();
window.libraries = libraries; // expose a command line API<|endoftext|>


<commit_before>const { list: validators } = require('../validators');
const { body, restore, template } = require('./template');

function State(schema = {}, env) {
  this.push(schema);

  Object.assign(this, {
    current: [0],
    context: [],
    entries: new Map(),
    env,
  });
}

function generate(env, schema, state = new State(schema, env), options) {
  const tpl = template(state, options);
  tpl.visit(schema);

  const source = body(tpl, state, options);
  return restore(source, schema, options);
}

State.prototype = Object.assign(Object.create(Array.prototype), {
  addEntry(url, schema) {
    if (typeof schema !== 'object') {
      return schema;
    }

    const options = { inner: true };
    const entry = this.entries.get(schema) || generate(this.env, schema, this, options);
    this.entries.set(schema, entry);
    this.revealReference(url);

    return this.context.push(entry);
  },
  addReference(url, schema) {
    const schemaIndex = this.indexOf(schema);
    if (schemaIndex !== -1 && schemaIndex !== this.length - 1) {
      // has already been added to process queue
      return this.context.push(url);
    }
    return false;
  },
  revealReference(url) {
    for (
      let doubled = this.context.indexOf(url);
      doubled !== -1;
      doubled = this.context.indexOf(url)
    ) {
      this.context[doubled] = this.context.length;
    }
  },
  reference(url) {
    const initialStateLength = this.length;
    const schema = this.resolve(url);
    const entry = this.addReference(url, schema) || this.addEntry(url, schema);

    const hasStateChanged = initialStateLength !== this.length;
    if (hasStateChanged) {
      this.length = this.current.pop();
    }

    return entry;
  },
  resolve(reference) {
    if (reference === '#') {
      return 0;
    }

    if (typeof reference !== 'string') {
      return reference;
    }

    const referenceParts = reference.split(/#\/?/);
    const name = referenceParts[1];
    const components = name && name.split('/');

    let uri = referenceParts[0] || '#';
    let currentSchema;

    if (uri === '#') {
      currentSchema = this[this.current[this.current.length - 1]];
    } else {
      if (!Object.prototype.hasOwnProperty.call(this, uri)) {
        uri = this.slice(this.current[this.current.length - 1] + 1).map(schema => schema.id).join('') + uri;
      }

      currentSchema = this.env.resolved[uri].schema;
    }

    this.current.push(this.length);
    this.push(currentSchema);

    while (components && components.length > 0) {
      const currentPath = decodeURIComponent(components[0].replace(/~1/g, '/').replace(/~0/g, '~'));
      if (!Object.prototype.hasOwnProperty.call(currentSchema, currentPath)) {
        throw new Error('Schema not found');
      }

      currentSchema = currentSchema[currentPath];
      this.push(currentSchema);
      components.shift();
    }

    return currentSchema;
  },
  visit(schema, tpl) {
    const initialStateLength = this.length;

    this.push(schema);
    validators.forEach(validator => validator(schema, tpl));
    this.length = initialStateLength;
  },
});

module.exports = {
  State,
  generate,
};
<commit_msg>refactor(state): Draft rename resolution scope<commit_after>const { list: validators } = require('../validators');
const { body, restore, template } = require('./template');
const { joinPath } = require('./');

function State(schema = {}, env) {
  Object.assign(this, {
    resolution: [0],
    context: [],
    entries: new Map(),
    env,
  });

  this.push(schema);
}

function generate(env, schema, state = new State(schema, env), options) {
  const tpl = template(state, options);
  tpl.visit(schema);

  const source = body(tpl, state, options);
  return restore(source, schema, options);
}

State.prototype = Object.assign(Object.create(Array.prototype), {
  // template related methods
  addEntry(url, schema) {
    if (typeof schema !== 'object') {
      return schema;
    }

    const options = { inner: true };
    const entry = this.entries.get(schema) || generate(this.env, schema, this, options);
    this.entries.set(schema, entry);
    this.revealReference(url);

    return this.context.push(entry);
  },
  addReference(url, schema) {
    const schemaIndex = this.indexOf(schema);
    if (schemaIndex !== -1 && schemaIndex !== this.length - 1) {
      // has already been added to process queue
      return this.context.push(url);
    }
    return false;
  },
  revealReference(url) {
    for (
      let doubled = this.context.indexOf(url);
      doubled !== -1;
      doubled = this.context.indexOf(url)
    ) {
      this.context[doubled] = this.context.length;
    }
  },
  reference(url) {
    const initialStateLength = this.length;

    const schema = this.resolve(url);
    const entry = this.addReference(url, schema) || this.addEntry(url, schema);

    const hasStateChanged = initialStateLength !== this.length;
    if (hasStateChanged) {
      this.length = this.resolution.pop();
    }

    return entry;
  },
  // pure scope resolution methods
  push(schema) {
    if (schema && schema.id && this.length) {
      this.resolution.push(this.length);
    }
    Array.prototype.push.call(this, schema);
  },
  ascend(uri) {
    const indexOfParent = this.resolution[this.resolution.length - 1];
    if (uri === '#') {
      return this[indexOfParent];
    }
    if (Object.prototype.hasOwnProperty.call(this, uri)) {
      return this.env.resolved[uri].schema;
    }

    const parentSchemaParts = this.slice(indexOfParent + 1)
      .map(({ id }) => id)
      .concat(uri);

    const subSchemaPath = joinPath(parentSchemaParts);
    const parentSchema = this.env.resolved[subSchemaPath].schema;

    return parentSchema;
  },
  descent(name, parentSchema) {
    let currentSchema = parentSchema;

    const components = name && name.split('/');
    while (components && components.length > 0) {
      const currentPath = decodeURIComponent(components[0].replace(/~1/g, '/').replace(/~0/g, '~'));
      if (!Object.prototype.hasOwnProperty.call(currentSchema, currentPath)) {
        throw new Error('Schema not found');
      }

      currentSchema = currentSchema[currentPath];
      components.shift();
    }

    return currentSchema;
  },
  resolve(reference) {
    if (reference === '#') {
      return 0;
    }
    if (typeof reference !== 'string') {
      return reference;
    }

    const referenceParts = reference.split(/#\/?/);
    const name = referenceParts[1];
    const parentReference = referenceParts[0] || '#';
    const parentSchema = this.ascend(parentReference);

    this.push(parentSchema);

    return this.descent(name, parentSchema);
  },
  visit(schema, tpl) {
    const initialStateLength = this.length;

    this.push(schema);
    validators.forEach(validator => validator(schema, tpl));
    this.length = initialStateLength;
  },
});

module.exports = {
  State,
  generate,
};
<|endoftext|>


<commit_before>// TODO
game.PlayerEntity = me.Entity.extend ({
	// this is a class
	init: function(x, y, settings) {
		// melon js uses this constructor on most things to help us set up
		this._super(me.Entity, "init", [x, y, {
			// this means reaching to the constructor of entites
			image: "player",
			width: 64,
			// tells the screen what amount of space to reserve
			height: 64,
			spritewidth: "64",
			// spritewidth/height are passing the main information tells what to do with the image
			spriteheight: "64",
			// these are setting the properties of the picture o the right demensions so the picture appears properly
			getShape: function() {
				return(new me.Rect(0, 0, 64, 64)).toPolygon();
				// rect is what the guy can walk in to
			}
		}]);

		this.body.setVelocity(5, 20);
		// this also changes the y velocity of the character
		// this is the movement speed of the character
		this.facing = "right";
		// keeps track of which direction the character is going
		me.game.viewport.follow(this.pos, me.game.viewport.AXIS.BOTH);
		// this says wherever the player goes the screen will follow him

		this.renderable.addAnimation("idle", [78]);
		// when the character is still this is what he will look like
		this.renderable.addAnimation("walk", [117, 118, 119, 120, 121, 122, 123, 124, 125], 80);
		// this is going to be what the cahracter is going to change into

		this.renderable.setCurrentAnimation("idle");
		this.renderable.addAnimation("attack", [65, 66, 67, 68, 69, 70, 71, 72] , 80);
	},

	update: function(delta) {
		// this function is what happens on the fly
		if(me.input.isKeyPressed("right")) {
			// set the position of my x by adding the velocity to find above in set veloctiy
			// setVeloctiy() and multiplying it by timer.tick
			// me.timer.tick makes the movement look smooth
			this.facing = "right";
			this.body.vel.x += this.body.accel.x * me.timer.tick;
			this.flipX(true);
			// this is flipping the animation around

		}
		else if(me.input.isKeyPressed("left")) {
			// set the position of my x by adding the velocity to find above in set veloctiy
			// setVeloctiy() and multiplying it by timer.tick
			// me.timer.tick makes the movement look smooth
			this.facing = "left";
			this.body.vel.x -= this.body.accel.x * me.timer.tick;
			this.flipX(false);
			// this is flipping the animation around

		}
		else {
			this.body.vel.x = 0;
		}
		if (me.input.isKeyPressed('jump')) {
     	 // make sure we are not already jumping or falling
      		if (!this.body.jumping && !this.body.falling) {
        // set current vel to the maximum defined value
        // gravity will then do the rest
        	this.body.vel.y = -this.body.maxVel.y * me.timer.tick;
        // set the jumping flag
        	this.body.jumping = true;
        }
    }
		if(me.input.isKeyPressed("attack")) {
			if (!this.renderable.isCurrentAnimation("attack")) {
				// set current animation to attack and once that is over
				// goes back to the idle animations
				this.renderable.setCurrentAnimation("attack", "idle");
				// makes it so that the next time we start this sequence we begin from the first animation not where we left off when we switched to another animation
				this.renderable.setAnimationFrame();
			}
		}
		if(this.body.vel.x !== 0)
		//allowing the guy to not immediately walk
		{
			if(!this.renderable.isCurrentAnimation("walk")) {
				this.renderable.setCurrentAnimation("walk");
				// this says it doesnt want to start the walk animation if it is already walking
			}
		}
		else if(!this.renderable.isCurrentAnimation("attack")) {
			this.renderable.setCurrentAnimation("idle");
		}
		me.collision.check(this, true, this.collideHandler.bind(this), true);
		// passing a parameter into collide function
		// delta is the change in time that has happens
		this.body.update(delta);

		this._super(me.Entity, "update", [delta]);
		// this is updating the animations on the fly
		return true;
	},
	collideHandler: function(response) {
		if(response.b.type==='EnemyBaseEntity'){
			var ydif = this.pos.y - response.b.pos.y;
			var xdif = this.pos.x - response.b.pos.x;

			console.log("xdif " + xdif + " ydif " + ydif);

			if (xdif>-20 && this.facing=== 'right' xdif<0) {
				this.body.vel.x = 0;
				// stops the player from moving
				this.pos.x = this.pos.x - 1;
				// slighty turns the character
			}
			else if (xdif<60 && this.facing=== 'left' && xdif>0) {
				this.body.vel.x = 0;
				// stops the player from moving
				this.pos.x = this.pos.x + 1;
				// cant walk into castle from left or right
			}

		}
		// this is going to determine what happens when we hit the enemy entity
	}
});

game.PlayerBaseEntity = me.Entity.extend ({
	init: function(x, y, settings) {
		this._super(me.Entity, 'init', [x, y, {
			image: "tower",
			width: 100,
			height: 100,
			spritewidth: "100",
			spriteheight: "100",

			getShape: function() {
				return (new me.Rect(0, 0, 100, 70)).toPolygon();
				// this shows the height of the bases
			}
}]);
		this.broken = false;
		// this is saying that the tower has not yet been touched/attacked
		this.health = 10;
		// starting energy for tower
		this.alwaysUpdate = true;
		// updates the screen whether or not we are not looking at it
		this.body.onCollision = this.onCollision.bind(this);
		// if somebody runs into the tower it will be able to collide with it

		this.type = "PlayerBase";
		// this is a type you can use to check to see what you are running into
		this.renderable.addAnimation("idle", [0]);
		this.renderable.addAnimation("broken", [1]);
		this.renderable.setCurrentAnimation("idle");
		// renderable is a class built in melon js that we can play with the animation with

	},

	update: function(delta) {
		if( this.health <= 0) {
			this.broken =  true;
			// this means that the character is dead
			this.renderable.setCurrentAnimation("broken");
	}
		this.body.update(delta);
		// updates the code

		this._super(me.Entity, "update", [delta]);
		// telling the superclass to update
		return true;
	},
		onCollision: function() {

		}

});
game.EnemyBaseEntity = me.Entity.extend ({
	init: function(x, y, settings) {
		this._super(me.Entity, "init", [x, y, {
			image: "tower",
			width: 100,
			height: 100,
			spritewidth: "100",
			spriteheight: "100",

			getShape: function() {
				return (new me.Rect(0, 0, 100, 70)).toPolygon();
				// this shows the hight of the bases
			}
}]);
		this.broken = false;
		// this is saying that the tower has not yet been
		this.health = 10;
		// starting energy for tower
		this.alwaysUpdate = true;
		// updates the screen whether or not we are not looking at it
		this.body.onCollision = this.onCollision.bind(this);
		// if somebody runs into the tower it will be able to collide with it

		this.type = "EnemyBase";
		// this is a type you can use to check to see what you are running into
		this.renderable.addAnimation("idle", [0]);
		this.renderable.addAnimation("broken", [1]);
		this.renderable.setCurrentAnimation("idle");
		// renderable is a class built in melon js that we can play with the animation with

	},

	update: function(delta) {
		if( this.health <= 0) {
			this.broken =  true;
			// this means that the character is dead
			this.renderable.setCurrentAnimation("broken");
	}
		this.body.update(delta);
		// updates the code

		this._super(me.Entity, "update", [delta]);
		// telling the super class to update
		return true;
	},
		onCollision: function() {

		}

});
<commit_msg>finished video 16 and found error for video 15<commit_after>// TODO
game.PlayerEntity = me.Entity.extend ({
	// this is a class
	init: function(x, y, settings) {
		// melon js uses this constructor on most things to help us set up
		this._super(me.Entity, "init", [x, y, {
			// this means reaching to the constructor of entites
			image: "player",
			width: 64,
			// tells the screen what amount of space to reserve
			height: 64,
			spritewidth: "64",
			// spritewidth/height are passing the main information tells what to do with the image
			spriteheight: "64",
			// these are setting the properties of the picture o the right demensions so the picture appears properly
			getShape: function() {
				return(new me.Rect(0, 0, 64, 64)).toPolygon();
				// rect is what the guy can walk in to
			}
		}]);

		this.body.setVelocity(8, 20);
		// this also changes the y velocity of the character
		// this is the movement speed of the character
		this.facing = "right";
		// keeps track of which direction the character is going
		me.game.viewport.follow(this.pos, me.game.viewport.AXIS.BOTH);
		// this says wherever the player goes the screen will follow him

		this.renderable.addAnimation("idle", [78]);
		// when the character is still this is what he will look like
		this.renderable.addAnimation("walk", [117, 118, 119, 120, 121, 122, 123, 124, 125], 80);
		// this is going to be what the cahracter is going to change into

		this.renderable.setCurrentAnimation("idle");
		this.renderable.addAnimation("attack", [65, 66, 67, 68, 69, 70, 71, 72] , 80);
	},

	update: function(delta) {
		// this function is what happens on the fly
		if(me.input.isKeyPressed("right")) {
			// set the position of my x by adding the velocity to find above in set veloctiy
			// setVeloctiy() and multiplying it by timer.tick
			// me.timer.tick makes the movement look smooth
			this.facing = "right";
			this.body.vel.x += this.body.accel.x * me.timer.tick;
			this.flipX(true);
			// this is flipping the animation around

		}
		else if(me.input.isKeyPressed("left")) {
			// set the position of my x by adding the velocity to find above in set veloctiy
			// setVeloctiy() and multiplying it by timer.tick
			// me.timer.tick makes the movement look smooth
			this.facing = "left";
			this.body.vel.x -= this.body.accel.x * me.timer.tick;
			this.flipX(false);
			// this is flipping the animation around

		}
		else {
			this.body.vel.x = 0;
		}
		if (me.input.isKeyPressed('jump') && !this.body.jumping && !this.body.falling) {
     	 // make sure we are not already jumping or falling
      		this.body.jumping = true;
        // set current vel to the maximum defined value
        // gravity will then do the rest
        	this.body.vel.y -= this.body.accel.y * me.timer.tick;
    }
		if(me.input.isKeyPressed("attack")) {
			if (!this.renderable.isCurrentAnimation("attack")) {
				// set current animation to attack and once that is over
				// goes back to the idle animations
				this.renderable.setCurrentAnimation("attack", "idle");
				// makes it so that the next time we start this sequence we begin from the first animation not where we left off when we switched to another animation
				this.renderable.setAnimationFrame();
			}
		}
		if(this.body.vel.x !== 0)
		//allowing the guy to not immediately walk
		{
			if(!this.renderable.isCurrentAnimation("walk")) {
				this.renderable.setCurrentAnimation("walk");
				// this says it doesnt want to start the walk animation if it is already walking
			}
		}
		else if(!this.renderable.isCurrentAnimation("attack")) {
			this.renderable.setCurrentAnimation("idle");
		}
		me.collision.check(this, true, this.collideHandler.bind(this), true);
		// passing a parameter into collide function
		// delta is the change in time that has happens
		this.body.update(delta);

		this._super(me.Entity, "update", [delta]);
		// this is updating the animations on the fly
		return true;
	},

	collideHandler: function(response) {
		console.log("collision");
		if(response.b.type === 'EnemyBase'){
			var ydif = this.pos.y - response.b.pos.y;
			var xdif = this.pos.x - response.b.pos.x;

			if (ydif< -40 && xdif< 70 && xdif > -35) {
				this.body.falling = false;
				this.body.vel.y = -1;
			}

			else if (xdif > -30 && this.facing === 'right' && (xdif < 0)) {
				this.body.vel.x = 0;
				// stops the player from moving
				this.pos.x = this.pos.x - 1;
				// slighty turns the character
			}
			else if (xdif< 70 && this.facing === 'left' && xdif > 0) {
				this.body.vel.x = 0;
				// stops the player from moving
				this.pos.x = this.pos.x + 1;
				// cant walk into castle from left or right
			}
		}
		// this is going to determine what happens when we hit the enemy entity
	}
});

game.PlayerBaseEntity = me.Entity.extend ({
	init: function(x, y, settings) {
		this._super(me.Entity, 'init', [x, y, {
			image: "tower",
			width: 100,
			height: 100,
			spritewidth: "100",
			spriteheight: "100",

			getShape: function() {
				return (new me.Rect(0, 0, 100, 70)).toPolygon();
				// this shows the height of the bases
			}
}]);
		this.broken = false;
		// this is saying that the tower has not yet been touched/attacked
		this.health = 10;
		// starting energy for tower
		this.alwaysUpdate = true;
		// updates the screen whether or not we are not looking at it
		this.body.onCollision = this.onCollision.bind(this);
		// if somebody runs into the tower it will be able to collide with it

		this.type = "PlayerBase";
		// this is a type you can use to check to see what you are running into
		this.renderable.addAnimation("idle", [0]);
		this.renderable.addAnimation("broken", [1]);
		this.renderable.setCurrentAnimation("idle");
		// renderable is a class built in melon js that we can play with the animation with

	},

	update: function(delta) {
		if( this.health <= 0) {
			this.broken =  true;
			// this means that the character is dead
			this.renderable.setCurrentAnimation("broken");
	}
		this.body.update(delta);
		// updates the code

		this._super(me.Entity, "update", [delta]);
		// telling the superclass to update
		return true;
	},
		onCollision: function() {

		}

});
game.EnemyBaseEntity = me.Entity.extend ({
	init: function(x, y, settings) {
		this._super(me.Entity, "init", [x, y, {
			image: "tower",
			width: 100,
			height: 100,
			spritewidth: "100",
			spriteheight: "100",

			getShape: function() {
				return (new me.Rect(0, 0, 100, 70)).toPolygon();
				// this shows the hight of the bases
			}
}]);
		this.broken = false;
		// this is saying that the tower has not yet been
		this.health = 10;
		// starting energy for tower
		this.alwaysUpdate = true;
		// updates the screen whether or not we are not looking at it
		this.body.onCollision = this.onCollision.bind(this);
		// if somebody runs into the tower it will be able to collide with it

		this.type = "EnemyBase";
		// this is a type you can use to check to see what you are running into
		this.renderable.addAnimation("idle", [0]);
		this.renderable.addAnimation("broken", [1]);
		this.renderable.setCurrentAnimation("idle");
		// renderable is a class built in melon js that we can play with the animation with

	},

	update: function(delta) {
		if( this.health <= 0) {
			this.broken =  true;
			// this means that the character is dead
			this.renderable.setCurrentAnimation("broken");
	}
		this.body.update(delta);
		// updates the code

		this._super(me.Entity, "update", [delta]);
		// telling the super class to update
		return true;
	},
		onCollision: function() {

		}

});
<|endoftext|>


<commit_before>//sets the size of my player and
game.playerEntity = me.Entity.extend({
    init: function(x, y, settings) {
        this._super(me.Entity, 'init', [x, y, {
                image: "player",
                width: 64,
                height: 64,
                spritewidth: "64",
                spriteheight: "64",
                getShape: function() {
                    return(new me.Rect(0, 0, 64, 64)).toPolygon();
                }
            }]);
        this.body.setVelocity(10, 15);
        //keeps track on what direction my player is facing
        this.facing = "right";
        me.game.viewport.follow(this.pos, me.game.viewport.AXIS.BOTH);

        this.renderable.addAnimation("idle", [39]);
        this.renderable.addAnimation("walk", [117, 118, 119, 120, 121, 122, 123, 124, 125], 159);
        this.renderable.setCurrentAnimation("idle");
        this.renderable.addAnimation("attack", [89, 90, 91, 92, 93, 94, 95, 96, 97, 98], 80);
    },
    update: function(delta) {
        //check if right button is pressed
        if (me.input.isKeyPressed("right")) {
            this.body.vel.x += this.body.accel.x * me.timer.tick;
            //this line says to unflip the animation when going right
            this.facing = "right";
            this.flipX(false);
        } else if (me.input.isKeyPressed("left")) {
            this.facing = "left";
            //this line says to unflip the animation when going right
            this.body.vel.x -= this.body.accel.x * me.timer.tick;
            this.flipX(true);
        }
        else {
            this.body.vel.x = 0;
        }

        //this checks if a left button is pressed.

        //this checks if the player jumps
        if (me.input.isKeyPressed('jump')) {
//            console.log(me.state);
//            me.state.change(1);
            //me.state.change(me.state.MENU);
            if (!this.body.jumping && !this.body.falling) {
                // set current vel to the maximum defined value
                // gravity will then do the rest
                this.body.vel.y = -this.body.maxVel.y * me.timer.tick;
                // set the jumping flag
                this.body.jumping = true;
                // play some audio
                me.audio.play("jump");
            } else if (me.input.isKeyPressed('jump')) {
                if (!this.body.jumping && !this.body.falling) {
                    // set current vel to the maximum defined value
                    // gravity will then do the rest
                    this.body.vel.y = -this.body.maxVel.y * me.timer.tick;
                    // set the jumping flag
                    this.body.jumping = true;
                    // play some audio
                    me.audio.play("jump");
                }
            }
        }
        //these are my controlles for my player
        //me.collision.check(this, true, this.collideHandler.bind(this), true);
        //this is the position between mario and whatever he hits or lands on

        if (me.input.isKeyPressed("attack")) {

            console.log("attack1");
            if (!this.renderable.isCurrentAnimation("attack")) {

                console.log("attack2");
                //sets the currnt animation to attack and thenn go back to idle animation
                this.renderable.setCurrentAnimation("attack", "idle");
                //makes it so that the next time we start this sequence we begin
                //from the first animation not wherever we switched to another animation
                this.renderable.setAnimationFrame();
            }
        }
        else if (this.body.vel.x !== 0 && !this.renderable.isCurrentAnimation("attack")) {
            if (!this.renderable.isCurrentAnimation("walk")) {
                this.renderable.setCurrentAnimation("walk");
            }
        }else if (!this.renderable.isCurrentAnimation("attack")){
            this.renderable.setCurrentAnimation("idle");
        }

        me.collision.check(this, true, this.collideHandler.bind(this), true);

        this.body.update(delta);
        this._super(me.Entity, "update", [delta]);
        return true;

    },
    collideHandler: function(response) {
        //console.log(response.b.type);
        if (response.b.type === 'EnemyBaseEntity') {
            var ydif = this.pos.y - response.b.pos.y;
            var xdif = this.pos.x - response.b.pos.x;

            console.log("xdif" + xdif + "ydif" + ydif);
            if (ydif<-40 && xdif<70 && xdif>-35) {
                this.body.falling = false;
                this.body.vel.y = -1;
            }
            else if (xdif>-35 && this.facing === 'right' && (xdif<0)) {
                this.body.vel.x = 0;
                this.pos.x = this.pos.x - 1;
            } else if (xdif<70 && this.facing === 'left' && (xdif>0)) {
                this.body.vel.x = 0;
                this.pos.x = this.pos.x + 1;
            }
        }
    }
});

game.PlayerBaseEntity = me.Entity.extend({
    init: function(x, y, settings) {
        this._super(me.Entity, 'init', [x, y, {
                image: "tower",
                width: 100,
                height: 100,
                spritewidth: "100",
                spriteheight: "100",
                getShape: function() {
                    return(new me.Rect(0, 0, 100, 70)).toPolygon();
                }

            }]);
        this.broken = false;
        this.health = 10;
        this.alwaysUpdate = true;
        this.body.onCollision = this.onCollision.bind(this);

        this.type = "PlayerBaseEntity";
        this.renderable.addAnimation("idle", [0]);
        this.renderable.addAnimation("broken", [1]);
        this.renderable.setCurrentAnimation("idle");
    },
    update: function(delta) {
        if (this.health <= 0) {
            this.broken = true;
            this.renderrable.setCurrentAnimation("broken");
        }
        this.body.update(delta);
        this._super(me.Entity, "update", [delta]);
        return true;
    },
    onCollision: function() {

    }
});

game.EnemyBaseEntity = me.Entity.extend({
    init: function(x, y, settings) {
        this._super(me.Entity, 'init', [x, y, {
                image: "tower",
                width: 100,
                height: 100,
                spritewidth: "100",
                spriteheight: "100",
                getShape: function() {
                    return(new me.Rect(0, 0, 100, 70)).toPolygon();

                }
            }]);
        this.broken = false;
        this.health = 10;
        this.alwaysUpdate = true;
        this.body.onCollision = this.onCollision.bind(this);

        this.type = "EnemyBaseEntity";
        this.renderable.addAnimation("idle", [0]);
        this.renderable.addAnimation("broken", [1]);
        this.renderable.setCurrentAnimation("idle");
    },
    update: function(delta) {
        if (this.health <= 0) {
            this.broken = true;
            this.renderrable.setCurrentAnimation("broken");
        }
        this.body.update(delta);
        this._super(me.Entity, "update", [delta]);
        return true;
    },
    onCollision: function() {

    }
});<commit_msg>3/27/15<commit_after>//sets the size of my player and
game.playerEntity = me.Entity.extend({
    init: function(x, y, settings) {
        this._super(me.Entity, 'init', [x, y, {
                image: "player",
                width: 64,
                height: 64,
                spritewidth: "64",
                spriteheight: "64",
                getShape: function() {
                    return(new me.Rect(0, 0, 64, 64)).toPolygon();
                }
            }]);
        this.body.setVelocity(10, 15);
        //keeps track on what direction my player is facing
        this.facing = "right";
        me.game.viewport.follow(this.pos, me.game.viewport.AXIS.BOTH);

        this.renderable.addAnimation("idle", [39]);
        this.renderable.addAnimation("walk", [117, 118, 119, 120, 121, 122, 123, 124, 125], 159);
        this.renderable.setCurrentAnimation("idle");
        this.renderable.addAnimation("attack", [156, 157, 158, 159, 160, 161, 162], 80);
    },
    update: function(delta) {
        //check if right button is pressed
        if (me.input.isKeyPressed("right")) {
            this.body.vel.x += this.body.accel.x * me.timer.tick;
            //this line says to unflip the animation when going right
            this.facing = "right";
            this.flipX(true);
        } else if (me.input.isKeyPressed("left")) {
            this.facing = "left";
            //this line says to unflip the animation when going right
            this.body.vel.x -= this.body.accel.x * me.timer.tick;
            this.flipX(false);
        }
        else {
            this.body.vel.x = 0;
        }

        //this checks if a left button is pressed.

        //this checks if the player jumps
        if (me.input.isKeyPressed('jump')) {
//            console.log(me.state);
//            me.state.change(1);
            //me.state.change(me.state.MENU);
            if (!this.body.jumping && !this.body.falling) {
                // set current vel to the maximum defined value
                // gravity will then do the rest
                this.body.vel.y = -this.body.maxVel.y * me.timer.tick;
                // set the jumping flag
                this.body.jumping = true;
                // play some audio
                me.audio.play("jump");
            } else if (me.input.isKeyPressed('jump')) {
                if (!this.body.jumping && !this.body.falling) {
                    // set current vel to the maximum defined value
                    // gravity will then do the rest
                    this.body.vel.y = -this.body.maxVel.y * me.timer.tick;
                    // set the jumping flag
                    this.body.jumping = true;
                    // play some audio
                    me.audio.play("jump");
                }
            }
        }
        //these are my controlles for my player
        //me.collision.check(this, true, this.collideHandler.bind(this), true);
        //this is the position between mario and whatever he hits or lands on

        if (me.input.isKeyPressed("attack")) {

            console.log("attack1");
            if (!this.renderable.isCurrentAnimation("attack")) {

                console.log("attack2");
                //sets the currnt animation to attack and thenn go back to idle animation
                this.renderable.setCurrentAnimation("attack", "idle");
                //makes it so that the next time we start this sequence we begin
                //from the first animation not wherever we switched to another animation
                this.renderable.setAnimationFrame();
            }
        }
        else if (this.body.vel.x !== 0 && !this.renderable.isCurrentAnimation("attack")) {
            if (!this.renderable.isCurrentAnimation("walk")) {
                this.renderable.setCurrentAnimation("walk");
            }
        }else if (!this.renderable.isCurrentAnimation("attack")){
            this.renderable.setCurrentAnimation("idle");
        }

        me.collision.check(this, true, this.collideHandler.bind(this), true);

        this.body.update(delta);
        this._super(me.Entity, "update", [delta]);
        return true;

    },
    collideHandler: function(response) {
        //console.log(response.b.type);
        if (response.b.type === 'EnemyBaseEntity') {
            var ydif = this.pos.y - response.b.pos.y;
            var xdif = this.pos.x - response.b.pos.x;

            console.log("xdif" + xdif + "ydif" + ydif);
            if (ydif<-40 && xdif<70 && xdif>-35) {
                this.body.falling = false;
                this.body.vel.y = -1;
            }
            else if (xdif>-35 && this.facing === 'right' && (xdif<0)) {
                this.body.vel.x = 0;
                this.pos.x = this.pos.x - 1;
            } else if (xdif<70 && this.facing === 'left' && (xdif>0)) {
                this.body.vel.x = 0;
                this.pos.x = this.pos.x + 1;
            }
        }
    }
});

game.PlayerBaseEntity = me.Entity.extend({
    init: function(x, y, settings) {
        this._super(me.Entity, 'init', [x, y, {
                image: "tower",
                width: 100,
                height: 100,
                spritewidth: "100",
                spriteheight: "100",
                getShape: function() {
                    return(new me.Rect(0, 0, 100, 70)).toPolygon();
                }

            }]);
        this.broken = false;
        this.health = 10;
        this.alwaysUpdate = true;
        this.body.onCollision = this.onCollision.bind(this);

        this.type = "PlayerBaseEntity";
        this.renderable.addAnimation("idle", [0]);
        this.renderable.addAnimation("broken", [1]);
        this.renderable.setCurrentAnimation("idle");
    },
    update: function(delta) {
        if (this.health <= 0) {
            this.broken = true;
            this.renderrable.setCurrentAnimation("broken");
        }
        this.body.update(delta);
        this._super(me.Entity, "update", [delta]);
        return true;
    },
    onCollision: function() {

    }
});

game.EnemyBaseEntity = me.Entity.extend({
    init: function(x, y, settings) {
        this._super(me.Entity, 'init', [x, y, {
                image: "tower",
                width: 100,
                height: 100,
                spritewidth: "100",
                spriteheight: "100",
                getShape: function() {
                    return(new me.Rect(0, 0, 100, 70)).toPolygon();

                }
            }]);
        this.broken = false;
        this.health = 10;
        this.alwaysUpdate = true;
        this.body.onCollision = this.onCollision.bind(this);

        this.type = "EnemyBaseEntity";
        this.renderable.addAnimation("idle", [0]);
        this.renderable.addAnimation("broken", [1]);
        this.renderable.setCurrentAnimation("idle");
    },
    update: function(delta) {
        if (this.health <= 0) {
            this.broken = true;
            this.renderrable.setCurrentAnimation("broken");
        }
        this.body.update(delta);
        this._super(me.Entity, "update", [delta]);
        return true;
    },
    onCollision: function() {

    }
});<|endoftext|>