Task 449: .NEX File Format
Task 449: .NEX File Format
1. List of Properties of the .NEX File Format Intrinsic to Its File System
The .NEX file format is an executable format for the ZX Spectrum Next computer. Its structure includes a 512-byte header followed by optional blocks for palettes, loading screens, copper code, memory banks, and extra binary data. The properties are the fields in the header, which define the configuration and content of the file. These are intrinsic to how the file is loaded and executed on the ZX Spectrum Next system.
- Magic String: 4 bytes at offset 0, always "Next".
- Version: 4 bytes at offset 4, e.g., "V1.2" (the official supported version).
- RAM Required: 1 byte at offset 8 (0 = 768k, 1 = 1792k).
- Number of 16k Banks to Load: 1 byte at offset 9 (0-112, must match the count of set flags in the bank array).
- Loading-Screen Blocks: 1 byte at offset 10 (bit flags: 128 = no palette block, 16 = Hi-Colour, 8 = Hi-Res, 4 = Lo-Res, 2 = ULA, 1 = Layer2).
- Border Colour: 1 byte at offset 11 (0-7).
- Stack Pointer: 2 bytes at offset 12 (16-bit value).
- Program Counter: 2 bytes at offset 14 (16-bit value; 0 = don't run, just load).
- Number of Extra Files: 2 bytes at offset 16 (currently unused).
- Banks Included: 112 bytes at offset 18 (array of 0/1 flags for banks 0-111; data order in file is 5,2,0,1,3,4,6,7,8-111).
- Layer2 Loading Bar: 1 byte at offset 130 (0 = OFF, 1 = ON; only for Layer2 screen).
- Loading Bar Colour: 1 byte at offset 131 (0-255; for 640x256x4 mode, defines pixel pair).
- Loading Delay Per Bank: 1 byte at offset 132 (0-255 frames; 0 = no delay).
- Start Delay: 1 byte at offset 133 (0-255 frames; 0 = no delay).
- Preserve Current Next-Registers Values: 1 byte at offset 134 (0 = reset machine state, 1 = preserve).
- Required Core Version: 3 bytes at offset 135 (major 0-15, minor 0-15, subminor 0-255; checked only on Next machine ID 10).
- Timex HiRes Mode Colour / Palette Offset: 1 byte at offset 138 (for HiRes: 0,8,16,...,56; for 320x256x8 or 640x256x4 screens: 0-15 palette offset).
- Entry Bank: 1 byte at offset 139 (bank to map into slot 3 at 0xC000-0xFFFF; default 0).
- File Handle Address: 2 bytes at offset 140 (0 = close file, 1-0x3FFF = pass handle in BC register (1 recommended), 0x4000-0xFFFF = write handle to memory address).
The remaining header bytes (142-511) are reserved (usually zero).
2. Two Direct Download Links for .NEX Files
- https://zxart.ee/zxfile/id:516169/fileId:750983/ANP2_DEMO.nex
- https://raw.githubusercontent.com/dave18/BubNext/main/BUBNEXT.nex
3. Ghost Blog Embedded HTML JavaScript for Drag and Drop .NEX File Dump
Drag and drop a .NEX file here
4. Python Class for .NEX File
import struct
import os
class NexFile:
def __init__(self):
self.magic = b'Next'
self.version = b'V1.2'
self.ram_required = 0
self.num_banks = 0
self.loading_screen = 0
self.border_colour = 0
self.stack_pointer = 0
self.program_counter = 0
self.num_extra_files = 0
self.banks_included = [0] * 112
self.layer2_loading_bar = 0
self.loading_bar_colour = 0
self.loading_delay_bank = 0
self.start_delay = 0
self.preserve_regs = 0
self.core_major = 0
self.core_minor = 0
self.core_subminor = 0
self.timex_colour_or_offset = 0
self.entry_bank = 0
self.file_handle_addr = 0
self.header = b''
self.data = b'' # The rest of the file after header
def load(self, filename):
with open(filename, 'rb') as f:
self.header = f.read(512)
self.data = f.read()
if len(self.header) < 512:
raise ValueError('Invalid .NEX file: too short.')
self.magic = self.header[0:4]
self.version = self.header[4:8]
self.ram_required = self.header[8]
self.num_banks = self.header[9]
self.loading_screen = self.header[10]
self.border_colour = self.header[11]
self.stack_pointer = struct.unpack('<H', self.header[12:14])[0]
self.program_counter = struct.unpack('<H', self.header[14:16])[0]
self.num_extra_files = struct.unpack('<H', self.header[16:18])[0]
self.banks_included = list(self.header[18:130])
self.layer2_loading_bar = self.header[130]
self.loading_bar_colour = self.header[131]
self.loading_delay_bank = self.header[132]
self.start_delay = self.header[133]
self.preserve_regs = self.header[134]
self.core_major = self.header[135]
self.core_minor = self.header[136]
self.core_subminor = self.header[137]
self.timex_colour_or_offset = self.header[138]
self.entry_bank = self.header[139]
self.file_handle_addr = struct.unpack('<H', self.header[140:142])[0]
def print_properties(self):
print(' .NEX File Properties:')
print(f'Magic String: {self.magic.decode()}')
print(f'Version: {self.version.decode()}')
print(f'RAM Required: {self.ram_required} (0=768k, 1=1792k)')
print(f'Number of 16k Banks: {self.num_banks}')
print(f'Loading-Screen Blocks: {bin(self.loading_screen)} (bit flags)')
print(f'Border Colour: {self.border_colour}')
print(f'Stack Pointer: 0x{self.stack_pointer:04X}')
print(f'Program Counter: 0x{self.program_counter:04X}')
print(f'Number of Extra Files: {self.num_extra_files}')
print(f'Banks Included: {self.banks_included}')
print(f'Layer2 Loading Bar: {self.layer2_loading_bar}')
print(f'Loading Bar Colour: {self.loading_bar_colour}')
print(f'Loading Delay Per Bank: {self.loading_delay_bank}')
print(f'Start Delay: {self.start_delay}')
print(f'Preserve Next-Registers: {self.preserve_regs}')
print(f'Required Core Version: {self.core_major}.{self.core_minor}.{self.core_subminor}')
print(f'Timex HiRes Colour / Palette Offset: {self.timex_colour_or_offset}')
print(f'Entry Bank: {self.entry_bank}')
print(f'File Handle Address: 0x{self.file_handle_addr:04X}')
def save(self, filename):
header = bytearray(512)
header[0:4] = self.magic
header[4:8] = self.version
header[8] = self.ram_required
header[9] = self.num_banks
header[10] = self.loading_screen
header[11] = self.border_colour
struct.pack_into('<H', header, 12, self.stack_pointer)
struct.pack_into('<H', header, 14, self.program_counter)
struct.pack_into('<H', header, 16, self.num_extra_files)
header[18:130] = self.banks_included
header[130] = self.layer2_loading_bar
header[131] = self.loading_bar_colour
header[132] = self.loading_delay_bank
header[133] = self.start_delay
header[134] = self.preserve_regs
header[135] = self.core_major
header[136] = self.core_minor
header[137] = self.core_subminor
header[138] = self.timex_colour_or_offset
header[139] = self.entry_bank
struct.pack_into('<H', header, 140, self.file_handle_addr)
with open(filename, 'wb') as f:
f.write(header)
f.write(self.data)
# Example usage:
# nex = NexFile()
# nex.load('example.nex')
# nex.print_properties()
# nex.ram_required = 1 # Modify
# nex.save('modified.nex')
5. Java Class for .NEX File
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class NexFile {
private String magic = "Next";
private String version = "V1.2";
private byte ramRequired = 0;
private byte numBanks = 0;
private byte loadingScreen = 0;
private byte borderColour = 0;
private short stackPointer = 0;
private short programCounter = 0;
private short numExtraFiles = 0;
private byte[] banksIncluded = new byte[112];
private byte layer2LoadingBar = 0;
private byte loadingBarColour = 0;
private byte loadingDelayBank = 0;
private byte startDelay = 0;
private byte preserveRegs = 0;
private byte coreMajor = 0;
private byte coreMinor = 0;
private byte coreSubminor = 0;
private byte timexColourOrOffset = 0;
private byte entryBank = 0;
private short fileHandleAddr = 0;
private byte[] header = new byte[512];
private byte[] data;
public void load(String filename) throws IOException {
try (RandomAccessFile raf = new RandomAccessFile(filename, "r")) {
if (raf.length() < 512) throw new IOException("Invalid .NEX file: too short.");
raf.readFully(header);
data = new byte[(int) (raf.length() - 512)];
raf.readFully(data);
}
ByteBuffer bb = ByteBuffer.wrap(header).order(ByteOrder.LITTLE_ENDIAN);
magic = new String(header, 0, 4);
version = new String(header, 4, 4);
ramRequired = bb.get(8);
numBanks = bb.get(9);
loadingScreen = bb.get(10);
borderColour = bb.get(11);
stackPointer = bb.getShort(12);
programCounter = bb.getShort(14);
numExtraFiles = bb.getShort(16);
System.arraycopy(header, 18, banksIncluded, 0, 112);
layer2LoadingBar = bb.get(130);
loadingBarColour = bb.get(131);
loadingDelayBank = bb.get(132);
startDelay = bb.get(133);
preserveRegs = bb.get(134);
coreMajor = bb.get(135);
coreMinor = bb.get(136);
coreSubminor = bb.get(137);
timexColourOrOffset = bb.get(138);
entryBank = bb.get(139);
fileHandleAddr = bb.getShort(140);
}
public void printProperties() {
System.out.println(" .NEX File Properties:");
System.out.println("Magic String: " + magic);
System.out.println("Version: " + version);
System.out.println("RAM Required: " + ramRequired + " (0=768k, 1=1792k)");
System.out.println("Number of 16k Banks: " + (numBanks & 0xFF));
System.out.println("Loading-Screen Blocks: " + Integer.toBinaryString(loadingScreen & 0xFF));
System.out.println("Border Colour: " + (borderColour & 0xFF));
System.out.println("Stack Pointer: 0x" + Integer.toHexString(stackPointer & 0xFFFF).toUpperCase());
System.out.println("Program Counter: 0x" + Integer.toHexString(programCounter & 0xFFFF).toUpperCase());
System.out.println("Number of Extra Files: " + (numExtraFiles & 0xFFFF));
System.out.print("Banks Included: [");
for (int i = 0; i < 112; i++) {
System.out.print((banksIncluded[i] & 0xFF) + (i < 111 ? ", " : ""));
}
System.out.println("]");
System.out.println("Layer2 Loading Bar: " + (layer2LoadingBar & 0xFF));
System.out.println("Loading Bar Colour: " + (loadingBarColour & 0xFF));
System.out.println("Loading Delay Per Bank: " + (loadingDelayBank & 0xFF));
System.out.println("Start Delay: " + (startDelay & 0xFF));
System.out.println("Preserve Next-Registers: " + (preserveRegs & 0xFF));
System.out.println("Required Core Version: " + (coreMajor & 0xFF) + "." + (coreMinor & 0xFF) + "." + (coreSubminor & 0xFF));
System.out.println("Timex HiRes Colour / Palette Offset: " + (timexColourOrOffset & 0xFF));
System.out.println("Entry Bank: " + (entryBank & 0xFF));
System.out.println("File Handle Address: 0x" + Integer.toHexString(fileHandleAddr & 0xFFFF).toUpperCase());
}
public void save(String filename) throws IOException {
ByteBuffer bb = ByteBuffer.wrap(header).order(ByteOrder.LITTLE_ENDIAN);
System.arraycopy(magic.getBytes(), 0, header, 0, 4);
System.arraycopy(version.getBytes(), 0, header, 4, 4);
bb.put(8, ramRequired);
bb.put(9, numBanks);
bb.put(10, loadingScreen);
bb.put(11, borderColour);
bb.putShort(12, stackPointer);
bb.putShort(14, programCounter);
bb.putShort(16, numExtraFiles);
System.arraycopy(banksIncluded, 0, header, 18, 112);
bb.put(130, layer2LoadingBar);
bb.put(131, loadingBarColour);
bb.put(132, loadingDelayBank);
bb.put(133, startDelay);
bb.put(134, preserveRegs);
bb.put(135, coreMajor);
bb.put(136, coreMinor);
bb.put(137, coreSubminor);
bb.put(138, timexColourOrOffset);
bb.put(139, entryBank);
bb.putShort(140, fileHandleAddr);
try (FileOutputStream fos = new FileOutputStream(filename)) {
fos.write(header);
fos.write(data);
}
}
// Example usage:
// public static void main(String[] args) throws IOException {
// NexFile nex = new NexFile();
// nex.load("example.nex");
// nex.printProperties();
// nex.ramRequired = 1; // Modify
// nex.save("modified.nex");
// }
}
6. JavaScript Class for .NEX File
class NexFile {
constructor() {
this.magic = 'Next';
this.version = 'V1.2';
this.ramRequired = 0;
this.numBanks = 0;
this.loadingScreen = 0;
this.borderColour = 0;
this.stackPointer = 0;
this.programCounter = 0;
this.numExtraFiles = 0;
this.banksIncluded = new Array(112).fill(0);
this.layer2LoadingBar = 0;
this.loadingBarColour = 0;
this.loadingDelayBank = 0;
this.startDelay = 0;
this.preserveRegs = 0;
this.coreMajor = 0;
this.coreMinor = 0;
this.coreSubminor = 0;
this.timexColourOrOffset = 0;
this.entryBank = 0;
this.fileHandleAddr = 0;
this.header = new Uint8Array(512);
this.data = new Uint8Array(0);
}
async load(filename) {
const fs = require('fs'); // For Node.js
const buffer = fs.readFileSync(filename);
if (buffer.length < 512) throw new Error('Invalid .NEX file: too short.');
this.header = buffer.slice(0, 512);
this.data = buffer.slice(512);
const dv = new DataView(this.header.buffer);
this.magic = String.fromCharCode(...this.header.slice(0,4));
this.version = String.fromCharCode(...this.header.slice(4,8));
this.ramRequired = dv.getUint8(8);
this.numBanks = dv.getUint8(9);
this.loadingScreen = dv.getUint8(10);
this.borderColour = dv.getUint8(11);
this.stackPointer = dv.getUint16(12, true);
this.programCounter = dv.getUint16(14, true);
this.numExtraFiles = dv.getUint16(16, true);
this.banksIncluded = Array.from(this.header.slice(18,130));
this.layer2LoadingBar = dv.getUint8(130);
this.loadingBarColour = dv.getUint8(131);
this.loadingDelayBank = dv.getUint8(132);
this.startDelay = dv.getUint8(133);
this.preserveRegs = dv.getUint8(134);
this.coreMajor = dv.getUint8(135);
this.coreMinor = dv.getUint8(136);
this.coreSubminor = dv.getUint8(137);
this.timexColourOrOffset = dv.getUint8(138);
this.entryBank = dv.getUint8(139);
this.fileHandleAddr = dv.getUint16(140, true);
}
printProperties() {
console.log(' .NEX File Properties:');
console.log(`Magic String: ${this.magic}`);
console.log(`Version: ${this.version}`);
console.log(`RAM Required: ${this.ramRequired} (0=768k, 1=1792k)`);
console.log(`Number of 16k Banks: ${this.numBanks}`);
console.log(`Loading-Screen Blocks: ${this.loadingScreen.toString(2)} (bit flags)`);
console.log(`Border Colour: ${this.borderColour}`);
console.log(`Stack Pointer: 0x${this.stackPointer.toString(16).toUpperCase()}`);
console.log(`Program Counter: 0x${this.programCounter.toString(16).toUpperCase()}`);
console.log(`Number of Extra Files: ${this.numExtraFiles}`);
console.log(`Banks Included: [${this.banksIncluded.join(', ')}]`);
console.log(`Layer2 Loading Bar: ${this.layer2LoadingBar}`);
console.log(`Loading Bar Colour: ${this.loadingBarColour}`);
console.log(`Loading Delay Per Bank: ${this.loadingDelayBank}`);
console.log(`Start Delay: ${this.startDelay}`);
console.log(`Preserve Next-Registers: ${this.preserveRegs}`);
console.log(`Required Core Version: ${this.coreMajor}.${this.coreMinor}.${this.coreSubminor}`);
console.log(`Timex HiRes Colour / Palette Offset: ${this.timexColourOrOffset}`);
console.log(`Entry Bank: ${this.entryBank}`);
console.log(`File Handle Address: 0x${this.fileHandleAddr.toString(16).toUpperCase()}`);
}
save(filename) {
const dv = new DataView(this.header.buffer);
this.header.set(this.magic.split('').map(c => c.charCodeAt(0)), 0);
this.header.set(this.version.split('').map(c => c.charCodeAt(0)), 4);
dv.setUint8(8, this.ramRequired);
dv.setUint8(9, this.numBanks);
dv.setUint8(10, this.loadingScreen);
dv.setUint8(11, this.borderColour);
dv.setUint16(12, this.stackPointer, true);
dv.setUint16(14, this.programCounter, true);
dv.setUint16(16, this.numExtraFiles, true);
this.header.set(this.banksIncluded, 18);
dv.setUint8(130, this.layer2LoadingBar);
dv.setUint8(131, this.loadingBarColour);
dv.setUint8(132, this.loadingDelayBank);
dv.setUint8(133, this.startDelay);
dv.setUint8(134, this.preserveRegs);
dv.setUint8(135, this.coreMajor);
dv.setUint8(136, this.coreMinor);
dv.setUint8(137, this.coreSubminor);
dv.setUint8(138, this.timexColourOrOffset);
dv.setUint8(139, this.entryBank);
dv.setUint16(140, this.fileHandleAddr, true);
const fs = require('fs'); // For Node.js
const fullBuffer = new Uint8Array(this.header.length + this.data.length);
fullBuffer.set(this.header, 0);
fullBuffer.set(this.data, this.header.length);
fs.writeFileSync(filename, fullBuffer);
}
}
// Example usage in Node.js:
// const nex = new NexFile();
// nex.load('example.nex');
// nex.printProperties();
// nex.ramRequired = 1; // Modify
// nex.save('modified.nex');
7. C "Class" for .NEX File
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
typedef struct {
char magic[5];
char version[5];
uint8_t ram_required;
uint8_t num_banks;
uint8_t loading_screen;
uint8_t border_colour;
uint16_t stack_pointer;
uint16_t program_counter;
uint16_t num_extra_files;
uint8_t banks_included[112];
uint8_t layer2_loading_bar;
uint8_t loading_bar_colour;
uint8_t loading_delay_bank;
uint8_t start_delay;
uint8_t preserve_regs;
uint8_t core_major;
uint8_t core_minor;
uint8_t core_subminor;
uint8_t timex_colour_or_offset;
uint8_t entry_bank;
uint16_t file_handle_addr;
uint8_t* header; // 512 bytes
uint8_t* data; // Rest of file
size_t data_size;
} NexFile;
NexFile* nex_create() {
NexFile* nex = malloc(sizeof(NexFile));
strcpy(nex->magic, "Next");
strcpy(nex->version, "V1.2");
nex->ram_required = 0;
nex->num_banks = 0;
nex->loading_screen = 0;
nex->border_colour = 0;
nex->stack_pointer = 0;
nex->program_counter = 0;
nex->num_extra_files = 0;
memset(nex->banks_included, 0, 112);
nex->layer2_loading_bar = 0;
nex->loading_bar_colour = 0;
nex->loading_delay_bank = 0;
nex->start_delay = 0;
nex->preserve_regs = 0;
nex->core_major = 0;
nex->core_minor = 0;
nex->core_subminor = 0;
nex->timex_colour_or_offset = 0;
nex->entry_bank = 0;
nex->file_handle_addr = 0;
nex->header = calloc(512, 1);
nex->data = NULL;
nex->data_size = 0;
return nex;
}
void nex_load(NexFile* nex, const char* filename) {
FILE* f = fopen(filename, "rb");
if (!f) {
perror("Failed to open file");
exit(1);
}
fseek(f, 0, SEEK_END);
size_t size = ftell(f);
fseek(f, 0, SEEK_SET);
if (size < 512) {
fprintf(stderr, "Invalid .NEX file: too short.\n");
exit(1);
}
fread(nex->header, 512, 1, f);
nex->data_size = size - 512;
nex->data = malloc(nex->data_size);
fread(nex->data, nex->data_size, 1, f);
fclose(f);
memcpy(nex->magic, nex->header + 0, 4);
nex->magic[4] = '\0';
memcpy(nex->version, nex->header + 4, 4);
nex->version[4] = '\0';
nex->ram_required = nex->header[8];
nex->num_banks = nex->header[9];
nex->loading_screen = nex->header[10];
nex->border_colour = nex->header[11];
nex->stack_pointer = *(uint16_t*)(nex->header + 12);
nex->program_counter = *(uint16_t*)(nex->header + 14);
nex->num_extra_files = *(uint16_t*)(nex->header + 16);
memcpy(nex->banks_included, nex->header + 18, 112);
nex->layer2_loading_bar = nex->header[130];
nex->loading_bar_colour = nex->header[131];
nex->loading_delay_bank = nex->header[132];
nex->start_delay = nex->header[133];
nex->preserve_regs = nex->header[134];
nex->core_major = nex->header[135];
nex->core_minor = nex->header[136];
nex->core_subminor = nex->header[137];
nex->timex_colour_or_offset = nex->header[138];
nex->entry_bank = nex->header[139];
nex->file_handle_addr = *(uint16_t*)(nex->header + 140);
}
void nex_print_properties(NexFile* nex) {
printf(" .NEX File Properties:\n");
printf("Magic String: %s\n", nex->magic);
printf("Version: %s\n", nex->version);
printf("RAM Required: %u (0=768k, 1=1792k)\n", nex->ram_required);
printf("Number of 16k Banks: %u\n", nex->num_banks);
printf("Loading-Screen Blocks: %02X (bit flags)\n", nex->loading_screen);
printf("Border Colour: %u\n", nex->border_colour);
printf("Stack Pointer: 0x%04X\n", nex->stack_pointer);
printf("Program Counter: 0x%04X\n", nex->program_counter);
printf("Number of Extra Files: %u\n", nex->num_extra_files);
printf("Banks Included: [");
for (int i = 0; i < 112; i++) {
printf("%u%s", nex->banks_included[i], i < 111 ? ", " : "");
}
printf("]\n");
printf("Layer2 Loading Bar: %u\n", nex->layer2_loading_bar);
printf("Loading Bar Colour: %u\n", nex->loading_bar_colour);
printf("Loading Delay Per Bank: %u\n", nex->loading_delay_bank);
printf("Start Delay: %u\n", nex->start_delay);
printf("Preserve Next-Registers: %u\n", nex->preserve_regs);
printf("Required Core Version: %u.%u.%u\n", nex->core_major, nex->core_minor, nex->core_subminor);
printf("Timex HiRes Colour / Palette Offset: %u\n", nex->timex_colour_or_offset);
printf("Entry Bank: %u\n", nex->entry_bank);
printf("File Handle Address: 0x%04X\n", nex->file_handle_addr);
}
void nex_save(NexFile* nex, const char* filename) {
memset(nex->header, 0, 512);
memcpy(nex->header + 0, nex->magic, 4);
memcpy(nex->header + 4, nex->version, 4);
nex->header[8] = nex->ram_required;
nex->header[9] = nex->num_banks;
nex->header[10] = nex->loading_screen;
nex->header[11] = nex->border_colour;
*(uint16_t*)(nex->header + 12) = nex->stack_pointer;
*(uint16_t*)(nex->header + 14) = nex->program_counter;
*(uint16_t*)(nex->header + 16) = nex->num_extra_files;
memcpy(nex->header + 18, nex->banks_included, 112);
nex->header[130] = nex->layer2_loading_bar;
nex->header[131] = nex->loading_bar_colour;
nex->header[132] = nex->loading_delay_bank;
nex->header[133] = nex->start_delay;
nex->header[134] = nex->preserve_regs;
nex->header[135] = nex->core_major;
nex->header[136] = nex->core_minor;
nex->header[137] = nex->core_subminor;
nex->header[138] = nex->timex_colour_or_offset;
nex->header[139] = nex->entry_bank;
*(uint16_t*)(nex->header + 140) = nex->file_handle_addr;
FILE* f = fopen(filename, "wb");
if (!f) {
perror("Failed to open file for writing");
exit(1);
}
fwrite(nex->header, 512, 1, f);
fwrite(nex->data, nex->data_size, 1, f);
fclose(f);
}
void nex_destroy(NexFile* nex) {
free(nex->header);
free(nex->data);
free(nex);
}
// Example usage:
// int main() {
// NexFile* nex = nex_create();
// nex_load(nex, "example.nex");
// nex_print_properties(nex);
// nex->ram_required = 1; // Modify
// nex_save(nex, "modified.nex");
// nex_destroy(nex);
// return 0;
// }