summaryrefslogtreecommitdiffstats
path: root/postgres.c
diff options
context:
space:
mode:
authorEmil Renner Berthing <esmil@mailme.dk>2012-01-06 17:54:40 +0100
committerEmil Renner Berthing <esmil@mailme.dk>2012-07-18 15:37:12 +0200
commitbc525acebe8dbe4ec89e73703906b46fa6206d89 (patch)
tree7f1a5e520248f1dfc81c55149623039150ad8fda /postgres.c
parenta646b691b54cdb44fd404ab1a1332ee1bc8d7d25 (diff)
downloadlem-postgres-bc525acebe8dbe4ec89e73703906b46fa6206d89.tar.gz
lem-postgres-bc525acebe8dbe4ec89e73703906b46fa6206d89.tar.xz
lem-postgres-bc525acebe8dbe4ec89e73703906b46fa6206d89.zip
update for LEM 0.3
Diffstat (limited to 'postgres.c')
-rw-r--r--postgres.c884
1 files changed, 0 insertions, 884 deletions
diff --git a/postgres.c b/postgres.c
deleted file mode 100644
index 16f2de8..0000000
--- a/postgres.c
+++ /dev/null
@@ -1,884 +0,0 @@
-/*
- * This file is part of lem-postgres.
- * Copyright 2011 Emil Renner Berthing
- *
- * lem-postgres is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * lem-postgres is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with lem-postgres. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdlib.h>
-#include <assert.h>
-#include <lem.h>
-#include <libpq-fe.h>
-
-struct connection {
- struct ev_io w;
- PGconn *conn;
- lua_State *T;
-};
-
-static void
-push_error(lua_State *T, PGconn *conn)
-{
- const char *msg = PQerrorMessage(conn);
- const char *p;
-
- for (p = msg; *p != '\n' && *p != '\0'; p++);
-
- lua_pushnil(T);
- if (p > msg)
- lua_pushlstring(T, msg, p - msg);
- else
- lua_pushliteral(T, "unknown error");
-}
-
-static int
-connection_gc(lua_State *T)
-{
- struct connection *c = lua_touserdata(T, 1);
-
- if (c->conn == NULL)
- return 0;
-
- ev_io_stop(EV_G_ &c->w);
- PQfinish(c->conn);
- return 0;
-}
-
-static int
-connection_close(lua_State *T)
-{
- struct connection *c;
-
- luaL_checktype(T, 1, LUA_TUSERDATA);
- c = lua_touserdata(T, 1);
- if (c->conn == NULL) {
- lua_pushnil(T);
- lua_pushliteral(T, "already closed");
- return 2;
- }
-
- if (c->T != NULL) {
- lua_pushnil(c->T);
- lua_pushliteral(c->T, "interrupted");
- lem_queue(c->T, 2);
- c->T = NULL;
- }
-
- ev_io_stop(EV_G_ &c->w);
- PQfinish(c->conn);
- c->conn = NULL;
-
- lua_pushboolean(T, 1);
- return 1;
-}
-
-static void
-connect_handler(EV_P_ struct ev_io *w, int revents)
-{
- struct connection *c = (struct connection *)w;
-
- (void)revents;
-
- ev_io_stop(EV_A_ &c->w);
- switch (PQconnectPoll(c->conn)) {
- case PGRES_POLLING_READING:
- lem_debug("PGRES_POLLING_READING, socket = %d", PQsocket(c->conn));
- ev_io_set(&c->w, PQsocket(c->conn), EV_READ);
- break;
-
- case PGRES_POLLING_WRITING:
- lem_debug("PGRES_POLLING_WRITING, socket = %d", PQsocket(c->conn));
- ev_io_set(&c->w, PQsocket(c->conn), EV_WRITE);
- break;
-
- case PGRES_POLLING_FAILED:
- lem_debug("PGRES_POLLING_FAILED");
- lua_settop(c->T, 0);
- push_error(c->T, c->conn);
- PQfinish(c->conn);
- c->conn = NULL;
- lem_queue(c->T, 2);
- c->T = NULL;
- return;
-
- case PGRES_POLLING_OK:
- lem_debug("PGRES_POLLING_OK");
- lem_queue(c->T, 1);
- c->T = NULL;
- return;
-
-#ifndef NDEBUG
- case PGRES_POLLING_ACTIVE:
- assert(0);
-#endif
- }
-
- ev_io_start(EV_A_ &c->w);
-}
-
-static int
-connection_connect(lua_State *T)
-{
- const char *conninfo = luaL_checkstring(T, 1);
- PGconn *conn;
- ConnStatusType status;
- struct connection *c;
-
- conn = PQconnectStart(conninfo);
- if (conn == NULL) {
- lua_pushnil(T);
- lua_pushliteral(T, "out of memory");
- return 2;
- }
-
- status = PQstatus(conn);
- if (status == CONNECTION_BAD) {
- lem_debug("CONNECTION_BAD");
- goto error;
- }
-
- c = lua_newuserdata(T, sizeof(struct connection));
- lua_pushvalue(T, lua_upvalueindex(1));
- lua_setmetatable(T, -2);
-
- c->conn = conn;
-
- switch (PQconnectPoll(conn)) {
- case PGRES_POLLING_READING:
- lem_debug("PGRES_POLLING_READING");
- ev_io_init(&c->w, connect_handler, PQsocket(conn), EV_READ);
- break;
-
- case PGRES_POLLING_WRITING:
- lem_debug("PGRES_POLLING_WRITING");
- ev_io_init(&c->w, connect_handler, PQsocket(conn), EV_WRITE);
- break;
-
- case PGRES_POLLING_FAILED:
- lem_debug("PGRES_POLLING_FAILED");
- goto error;
-
- case PGRES_POLLING_OK:
- lem_debug("PGRES_POLLING_OK");
- c->T = NULL;
- return 1;
-
-#ifndef NDEBUG
- case PGRES_POLLING_ACTIVE:
- assert(0);
-#endif
- }
-
- c->T = T;
- ev_io_start(EV_G_ &c->w);
-
- lua_replace(T, 1);
- lua_settop(T, 1);
- return lua_yield(T, 1);
-error:
- push_error(T, conn);
- PQfinish(conn);
- return 2;
-}
-
-static int
-connection_reset(lua_State *T)
-{
- struct connection *c;
-
- luaL_checktype(T, 1, LUA_TUSERDATA);
- c = lua_touserdata(T, 1);
- if (c->T != NULL) {
- lua_pushnil(T);
- lua_pushliteral(T, "busy");
- return 2;
- }
-
- if (c->conn == NULL) {
- lua_pushnil(T);
- lua_pushliteral(T, "closed");
- return 2;
- }
-
- if (PQresetStart(c->conn) != 1)
- goto error;
-
- c->w.cb = connect_handler;
- switch (PQconnectPoll(c->conn)) {
- case PGRES_POLLING_READING:
- lem_debug("PGRES_POLLING_READING");
- ev_io_set(&c->w, PQsocket(c->conn), EV_READ);
- break;
-
- case PGRES_POLLING_WRITING:
- lem_debug("PGRES_POLLING_WRITING");
- ev_io_set(&c->w, PQsocket(c->conn), EV_WRITE);
- break;
-
- case PGRES_POLLING_FAILED:
- lem_debug("PGRES_POLLING_FAILED");
- goto error;
-
- case PGRES_POLLING_OK:
- lem_debug("PGRES_POLLING_OK");
- return 1;
-
-#ifndef NDEBUG
- case PGRES_POLLING_ACTIVE:
- assert(0);
-#endif
- }
-
- c->T = T;
- ev_io_start(EV_G_ &c->w);
-
- lua_settop(T, 1);
- return lua_yield(T, 1);
-error:
- push_error(T, c->conn);
- return 2;
-}
-
-static void
-push_tuples(lua_State *T, PGresult *res)
-{
- int rows = PQntuples(res);
- int columns = PQnfields(res);
- int i;
-
- lua_createtable(T, rows, 0);
- for (i = 0; i < rows; i++) {
- int j;
-
- lua_createtable(T, columns, 0);
- for (j = 0; j < columns; j++) {
- if (PQgetisnull(res, i, j))
- lua_pushnil(T);
- else
- lua_pushlstring(T, PQgetvalue(res, i, j),
- PQgetlength(res, i, j));
- lua_rawseti(T, -2, j+1);
- }
- lua_rawseti(T, -2, i+1);
- }
-
- /* insert column names as "row 0" */
- lua_createtable(T, columns, 0);
- for (i = 0; i < columns; i++) {
- lua_pushstring(T, PQfname(res, i));
- lua_rawseti(T, -2, i+1);
- }
- lua_rawseti(T, -2, 0);
-}
-
-static void
-error_handler(EV_P_ struct ev_io *w, int revents)
-{
- struct connection *c = (struct connection *)w;
-
- (void)revents;
-
- if (PQconsumeInput(c->conn) == 0) {
- ev_io_stop(EV_A_ &c->w);
- lua_settop(c->T, 0);
- push_error(c->T, c->conn);
- lem_queue(c->T, 2);
- c->T = NULL;
- return;
- }
-
- while (!PQisBusy(c->conn)) {
- PGresult *res = PQgetResult(c->conn);
-
- if (res == NULL) {
- ev_io_stop(EV_A_ &c->w);
- lem_queue(c->T, 2);
- c->T = NULL;
- return;
- }
-
- PQclear(res);
- }
-}
-
-static void
-exec_handler(EV_P_ struct ev_io *w, int revents)
-{
- struct connection *c = (struct connection *)w;
- PGresult *res;
-
- (void)revents;
-
- if (PQconsumeInput(c->conn) != 1) {
- ev_io_stop(EV_A_ &c->w);
- lua_settop(c->T, 0);
- push_error(c->T, c->conn);
- lem_queue(c->T, 2);
- c->T = NULL;
- return;
- }
-
- while (!PQisBusy(c->conn)) {
- res = PQgetResult(c->conn);
-
- if (res == NULL) {
- ev_io_stop(EV_A_ &c->w);
- lem_debug("returning %d values", lua_gettop(c->T) - 1);
- lem_queue(c->T, lua_gettop(c->T) - 1);
- c->T = NULL;
- return;
- }
-
- switch (PQresultStatus(res)) {
- case PGRES_EMPTY_QUERY:
- lem_debug("PGRES_EMPTY_QUERY");
- lua_settop(c->T, 0);
- lua_pushnil(c->T);
- lua_pushliteral(c->T, "empty query");
- goto error;
-
- case PGRES_COMMAND_OK:
- lem_debug("PGRES_COMMAND_OK");
- lua_pushboolean(c->T, 1);
- break;
-
- case PGRES_TUPLES_OK:
- lem_debug("PGRES_TUPLES_OK");
- push_tuples(c->T, res);
- break;
-
- case PGRES_COPY_IN:
- lem_debug("PGRES_COPY_IN");
- (void)PQsetnonblocking(c->conn, 1);
- case PGRES_COPY_OUT:
- lem_debug("PGRES_COPY_OUT");
- PQclear(res);
- lua_pushboolean(c->T, 1);
- lem_queue(c->T, lua_gettop(c->T) - 1);
- c->T = NULL;
- return;
-
- case PGRES_BAD_RESPONSE:
- lem_debug("PGRES_BAD_RESPONSE");
- lua_settop(c->T, 0);
- push_error(c->T, c->conn);
- goto error;
-
- case PGRES_NONFATAL_ERROR:
- lem_debug("PGRES_NONFATAL_ERROR");
- break;
-
- case PGRES_FATAL_ERROR:
- lem_debug("PGRES_FATAL_ERROR");
- lua_settop(c->T, 0);
- push_error(c->T, c->conn);
- goto error;
-
- default:
- lem_debug("unknown result status");
- lua_settop(c->T, 0);
- lua_pushnil(c->T);
- lua_pushliteral(c->T, "unknown result status");
- goto error;
- }
-
- PQclear(res);
- }
-
- lem_debug("busy");
- return;
-error:
- PQclear(res);
- c->w.cb = error_handler;
- while (!PQisBusy(c->conn)) {
- res = PQgetResult(c->conn);
-
- if (res == NULL) {
- ev_io_stop(EV_A_ &c->w);
- lem_queue(c->T, 2);
- c->T = NULL;
- return;
- }
-
- PQclear(res);
- }
-}
-
-static int
-connection_exec(lua_State *T)
-{
- struct connection *c;
- const char *command;
- int n;
-
- luaL_checktype(T, 1, LUA_TUSERDATA);
- command = luaL_checkstring(T, 2);
-
- c = lua_touserdata(T, 1);
- if (c->T != NULL) {
- lua_pushnil(T);
- lua_pushliteral(T, "busy");
- return 2;
- }
-
- if (c->conn == NULL) {
- lua_pushnil(T);
- lua_pushliteral(T, "closed");
- return 2;
- }
-
- n = lua_gettop(T) - 2;
- if (n > 0) {
- const char **values = lem_xmalloc(n * sizeof(char *));
- int *lengths = lem_xmalloc(n * sizeof(int));
- int i;
-
- for (i = 0; i < n; i++) {
- size_t len;
-
- values[i] = lua_tolstring(T, i+3, &len);
- lengths[i] = len;
- }
-
- n = PQsendQueryParams(c->conn, command, n,
- NULL, values, lengths, NULL, 0);
- free(values);
- free(lengths);
- } else
- n = PQsendQuery(c->conn, command);
-
- if (n != 1) {
- lem_debug("PQsendQuery failed");
- push_error(T, c->conn);
- return 2;
- }
-
- c->T = T;
- c->w.cb = exec_handler;
- c->w.events = EV_READ;
- ev_io_start(EV_G_ &c->w);
-
- lua_settop(T, 1);
- return lua_yield(T, 1);
-}
-
-static int
-connection_prepare(lua_State *T)
-{
- struct connection *c;
- const char *name;
- const char *query;
-
- luaL_checktype(T, 1, LUA_TUSERDATA);
- name = luaL_checkstring(T, 2);
- query = luaL_checkstring(T, 3);
-
- c = lua_touserdata(T, 1);
- if (c->T != NULL) {
- lua_pushnil(T);
- lua_pushliteral(T, "busy");
- return 2;
- }
-
- if (c->conn == NULL) {
- lua_pushnil(T);
- lua_pushliteral(T, "closed");
- return 2;
- }
-
- if (PQsendPrepare(c->conn, name, query, 0, NULL) != 1) {
- push_error(T, c->conn);
- return 2;
- }
-
- c->T = T;
- c->w.cb = exec_handler;
- c->w.events = EV_READ;
- ev_io_start(EV_G_ &c->w);
-
- lua_settop(T, 1);
- return lua_yield(T, 1);
-}
-
-static int
-connection_run(lua_State *T)
-{
- struct connection *c;
- const char *name;
- const char **values;
- int *lengths;
- int n;
- int i;
-
- luaL_checktype(T, 1, LUA_TUSERDATA);
- name = luaL_checkstring(T, 2);
-
- c = lua_touserdata(T, 1);
- if (c->T != NULL) {
- lua_pushnil(T);
- lua_pushliteral(T, "busy");
- return 2;
- }
-
- if (c->conn == NULL) {
- lua_pushnil(T);
- lua_pushliteral(T, "closed");
- return 2;
- }
-
- n = lua_gettop(T) - 2;
- values = lem_xmalloc(n * sizeof(char *));
- lengths = lem_xmalloc(n * sizeof(int));
-
- for (i = 0; i < n; i++) {
- size_t len;
-
- values[i] = lua_tolstring(T, i+3, &len);
- lengths[i] = len;
- }
-
- n = PQsendQueryPrepared(c->conn, name, n,
- values, lengths, NULL, 0);
- free(values);
- free(lengths);
- if (n != 1) {
- push_error(T, c->conn);
- return 2;
- }
-
- c->T = T;
- c->w.cb = exec_handler;
- c->w.events = EV_READ;
- ev_io_start(EV_G_ &c->w);
-
- lua_settop(T, 1);
- return lua_yield(T, 1);
-}
-
-static void
-put_handler(EV_P_ struct ev_io *w, int revents)
-{
- struct connection *c = (struct connection *)w;
- size_t len;
- const char *data;
-
- (void)revents;
-
- data = lua_tolstring(c->T, 2, &len);
- switch (PQputCopyData(c->conn, data, (int)len)) {
- case 1: /* data sent */
- lem_debug("data sent");
- ev_io_stop(EV_A_ &c->w);
-
- lua_settop(c->T, 0);
- lua_pushboolean(c->T, 1);
- lem_queue(c->T, 1);
- c->T = NULL;
- break;
-
- case 0: /* would block */
- lem_debug("would block");
- break;
-
- default: /* should be -1 for error */
- lua_settop(c->T, 0);
- push_error(c->T, c->conn);
- lem_queue(c->T, 2);
- c->T = NULL;
- break;
- }
-}
-
-static int
-connection_put(lua_State *T)
-{
- struct connection *c;
- size_t len;
- const char *data;
-
- luaL_checktype(T, 1, LUA_TUSERDATA);
- data = luaL_checklstring(T, 2, &len);
-
- c = lua_touserdata(T, 1);
- if (c->T != NULL) {
- lua_pushnil(T);
- lua_pushliteral(T, "busy");
- return 2;
- }
-
- if (c->conn == NULL) {
- lua_pushnil(T);
- lua_pushliteral(T, "closed");
- return 2;
- }
-
- switch (PQputCopyData(c->conn, data, (int)len)) {
- case 1: /* data sent */
- lem_debug("data sent");
- lua_pushboolean(T, 1);
- return 1;
-
- case 0: /* would block */
- lem_debug("would block");
- break;
-
- default: /* should be -1 for error */
- push_error(T, c->conn);
- return 2;
- }
-
- c->T = T;
- c->w.cb = put_handler;
- c->w.events = EV_WRITE;
- ev_io_start(EV_G_ &c->w);
-
- lua_settop(T, 2);
- return lua_yield(T, 2);
-}
-
-static void
-done_handler(EV_P_ struct ev_io *w, int revents)
-{
- struct connection *c = (struct connection *)w;
- const char *error = lua_tostring(c->T, 2);
-
- (void)revents;
-
- switch (PQputCopyEnd(c->conn, error)) {
- case 1: /* data sent */
- lem_debug("data sent");
- ev_io_stop(EV_A_ &c->w);
- lua_settop(c->T, 1);
- (void)PQsetnonblocking(c->conn, 0);
- c->w.cb = exec_handler;
- c->w.events = EV_READ;
- ev_io_start(EV_A_ &c->w);
- break;
-
- case 0: /* would block */
- lem_debug("would block");
- break;
-
- default: /* should be -1 for error */
- ev_io_stop(EV_A_ &c->w);
- lua_settop(c->T, 0);
- push_error(c->T, c->conn);
- lem_queue(c->T, 2);
- c->T = NULL;
- break;
- }
-}
-
-static int
-connection_done(lua_State *T)
-{
- struct connection *c;
- const char *error;
-
- luaL_checktype(T, 1, LUA_TUSERDATA);
- error = luaL_optstring(T, 2, NULL);
-
- c = lua_touserdata(T, 1);
- if (c->T != NULL) {
- lua_pushnil(T);
- lua_pushliteral(T, "busy");
- return 2;
- }
-
- if (c->conn == NULL) {
- lua_pushnil(T);
- lua_pushliteral(T, "closed");
- return 2;
- }
-
- switch (PQputCopyEnd(c->conn, error)) {
- case 1: /* data sent */
- lem_debug("data sent");
- (void)PQsetnonblocking(c->conn, 0);
- c->T = T;
- c->w.cb = exec_handler;
- c->w.events = EV_READ;
- ev_io_start(EV_G_ &c->w);
- lua_settop(c->T, 1);
- return lua_yield(c->T, 1);
-
- case 0: /* would block */
- lem_debug("would block");
- break;
-
- default: /* should be -1 for error */
- push_error(T, c->conn);
- return 2;
- }
-
- c->T = T;
- c->w.cb = done_handler;
- c->w.events = EV_WRITE;
- ev_io_start(EV_G_ &c->w);
-
- if (error == NULL) {
- lua_settop(T, 1);
- lua_pushnil(T);
- } else
- lua_settop(T, 2);
- return lua_yield(T, 2);
-}
-
-static void
-get_handler(EV_P_ struct ev_io *w, int revents)
-{
- struct connection *c = (struct connection *)w;
- char *buf;
- int ret;
-
- ret = PQgetCopyData(c->conn, &buf, 1);
- if (ret > 0) {
- lem_debug("got data");
- ev_io_stop(EV_A_ &c->w);
-
- lua_pushlstring(c->T, buf, ret);
- PQfreemem(buf);
- lem_queue(c->T, 1);
- c->T = NULL;
- return;
- }
-
- switch (ret) {
- case 0: /* would block */
- lem_debug("would block");
- break;
-
- case -1: /* no more data */
- lem_debug("no more data");
- c->w.cb = exec_handler;
- exec_handler(EV_A_ &c->w, revents);
- break;
-
- default: /* should be -2 for error */
- ev_io_stop(EV_A_ &c->w);
- lua_settop(c->T, 0);
- push_error(c->T, c->conn);
- lem_queue(c->T, 2);
- c->T = NULL;
- break;
- }
-}
-
-static int
-connection_get(lua_State *T)
-{
- struct connection *c;
- char *buf;
- int ret;
-
- luaL_checktype(T, 1, LUA_TUSERDATA);
- c = lua_touserdata(T, 1);
- if (c->T != NULL) {
- lua_pushnil(T);
- lua_pushliteral(T, "busy");
- return 2;
- }
-
- if (c->conn == NULL) {
- lua_pushnil(T);
- lua_pushliteral(T, "closed");
- return 2;
- }
-
- ret = PQgetCopyData(c->conn, &buf, 1);
- if (ret > 0) {
- lem_debug("got data");
- lua_pushlstring(T, buf, ret);
- PQfreemem(buf);
- return 1;
- }
-
- switch (ret) {
- case 0: /* would block */
- lem_debug("would block");
- c->T = T;
- c->w.cb = get_handler;
- c->w.events = EV_READ;
- ev_io_start(EV_G_ &c->w);
-
- lua_settop(T, 1);
- return lua_yield(T, 1);
-
- case -1: /* no more data */
- lem_debug("no more data");
- break;
-
- default: /* should be -2 for error */
- push_error(T, c->conn);
- return 2;
- }
-
- c->T = T;
- c->w.cb = exec_handler;
- c->w.events = EV_READ;
- ev_io_start(EV_G_ &c->w);
-
- /* TODO: it is necessary but kinda ugly to call
- * the exec_handler directly from here.
- * find a better solution... */
- lua_settop(T, 1);
- exec_handler(EV_G_ &c->w, 0);
- return lua_yield(T, 1);
-}
-
-int
-luaopen_lem_postgres(lua_State *L)
-{
- lua_newtable(L);
-
- /* create Connection metatable mt */
- lua_newtable(L);
- lua_pushvalue(L, -1);
- lua_setfield(L, -2, "__index");
- /* mt.__gc = <connection_gc> */
- lua_pushcfunction(L, connection_gc);
- lua_setfield(L, -2, "__gc");
- /* mt.close = <connection_close> */
- lua_pushcfunction(L, connection_close);
- lua_setfield(L, -2, "close");
- /* mt.connect = <connection_connect> */
- lua_pushvalue(L, -1); /* upvalue 1: Connection */
- lua_pushcclosure(L, connection_connect, 1);
- lua_setfield(L, -3, "connect");
- /* mt.reset = <connection_reset> */
- lua_pushcfunction(L, connection_reset);
- lua_setfield(L, -2, "reset");
- /* mt.exec = <connection_exec> */
- lua_pushcfunction(L, connection_exec);
- lua_setfield(L, -2, "exec");
- /* mt.prepare = <connection_prepare> */
- lua_pushcfunction(L, connection_prepare);
- lua_setfield(L, -2, "prepare");
- /* mt.run = <connection_run> */
- lua_pushcfunction(L, connection_run);
- lua_setfield(L, -2, "run");
- /* mt.put = <connection_put> */
- lua_pushcfunction(L, connection_put);
- lua_setfield(L, -2, "put");
- /* mt.done = <connection_done> */
- lua_pushcfunction(L, connection_done);
- lua_setfield(L, -2, "done");
- /* mt.get = <connection_get> */
- lua_pushcfunction(L, connection_get);
- lua_setfield(L, -2, "get");
- /* set Connection */
- lua_setfield(L, -2, "Connection");
-
- return 1;
-}