<commit_before>describe('Testing aggregator file upload controller', function () {
    var controller, configService, deferred, $q, httpBackend;

    var windowMock = {
        alert: function(message) {
        },
        confirm: function(message){

        }
    };
    var modalInstance = { dismiss: function() {} };
    var mission = 'AZero';
    var sourceip = '100.100.100.100';

    beforeEach(function () {
        // load the module
        module('sourceApp', function ($provide) {
            $provide.value('$window', windowMock);
        });

        spyOn(windowMock, 'alert');

        inject(function($controller, $rootScope, _$q_, _configService_, _$httpBackend_){
            scope = $rootScope.$new();
            $q = _$q_;
            httpBackend = _$httpBackend_;
            configService = _configService_;

            deferred = _$q_.defer();
            spyOn(configService, "getAttachments").and.returnValue(deferred.promise);

            deferredRmvAtchmt = _$q_.defer();
            spyOn(configService, "removeAttachment").and.returnValue(deferredRmvAtchmt.promise);

            controller = $controller('aggFileUploadController', {
                $scope: scope,
                configService: configService,
                $uibModalInstance: modalInstance,
                mission: mission,
                sourceip: sourceip
            });
        });
    });

    it('should define the aggFileUpload controller', function() {
        expect(controller).toBeDefined();
    });

    it('should define the function submit()', function(){
        expect(controller.submit).toBeDefined();
    });

    it('should define the function upload()', function(){
        expect(controller.uploadCsv).toBeDefined();
    });

    it('should define the function upload()', function(){
        expect(controller.close).toBeDefined();
    });

    it('should define the function upload()', function(){
        expect(controller.removeAttachment).toBeDefined();
    });

    it('should call the service to get attachments list', function() {
        var result = [
                {
                    id: "100",
                    filename: "testAggConfig.csv"
                },
                {
                    id: "101",
                    filename: "testAggConfig copy.csv"
                }
            ]

        deferred.resolve({ data : result,status:200 });
        // We have to call digest cycle for this to work
        scope.$digest();

        expect(configService.getAttachments).toHaveBeenCalledWith("100.100.100.100");
        expect(controller.list).toBeDefined();
        expect(controller.list).toEqual(result);
    });

    it('should call the upload function when aggregator upload form is valid', function(){
        var args = {
            name
:
 "aggTest.csv"
        };

        controller.uploadAggFile_form = {
            $valid: true,
            $setPristine : function(){}
        };

        controller.formDetails = {
            file: {
                name
:
 "aggTest.csv"
            },
            id:102
        };
        var result = [
            {
                id: "100",
                filename: "testAggConfig.csv"
            },
            {
                id: "101",
                filename: "testAggConfig copy.csv"
            }
        ]
        spyOn(controller, "uploadCsv");

        deferred.resolve({ data :result,status:200 });

        controller.submit();
        scope.$digest();
        expect(configService.getAttachments).toHaveBeenCalledWith("100.100.100.100");
        expect(controller.uploadCsv).toHaveBeenCalled();
        expect(controller.uploadCsv).toHaveBeenCalledWith(args);
    });

    it('should call the upload function when aggregator upload form is valid and user wants to update with a new file', function(){
        var args = {
            name
:
 "aggTest.csv"
        };

        controller.uploadAggFile_form = {
            $valid: true,
            $setPristine : function(){}
        };

        controller.formDetails = {
            file: {
                name
:
 "aggTest.csv"
            },
            id:100
        };
        var result = [
            {
                id: "100",
                filename: "testAggConfig.csv"
            },
            {
                id: "101",
                filename: "testAggConfig copy.csv"
            }
        ]
        spyOn(controller, "uploadCsv");
        spyOn(windowMock, 'confirm').and.returnValue(true);
        deferred.resolve({ data :result,status:200 });

        controller.submit();
        scope.$digest();
        expect(configService.getAttachments).toHaveBeenCalledWith("100.100.100.100");
        expect(controller.uploadCsv).toHaveBeenCalled();
        expect(controller.uploadCsv).toHaveBeenCalledWith(args);
    });

    it('should not call the upload function when aggregator upload form is valid and user does not wants to update with a new file', function(){
        controller.uploadAggFile_form = {
            $valid: true,
            $setPristine : function(){}
        };

        controller.formDetails = {
            file: {
                name
:
 "aggTest.csv"
            },
            id:100
        };
        var result = [
            {
                id: "100",
                filename: "testAggConfig.csv"
            },
            {
                id: "101",
                filename: "testAggConfig copy.csv"
            }
        ]

        spyOn(windowMock, 'confirm').and.returnValue(false);
        deferred.resolve({ data :result,status:200 });

        controller.submit();
        scope.$digest();
        expect(configService.getAttachments).toHaveBeenCalledWith("100.100.100.100");
        expect(controller.formDetails).toEqual({});
    });

    it('should alert the user when file is selected on upload', function(){
        controller.uploadAggFile_form = {
            $valid: true,
            $setPristine : function(){}
        };

        controller.formDetails = {
            id:100
        };

        controller.submit();
        scope.$digest();
        expect(windowMock.alert).toHaveBeenCalledWith("No file passed. Please upload a csv file.");
    });

    it('should upload the aggregator file when uploadCsv() is called and successfully alert the user', function(){
        controller.uploadAggFile_form= {
            $valid: true,
            $setPristine : function(){}
        };
        controller.formDetails = {
            file: {
                name
:
 "aggTest.csv"
            },
            id:100,
            sourceip: '100.100.100.100'
        };

        var resp = {
            config: {
                data: {
                    file:{
                        name: 'aggTest.csv'
                    }
                }
            },
            error_code : 0,
            error_desc : "add"
        }

        var mockFile = {
            "name": "aggTest.csv",
            "size": 220,
            "type": "text/csv"
        };

        httpBackend.when('POST', '/saveAggregatorFile').respond(200, resp);
        controller.uploadCsv(mockFile);
        httpBackend.flush();
        expect(windowMock.alert).toHaveBeenCalledWith('Success: aggTest.csv uploaded.');
        expect(controller.formDetails).toEqual({});
    });

    it('should update the aggregator file when uploadCsv() is called and successfully alert the user', function(){
        controller.uploadAggFile_form= {
            $valid: true,
            $setPristine : function(){}
        };
        controller.formDetails = {
            file: {
                name
:
 "aggTest.csv"
            },
            id:100,
            sourceip: '100.100.100.100'
        };

        var resp = {
            config: {
                data: {
                    file:{
                        name: 'aggTest.csv'
                    }
                }
            },
            error_code : 0,
            error_desc : "update"
        }

        var mockFile = {
            "name": "aggTest.csv",
            "size": 220,
            "type": "text/csv"
        };

        httpBackend.when('POST', '/saveAggregatorFile').respond(200, resp);
        controller.uploadCsv(mockFile);
        httpBackend.flush();
        expect(windowMock.alert).toHaveBeenCalledWith('Success: aggTest.csv updated.');
        expect(controller.formDetails).toEqual({});
    });

    it('should not upload the aggregator file when all the rows do not have parameter value and bit length value', function(){
        controller.uploadAggFile_form= {
            $valid: true,
            $setPristine : function(){}
        };
        controller.formDetails = {
            file: {
                name
:
 "aggTest.csv"
            },
            id:100,
            sourceip: '100.100.100.100'
        };

        var resp = {
            config: {
                data: {
                    file:{
                        name: 'aggTest.csv'
                    }
                }
            },
            error_code : 1,
            error_desc : "Does not have all the rows data"
        }

        var mockFile = {
            "name": "aggTest.csv",
            "size": 220,
            "type": "text/csv"
        };

        httpBackend.when('POST', '/saveAggregatorFile').respond(200, resp);
        controller.uploadCsv(mockFile);
        httpBackend.flush();
        expect(windowMock.alert).toHaveBeenCalledWith('All the rows in the file should have both parameter value and bit length value.Please recheck your file.');
        expect(controller.formDetails).toEqual({});
    });

    it('should not upload the aggregator file when some error', function(){
        controller.uploadAggFile_form= {
            $valid: true,
            $setPristine : function(){}
        };
        controller.formDetails = {
            file: {
                name
:
 "aggTest.csv"
            },
            id:100,
            sourceip: '100.100.100.100'
        };

        var resp = {
            config: {
                data: {
                    file:{
                        name: 'aggTest.csv'
                    }
                }
            },
            error_code : 0,
            error_desc : ""
        }

        var mockFile = {
            "name": "aggTest.csv",
            "size": 220,
            "type": "text/csv"
        };

        httpBackend.when('POST', '/saveAggregatorFile').respond(200, resp);
        controller.uploadCsv(mockFile);
        httpBackend.flush();
        expect(windowMock.alert).toHaveBeenCalledWith('An error occured');
    });

    it('should remove file from list when removeAttachment() is called', function(){
        spyOn(windowMock, 'confirm').and.returnValue(true);

        deferredRmvAtchmt.resolve({ data : {error_code : 0},config:{data:{id:100,sourceip: "100.100.100.100"}}});
        controller.removeAttachment(100, "100.100.100.100");
        // call digest cycle for this to work
        scope.$digest();

        expect(configService.removeAttachment).toHaveBeenCalledWith(100, "100.100.100.100");
        expect(windowMock.alert).toHaveBeenCalledWith('Aggregator File with Id: ' + 100 +' is deleted.');
    });

    it('should call the modalInstance dismiss on close function call', function() {
        spyOn(modalInstance, 'dismiss');

        controller.close();
        expect(modalInstance.dismiss).toHaveBeenCalledWith('cancel');
    });

});<commit_msg>updated jasmine test cases<commit_after>describe('Testing aggregator file upload controller', function () {
    var controller, configService, deferred, $q, httpBackend;

    var windowMock = {
        alert: function(message) {
        },
        confirm: function(message){

        }
    };
    var modalInstance = { dismiss: function() {} };
    var mission = 'AZero';
    var sourceip = '100.100.100.100';

    beforeEach(function () {
        // load the module
        module('sourceApp', function ($provide) {
            $provide.value('$window', windowMock);
        });

        spyOn(windowMock, 'alert');

        inject(function($controller, $rootScope, _$q_, _configService_, _$httpBackend_){
            scope = $rootScope.$new();
            $q = _$q_;
            httpBackend = _$httpBackend_;
            configService = _configService_;

            deferred = _$q_.defer();
            spyOn(configService, "getAttachments").and.returnValue(deferred.promise);

            deferredRmvAtchmt = _$q_.defer();
            spyOn(configService, "removeAttachment").and.returnValue(deferredRmvAtchmt.promise);

            controller = $controller('aggFileUploadController', {
                $scope: scope,
                configService: configService,
                $uibModalInstance: modalInstance,
                mission: mission,
                sourceip: sourceip
            });
        });
    });

    it('should define the aggFileUpload controller', function() {
        expect(controller).toBeDefined();
    });

    it('should define the function submit()', function(){
        expect(controller.submit).toBeDefined();
    });

    it('should define the function upload()', function(){
        expect(controller.uploadCsv).toBeDefined();
    });

    it('should define the function upload()', function(){
        expect(controller.close).toBeDefined();
    });

    it('should define the function upload()', function(){
        expect(controller.removeAttachment).toBeDefined();
    });

    it('should call the service to get attachments list', function() {
        var result = [
                {
                    id: "100",
                    filename: "testAggConfig.csv"
                },
                {
                    id: "101",
                    filename: "testAggConfig copy.csv"
                }
            ]

        deferred.resolve({ data : result,status:200 });
        // We have to call digest cycle for this to work
        scope.$digest();

        expect(configService.getAttachments).toHaveBeenCalledWith("100.100.100.100");
        expect(controller.list).toBeDefined();
        expect(controller.list).toEqual(result);
    });

    it('should call the upload function when aggregator upload form is valid', function(){
        var args = {
            name
:
 "aggTest.csv"
        };

        controller.uploadAggFile_form = {
            $valid: true,
            $setPristine : function(){}
        };

        controller.formDetails = {
            file: {
                name
:
 "aggTest.csv"
            },
            id:102
        };
        var result = [
            {
                id: "100",
                filename: "testAggConfig.csv"
            },
            {
                id: "101",
                filename: "testAggConfig copy.csv"
            }
        ]
        spyOn(controller, "uploadCsv");

        deferred.resolve({ data :result,status:200 });

        controller.submit();
        scope.$digest();
        expect(configService.getAttachments).toHaveBeenCalledWith("100.100.100.100");
        expect(controller.uploadCsv).toHaveBeenCalled();
        expect(controller.uploadCsv).toHaveBeenCalledWith(args);
    });

    it('should call the upload function when aggregator upload form is valid and user wants to update with a new file', function(){
        var args = {
            name
:
 "aggTest.csv"
        };

        controller.uploadAggFile_form = {
            $valid: true,
            $setPristine : function(){}
        };

        controller.formDetails = {
            file: {
                name
:
 "aggTest.csv"
            },
            id:100
        };
        var result = [
            {
                id: "100",
                filename: "testAggConfig.csv"
            },
            {
                id: "101",
                filename: "testAggConfig copy.csv"
            }
        ]
        spyOn(controller, "uploadCsv");
        spyOn(windowMock, 'confirm').and.returnValue(true);
        deferred.resolve({ data :result,status:200 });

        controller.submit();
        scope.$digest();
        expect(configService.getAttachments).toHaveBeenCalledWith("100.100.100.100");
        expect(controller.uploadCsv).toHaveBeenCalled();
        expect(controller.uploadCsv).toHaveBeenCalledWith(args);
    });

    it('should not call the upload function when aggregator upload form is valid and user does not wants to update with a new file', function(){
        controller.uploadAggFile_form = {
            $valid: true,
            $setPristine : function(){}
        };

        controller.formDetails = {
            file: {
                name
:
 "aggTest.csv"
            },
            id:100
        };
        var result = [
            {
                id: "100",
                filename: "testAggConfig.csv"
            },
            {
                id: "101",
                filename: "testAggConfig copy.csv"
            }
        ]

        spyOn(windowMock, 'confirm').and.returnValue(false);
        deferred.resolve({ data :result,status:200 });

        controller.submit();
        scope.$digest();
        expect(configService.getAttachments).toHaveBeenCalledWith("100.100.100.100");
        expect(controller.formDetails).toEqual({});
    });

    it('should alert the user when no file is selected on upload', function(){
        controller.uploadAggFile_form = {
            $valid: true,
            $setPristine : function(){}
        };

        controller.formDetails = {
            id:100
        };

        controller.submit();
        scope.$digest();
        expect(windowMock.alert).toHaveBeenCalledWith("No file passed. Please upload a csv file.");
    });

    it('should upload the aggregator file when uploadCsv() is called and successfully alert the user', function(){
        controller.uploadAggFile_form= {
            $valid: true,
            $setPristine : function(){}
        };
        controller.formDetails = {
            file: {
                name
:
 "aggTest.csv"
            },
            id:100,
            sourceip: '100.100.100.100'
        };

        var resp = {
            config: {
                data: {
                    file:{
                        name: 'aggTest.csv'
                    }
                }
            },
            error_code : 0,
            error_desc : "add"
        }

        var mockFile = {
            "name": "aggTest.csv",
            "size": 220,
            "type": "text/csv"
        };

        httpBackend.when('POST', '/saveAggregatorFile').respond(200, resp);
        controller.uploadCsv(mockFile);
        httpBackend.flush();
        expect(windowMock.alert).toHaveBeenCalledWith('Success: aggTest.csv uploaded.');
        expect(controller.formDetails).toEqual({});
    });

    it('should update the aggregator file when uploadCsv() is called and successfully alert the user', function(){
        controller.uploadAggFile_form= {
            $valid: true,
            $setPristine : function(){}
        };
        controller.formDetails = {
            file: {
                name
:
 "aggTest.csv"
            },
            id:100,
            sourceip: '100.100.100.100'
        };

        var resp = {
            config: {
                data: {
                    file:{
                        name: 'aggTest.csv'
                    }
                }
            },
            error_code : 0,
            error_desc : "update"
        }

        var mockFile = {
            "name": "aggTest.csv",
            "size": 220,
            "type": "text/csv"
        };

        httpBackend.when('POST', '/saveAggregatorFile').respond(200, resp);
        controller.uploadCsv(mockFile);
        httpBackend.flush();
        expect(windowMock.alert).toHaveBeenCalledWith('Success: aggTest.csv updated.');
        expect(controller.formDetails).toEqual({});
    });

    it('should not upload the aggregator file when all the rows do not have parameter value and bit length value', function(){
        controller.uploadAggFile_form= {
            $valid: true,
            $setPristine : function(){}
        };
        controller.formDetails = {
            file: {
                name
:
 "aggTest.csv"
            },
            id:100,
            sourceip: '100.100.100.100'
        };

        var resp = {
            config: {
                data: {
                    file:{
                        name: 'aggTest.csv'
                    }
                }
            },
            error_code : 1,
            error_desc : "Does not have all the rows data"
        }

        var mockFile = {
            "name": "aggTest.csv",
            "size": 220,
            "type": "text/csv"
        };

        httpBackend.when('POST', '/saveAggregatorFile').respond(200, resp);
        controller.uploadCsv(mockFile);
        httpBackend.flush();
        expect(windowMock.alert).toHaveBeenCalledWith('All the rows in the file should have both parameter value and bit length value.Please recheck your file.');
        expect(controller.formDetails).toEqual({});
    });

    it('should not upload the aggregator file when some error', function(){
        controller.uploadAggFile_form= {
            $valid: true,
            $setPristine : function(){}
        };
        controller.formDetails = {
            file: {
                name
:
 "aggTest.csv"
            },
            id:100,
            sourceip: '100.100.100.100'
        };

        var resp = {
            config: {
                data: {
                    file:{
                        name: 'aggTest.csv'
                    }
                }
            },
            error_code : 0,
            error_desc : ""
        }

        var mockFile = {
            "name": "aggTest.csv",
            "size": 220,
            "type": "text/csv"
        };

        httpBackend.when('POST', '/saveAggregatorFile').respond(200, resp);
        controller.uploadCsv(mockFile);
        httpBackend.flush();
        expect(windowMock.alert).toHaveBeenCalledWith('An error occured');
    });

    it('should remove file from list when removeAttachment() is called', function(){
        spyOn(windowMock, 'confirm').and.returnValue(true);

        deferredRmvAtchmt.resolve({ data : {error_code : 0},config:{data:{id:100,sourceip: "100.100.100.100"}}});
        controller.removeAttachment(100, "100.100.100.100");
        // call digest cycle for this to work
        scope.$digest();

        expect(configService.removeAttachment).toHaveBeenCalledWith(100, "100.100.100.100");
        expect(windowMock.alert).toHaveBeenCalledWith('Aggregator File with Id: ' + 100 +' is deleted.');
    });

    it('should call the modalInstance dismiss on close function call', function() {
        spyOn(modalInstance, 'dismiss');

        controller.close();
        expect(modalInstance.dismiss).toHaveBeenCalledWith('cancel');
    });

});<|endoftext|>


<commit_before>
var sbOutputService = {

	depth : 0,
	content : "",
	optionAll   : true,
	optionFrame : false,

	init : function()
	{
		document.documentElement.getButton("accept").label = sbCommonUtils.lang("scrapbook", "START_BUTTON");
		sbTreeHandler.init(true);
		this.selectAllFolders();
		if ( window.location.search == "?auto" )
		{
			document.getElementById("ScrapBookOutputOptionO").checked = false;
			this.start();
		}
	},

	selectAllFolders : function()
	{
		if ( document.getElementById('ScrapBookOutputOptionA').checked )
		{
			sbTreeHandler.toggleAllFolders(true);
			sbTreeHandler.TREE.view.selection.selectAll();
			sbTreeHandler.TREE.treeBoxObject.focused = true;
		}
		this.optionAll = true;
	},

	toggleAllSelection : function()
	{
		if ( this.optionAll )
		{
			document.getElementById("ScrapBookOutputOptionA").checked = false;
			this.optionAll = false;
		}
	},

	start : function()
	{
		this.optionFrame = document.getElementById("ScrapBookOutputOptionF").checked;
		this.optionAll ? this.execAll() : this.exec();
		sbTreeHandler.toggleAllFolders(true);
		if ( window.location.search == "?auto" ) setTimeout(function(){ window.close(); }, 1000);
	},

	execAll : function()
	{
		this.content = this.getHTMLHead();
		this.processRescursively(sbTreeHandler.TREE.resource);
		this.finalize();
	},

	exec : function()
	{
		this.content = this.getHTMLHead();
		var selResList = sbTreeHandler.getSelection(true, 1);
		this.content += "
\n";
		for ( var i = 0; i < selResList.length; i++ )
		{
			this.content += '
';
			this.content += this.getHTMLBody(selResList[i]);
			this.processRescursively(selResList[i]);
			this.content += "
\n";
		}
		this.content += "
\n";
		this.finalize();
	},

	finalize : function()
	{
		var dir = sbCommonUtils.getScrapBookDir().clone();
		dir.append("tree");
		if ( !dir.exists() ) dir.create(dir.DIRECTORY_TYPE, 0700);
		var urlHash = {
			"chrome://scrapbook/skin/output.css"     : "output.css",
			"chrome://scrapbook/skin/treeitem.png"   : "treeitem.png",
			"chrome://scrapbook/skin/treenote.png"   : "treenote.png",
			"chrome://scrapbook/skin/treenotex.png"  : "treenotex.png",
			"chrome://scrapbook/skin/treefolder.png" : "folder.png",
			"chrome://scrapbook/skin/toolbar_toggle.png" : "toggle.png",
		};
		for ( var url in urlHash )
		{
			var destFile = dir.clone();
			destFile.append(urlHash[url]);
			sbCommonUtils.saveTemplateFile(url, destFile);
		}
		var frameFile = dir.clone();
		frameFile.append("frame.html");
		if ( !frameFile.exists() ) frameFile.create(frameFile.NORMAL_FILE_TYPE, 0666);
		sbCommonUtils.writeFile(frameFile, this.getHTMLFrame(), "UTF-8");
		var indexFile = dir.clone();
		indexFile.append("index.html");
		if ( !indexFile.exists() ) indexFile.create(indexFile.NORMAL_FILE_TYPE, 0666);
		this.content += this.getHTMLFoot();
		sbCommonUtils.writeFile(indexFile, this.content, "UTF-8");
		var fileName = this.optionFrame ? "frame.html" : "index.html";
		if ( document.getElementById("ScrapBookOutputOptionO").checked )
		{
			sbCommonUtils.loadURL(sbCommonUtils.convertFilePathToURL(dir.path) + fileName, true);
		}
	},

	processRescursively : function(aContRes)
	{
		this.depth++;
		var id = sbDataSource.getProperty(aContRes, "id") || "root";
		this.content += '
\n';
		var resList = sbDataSource.flattenResources(aContRes, 0, false);
		for (var i = 1; i < resList.length; i++) {
			this.content += '
';
			this.content += this.getHTMLBody(resList[i]);
			if (sbDataSource.isContainer(resList[i]))
				this.processRescursively(resList[i]);
			this.content += "
\n";
		}
		this.content += "
\n";
		this.depth--;
	},

	getHTMLHead : function()
	{
		var HTML = '<!DOCTYPE html>\n\n'
			+ '\n\n'
			+ '\n'
			+ '	<meta charset="UTF-8">\n'
			+ '	<title>' + document.title + '</title>\n'
			+ '	<link rel="stylesheet" type="text/css" href="./output.css" media="all">\n'
			+ '	\n'
			+ '\n\n'
			+ '\n'
			+ '
ScrapBook
\n'
		return HTML;
	},

	getHTMLBody : function(aRes)
	{
		var id    = sbDataSource.getProperty(aRes, "id");
		var title = sbDataSource.getProperty(aRes, "title");
		var icon  = sbDataSource.getProperty(aRes, "icon");
		var type  = sbDataSource.getProperty(aRes, "type");
		if ( icon.match(/(\/data\/\d{14}\/.*$)/) ) icon = ".." + RegExp.$1;
		if ( !icon ) icon = sbCommonUtils.getFileName( sbCommonUtils.getDefaultIcon(type) );
		title = sbCommonUtils.escapeHTML(title);
		var ret;
		switch (type) {
			case "separator":
				ret = '' + title + ' ----------------------------------------' + '';
				break;
			case "folder":
				ret = ''
				    + '' + title + '\n';
				break;
			default:
				var href = (type == "bookmark") ?
				           sbDataSource.getProperty(aRes, "source") :
				           "../data/" + id + "/index.html";
				var target = this.optionFrame ? ' target="main"' : "";
				ret = ''
				    + '' + title + '';
				break;
		}
		return ret;
	},

	getHTMLFoot : function()
	{
		var HTML = "\n\n\n";
		return HTML;
	},

	getHTMLFrame : function()
	{
		var HTML = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN">\n\n'
			+ '\n\n'
			+ '\n'
			+ '	<meta http-equiv="Content-Type" Content="text/html;charset=UTF-8">\n'
			+ '	<title>' + document.title + '</title>\n'
			+ '\n\n'
			+ '<frameset cols="200,*">\n'
			+ '	<frame name="side" src="./index.html">\n'
			+ '	<frame name="main">\n'
			+ '</frameset>\n\n'
			+ '\n';
		return HTML;
	},

};

<commit_msg>Code optimization. Bookmarks now open in new window/tab(s).<commit_after>
var sbOutputService = {

	depth : 0,
	content : "",
	optionAll   : true,
	optionFrame : false,

	init : function()
	{
		document.documentElement.getButton("accept").label = sbCommonUtils.lang("scrapbook", "START_BUTTON");
		sbTreeHandler.init(true);
		this.selectAllFolders();
		if ( window.location.search == "?auto" )
		{
			document.getElementById("ScrapBookOutputOptionO").checked = false;
			this.start();
		}
	},

	selectAllFolders : function()
	{
		if ( document.getElementById('ScrapBookOutputOptionA').checked )
		{
			sbTreeHandler.toggleAllFolders(true);
			sbTreeHandler.TREE.view.selection.selectAll();
			sbTreeHandler.TREE.treeBoxObject.focused = true;
		}
		this.optionAll = true;
	},

	toggleAllSelection : function()
	{
		if ( this.optionAll )
		{
			document.getElementById("ScrapBookOutputOptionA").checked = false;
			this.optionAll = false;
		}
	},

	start : function()
	{
		this.optionFrame = document.getElementById("ScrapBookOutputOptionF").checked;
		this.optionAll ? this.execAll() : this.exec();
		sbTreeHandler.toggleAllFolders(true);
		if ( window.location.search == "?auto" ) setTimeout(function(){ window.close(); }, 1000);
	},

	execAll : function()
	{
		this.content = this.getHTMLHead();
		this.processRescursively(sbTreeHandler.TREE.resource);
		this.finalize();
	},

	exec : function()
	{
		this.content = this.getHTMLHead();
		var selResList = sbTreeHandler.getSelection(true, 1);
		this.content += "
\n";
		for ( var i = 0; i < selResList.length; i++ )
		{
			this.content += '
';
			this.content += this.getHTMLBody(selResList[i]);
			this.processRescursively(selResList[i]);
			this.content += "
\n";
		}
		this.content += "
\n";
		this.finalize();
	},

	finalize : function()
	{
		var dir = sbCommonUtils.getScrapBookDir().clone();
		dir.append("tree");
		if ( !dir.exists() ) dir.create(dir.DIRECTORY_TYPE, 0700);
		var urlHash = {
			"chrome://scrapbook/skin/output.css"     : "output.css",
			"chrome://scrapbook/skin/treeitem.png"   : "treeitem.png",
			"chrome://scrapbook/skin/treenote.png"   : "treenote.png",
			"chrome://scrapbook/skin/treenotex.png"  : "treenotex.png",
			"chrome://scrapbook/skin/treefolder.png" : "folder.png",
			"chrome://scrapbook/skin/toolbar_toggle.png" : "toggle.png",
		};
		for ( var url in urlHash )
		{
			var destFile = dir.clone();
			destFile.append(urlHash[url]);
			sbCommonUtils.saveTemplateFile(url, destFile);
		}
		var frameFile = dir.clone();
		frameFile.append("frame.html");
		if ( !frameFile.exists() ) frameFile.create(frameFile.NORMAL_FILE_TYPE, 0666);
		sbCommonUtils.writeFile(frameFile, this.getHTMLFrame(), "UTF-8");
		var indexFile = dir.clone();
		indexFile.append("index.html");
		if ( !indexFile.exists() ) indexFile.create(indexFile.NORMAL_FILE_TYPE, 0666);
		this.content += this.getHTMLFoot();
		sbCommonUtils.writeFile(indexFile, this.content, "UTF-8");
		var fileName = this.optionFrame ? "frame.html" : "index.html";
		if ( document.getElementById("ScrapBookOutputOptionO").checked )
		{
			sbCommonUtils.loadURL(sbCommonUtils.convertFilePathToURL(dir.path) + fileName, true);
		}
	},

	processRescursively : function(aContRes)
	{
		this.depth++;
		var id = sbDataSource.getProperty(aContRes, "id") || "root";
		this.content += '
\n';
		var resList = sbDataSource.flattenResources(aContRes, 0, false);
		for (var i = 1; i < resList.length; i++) {
			this.content += '
';
			this.content += this.getHTMLBody(resList[i]);
			if (sbDataSource.isContainer(resList[i]))
				this.processRescursively(resList[i]);
			this.content += "
\n";
		}
		this.content += "
\n";
		this.depth--;
	},

	getHTMLHead : function()
	{
		var HTML = '<!DOCTYPE html>\n\n'
			+ '\n\n'
			+ '\n'
			+ '	<meta charset="UTF-8">\n'
			+ '	<title>' + document.title + '</title>\n'
			+ '	<link rel="stylesheet" type="text/css" href="./output.css" media="all">\n'
			+ '	\n'
			+ '\n\n'
			+ '\n'
			+ '
ScrapBook
\n'
		return HTML;
	},

	getHTMLBody : function(aRes)
	{
		var id    = sbDataSource.getProperty(aRes, "id");
		var type  = sbDataSource.getProperty(aRes, "type");
		var icon  = sbDataSource.getProperty(aRes, "icon");
		var title = sbDataSource.getProperty(aRes, "title");
		var source = sbDataSource.getProperty(aRes, "source");
		if ( icon.match(/(\/data\/\d{14}\/.*$)/) ) icon = ".." + RegExp.$1;
		if ( !icon ) icon = sbCommonUtils.escapeFileName(sbCommonUtils.getFileName( sbCommonUtils.getDefaultIcon(type) ));
		icon = sbCommonUtils.escapeHTML(icon);
		title = sbCommonUtils.escapeHTML(title);
		source = sbCommonUtils.escapeHTML(source);
		var ret;
		switch (type) {
			case "separator":
				ret = '' + title + ' ----------------------------------------' + '';
				break;
			case "folder":
				ret = ''
				    + '' + title + '\n';
				break;
			case "bookmark":
				ret = ''
				    + '' + title + '';
				break;
			default:
				var href = sbCommonUtils.escapeHTML("../data/" + id + "/index.html");
				var target = this.optionFrame ? ' target="main"' : "";
				ret = ''
				    + '' + title + '';
				break;
		}
		return ret;
	},

	getHTMLFoot : function()
	{
		var HTML = "\n\n\n";
		return HTML;
	},

	getHTMLFrame : function()
	{
		var HTML = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN">\n\n'
			+ '\n\n'
			+ '\n'
			+ '	<meta http-equiv="Content-Type" Content="text/html;charset=UTF-8">\n'
			+ '	<title>' + document.title + '</title>\n'
			+ '\n\n'
			+ '<frameset cols="200,*">\n'
			+ '	<frame name="side" src="./index.html">\n'
			+ '	<frame name="main">\n'
			+ '</frameset>\n\n'
			+ '\n';
		return HTML;
	},

};

<|endoftext|>


<commit_before>/**
 Copyright 2014 Gordon Williams (gw@pur3.co.uk)

 This Source Code is subject to the terms of the Mozilla Public
 License, v2.0. If a copy of the MPL was not distributed with this
 file, You can obtain one at http://mozilla.org/MPL/2.0/.

 ----------------------------------------------------------49--------
  An Compiler that converts any bit of JavaScript tagged with
  "compiled" into native code.

  function foo(a,b) {
    "compiled";
    return a+b;
  }
 ------------------------------------------------------------------
**/
"use strict";
(function(){

  function init() {
    Espruino.Core.Config.add("COMPILATION", {
      section : "Communications",
      name : "JavaScript Compiler",
      descriptionHTML : 'Compile JavaScript functions prefixed with "compiled" into Native code. (More Info)',
      type : "boolean",
      defaultValue : true
    });
    Espruino.Core.Config.add("COMPILATION_URL", {
      section : "Communications",
      name : "JavaScript Compiler URL",
      description : "When JavaScript Compilation is enabled, this is the URL of the JavaScript compiler",
      type : "string",
      defaultValue : "http://www.espruino.com:32766"
    });

    // When code is sent to Espruino, search it for modules and add extra code required to load them
    Espruino.addProcessor("transformForEspruino", function(code, callback) {
      compileCode(code, callback);
    });
  }

  function compileCode(code, callback) {
    if (!Espruino.Config.COMPILATION)
      return callback(code);

    var board = Espruino.Core.Env.getBoardData();
    if (board == undefined) {
      Espruino.Core.Notifications.error("Current board not known - please connect to the Espruino board first");
      return callback(code);
    }

    var tasks = 0;
    try {
      var ast = acorn.parse(code, { ecmaVersion : 6 });
      var nodes = [];
      ast.body.forEach(function(node) {
        if (node.type=="FunctionDeclaration") {
          if (node.body.type=="BlockStatement" &&
              node.body.body.length>0 &&
              node.body.body[0].type=="ExpressionStatement" &&
              node.body.body[0].expression.type=="Literal" &&
              node.body.body[0].expression.value=="compiled") {
            if (typeof board.EXPORTS != "object") {
              Espruino.Core.Notifications.error("Compiler not active as no process.env.EXPORTS available.
Is your firmware up to date?");
              return callback(code);
            }
            nodes.push(node);
          }
        }
      });
      nodes.forEach(function (node) {
        tasks++;
        $.post(Espruino.Config.COMPILATION_URL, {
              js : code.substring(node.start, node.end),
              exports : JSON.stringify(board.EXPORTS)
            }, function(newCode) {
                  if (newCode) {
                    //console.log(asm);
                    //console.log(node);
                    code = code.substr(0,node.start) + newCode + code.substr(node.end);
                    var offs = newCode.length - (node.end-node.start); // offset for future code snippets
                    for (var i in nodes)
                      if (nodes[i].start > node.start) {
                        nodes[i].start += offs;
                        nodes[i].end += offs;
                      }
                  }
                  tasks--;
                  if (tasks==0)
                    callback(code);
            }).fail(function() {
              Espruino.Core.Notifications.error( "Error contacting server. Unable to compile code right now." );
              tasks--;
              if (tasks==0) callback(code);
            });
      });

    } catch (err) {
      console.log(err);
      Espruino.Core.Notifications.error("Acorn parse for plugins/compiler.js failed.
Check the editor window for syntax errors");
    }
    if (tasks==0)
      callback(code);
  }

  Espruino.Plugins.Compiler = {
    init : init,
  };
}());

<commit_msg>Added option to compile C code<commit_after>/**
 Copyright 2014 Gordon Williams (gw@pur3.co.uk)

 This Source Code is subject to the terms of the Mozilla Public
 License, v2.0. If a copy of the MPL was not distributed with this
 file, You can obtain one at http://mozilla.org/MPL/2.0/.

 ----------------------------------------------------------49--------
  An Compiler that converts any bit of JavaScript tagged with
  "compiled" into native code.

  function foo(a,b) {
    "compiled";
    return a+b;
  }
 ------------------------------------------------------------------
**/
"use strict";
(function(){

  function init() {
    Espruino.Core.Config.add("COMPILATION", {
      section : "Communications",
      name : "JavaScript Compiler",
      descriptionHTML : 'Compile JavaScript functions prefixed with "compiled" into Native code. (More Info)',
      type : "boolean",
      defaultValue : true
    });
    Espruino.Core.Config.add("COMPILATION_URL", {
      section : "Communications",
      name : "JavaScript Compiler URL",
      description : "When JavaScript Compilation is enabled, this is the URL of the JavaScript compiler",
      type : "string",
      defaultValue : "http://www.espruino.com:32766"
    });

    // When code is sent to Espruino, search it for modules and add extra code required to load them
    Espruino.addProcessor("transformForEspruino", function(code, callback) {
      compileCode(code, callback);
    });
  }

  function compileCode(code, callback) {
    if (!Espruino.Config.COMPILATION)
      return callback(code);

    var board = Espruino.Core.Env.getBoardData();
    if (board == undefined) {
      Espruino.Core.Notifications.error("Current board not known - please connect to the Espruino board first");
      return callback(code);
    }

    var tasks = 0;
    try {
      var ast = acorn.parse(code, { ecmaVersion : 6 });
      var tasks = [];
      // function xyz() { "compiled" ... }
      ast.body.forEach(function(node) {
        if (node.type=="FunctionDeclaration") {
          if (node.body.type=="BlockStatement" &&
              node.body.body.length>0 &&
              node.body.body[0].type=="ExpressionStatement" &&
              node.body.body[0].expression.type=="Literal" &&
              node.body.body[0].expression.value=="compiled") {
            tasks.push({
              type:"js",
              node:node,
              source: code.substring(node.start, node.end),
            });
          }
        }
        // 'var xyz = E.compiledC(`templateliteral`)'
        if (node.type=="VariableDeclaration" && node.declarations.length==1) {
          var d = node.declarations[0];
          if (d.type=="VariableDeclarator" &&
              d.init &&
              d.init.type=="CallExpression" &&
              d.init.callee.type=="MemberExpression" &&
              d.init.callee.object.name=="E" &&
              d.init.callee.property.name=="compiledC" &&
              d.init.arguments &&
              d.init.arguments.length==1 &&
              d.init.arguments[0].type=="TemplateLiteral") {
                tasks.push({
                  type:"c",
                  node:d.init,
                  source: d.init.arguments[0].quasis[0].value.raw,
                });
          }
        }
      });
      if (tasks.length) {
        if (typeof board.EXPORTS != "object" &&
            typeof board.EXPTR != "number"  ) {
          Espruino.Core.Notifications.error("Compiler not active as no process.env.EXPORTS/EXPTR available.
Is your board supported and firmware up to date?");
          return callback(code);
        }
      }

      /* Replace this node with the given text, and
      update node start/end positions of other nodes
      we're interested in */
      function replaceNode(node, newCode) {
        code = code.substr(0,node.start) + newCode + code.substr(node.end);
        var offs = newCode.length - (node.end-node.start); // offset for future code snippets
        for (var i in tasks)
          if (tasks[i].node.start > node.start) {
            tasks[i].node.start += offs;
            tasks[i].node.end += offs;
          }
      }
      var taskCount = 0;
      tasks.forEach(function (task) {
        taskCount++;
        var compileData = {};
        if (task.type=="js") {
          compileData.js = task.source;
        } else if (task.type == "c") {
          compileData.c = task.source;
        } else throw new Error("Unknown Node type");
        if (board.EXPORTS)
          compileData.exports = JSON.stringify(board.EXPORTS);
        if (board.EXPTR)
          compileData.exptr = JSON.stringify(board.EXPTR);

        $.post(Espruino.Config.COMPILATION_URL, compileData, function(newCode) {
          if (newCode) {
            replaceNode(task.node, newCode);
          }
          taskCount--;
          if (taskCount==0)
            callback(code);
        }).fail(function() {
          Espruino.Core.Notifications.error( "Error contacting server. Unable to compile code right now." );
          taskCount--;
          if (taskCount==0) callback(code);
        });
      });

    } catch (err) {
      console.log(err);
      Espruino.Core.Notifications.error("Acorn parse for plugins/compiler.js failed.
Check the editor window for syntax errors");
    }
    if (tasks==0)
      callback(code);
  }

  Espruino.Plugins.Compiler = {
    init : init,
  };
}());
<|endoftext|>


<commit_before>/**
* Connector will handel all Ajax code
*/
define(["modules/response", "jquery"], function (Response, $) {

   /**
    * Ajax GET method
    * @param {String} url Url of resource
    * @param {Function} successCallback Function called if a request executes successfully
    * @param {Function} failCallback Function called if a request does not execute successfully
    */
   var publicGet = function (url, successCallback, failCallback) {
       $.ajax({
           accepts: "application/json",
           url: url,
           dataType: "json" // Do not let jQuery automatically parse the JSON response
       }).done(function (data, textStatus) {
           // Request was successful
           successCallback(parseJson(data));
       }).fail(function (jqXHR, textStatus, errorThrown) {
           // Request failed for some reason
           var response = new Response();

           response.setStatus(textStatus);
           response.setError("GET " + url + " " + jqXHR.status + " (" + jqXHR.statusText + ")");

           failCallback(response);
       });
   };

   /**
    * Ajax DELETE method
    * @param {type} url Url of resource
    * @param {type} successCallback Callback to execute on success
    * @param {type} failCallback Callback to execute on failure
    */
   var publicDelete = function (url, successCallback, failCallback) {
       $.ajax({
           type: "DELETE",
           accepts: "application/json",
           url: url,
           dataType: "json"
       }).done(function (data, textStatus) {
           successCallback(parseJson(data));
       }).fail(function (jqXHR, textStatus, errorThrown) {
           // Request failed for some reason
           var response = new Response();

           response.setStatus(textStatus);
           response.setError("DELETE " + url + " " + jqXHR.status + " (" + jqXHR.statusText + ")");

           failCallback(response);
       });
   };

   /**
    * Ajax PUT method
    * @param {type} url Url of resource
    * @param {type} data String or plain object that will be sent
    * @param {type} successCallback Callback to execute on success
    * @param {type} failCallback Callback to execute on failure
    */
   var publicPut = function(url, data,successCallback, failCallback) {
       $.ajax({
           type: "PUT",
           url: url,
           data: data,
           dataType: "json"
       }).done(function (data, textStatus) {
           successCallback(parseJson(data));
       }).fail(function (jqXHR, textStatus, errorThrown) {
           // Request failed for some reason
           var response = new Response();

           response.setStatus(textStatus);
           response.setError("DELETE " + url + " " + jqXHR.status + " (" + jqXHR.statusText + ")");

           failCallback(response);

       });

   }

   /**
    * Parse a JSON object
    * @param {jsonObject} jsonObject JSON document that has been translated by jQuery to an Object
    * @param {String} textStatus Status text from jQuery.ajax
    */
   var parseJson = function (jsonObject, textStatus) {
       var response = new Response();

       response.setData(jsonObject);
       response.setStatus(textStatus);

       return response;
   };

   return {
       get: publicGet,
       delete: publicDelete,
       put: publicPut
   };
});<commit_msg>Summary - Made Status not undefined when returning a Response in Connector<commit_after>/**
* Connector will handel all Ajax code
*/
define(["modules/response", "jquery"], function (Response, $) {

   /**
    * Ajax GET method
    * @param {String} url Url of resource
    * @param {Function} successCallback Function called if a request executes successfully
    * @param {Function} failCallback Function called if a request does not execute successfully
    */
   var publicGet = function (url, successCallback, failCallback) {
       $.ajax({
           accepts: "application/json",
           url: url,
           dataType: "json" // Do not let jQuery automatically parse the JSON response
       }).done(function (data, textStatus) {
           // Request was successful
           successCallback(parseJson(data));
       }).fail(function (jqXHR, textStatus, errorThrown) {
           // Request failed for some reason
           var response = new Response();

           response.setStatus(textStatus);
           response.setError("GET " + url + " " + jqXHR.status + " (" + jqXHR.statusText + ")");

           failCallback(response);
       });
   };

   /**
    * Ajax DELETE method
    * @param {type} url Url of resource
    * @param {type} successCallback Callback to execute on success
    * @param {type} failCallback Callback to execute on failure
    */
   var publicDelete = function (url, successCallback, failCallback) {
       $.ajax({
           type: "DELETE",
           accepts: "application/json",
           url: url,
           dataType: "json"
       }).done(function (data, textStatus) {
           successCallback(parseJson(data));
       }).fail(function (jqXHR, textStatus, errorThrown) {
           // Request failed for some reason
           var response = new Response();

           response.setStatus(textStatus);
           response.setError("DELETE " + url + " " + jqXHR.status + " (" + jqXHR.statusText + ")");

           failCallback(response);
       });
   };

   /**
    * Ajax PUT method
    * @param {type} url Url of resource
    * @param {type} data String or plain object that will be sent
    * @param {type} successCallback Callback to execute on success
    * @param {type} failCallback Callback to execute on failure
    */
   var publicPut = function(url, data,successCallback, failCallback) {
       $.ajax({
           type: "PUT",
           url: url,
           data: data,
           dataType: "json"
       }).done(function (data, textStatus) {
           successCallback(parseJson(data));
       }).fail(function (jqXHR, textStatus, errorThrown) {
           // Request failed for some reason
           var response = new Response();

           response.setStatus(textStatus);
           response.setError("DELETE " + url + " " + jqXHR.status + " (" + jqXHR.statusText + ")");

           failCallback(response);

       });

   }

   /**
    * Parse a JSON object
    * @param {jsonObject} jsonObject JSON document that has been translated by jQuery to an Object
    * @param {String} textStatus Status text from jQuery.ajax
    */
   var parseJson = function (jsonObject, textStatus) {
       var response = new Response();

       response.setData(jsonObject);
       if (textStatus) {
            response.setStatus(textStatus);
       }

       return response;
   };

   return {
       get: publicGet,
       delete: publicDelete,
       put: publicPut
   };
});<|endoftext|>


<commit_before>module.exports = function(game) {
  game.on("player:join", function(player) {
    player.client.on("packet:0a", on_move.bind(player));
    player.client.on("packet:0b", on_move.bind(player));
    player.client.on("packet:0c", on_move.bind(player));
    player.client.on("packet:0d", on_move.bind(player));
  });

  game.on("tick", update_positions.bind(null, game));
};

var on_move = function on_move(packet) {
  ["yaw", "pitch"].forEach(function(e) {
    if (typeof packet[e] !== "undefined") {
      packet[e] = packet[e] % 360;

      while (packet[e] < 0) {
        packet[e] += 360;
      }
    }
  });

  ["x", "y", "z", "stance", "on_ground", "yaw", "pitch"].forEach(function(k) {
    if (typeof packet[k] !== "undefined" && packet[k] !== this.position[k]) {
      this.new_position[k] = packet[k];
    }
  }.bind(this));

  if (this.new_position.y < -32) {
    this.new_position.y = 10;
    this.new_position.stance = 11.62;
  }
};

var update_positions = function update_positions(game) {
  game.players.filter(function(e) { return Object.keys(e.new_position).length > 0; }).forEach(function(player) {
    var x_delta = typeof player.new_position.x === "number" ? player.new_position.x - player.position.x : 0,
        y_delta = typeof player.new_position.y === "number" ? player.new_position.y - player.position.y : 0,
        z_delta = typeof player.new_position.z === "number" ? player.new_position.z - player.position.z : 0;

    var packet;

    if (x_delta > -4 && x_delta < 4 && y_delta > -4 && y_delta < 4 && z_delta > -4 && z_delta < 4) {
      packet = {
        pid:   0x21,
        eid:   player.eid,
        x:     x_delta,
        y:     y_delta,
        z:     z_delta,
        yaw:   player.new_position.yaw || player.position.yaw,
        pitch: player.new_position.pitch || player.position.pitch,
      };
    } else {
      packet = {
        pid:   0x22,
        eid:   player.eid,
        x:     player.new_position.x || player.position.x,
        y:     player.new_position.y || player.position.y,
        z:     player.new_position.z || player.position.z,
        yaw:   player.new_position.yaw || player.position.yaw,
        pitch: player.new_position.pitch || player.position.pitch,
      };
    }

    game.players.forEach(function(other) {
      if (other === player) { return; }
      other.client.emit("data", packet);
    });

    Object.keys(player.new_position).forEach(function(k) {
      player.position[k] = player.new_position[k];
      delete player.new_position[k];
    });
  });
};
<commit_msg>clamped maximum relative move packet values down to 3 from 4<commit_after>module.exports = function(game) {
  game.on("player:join", function(player) {
    player.client.on("packet:0a", on_move.bind(player));
    player.client.on("packet:0b", on_move.bind(player));
    player.client.on("packet:0c", on_move.bind(player));
    player.client.on("packet:0d", on_move.bind(player));
  });

  game.on("tick", update_positions.bind(null, game));
};

var on_move = function on_move(packet) {
  ["yaw", "pitch"].forEach(function(e) {
    if (typeof packet[e] !== "undefined") {
      packet[e] = packet[e] % 360;

      while (packet[e] < 0) {
        packet[e] += 360;
      }
    }
  });

  ["x", "y", "z", "stance", "on_ground", "yaw", "pitch"].forEach(function(k) {
    if (typeof packet[k] !== "undefined" && packet[k] !== this.position[k]) {
      this.new_position[k] = packet[k];
    }
  }.bind(this));

  if (this.new_position.y < -32) {
    this.new_position.y = 10;
    this.new_position.stance = 11.62;
  }
};

var update_positions = function update_positions(game) {
  game.players.filter(function(e) { return Object.keys(e.new_position).length > 0; }).forEach(function(player) {
    var x_delta = typeof player.new_position.x === "number" ? player.new_position.x - player.position.x : 0,
        y_delta = typeof player.new_position.y === "number" ? player.new_position.y - player.position.y : 0,
        z_delta = typeof player.new_position.z === "number" ? player.new_position.z - player.position.z : 0;

    var packet;

    if (x_delta > -3 && x_delta < 3 && y_delta > -3 && y_delta < 3 && z_delta > -3 && z_delta < 3) {
      packet = {
        pid:   0x21,
        eid:   player.eid,
        x:     x_delta,
        y:     y_delta,
        z:     z_delta,
        yaw:   player.new_position.yaw || player.position.yaw,
        pitch: player.new_position.pitch || player.position.pitch,
      };
    } else {
      packet = {
        pid:   0x22,
        eid:   player.eid,
        x:     player.new_position.x || player.position.x,
        y:     player.new_position.y || player.position.y,
        z:     player.new_position.z || player.position.z,
        yaw:   player.new_position.yaw || player.position.yaw,
        pitch: player.new_position.pitch || player.position.pitch,
      };
    }

    game.players.forEach(function(other) {
      if (other === player) { return; }
      other.client.emit("data", packet);
    });

    Object.keys(player.new_position).forEach(function(k) {
      player.position[k] = player.new_position[k];
      delete player.new_position[k];
    });
  });
};
<|endoftext|>


<commit_before>var inherits = require('inherits');
var EventEmitter = require('events').EventEmitter;

var bcoin = require('../bcoin');
var constants = bcoin.protocol.constants;
var preload = bcoin.protocol.preload;
var utils = bcoin.utils;
var assert = utils.assert;

function Chain(options) {
  if (!(this instanceof Chain))
    return new Chain(options);

  EventEmitter.call(this);

  this.options = options || {};
  this.prefix = 'bt/chain/';
  this.storage = this.options.storage;
  this.strict = this.options.strict || false;
  this.block = {
    list: [],

    // Bloom filter for all known blocks
    bloom: new bcoin.bloom(8 * 1024 * 1024, 16, 0xdeadbeef)
  };
  this.orphan = {
    map: {},
    count: 0
  };
  this.index = {
    bloom: null,
    hashes: [],
    ts: [],
    heights: [],
    lastTs: 0
  };
  this.request = new utils.RequestCache();

  this.fromJSON(preload);

  // Last TS after preload, needed for fill percent
  this.index.lastTs = this.index.ts[this.index.ts.length - 1];

  this.loading = false;
  this._init();
}
inherits(Chain, EventEmitter);
module.exports = Chain;

function compareTs(a, b) {
  return a -b;
}

Chain.prototype._init = function _init() {
  if (!this.storage)
    return;

  this.loading = true;
  var self = this;
  var s = this.storage.createReadStream({
    start: this.prefix,
    end: this.prefix + 'z'
  });
  s.on('data', function(data) {
    var hash = data.key.slice(self.prefix.length);
    self._addIndex(hash, data.value.ts, data.value.height);
  });
  s.on('error', function(err) {
    self.emit('error', err);
  });
  s.on('end', function() {
    self.loading = false;
    self.emit('load');
  });
};

Chain.prototype._getRange = function _getRange(hash, ts, futureOnly) {
  var pos = utils.binaryInsert(this.index.ts, ts, compareTs, true);
  var start = Math.min(Math.max(0, pos), this.index.ts.length - 1);

  while (start > 0 && this.index.ts[start] > ts)
    start--;

  var curr = this.index.ts[start];
  var wnd = 2 * 3600;

  if (!futureOnly)
    while (start > 0 && this.index.ts[start] + wnd > curr)
      start--;

  var end = Math.min(Math.max(0, pos), this.index.ts.length - 1);
  while (end < this.index.ts.length - 1 && this.index.ts[end] - wnd < ts)
    end++;

  return { start: start, end: end };
};

Chain.prototype._probeIndex = function _probeIndex(hash, ts) {
  if (!this.index.bloom.test(hash, 'hex'))
    return false;

  var start = 0;
  var end = this.index.ts.length;
  if (ts) {
    var range = this._getRange(hash, ts);
    start = range.start;
    end = range.end;
  }

  for (var i = start; i <= end; i++)
    if (this.index.hashes[i] === hash)
      return { i: i, height: this.index.heights[i], ts: this.index.ts[i] };

  return false;
};

Chain.prototype._addIndex = function _addIndex(hash, ts, height) {
  if (this._probeIndex(hash, ts))
    return;

  var pos = utils.binaryInsert(this.index.ts, ts, compareTs, true);

  // Avoid duplicates
  if (this.index.hashes[pos] === hash ||
      this.index.hashes[pos - 1] === hash ||
      this.index.hashes[pos + 1] === hash) {
    return;
  }

  this.index.ts.splice(pos, 0, ts);
  this.index.hashes.splice(pos, 0, hash);
  this.index.heights.splice(pos, 0, height);
  this.index.bloom.add(hash, 'hex');

  if (!this.storage)
    return;

  var self = this;
  var obj = { ts: ts, height: height };
  this.storage.put(this.prefix + hash, obj, function(err) {
    if (err)
      self.emit('error', err);
  });
};

Chain.prototype._killFork = function _killFork(probe) {
  var delta = 2 * 3600;
  var upper = probe.ts + delta;
  var lower = probe.ts - delta;

  // Search duplicate heights down
  var index = -1;
  for (var i = probe.i - 1; i > 0 && this.index.ts[i] > lower; i--) {
    if (probe.height === this.index.heights[i]) {
      index = i;
      break;
    }
  }

  // And up
  if (index === -1) {
    var len = this.index.ts.length;
    for (var i = probe.i + 1; i < len && this.index.ts[i] < upper; i++) {
      if (probe.height === this.index.heights[i]) {
        index = i;
        break;
      }
    }
  }

  if (index === -1)
    return false;

  var hash = this.index.hashes[index];
  this.index.hashes.splice(index, 1);
  this.index.ts.splice(index, 1);
  this.index.heights.splice(index, 1);

  // Delete both blocks, let's see what others will choose
  if (!this.storage)
    return true;

  var self = this;
  this.storage.del(this.prefix + hash, obj, function(err) {
    if (err)
      self.emit('error', err);
  });

  return true;
};

Chain.prototype.add = function add(block) {
  if (this.loading) {
    this.once('load', function() {
      this.add(block);
    });
    return;
  }

  var res = false;
  var initial = block;
  do {
    // No need to revalidate orphans
    if (!res && !block.verify())
      break;

    var hash = block.hash('hex');
    var prev = block.prevBlock;

    // If the block is already known to be an orphan
    if (this.orphan.map[prev])
      break;

    var prevProbe = this._probeIndex(prev, block.ts);

    // Remove forked nodes from storage, if shorter chain is detected
    if (this._killFork(prevProbe))
      break;

    // If previous block wasn't ever seen - add current to orphans
    if (!this._probeIndex(hash, block.ts) && !prevProbe) {
      this.orphan.count++;
      this.orphan.map[prev] = block;

      var range = this._getRange(hash, block.ts, true);
      var hashes = this.index.hashes.slice(range.start, range.end + 1);
      this.emit('missing', prev, hashes, block);
      break;
    }

    // Validated known block at this point - add it to index
    if (prevProbe)
      this._addIndex(hash, block.ts, prevProbe.height + 1);

    // At least one block was added
    res = true;
    this.block.list.push(block);
    this._bloomBlock(block);

    // Fullfill request
    this.request.fullfill(hash, block);

    if (!this.orphan.map[hash])
      break;

    // We have orphan child for this block - add it to chain
    block = this.orphan.map[hash];
    delete this.orphan.map[hash];
    this.orphan.count--;
  } while (true);

  // Compress old blocks
  this._compress();

  return res;
};

Chain.prototype._compress = function compress() {
  // Keep at least 1000 blocks and at most 2000
  if (this.block.list.length < 2000)
    return;

  // Bloom filter rebuilt is needed
  this.block.list = this.block.list.slice(-1000);
  this.block.bloom.reset();

  for (var i = 0; i < this.block.list.length; i++)
    this._bloomBlock(this.block.list[i]);
};

Chain.prototype._bloomBlock = function _bloomBlock(block) {
  this.block.bloom.add(block.hash(), 'hex');
};

Chain.prototype.has = function has(hash, noProbe, cb) {
  if (typeof noProbe === 'function') {
    cb = noProbe;
    noProbe = false;
  }
  if (this.loading) {
    this.once('load', function() {
      this.has(hash, noProbe, cb);
    });
    return;
  }
  cb = utils.asyncify(cb);

  if (this.block.bloom.test(hash, 'hex')) {
    if (this.strict) {
      for (var i = 0; i < this.block.list.length; i++)
        if (this.block.list[i].hash('hex') === hash)
          return cb(true);
    } else {
      return cb(true);
    }
  }

  if (!noProbe && this.index.bloom.test(hash, 'hex')) {
    // XXX find hash
    return cb(true);
  }

  return cb(!!this.orphan.map[hash]);
};

Chain.prototype.get = function get(hash, force, cb) {
  if (typeof force === 'function') {
    cb = force;
    force = false;
  }

  // Cached block found
  if (!force && this.block.bloom.test(hash, 'hex')) {
    for (var i = 0; i < this.block.list.length; i++) {
      if (this.block.list[i].hash('hex') === hash) {
        // NOTE: we return right after the statement - so `block` should be
        // valid at the time of nextTick call
        var block = this.block.list[i];
        bcoin.utils.nextTick(function() {
          cb(block);
        });
        return;
      }
    }
    assert(false);
  }

  if (this.request.add(hash, cb))
    this.emit('missing', hash, null, null);
};

Chain.prototype.isFull = function isFull() {
  // < 40m since last block
  if (this.request.count)
    return false;

  var delta = (+new Date() / 1000) - this.index.ts[this.index.ts.length - 1];
  return delta < 40 * 60;
};

Chain.prototype.fillPercent = function fillPercent() {
  var total = (+new Date() / 1000 - 40 * 60) - this.index.lastTs;
  var current = this.index.ts[this.index.ts.length - 1] - this.index.lastTs;
  return Math.min(0, Math.max(current / total, 1));
};

Chain.prototype.hashesInRange = function hashesInRange(start, end, cb) {
  if (this.loading) {
    this.once('load', function() {
      this.hashesInRange(start, end, cb);
    });
    return;
  }
  cb = utils.asyncify(cb);
  var ts = this.index.ts;

  start = utils.binaryInsert(ts, start, compareTs, true);
  if (start > 0 && ts[start - 1] >= start)
    start--;
  end = utils.binaryInsert(ts, end, compareTs, true);

  // Zip hashes and heights together and sort them by height
  var hashes = this.index.hashes.slice(start, end);
  var heights = this.index.heights.slice(start, end);
  var zip = [];
  for (var i = 0; i < hashes.length; i++)
    zip.push({ hash: hashes[i], height: heights[i] });
  zip = zip.sort(function(a, b) {
    return a.height - b.height;
  });
  var hashes = zip.map(function(a) {
    return a.hash;
  });

  var count = zip[zip.length - 1].height - zip[0].height + 1;
  return cb(hashes, count);
};

Chain.prototype.getLast = function getLast(cb) {
  if (this.loading) {
    this.once('load', function() {
      this.getLast(cb);
    });
    return;
  }
  cb = utils.asyncify(cb);
  return cb(this.index.hashes[this.index.hashes.length - 1]);
};

Chain.prototype.toJSON = function toJSON() {
  var keep = 1000;

  // Keep only last 1000 consequent blocks, dilate others at:
  // 7 day range for blocks before 2013
  // 12 hour for blocks before 2014
  // 6 hour for blocks in 2014 and after it
  // (or at maximum 250 block range)
  var last = {
    hashes: this.index.hashes.slice(-keep),
    ts: this.index.ts.slice(-keep),
    heights: this.index.heights.slice(-keep)
  };

  var first = {
    hashes: [],
    ts: [],
    heights: []
  };

  var delta1 = 7 * 24 * 3600;
  var delta2 = 12 * 3600;
  var delta3 = 6 * 3600;

  var lastTs = 0;
  var lastHeight = -1000;
  for (var i = 0; i < this.index.ts.length - keep; i++) {
    var ts = this.index.ts[i];
    var delta = ts < 1356984000 ? delta1 :
                ts < 1388520000 ? delta2 : delta3;
    var hdelta = this.index.heights[i] - lastHeight;
    if (ts - lastTs < delta && hdelta < 250)
      continue;

    lastTs = ts;
    lastHeight = this.index.heights[i];
    first.hashes.push(this.index.hashes[i]);
    first.ts.push(this.index.ts[i]);
    first.heights.push(this.index.heights[i]);
  }

  return {
    v: 1,
    type: 'chain',
    hashes: first.hashes.concat(last.hashes),
    ts: first.ts.concat(last.ts),
    heights: first.heights.concat(last.heights)
  };
};

Chain.prototype.fromJSON = function fromJSON(json) {
  assert.equal(json.v, 1);
  assert.equal(json.type, 'chain');
  this.index.hashes = json.hashes.slice();
  this.index.ts = json.ts.slice();
  this.index.heights = json.heights.slice();
  if (this.index.bloom)
    this.index.bloom.reset();
  else
    this.index.bloom = new bcoin.bloom(28 * 1024 * 1024, 16, 0xdeadbee0);

  if (this.index.hashes.length === 0)
    this.add(new bcoin.block(constants.genesis, 'block'));

  for (var i = 0; i < this.index.hashes.length; i++) {
    this.index.bloom.add(this.index.hashes[i], 'hex');
  }
};
<commit_msg>chain: fix undefined var in storage.del call.<commit_after>var inherits = require('inherits');
var EventEmitter = require('events').EventEmitter;

var bcoin = require('../bcoin');
var constants = bcoin.protocol.constants;
var preload = bcoin.protocol.preload;
var utils = bcoin.utils;
var assert = utils.assert;

function Chain(options) {
  if (!(this instanceof Chain))
    return new Chain(options);

  EventEmitter.call(this);

  this.options = options || {};
  this.prefix = 'bt/chain/';
  this.storage = this.options.storage;
  this.strict = this.options.strict || false;
  this.block = {
    list: [],

    // Bloom filter for all known blocks
    bloom: new bcoin.bloom(8 * 1024 * 1024, 16, 0xdeadbeef)
  };
  this.orphan = {
    map: {},
    count: 0
  };
  this.index = {
    bloom: null,
    hashes: [],
    ts: [],
    heights: [],
    lastTs: 0
  };
  this.request = new utils.RequestCache();

  this.fromJSON(preload);

  // Last TS after preload, needed for fill percent
  this.index.lastTs = this.index.ts[this.index.ts.length - 1];

  this.loading = false;
  this._init();
}
inherits(Chain, EventEmitter);
module.exports = Chain;

function compareTs(a, b) {
  return a -b;
}

Chain.prototype._init = function _init() {
  if (!this.storage)
    return;

  this.loading = true;
  var self = this;
  var s = this.storage.createReadStream({
    start: this.prefix,
    end: this.prefix + 'z'
  });
  s.on('data', function(data) {
    var hash = data.key.slice(self.prefix.length);
    self._addIndex(hash, data.value.ts, data.value.height);
  });
  s.on('error', function(err) {
    self.emit('error', err);
  });
  s.on('end', function() {
    self.loading = false;
    self.emit('load');
  });
};

Chain.prototype._getRange = function _getRange(hash, ts, futureOnly) {
  var pos = utils.binaryInsert(this.index.ts, ts, compareTs, true);
  var start = Math.min(Math.max(0, pos), this.index.ts.length - 1);

  while (start > 0 && this.index.ts[start] > ts)
    start--;

  var curr = this.index.ts[start];
  var wnd = 2 * 3600;

  if (!futureOnly)
    while (start > 0 && this.index.ts[start] + wnd > curr)
      start--;

  var end = Math.min(Math.max(0, pos), this.index.ts.length - 1);
  while (end < this.index.ts.length - 1 && this.index.ts[end] - wnd < ts)
    end++;

  return { start: start, end: end };
};

Chain.prototype._probeIndex = function _probeIndex(hash, ts) {
  if (!this.index.bloom.test(hash, 'hex'))
    return false;

  var start = 0;
  var end = this.index.ts.length;
  if (ts) {
    var range = this._getRange(hash, ts);
    start = range.start;
    end = range.end;
  }

  for (var i = start; i <= end; i++)
    if (this.index.hashes[i] === hash)
      return { i: i, height: this.index.heights[i], ts: this.index.ts[i] };

  return false;
};

Chain.prototype._addIndex = function _addIndex(hash, ts, height) {
  if (this._probeIndex(hash, ts))
    return;

  var pos = utils.binaryInsert(this.index.ts, ts, compareTs, true);

  // Avoid duplicates
  if (this.index.hashes[pos] === hash ||
      this.index.hashes[pos - 1] === hash ||
      this.index.hashes[pos + 1] === hash) {
    return;
  }

  this.index.ts.splice(pos, 0, ts);
  this.index.hashes.splice(pos, 0, hash);
  this.index.heights.splice(pos, 0, height);
  this.index.bloom.add(hash, 'hex');

  if (!this.storage)
    return;

  var self = this;
  var obj = { ts: ts, height: height };
  this.storage.put(this.prefix + hash, obj, function(err) {
    if (err)
      self.emit('error', err);
  });
};

Chain.prototype._killFork = function _killFork(probe) {
  var delta = 2 * 3600;
  var upper = probe.ts + delta;
  var lower = probe.ts - delta;

  // Search duplicate heights down
  var index = -1;
  for (var i = probe.i - 1; i > 0 && this.index.ts[i] > lower; i--) {
    if (probe.height === this.index.heights[i]) {
      index = i;
      break;
    }
  }

  // And up
  if (index === -1) {
    var len = this.index.ts.length;
    for (var i = probe.i + 1; i < len && this.index.ts[i] < upper; i++) {
      if (probe.height === this.index.heights[i]) {
        index = i;
        break;
      }
    }
  }

  if (index === -1)
    return false;

  var hash = this.index.hashes[index];
  this.index.hashes.splice(index, 1);
  this.index.ts.splice(index, 1);
  this.index.heights.splice(index, 1);

  // Delete both blocks, let's see what others will choose
  if (!this.storage)
    return true;

  var self = this;
  this.storage.del(this.prefix + hash, function(err) {
    if (err)
      self.emit('error', err);
  });

  return true;
};

Chain.prototype.add = function add(block) {
  if (this.loading) {
    this.once('load', function() {
      this.add(block);
    });
    return;
  }

  var res = false;
  var initial = block;
  do {
    // No need to revalidate orphans
    if (!res && !block.verify())
      break;

    var hash = block.hash('hex');
    var prev = block.prevBlock;

    // If the block is already known to be an orphan
    if (this.orphan.map[prev])
      break;

    var prevProbe = this._probeIndex(prev, block.ts);

    // Remove forked nodes from storage, if shorter chain is detected
    if (this._killFork(prevProbe))
      break;

    // If previous block wasn't ever seen - add current to orphans
    if (!this._probeIndex(hash, block.ts) && !prevProbe) {
      this.orphan.count++;
      this.orphan.map[prev] = block;

      var range = this._getRange(hash, block.ts, true);
      var hashes = this.index.hashes.slice(range.start, range.end + 1);
      this.emit('missing', prev, hashes, block);
      break;
    }

    // Validated known block at this point - add it to index
    if (prevProbe)
      this._addIndex(hash, block.ts, prevProbe.height + 1);

    // At least one block was added
    res = true;
    this.block.list.push(block);
    this._bloomBlock(block);

    // Fullfill request
    this.request.fullfill(hash, block);

    if (!this.orphan.map[hash])
      break;

    // We have orphan child for this block - add it to chain
    block = this.orphan.map[hash];
    delete this.orphan.map[hash];
    this.orphan.count--;
  } while (true);

  // Compress old blocks
  this._compress();

  return res;
};

Chain.prototype._compress = function compress() {
  // Keep at least 1000 blocks and at most 2000
  if (this.block.list.length < 2000)
    return;

  // Bloom filter rebuilt is needed
  this.block.list = this.block.list.slice(-1000);
  this.block.bloom.reset();

  for (var i = 0; i < this.block.list.length; i++)
    this._bloomBlock(this.block.list[i]);
};

Chain.prototype._bloomBlock = function _bloomBlock(block) {
  this.block.bloom.add(block.hash(), 'hex');
};

Chain.prototype.has = function has(hash, noProbe, cb) {
  if (typeof noProbe === 'function') {
    cb = noProbe;
    noProbe = false;
  }
  if (this.loading) {
    this.once('load', function() {
      this.has(hash, noProbe, cb);
    });
    return;
  }
  cb = utils.asyncify(cb);

  if (this.block.bloom.test(hash, 'hex')) {
    if (this.strict) {
      for (var i = 0; i < this.block.list.length; i++)
        if (this.block.list[i].hash('hex') === hash)
          return cb(true);
    } else {
      return cb(true);
    }
  }

  if (!noProbe && this.index.bloom.test(hash, 'hex')) {
    // XXX find hash
    return cb(true);
  }

  return cb(!!this.orphan.map[hash]);
};

Chain.prototype.get = function get(hash, force, cb) {
  if (typeof force === 'function') {
    cb = force;
    force = false;
  }

  // Cached block found
  if (!force && this.block.bloom.test(hash, 'hex')) {
    for (var i = 0; i < this.block.list.length; i++) {
      if (this.block.list[i].hash('hex') === hash) {
        // NOTE: we return right after the statement - so `block` should be
        // valid at the time of nextTick call
        var block = this.block.list[i];
        bcoin.utils.nextTick(function() {
          cb(block);
        });
        return;
      }
    }
    assert(false);
  }

  if (this.request.add(hash, cb))
    this.emit('missing', hash, null, null);
};

Chain.prototype.isFull = function isFull() {
  // < 40m since last block
  if (this.request.count)
    return false;

  var delta = (+new Date() / 1000) - this.index.ts[this.index.ts.length - 1];
  return delta < 40 * 60;
};

Chain.prototype.fillPercent = function fillPercent() {
  var total = (+new Date() / 1000 - 40 * 60) - this.index.lastTs;
  var current = this.index.ts[this.index.ts.length - 1] - this.index.lastTs;
  return Math.min(0, Math.max(current / total, 1));
};

Chain.prototype.hashesInRange = function hashesInRange(start, end, cb) {
  if (this.loading) {
    this.once('load', function() {
      this.hashesInRange(start, end, cb);
    });
    return;
  }
  cb = utils.asyncify(cb);
  var ts = this.index.ts;

  start = utils.binaryInsert(ts, start, compareTs, true);
  if (start > 0 && ts[start - 1] >= start)
    start--;
  end = utils.binaryInsert(ts, end, compareTs, true);

  // Zip hashes and heights together and sort them by height
  var hashes = this.index.hashes.slice(start, end);
  var heights = this.index.heights.slice(start, end);
  var zip = [];
  for (var i = 0; i < hashes.length; i++)
    zip.push({ hash: hashes[i], height: heights[i] });
  zip = zip.sort(function(a, b) {
    return a.height - b.height;
  });
  var hashes = zip.map(function(a) {
    return a.hash;
  });

  var count = zip[zip.length - 1].height - zip[0].height + 1;
  return cb(hashes, count);
};

Chain.prototype.getLast = function getLast(cb) {
  if (this.loading) {
    this.once('load', function() {
      this.getLast(cb);
    });
    return;
  }
  cb = utils.asyncify(cb);
  return cb(this.index.hashes[this.index.hashes.length - 1]);
};

Chain.prototype.toJSON = function toJSON() {
  var keep = 1000;

  // Keep only last 1000 consequent blocks, dilate others at:
  // 7 day range for blocks before 2013
  // 12 hour for blocks before 2014
  // 6 hour for blocks in 2014 and after it
  // (or at maximum 250 block range)
  var last = {
    hashes: this.index.hashes.slice(-keep),
    ts: this.index.ts.slice(-keep),
    heights: this.index.heights.slice(-keep)
  };

  var first = {
    hashes: [],
    ts: [],
    heights: []
  };

  var delta1 = 7 * 24 * 3600;
  var delta2 = 12 * 3600;
  var delta3 = 6 * 3600;

  var lastTs = 0;
  var lastHeight = -1000;
  for (var i = 0; i < this.index.ts.length - keep; i++) {
    var ts = this.index.ts[i];
    var delta = ts < 1356984000 ? delta1 :
                ts < 1388520000 ? delta2 : delta3;
    var hdelta = this.index.heights[i] - lastHeight;
    if (ts - lastTs < delta && hdelta < 250)
      continue;

    lastTs = ts;
    lastHeight = this.index.heights[i];
    first.hashes.push(this.index.hashes[i]);
    first.ts.push(this.index.ts[i]);
    first.heights.push(this.index.heights[i]);
  }

  return {
    v: 1,
    type: 'chain',
    hashes: first.hashes.concat(last.hashes),
    ts: first.ts.concat(last.ts),
    heights: first.heights.concat(last.heights)
  };
};

Chain.prototype.fromJSON = function fromJSON(json) {
  assert.equal(json.v, 1);
  assert.equal(json.type, 'chain');
  this.index.hashes = json.hashes.slice();
  this.index.ts = json.ts.slice();
  this.index.heights = json.heights.slice();
  if (this.index.bloom)
    this.index.bloom.reset();
  else
    this.index.bloom = new bcoin.bloom(28 * 1024 * 1024, 16, 0xdeadbee0);

  if (this.index.hashes.length === 0)
    this.add(new bcoin.block(constants.genesis, 'block'));

  for (var i = 0; i < this.index.hashes.length; i++) {
    this.index.bloom.add(this.index.hashes[i], 'hex');
  }
};
<|endoftext|>