diff --git a/09-fuzz/flat-azam-shaprunov/README.md b/09-fuzz/flat-azam-shaprunov/README.md new file mode 100644 index 00000000..6d4f7a9b --- /dev/null +++ b/09-fuzz/flat-azam-shaprunov/README.md @@ -0,0 +1,22 @@ +# Bekhruz Azam Flat Buffers solution Node.js + +_student_generated.js file should be in the same folder as solution.js_ + + $ sha256sum data/students.bin + 0c016dc4ca1a8b24b34daa6c05472d16b401fd3c0c5417da18e9810b136704a6 data/students.bin + $ node solution.js data/students.bin + Reading binary student data from data/students.bin... + 3 students read... + written to data/students.flat + $ rm -f data/students.bin + $ node solution.js data/students.flat + Reading flatbuffers student data from data/students.flat... + 3 students read... + written to data/students.bin + $ sha256sum data/students.bin + 0c016dc4ca1a8b24b34daa6c05472d16b401fd3c0c5417da18e9810b136704a6 data/students.bin + +# Shaprunov Kirill Flat buffers Node.js fuzzer +To fuzz for correctness run ```node fuzzer.jz``` setupable TEST_COUNT variable. +All tests completed for me, i fuzzed 100000 times in context of proper input file. +The only change i made was check for input file size for dividing by 128 without any remains. diff --git a/09-fuzz/flat-azam-shaprunov/fuzzer.js b/09-fuzz/flat-azam-shaprunov/fuzzer.js new file mode 100644 index 00000000..ca37bba7 --- /dev/null +++ b/09-fuzz/flat-azam-shaprunov/fuzzer.js @@ -0,0 +1,136 @@ +const fs = require('fs'); +const { exec } = require('child_process'); +const crypto = require('crypto'); +const { v4: uuidv4 } = require('uuid'); +const { getFlat } = require('./solution'); +const { dumpBin } = require('./solution'); +const { parseDataToJson } = require('./solution'); +var flatbuffers = require('flatbuffers').flatbuffers; +var ds = require('./student_generated').ds +var Buffer = require('buffer/').Buffer + +function randomCharString(length, charSet) { + let randomString = ''; + const characters = charSet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + const charactersLength = characters.length; + for (let i = 0; i < length; i++) { + randomString += characters.charAt(Math.floor(Math.random() * charactersLength)); + } + return randomString; +} + +function randomUtf8String(length) { + return randomCharString(length).padEnd(length, '\0'); +} + +function randomAsciiString(length) { + return randomCharString(length, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789').padEnd(length, '\0'); +} + +function randomUrl(length) { + return 'http://'.concat(randomCharString(length - 7, 'abcdefghijklmnopqrstuvwxyz')).padEnd(length, '\0'); +} + +function generateRandomStudentData() { + const name = Buffer.from(randomUtf8String(32), 'utf8'); + const login = Buffer.from(randomAsciiString(16), 'utf8'); + const group = Buffer.from(randomAsciiString(8), 'utf8'); + const practice = crypto.randomBytes(8).map(x => x % 2); // Генерация 8 случайных битовых значений (0 или 1) + const projectRepo = Buffer.from(randomUrl(59), 'utf8'); + const projectMark = Buffer.allocUnsafe(1); // Генерация одного случайного байта для оценки + projectMark.writeUInt8(Math.floor(Math.random() * 100), 0); // Записываем случайное число от 0 до 100 в буфер + const mark = Buffer.allocUnsafe(4); + mark.writeFloatLE(Math.random() * 100, 0); // Записываем случайную оценку в буфер как 32-битное число с плавающей точкой + + const data = Buffer.concat([name, login, group, Buffer.from(practice), projectRepo, projectMark, mark]); + + return data; +} + +function generateMultipleStudentsData(count) { + let studentsData = []; + for (let i = 0; i < count; i++) { + studentsData.push(generateRandomStudentData()); + } + return Buffer.concat(studentsData); +} + +const COUNT = 5; +const studentsData = generateMultipleStudentsData(COUNT); +// console.log(studentsData); +// console.log("Generated data length:", studentsData.length); + +function runCommand(command, callback) { + exec(command, (error, stdout, stderr) => { + if (error) { + console.error(`exec error: ${error}`); + return; + } + // console.log(`stdout: ${stdout}`); + // console.error(`stderr: ${stderr}`); + callback(); + }); +} + +function testConversion(callback) { + const uniqueId = uuidv4(); + const originalFilename = `temp_original_${uniqueId}.bin`; + let fuken = originalFilename.split('.'); + const convertedFilename = `${fuken[0]}.flat`; + + const originalData = generateMultipleStudentsData(1); + fs.writeFileSync(originalFilename, originalData); + + runCommand(`node solution.js ${originalFilename}`, () => { + runCommand(`node solution.js ${convertedFilename}`, () => { + const convertedData = fs.readFileSync(originalFilename); + const result = originalData.compare(convertedData) == 0 ? "Тест пройден: Данные совпадают" : "Ошибка теста: Данные не совпадают"; + const completed = originalData.compare(convertedData) == 0 ? true : false; + // console.log(result); + fs.unlinkSync(originalFilename); + fs.unlinkSync(convertedFilename); + callback(completed); + }); + }); + +} + +function runTests(testCount) { + let completedTests = 0; + const testCompletedCallback = (completed) => { + completedTests++; + if (!completed) { + console.log(`Выполнено тестов: ${completedTests} из ${testCount}`); + console.log("Тест не пройден"); + return; + } + console.log(`Выполнено тестов: ${completedTests}`); + if (completedTests === testCount) { + console.log("Все тесты завершены"); + } + }; + + for (let i = 0; i < testCount; i++) { + testConversion(testCompletedCallback); + } +} + +const TEST_COUNT = 100; +// runTests(TEST_COUNT); + +function fuzz(data) { + try { + let parsedData = parseDataToJson(data); + let flatBuf = getFlat(parsedData); + const resultData = dumpBin(flatBuf); + if (data.compare(resultData) != 0) { + console.log("Ошибка теста: Данные не совпадают"); + } + } catch (error) { + console.error(`Malformed input`); + } +}; + +module.exports = { + fuzz +}; diff --git a/09-fuzz/flat-azam-shaprunov/solution.js b/09-fuzz/flat-azam-shaprunov/solution.js new file mode 100644 index 00000000..0eb33680 --- /dev/null +++ b/09-fuzz/flat-azam-shaprunov/solution.js @@ -0,0 +1,157 @@ +var flatbuffers = require('flatbuffers'); +var fs = require('fs'); +var ds = require('./student_generated').ds +var Buffer = require('buffer/').Buffer + + +function parseBin(path) { + var data = fs.readFileSync(path); + return parseDataToJson(data); +} + +function safelyReadFloatLE(buffer, offset) { + const FLOAT_SIZE = 4; + if (offset + FLOAT_SIZE > buffer.length) { + throw new Error("Trying to read beyond buffer length"); + } + return buffer.readFloatLE(offset); +} + +function parseDataToJson(data) { + var fileData = Buffer.from(data, "utf8"); + var N = Buffer.byteLength(data, "utf8"); + if (N % 128 != 0) { + // console.error("Parsing error: invalid file size to input .bin"); + throw new Error("Invalid file size to input .bin"); + } + var res = []; + for (var i = 0; i < N; i += 128) { + var name = fileData.slice(i + 0, i + 32).toString(); + var login = fileData.slice(i + 32, i + 48).toString(); + var group = fileData.slice(i + 48, i + 56).toString(); + var practice = Array.from(new TextEncoder().encode(fileData.slice(i + 56, i + 64))); + var repo = fileData.slice(i + 64, i + 123).toString(); + var markk = new TextEncoder().encode(fileData.slice(i + 123, i + 124))[0]; + try { + var mark = safelyReadFloatLE(fileData, 124); + } catch (e) { + console.log(e.message); + throw e; + } + res.push({ + 'name' : name, + 'login' : login, + 'group' : group, + 'practice' : practice, + 'project' : { + 'repo' : repo, + 'mark' : markk + }, + 'mark' : mark + }); + + } + return res; +} + +function getFlat(binStudent) { + studs = [] + var builder = new flatbuffers.Builder(1024); + for (var i = 0; i < N; i++) { + var stud = binStudent[i] + + var name = builder.createString(stud.name); + var login = builder.createString(stud.login); + var group = builder.createString(stud.group); + + var repo = builder.createString(stud.project.repo); + ds.Proj.startProj(builder); + ds.Proj.addRepo(builder, repo); + ds.Proj.addMark(builder, stud.project.mark) + var project = ds.Proj.endProj(builder); + + var practice = ds.Student.createPracticeVector(builder, stud.practice); + + ds.Student.startStudent(builder); + ds.Student.addName(builder, name); + ds.Student.addLogin(builder, login); + ds.Student.addGroup(builder, group); + ds.Student.addPractice(builder, practice); + + ds.Student.addProject(builder, project); + + ds.Student.addMark(builder, stud.mark); + var student = ds.Student.endStudent(builder); + studs.push(student) + } + var kings = ds.Students.createKingsVector(builder, studs); + ds.Students.startStudents(builder); + ds.Students.addKings(builder, kings); + var students = ds.Students.endStudents(builder); + builder.finish(students); + var buf = builder.asUint8Array(); + var kek = builder.dataBuffer(); + return kek; +} + +function dumpBin(buf) { + var students = ds.Students.getRootAsStudents(buf); + var N = students.kingsLength(); + res = [] + for (var i = 0; i < N; i++) { + var king = studs.kings(i); + var name = Buffer.from(king.name()); + var login = Buffer.from(king.login()); + var group = Buffer.from(king.group()); + var practice = []; + for (var j = 0; j < 8; ++j) { + practice.push(king.practice(j)); + } + practice = Buffer.from(practice) + var repo = Buffer.from(king.project().repo()); + var markk = Buffer.from([king.project().mark()]); + var mark = Buffer.allocUnsafe(4); + mark.writeFloatLE(king.mark()); + res.push(Buffer.concat([name, login, group, practice, repo, markk, mark])); + } + return Buffer.concat(res); +} + + +if (process.argv.length < 3) { + console.log("provide arguments") + return; +} + +if (process.argv[2].split('.').pop() == 'bin') { + console.log(`Reading binary student data from ${process.argv[2]}...`); + var binStudents = parseBin(process.argv[2]); + var N = binStudents.length; + console.log(`${N} student${N > 1 ? 's' : ''} read...`); + var fileName = process.argv[2].split('.'); + fileName.pop(); + fileName.push('flat'); + fileName = fileName.join('.'); + + buf = getFlat(binStudents); + fs.writeFileSync(fileName, buf, 'binary'); + console.log(`written to ${fileName}`); +} else if (process.argv[2].split('.').pop() == 'flat') { + console.log(`Reading flatbuffers student data from ${process.argv[2]}...`); + var bytes = new Uint8Array(fs.readFileSync(process.argv[2])); + var buf = new flatbuffers.ByteBuffer(bytes); + console.log(`${N} student${N > 1 ? 's' : ''} read...`); + var fileName = process.argv[2].split('.'); + fileName.pop(); + fileName.push('bin'); + fileName = fileName.join('.'); + let bufNew = dumpBin(buf); + fs.writeFileSync(fileName, bufNew, 'binary'); + console.log(`written to ${fileName}`); +} else { + console.log("wrong format"); +} + +module.exports.parseDataToJson = parseDataToJson; +module.exports.dumpBin = dumpBin; +module.exports.getFlat = getFlat; diff --git a/09-fuzz/flat-azam-shaprunov/student.fbs b/09-fuzz/flat-azam-shaprunov/student.fbs new file mode 100644 index 00000000..a6818a1a --- /dev/null +++ b/09-fuzz/flat-azam-shaprunov/student.fbs @@ -0,0 +1,21 @@ +namespace ds; + +table Proj { + repo : string; + mark : ubyte; +} + +table Student { + name : string; + login : string; + group : string; + practice : [ubyte]; + project : Proj; + mark : float; +} + +table Students { + kings : [Student]; +} + +root_type Students; \ No newline at end of file diff --git a/09-fuzz/flat-azam-shaprunov/student_generated.js b/09-fuzz/flat-azam-shaprunov/student_generated.js new file mode 100644 index 00000000..0d154a1d --- /dev/null +++ b/09-fuzz/flat-azam-shaprunov/student_generated.js @@ -0,0 +1,472 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +/** + * @const + * @namespace + */ +var ds = ds || {}; + +/** + * @constructor + */ +ds.Proj = function() { + /** + * @type {flatbuffers.ByteBuffer} + */ + this.bb = null; + + /** + * @type {number} + */ + this.bb_pos = 0; +}; + +/** + * @param {number} i + * @param {flatbuffers.ByteBuffer} bb + * @returns {ds.Proj} + */ +ds.Proj.prototype.__init = function(i, bb) { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {ds.Proj=} obj + * @returns {ds.Proj} + */ +ds.Proj.getRootAsProj = function(bb, obj) { + return (obj || new ds.Proj).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {ds.Proj=} obj + * @returns {ds.Proj} + */ +ds.Proj.getSizePrefixedRootAsProj = function(bb, obj) { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new ds.Proj).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {flatbuffers.Encoding=} optionalEncoding + * @returns {string|Uint8Array|null} + */ +ds.Proj.prototype.repo = function(optionalEncoding) { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @returns {number} + */ +ds.Proj.prototype.mark = function() { + var offset = this.bb.__offset(this.bb_pos, 6); + return offset ? this.bb.readUint8(this.bb_pos + offset) : 0; +}; + +/** + * @param {flatbuffers.Builder} builder + */ +ds.Proj.startProj = function(builder) { + builder.startObject(2); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} repoOffset + */ +ds.Proj.addRepo = function(builder, repoOffset) { + builder.addFieldOffset(0, repoOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} mark + */ +ds.Proj.addMark = function(builder, mark) { + builder.addFieldInt8(1, mark, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @returns {flatbuffers.Offset} + */ +ds.Proj.endProj = function(builder) { + var offset = builder.endObject(); + return offset; +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} repoOffset + * @param {number} mark + * @returns {flatbuffers.Offset} + */ +ds.Proj.createProj = function(builder, repoOffset, mark) { + ds.Proj.startProj(builder); + ds.Proj.addRepo(builder, repoOffset); + ds.Proj.addMark(builder, mark); + return ds.Proj.endProj(builder); +} + +/** + * @constructor + */ +ds.Student = function() { + /** + * @type {flatbuffers.ByteBuffer} + */ + this.bb = null; + + /** + * @type {number} + */ + this.bb_pos = 0; +}; + +/** + * @param {number} i + * @param {flatbuffers.ByteBuffer} bb + * @returns {ds.Student} + */ +ds.Student.prototype.__init = function(i, bb) { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {ds.Student=} obj + * @returns {ds.Student} + */ +ds.Student.getRootAsStudent = function(bb, obj) { + return (obj || new ds.Student).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {ds.Student=} obj + * @returns {ds.Student} + */ +ds.Student.getSizePrefixedRootAsStudent = function(bb, obj) { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new ds.Student).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {flatbuffers.Encoding=} optionalEncoding + * @returns {string|Uint8Array|null} + */ +ds.Student.prototype.name = function(optionalEncoding) { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param {flatbuffers.Encoding=} optionalEncoding + * @returns {string|Uint8Array|null} + */ +ds.Student.prototype.login = function(optionalEncoding) { + var offset = this.bb.__offset(this.bb_pos, 6); + return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param {flatbuffers.Encoding=} optionalEncoding + * @returns {string|Uint8Array|null} + */ +ds.Student.prototype.group = function(optionalEncoding) { + var offset = this.bb.__offset(this.bb_pos, 8); + return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param {number} index + * @returns {number} + */ +ds.Student.prototype.practice = function(index) { + var offset = this.bb.__offset(this.bb_pos, 10); + return offset ? this.bb.readUint8(this.bb.__vector(this.bb_pos + offset) + index) : 0; +}; + +/** + * @returns {number} + */ +ds.Student.prototype.practiceLength = function() { + var offset = this.bb.__offset(this.bb_pos, 10); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @returns {Uint8Array} + */ +ds.Student.prototype.practiceArray = function() { + var offset = this.bb.__offset(this.bb_pos, 10); + return offset ? new Uint8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null; +}; + +/** + * @param {ds.Proj=} obj + * @returns {ds.Proj|null} + */ +ds.Student.prototype.project = function(obj) { + var offset = this.bb.__offset(this.bb_pos, 12); + return offset ? (obj || new ds.Proj).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null; +}; + +/** + * @returns {number} + */ +ds.Student.prototype.mark = function() { + var offset = this.bb.__offset(this.bb_pos, 14); + return offset ? this.bb.readFloat32(this.bb_pos + offset) : 0.0; +}; + +/** + * @param {flatbuffers.Builder} builder + */ +ds.Student.startStudent = function(builder) { + builder.startObject(6); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} nameOffset + */ +ds.Student.addName = function(builder, nameOffset) { + builder.addFieldOffset(0, nameOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} loginOffset + */ +ds.Student.addLogin = function(builder, loginOffset) { + builder.addFieldOffset(1, loginOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} groupOffset + */ +ds.Student.addGroup = function(builder, groupOffset) { + builder.addFieldOffset(2, groupOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} practiceOffset + */ +ds.Student.addPractice = function(builder, practiceOffset) { + builder.addFieldOffset(3, practiceOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +ds.Student.createPracticeVector = function(builder, data) { + builder.startVector(1, data.length, 1); + for (var i = data.length - 1; i >= 0; i--) { + builder.addInt8(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +ds.Student.startPracticeVector = function(builder, numElems) { + builder.startVector(1, numElems, 1); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} projectOffset + */ +ds.Student.addProject = function(builder, projectOffset) { + builder.addFieldOffset(4, projectOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} mark + */ +ds.Student.addMark = function(builder, mark) { + builder.addFieldFloat32(5, mark, 0.0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @returns {flatbuffers.Offset} + */ +ds.Student.endStudent = function(builder) { + var offset = builder.endObject(); + return offset; +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} nameOffset + * @param {flatbuffers.Offset} loginOffset + * @param {flatbuffers.Offset} groupOffset + * @param {flatbuffers.Offset} practiceOffset + * @param {flatbuffers.Offset} projectOffset + * @param {number} mark + * @returns {flatbuffers.Offset} + */ +ds.Student.createStudent = function(builder, nameOffset, loginOffset, groupOffset, practiceOffset, projectOffset, mark) { + ds.Student.startStudent(builder); + ds.Student.addName(builder, nameOffset); + ds.Student.addLogin(builder, loginOffset); + ds.Student.addGroup(builder, groupOffset); + ds.Student.addPractice(builder, practiceOffset); + ds.Student.addProject(builder, projectOffset); + ds.Student.addMark(builder, mark); + return ds.Student.endStudent(builder); +} + +/** + * @constructor + */ +ds.Students = function() { + /** + * @type {flatbuffers.ByteBuffer} + */ + this.bb = null; + + /** + * @type {number} + */ + this.bb_pos = 0; +}; + +/** + * @param {number} i + * @param {flatbuffers.ByteBuffer} bb + * @returns {ds.Students} + */ +ds.Students.prototype.__init = function(i, bb) { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {ds.Students=} obj + * @returns {ds.Students} + */ +ds.Students.getRootAsStudents = function(bb, obj) { + return (obj || new ds.Students).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {ds.Students=} obj + * @returns {ds.Students} + */ +ds.Students.getSizePrefixedRootAsStudents = function(bb, obj) { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new ds.Students).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {number} index + * @param {ds.Student=} obj + * @returns {ds.Student} + */ +ds.Students.prototype.kings = function(index, obj) { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? (obj || new ds.Student).__init(this.bb.__indirect(this.bb.__vector(this.bb_pos + offset) + index * 4), this.bb) : null; +}; + +/** + * @returns {number} + */ +ds.Students.prototype.kingsLength = function() { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @param {flatbuffers.Builder} builder + */ +ds.Students.startStudents = function(builder) { + builder.startObject(1); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} kingsOffset + */ +ds.Students.addKings = function(builder, kingsOffset) { + builder.addFieldOffset(0, kingsOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +ds.Students.createKingsVector = function(builder, data) { + builder.startVector(4, data.length, 4); + for (var i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +ds.Students.startKingsVector = function(builder, numElems) { + builder.startVector(4, numElems, 4); +}; + +/** + * @param {flatbuffers.Builder} builder + * @returns {flatbuffers.Offset} + */ +ds.Students.endStudents = function(builder) { + var offset = builder.endObject(); + return offset; +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} offset + */ +ds.Students.finishStudentsBuffer = function(builder, offset) { + builder.finish(offset); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} offset + */ +ds.Students.finishSizePrefixedStudentsBuffer = function(builder, offset) { + builder.finish(offset, undefined, true); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} kingsOffset + * @returns {flatbuffers.Offset} + */ +ds.Students.createStudents = function(builder, kingsOffset) { + ds.Students.startStudents(builder); + ds.Students.addKings(builder, kingsOffset); + return ds.Students.endStudents(builder); +} + +// Exports for Node.js and RequireJS +this.ds = ds;