aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/defs.js2
-rw-r--r--src/fengari.js7
-rw-r--r--src/lauxlib.js257
-rw-r--r--src/lbaselib.js59
-rw-r--r--src/ldblib.js57
-rw-r--r--src/linit.js4
-rw-r--r--src/loadlib.js29
-rw-r--r--src/loslib.js153
-rw-r--r--src/lualib.js8
9 files changed, 277 insertions, 299 deletions
diff --git a/src/defs.js b/src/defs.js
index 3b5a923..be27032 100644
--- a/src/defs.js
+++ b/src/defs.js
@@ -293,7 +293,7 @@ const LUA_VDIR = LUA_VERSION_MAJOR + "." + LUA_VERSION_MINOR;
module.exports.LUA_VDIR = LUA_VDIR;
let os = false;
-if (typeof require === "function" && (os = require('os')) && typeof os.platform === "function" && os.platform() === 'win32') {
+if (!WEB && os.platform() === 'win32') {
const LUA_DIRSEP = "\\";
module.exports.LUA_DIRSEP = LUA_DIRSEP;
diff --git a/src/fengari.js b/src/fengari.js
new file mode 100644
index 0000000..abbf2a4
--- /dev/null
+++ b/src/fengari.js
@@ -0,0 +1,7 @@
+"use strict";
+
+const lua = require('./lua.js');
+const lauxlib = require('./lauxlib.js');
+
+module.exports.lua = lua;
+module.exports.lauxlib = lauxlib;
diff --git a/src/lauxlib.js b/src/lauxlib.js
index c0f1ecf..4f55e13 100644
--- a/src/lauxlib.js
+++ b/src/lauxlib.js
@@ -617,149 +617,144 @@ const luaL_newlib = function(L, l) {
};
// Only with Node
-if (typeof require === "function") {
- let fs = false;
- try {
- fs = require('fs');
- } catch (e) {}
-
- if (fs) {
- class LoadF {
- constructor() {
- this.n = NaN; /* number of pre-read characters */
- this.f = null; /* file being read */
- this.buff = new Buffer(1024); /* area for reading file */
- this.pos = 0; /* current position in file */
- this.binary = false;
- }
+if (!WEB) {
+ const fs = require('fs');
+
+ class LoadF {
+ constructor() {
+ this.n = NaN; /* number of pre-read characters */
+ this.f = null; /* file being read */
+ this.buff = new Buffer(1024); /* area for reading file */
+ this.pos = 0; /* current position in file */
+ this.binary = false;
}
+ }
- const toDataView = function(buffer) {
- let ab = new ArrayBuffer(buffer.length);
- let au = new Uint8Array(ab);
- for (let i = 0; i < buffer.length; i++)
- au[i] = buffer[i];
- return new DataView(ab);
- };
-
- const getF = function(L, ud) {
- let lf = ud;
- let bytes = 0;
- if (lf.n > 0) { /* are there pre-read characters to be read? */
- lf.n = 0; /* no more pre-read characters */
- } else { /* read a block from file */
- lf.buff.fill(0);
- bytes = fs.readSync(lf.f, lf.buff, 0, lf.buff.length, lf.pos); /* read block */
- lf.pos += bytes;
- }
- if (bytes > 0)
- return lf.binary ? toDataView(lf.buff) : lf.buff.slice(0, bytes);
- else return null;
- };
-
- const errfile = function(L, what, fnameindex, error) {
- let serr = error.message;
- let filename = lua.lua_tostring(L, fnameindex).slice(1);
- lua.lua_pushstring(L, lua.to_luastring(`cannot ${what} ${lua.to_jsstring(filename)}: ${serr}`));
- lua.lua_remove(L, fnameindex);
- return lua.LUA_ERRFILE;
- };
-
- const getc = function(lf) {
- let b = new Buffer(1);
- let bytes = fs.readSync(lf.f, b, 0, 1, lf.pos);
+ const toDataView = function(buffer) {
+ let ab = new ArrayBuffer(buffer.length);
+ let au = new Uint8Array(ab);
+ for (let i = 0; i < buffer.length; i++)
+ au[i] = buffer[i];
+ return new DataView(ab);
+ };
+
+ const getF = function(L, ud) {
+ let lf = ud;
+ let bytes = 0;
+ if (lf.n > 0) { /* are there pre-read characters to be read? */
+ lf.n = 0; /* no more pre-read characters */
+ } else { /* read a block from file */
+ lf.buff.fill(0);
+ bytes = fs.readSync(lf.f, lf.buff, 0, lf.buff.length, lf.pos); /* read block */
lf.pos += bytes;
- return bytes > 0 ? b.readUInt8() : null;
- };
-
- const skipBOM = function(lf) {
- let p = [0XEF, 0XBB, 0XBF]; /* UTF-8 BOM mark */
- lf.n = 0;
- let c;
- do {
+ }
+ if (bytes > 0)
+ return lf.binary ? toDataView(lf.buff) : lf.buff.slice(0, bytes);
+ else return null;
+ };
+
+ const errfile = function(L, what, fnameindex, error) {
+ let serr = error.message;
+ let filename = lua.lua_tostring(L, fnameindex).slice(1);
+ lua.lua_pushstring(L, lua.to_luastring(`cannot ${what} ${lua.to_jsstring(filename)}: ${serr}`));
+ lua.lua_remove(L, fnameindex);
+ return lua.LUA_ERRFILE;
+ };
+
+ const getc = function(lf) {
+ let b = new Buffer(1);
+ let bytes = fs.readSync(lf.f, b, 0, 1, lf.pos);
+ lf.pos += bytes;
+ return bytes > 0 ? b.readUInt8() : null;
+ };
+
+ const skipBOM = function(lf) {
+ let p = [0XEF, 0XBB, 0XBF]; /* UTF-8 BOM mark */
+ lf.n = 0;
+ let c;
+ do {
+ c = getc(lf);
+ if (c === null || c !== p[0]) return c;
+ p = p.slice(1);
+ lf.buff[lf.n++] = c; /* to be read by the parser */
+ } while (p.length > 0);
+ lf.n = 0; /* prefix matched; discard it */
+ return getc(lf); /* return next character */
+ };
+
+ /*
+ ** reads the first character of file 'f' and skips an optional BOM mark
+ ** in its beginning plus its first line if it starts with '#'. Returns
+ ** true if it skipped the first line. In any case, '*cp' has the
+ ** first "valid" character of the file (after the optional BOM and
+ ** a first-line comment).
+ */
+ const skipcomment = function(lf) {
+ let c = skipBOM(lf);
+ if (c === '#'.charCodeAt(0)) { /* first line is a comment (Unix exec. file)? */
+ do { /* skip first line */
c = getc(lf);
- if (c === null || c !== p[0]) return c;
- p = p.slice(1);
- lf.buff[lf.n++] = c; /* to be read by the parser */
- } while (p.length > 0);
- lf.n = 0; /* prefix matched; discard it */
- return getc(lf); /* return next character */
- };
-
- /*
- ** reads the first character of file 'f' and skips an optional BOM mark
- ** in its beginning plus its first line if it starts with '#'. Returns
- ** true if it skipped the first line. In any case, '*cp' has the
- ** first "valid" character of the file (after the optional BOM and
- ** a first-line comment).
- */
- const skipcomment = function(lf) {
- let c = skipBOM(lf);
- if (c === '#'.charCodeAt(0)) { /* first line is a comment (Unix exec. file)? */
- do { /* skip first line */
- c = getc(lf);
- } while (c && c !== '\n'.charCodeAt(0));
-
- return {
- skipped: true,
- c: getc(lf) /* skip end-of-line, if present */
- };
- } else {
- lf.pos--;
- return {
- skipped: false,
- c: c
- };
- }
- };
-
- const luaL_loadfilex = function(L, filename, mode) {
- let lf = new LoadF();
- let fnameindex = lua.lua_gettop(L) + 1; /* index of filename on the stack */
- if (filename === null) {
- lua.lua_pushliteral(L, "=stdin");
- lf.f = process.stdin.fd;
- } else {
- let jsfilename = lua.to_jsstring(filename);
- lua.lua_pushliteral(L, `@${jsfilename}`);
- try {
- lf.f = fs.openSync(jsfilename, "r");
- } catch (e) {
- return errfile(L, "open", fnameindex, e);
- }
- }
+ } while (c && c !== '\n'.charCodeAt(0));
+ return {
+ skipped: true,
+ c: getc(lf) /* skip end-of-line, if present */
+ };
+ } else {
+ lf.pos--;
+ return {
+ skipped: false,
+ c: c
+ };
+ }
+ };
+
+ const luaL_loadfilex = function(L, filename, mode) {
+ let lf = new LoadF();
+ let fnameindex = lua.lua_gettop(L) + 1; /* index of filename on the stack */
+ if (filename === null) {
+ lua.lua_pushliteral(L, "=stdin");
+ lf.f = process.stdin.fd;
+ } else {
+ let jsfilename = lua.to_jsstring(filename);
+ lua.lua_pushliteral(L, `@${jsfilename}`);
try {
- let com;
- if ((com = skipcomment(lf)).skipped) /* read initial portion */
- lf.buff[lf.n++] = '\n'.charCodeAt(0); /* add line to correct line numbers */
+ lf.f = fs.openSync(jsfilename, "r");
+ } catch (e) {
+ return errfile(L, "open", fnameindex, e);
+ }
+ }
- if (com.c === lua.LUA_SIGNATURE.charCodeAt(0) && filename) { /* binary file? */
- lf.binary = true;
- }
+ try {
+ let com;
+ if ((com = skipcomment(lf)).skipped) /* read initial portion */
+ lf.buff[lf.n++] = '\n'.charCodeAt(0); /* add line to correct line numbers */
- let status = lua.lua_load(L, getF, lf, lua.lua_tostring(L, -1), mode);
- if (filename) fs.closeSync(lf.f); /* close file (even in case of errors) */
- lua.lua_remove(L, fnameindex);
- return status;
- } catch (err) {
- lua.lua_settop(L, fnameindex); /* ignore results from 'lua_load' */
- return errfile(L, "read", fnameindex, err);
+ if (com.c === lua.LUA_SIGNATURE.charCodeAt(0) && filename) { /* binary file? */
+ lf.binary = true;
}
- };
- const luaL_loadfile = function(L, filename) {
- return luaL_loadfilex(L, filename, null);
- };
+ let status = lua.lua_load(L, getF, lf, lua.lua_tostring(L, -1), mode);
+ if (filename) fs.closeSync(lf.f); /* close file (even in case of errors) */
+ lua.lua_remove(L, fnameindex);
+ return status;
+ } catch (err) {
+ lua.lua_settop(L, fnameindex); /* ignore results from 'lua_load' */
+ return errfile(L, "read", fnameindex, err);
+ }
+ };
- const luaL_dofile = function(L, filename) {
- return (luaL_loadfile(L, filename) || lua.lua_pcall(L, 0, lua.LUA_MULTRET, 0));
- };
+ const luaL_loadfile = function(L, filename) {
+ return luaL_loadfilex(L, filename, null);
+ };
- module.exports.luaL_dofile = luaL_dofile;
- module.exports.luaL_loadfilex = luaL_loadfilex;
- module.exports.luaL_loadfile = luaL_loadfile;
- }
+ const luaL_dofile = function(L, filename) {
+ return (luaL_loadfile(L, filename) || lua.lua_pcall(L, 0, lua.LUA_MULTRET, 0));
+ };
+
+ module.exports.luaL_dofile = luaL_dofile;
+ module.exports.luaL_loadfilex = luaL_loadfilex;
+ module.exports.luaL_loadfile = luaL_loadfile;
}
const lua_writestringerror = function(s) {
diff --git a/src/lbaselib.js b/src/lbaselib.js
index d1d930a..8f0827e 100644
--- a/src/lbaselib.js
+++ b/src/lbaselib.js
@@ -331,38 +331,33 @@ const base_funcs = {
};
// Only with Node
-if (typeof require === "function") {
-
- let fs = false;
- try {
- fs = require('fs');
- } catch (e) {}
-
- if (fs) {
- const luaB_loadfile = function(L) {
- let fname = lauxlib.luaL_optstring(L, 1, null);
- let mode = lauxlib.luaL_optstring(L, 2, null);
- let env = !lua.lua_isnone(L, 3) ? 3 : 0; /* 'env' index or 0 if no 'env' */
- let status = lauxlib.luaL_loadfilex(L, fname, mode);
- return load_aux(L, status, env);
- };
-
- const dofilecont = function(L, d1, d2) {
- return lua.lua_gettop(L) - 1;
- };
-
- const luaB_dofile = function(L) {
- let fname = lauxlib.luaL_optstring(L, 1, null);
- lua.lua_settop(L, 1);
- if (lauxlib.luaL_loadfile(L, fname) !== lua.LUA_OK)
- return lua.lua_error(L);
- lua.lua_callk(L, 0, lua.LUA_MULTRET, 0, dofilecont);
- return dofilecont(L, 0, 0);
- };
-
- base_funcs.loadfile = luaB_loadfile;
- base_funcs.dofile = luaB_dofile;
- }
+if (!WEB) {
+
+ const fs = require('fs');
+
+ const luaB_loadfile = function(L) {
+ let fname = lauxlib.luaL_optstring(L, 1, null);
+ let mode = lauxlib.luaL_optstring(L, 2, null);
+ let env = !lua.lua_isnone(L, 3) ? 3 : 0; /* 'env' index or 0 if no 'env' */
+ let status = lauxlib.luaL_loadfilex(L, fname, mode);
+ return load_aux(L, status, env);
+ };
+
+ const dofilecont = function(L, d1, d2) {
+ return lua.lua_gettop(L) - 1;
+ };
+
+ const luaB_dofile = function(L) {
+ let fname = lauxlib.luaL_optstring(L, 1, null);
+ lua.lua_settop(L, 1);
+ if (lauxlib.luaL_loadfile(L, fname) !== lua.LUA_OK)
+ return lua.lua_error(L);
+ lua.lua_callk(L, 0, lua.LUA_MULTRET, 0, dofilecont);
+ return dofilecont(L, 0, 0);
+ };
+
+ base_funcs.loadfile = luaB_loadfile;
+ base_funcs.dofile = luaB_dofile;
}
diff --git a/src/ldblib.js b/src/ldblib.js
index fbf31e8..90f08cd 100644
--- a/src/ldblib.js
+++ b/src/ldblib.js
@@ -397,40 +397,33 @@ const dblib = {
};
// Only with Node
-if (typeof require === "function") {
- let fs = false;
- try {
- fs = require('fs');
- } catch (e) {}
-
- if (fs) {
- const readlineSync = require('readline-sync');
- readlineSync.setDefaultOptions({
- prompt: 'lua_debug> '
- });
-
- // TODO: if in browser, use a designated input in the DOM ?
- const db_debug = function(L) {
- for (;;) {
- let input = readlineSync.prompt();
-
- if (input === "cont")
- return 0;
-
- if (input.length === 0)
- continue;
-
- let buffer = lua.to_luastring(input);
- if (lauxlib.luaL_loadbuffer(L, buffer, buffer.length, lua.to_luastring("=(debug command)", true))
- || lua.lua_pcall(L, 0, 0, 0)) {
- lauxlib.lua_writestringerror(`${lua.lua_tojsstring(L, -1)}\n`);
- }
- lua.lua_settop(L, 0); /* remove eventual returns */
+if (!WEB) {
+ const readlineSync = require('readline-sync');
+ readlineSync.setDefaultOptions({
+ prompt: 'lua_debug> '
+ });
+
+ // TODO: if in browser, use a designated input in the DOM ?
+ const db_debug = function(L) {
+ for (;;) {
+ let input = readlineSync.prompt();
+
+ if (input === "cont")
+ return 0;
+
+ if (input.length === 0)
+ continue;
+
+ let buffer = lua.to_luastring(input);
+ if (lauxlib.luaL_loadbuffer(L, buffer, buffer.length, lua.to_luastring("=(debug command)", true))
+ || lua.lua_pcall(L, 0, 0, 0)) {
+ lauxlib.lua_writestringerror(`${lua.lua_tojsstring(L, -1)}\n`);
}
- };
+ lua.lua_settop(L, 0); /* remove eventual returns */
+ }
+ };
- dblib.debug = db_debug;
- }
+ dblib.debug = db_debug;
}
const luaopen_debug = function(L) {
diff --git a/src/linit.js b/src/linit.js
index 6cc48b1..4139f20 100644
--- a/src/linit.js
+++ b/src/linit.js
@@ -9,7 +9,6 @@ const lstrlib = require('./lstrlib.js');
const ltablib = require('./ltablib.js');
const lutf8lib = require('./lutf8lib.js');
const ldblib = require('./ldblib.js');
-const liolib = require('./liolib.js');
const loslib = require('./loslib.js');
const loadlib = require('./loadlib.js');
const lualib = require('./lualib.js');
@@ -19,7 +18,6 @@ const loadedlibs = {
[lualib.LUA_COLIBNAME]: lcorolib.luaopen_coroutine,
[lualib.LUA_DBLIBNAME]: ldblib.luaopen_debug,
[lualib.LUA_MATHLIBNAME]: lmathlib.luaopen_math,
- [lualib.LUA_IOLIBNAME]: liolib.luaopen_io,
[lualib.LUA_OSLIBNAME]: loslib.luaopen_os,
[lualib.LUA_STRLIBNAME]: lstrlib.luaopen_string,
[lualib.LUA_TABLIBNAME]: ltablib.luaopen_table,
@@ -27,6 +25,8 @@ const loadedlibs = {
"_G": lbaselib.luaopen_base
};
+if (!WEB) loadedlibs[lualib.LUA_IOLIBNAME] = require('./liolib.js').luaopen_io;
+
const luaL_openlibs = function(L) {
/* "require" functions from 'loadedlibs' and set results to global table */
for (let lib in loadedlibs) {
diff --git a/src/loadlib.js b/src/loadlib.js
index e7b1680..c2e867a 100644
--- a/src/loadlib.js
+++ b/src/loadlib.js
@@ -79,28 +79,23 @@ let readable = function(filename) {
return false;
};
// Only with Node
-if (typeof require === "function") {
+if (!WEB) {
- let fs = false;
- try {
- fs = require('fs');
- } catch (e) {}
+ const fs = require('fs');
- if (fs) {
- readable = function(filename) {
- let fd = false;
+ readable = function(filename) {
+ let fd = false;
- try {
- fd = fs.openSync(lua.to_jsstring(filename), 'r');
- } catch (e) {
- return false;
- }
+ try {
+ fd = fs.openSync(lua.to_jsstring(filename), 'r');
+ } catch (e) {
+ return false;
+ }
- fs.closeSync(fd);
+ fs.closeSync(fd);
- return true;
- };
- }
+ return true;
+ };
}
diff --git a/src/loslib.js b/src/loslib.js
index b93071b..976ab92 100644
--- a/src/loslib.js
+++ b/src/loslib.js
@@ -180,96 +180,87 @@ if (process && process.exit && process.env && process.uptime) {
// Only with Node
-if (typeof require === "function") {
-
- let fs = false;
- let tmp = false;
- let child_process = false;
- try {
- fs = require('fs');
- tmp = require('tmp');
- child_process = require('child_process');
- } catch (e) {}
-
- if (fs && tmp) {
- // TODO: on POSIX system, should create the file
- const lua_tmpname = function() {
- return tmp.tmpNameSync();
- };
-
- const os_remove = function(L) {
- let filename = lauxlib.luaL_checkstring(L, 1);
+if (!WEB) {
+
+ const fs = require('fs');
+ const tmp = require('tmp');
+ const child_process = require('child_process');
+
+ // TODO: on POSIX system, should create the file
+ const lua_tmpname = function() {
+ return tmp.tmpNameSync();
+ };
+
+ const os_remove = function(L) {
+ let filename = lauxlib.luaL_checkstring(L, 1);
+ try {
+ if (fs.lstatSync(lua.to_jsstring(filename)).isDirectory()) {
+ fs.rmdirSync(lua.to_jsstring(filename));
+ } else {
+ fs.unlinkSync(lua.to_jsstring(filename));
+ }
+ } catch (e) {
+ return lauxlib.luaL_fileresult(L, false, filename, e);
+ }
+ return lauxlib.luaL_fileresult(L, true);
+ };
+
+ const os_rename = function(L) {
+ let fromname = lua.to_jsstring(lauxlib.luaL_checkstring(L, 1));
+ let toname = lua.to_jsstring(lauxlib.luaL_checkstring(L, 2));
+ try {
+ fs.renameSync(fromname, toname);
+ } catch (e) {
+ return lauxlib.luaL_fileresult(L, false, false, e);
+ }
+ return lauxlib.luaL_fileresult(L, true);
+ };
+
+ const os_tmpname = function(L) {
+ let name = lua_tmpname();
+ if (!name)
+ return lauxlib.luaL_error(L, lua.to_luastring("unable to generate a unique filename"));
+ lua.lua_pushstring(L, lua.to_luastring(name));
+ return 1;
+ };
+
+ syslib.remove = os_remove;
+ syslib.rename = os_rename;
+ syslib.tmpname = os_tmpname;
+
+ const os_execute = function(L) {
+ let cmd = lauxlib.luaL_optstring(L, 1, null);
+ if (cmd !== null) {
try {
- if (fs.lstatSync(lua.to_jsstring(filename)).isDirectory()) {
- fs.rmdirSync(lua.to_jsstring(filename));
- } else {
- fs.unlinkSync(lua.to_jsstring(filename));
- }
+ child_process.execSync(
+ lua.to_jsstring(cmd),
+ {
+ stdio: [process.stdin, process.stdout, process.stderr]
+ }
+ );
} catch (e) {
- return lauxlib.luaL_fileresult(L, false, filename, e);
+ return lauxlib.luaL_execresult(L, e);
}
- return lauxlib.luaL_fileresult(L, true);
- };
- const os_rename = function(L) {
- let fromname = lua.to_jsstring(lauxlib.luaL_checkstring(L, 1));
- let toname = lua.to_jsstring(lauxlib.luaL_checkstring(L, 2));
+ return lauxlib.luaL_execresult(L, null);
+ } else {
try {
- fs.renameSync(fromname, toname);
+ child_process.execSync(
+ lua.to_jsstring(cmd),
+ {
+ stdio: [process.stdin, process.stdout, process.stderr]
+ }
+ );
+ lua.lua_pushboolean(L, 1);
} catch (e) {
- return lauxlib.luaL_fileresult(L, false, false, e);
+ lua.lua_pushboolean(L, 0);
}
- return lauxlib.luaL_fileresult(L, true);
- };
-
- const os_tmpname = function(L) {
- let name = lua_tmpname();
- if (!name)
- return lauxlib.luaL_error(L, lua.to_luastring("unable to generate a unique filename"));
- lua.lua_pushstring(L, lua.to_luastring(name));
- return 1;
- };
-
- syslib.remove = os_remove;
- syslib.rename = os_rename;
- syslib.tmpname = os_tmpname;
- }
- if (child_process) {
- const os_execute = function(L) {
- let cmd = lauxlib.luaL_optstring(L, 1, null);
- if (cmd !== null) {
- try {
- child_process.execSync(
- lua.to_jsstring(cmd),
- {
- stdio: [process.stdin, process.stdout, process.stderr]
- }
- );
- } catch (e) {
- return lauxlib.luaL_execresult(L, e);
- }
-
- return lauxlib.luaL_execresult(L, null);
- } else {
- try {
- child_process.execSync(
- lua.to_jsstring(cmd),
- {
- stdio: [process.stdin, process.stdout, process.stderr]
- }
- );
- lua.lua_pushboolean(L, 1);
- } catch (e) {
- lua.lua_pushboolean(L, 0);
- }
-
- return 1;
- }
- };
+ return 1;
+ }
+ };
- syslib.execute = os_execute;
- }
+ syslib.execute = os_execute;
}
diff --git a/src/lualib.js b/src/lualib.js
index 549ab28..ed02273 100644
--- a/src/lualib.js
+++ b/src/lualib.js
@@ -14,9 +14,11 @@ const LUA_TABLIBNAME = "table";
module.exports.LUA_TABLIBNAME = LUA_TABLIBNAME;
module.exports[LUA_TABLIBNAME] = require("./ltablib.js").luaopen_table;
-const LUA_IOLIBNAME = "io";
-module.exports.LUA_IOLIBNAME = LUA_IOLIBNAME;
-module.exports[LUA_IOLIBNAME] = require("./liolib.js").luaopen_io;
+if (!WEB) {
+ const LUA_IOLIBNAME = "io";
+ module.exports.LUA_IOLIBNAME = LUA_IOLIBNAME;
+ module.exports[LUA_IOLIBNAME] = require("./liolib.js").luaopen_io;
+}
const LUA_OSLIBNAME = "os";
module.exports.LUA_OSLIBNAME = LUA_OSLIBNAME;