summaryrefslogtreecommitdiff
path: root/data/vim/patches/8.1.0134
diff options
context:
space:
mode:
Diffstat (limited to 'data/vim/patches/8.1.0134')
-rw-r--r--data/vim/patches/8.1.0134724
1 files changed, 724 insertions, 0 deletions
diff --git a/data/vim/patches/8.1.0134 b/data/vim/patches/8.1.0134
new file mode 100644
index 000000000..ff07dfe27
--- /dev/null
+++ b/data/vim/patches/8.1.0134
@@ -0,0 +1,724 @@
+To: vim_dev@googlegroups.com
+Subject: Patch 8.1.0134
+Fcc: outbox
+From: Bram Moolenaar <Bram@moolenaar.net>
+Mime-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+------------
+
+Patch 8.1.0134
+Problem: Lua interface does not support funcref.
+Solution: Add funcref support. (Luis Carvalho)
+Files: src/if_lua.c, src/testdir/test_lua.vim
+
+
+*** ../vim-8.1.0133/src/if_lua.c 2017-12-16 18:17:27.000000000 +0100
+--- src/if_lua.c 2018-07-01 14:49:42.013143173 +0200
+***************
+*** 28,37 ****
+--- 28,43 ----
+ typedef win_T *luaV_Window;
+ typedef dict_T *luaV_Dict;
+ typedef list_T *luaV_List;
++ typedef struct {
++ typval_T tv; // funcref
++ typval_T args;
++ dict_T *self; // selfdict
++ } luaV_Funcref;
+ typedef void (*msgfunc_T)(char_u *);
+
+ static const char LUAVIM_DICT[] = "dict";
+ static const char LUAVIM_LIST[] = "list";
++ static const char LUAVIM_FUNCREF[] = "funcref";
+ static const char LUAVIM_BUFFER[] = "buffer";
+ static const char LUAVIM_WINDOW[] = "window";
+ static const char LUAVIM_FREE[] = "luaV_free";
+***************
+*** 55,63 ****
+ if (sandbox) luaL_error((L), "not allowed in sandbox")
+ #define luaV_msg(L) luaV_msgfunc((L), (msgfunc_T) msg)
+ #define luaV_emsg(L) luaV_msgfunc((L), (msgfunc_T) emsg)
+!
+! static luaV_List *luaV_pushlist (lua_State *L, list_T *lis);
+! static luaV_Dict *luaV_pushdict (lua_State *L, dict_T *dic);
+
+ #if LUA_VERSION_NUM <= 501
+ #define luaV_openlib(L, l, n) luaL_openlib(L, NULL, l, n)
+--- 61,75 ----
+ if (sandbox) luaL_error((L), "not allowed in sandbox")
+ #define luaV_msg(L) luaV_msgfunc((L), (msgfunc_T) msg)
+ #define luaV_emsg(L) luaV_msgfunc((L), (msgfunc_T) emsg)
+! #define luaV_checktypval(L, a, v, msg) \
+! do { \
+! if (luaV_totypval(L, a, v) == FAIL) \
+! luaL_error(L, msg ": cannot convert value"); \
+! } while (0)
+!
+! static luaV_List *luaV_pushlist(lua_State *L, list_T *lis);
+! static luaV_Dict *luaV_pushdict(lua_State *L, dict_T *dic);
+! static luaV_Funcref *luaV_pushfuncref(lua_State *L, typval_T *tv);
+
+ #if LUA_VERSION_NUM <= 501
+ #define luaV_openlib(L, l, n) luaL_openlib(L, NULL, l, n)
+***************
+*** 506,521 ****
+ else
+ lua_pushnil(L);
+ break;
+ default:
+ lua_pushnil(L);
+ }
+ }
+
+! /* converts lua value at 'pos' to typval 'tv' */
+! static void
+! luaV_totypval (lua_State *L, int pos, typval_T *tv)
+ {
+! switch(lua_type(L, pos)) {
+ case LUA_TBOOLEAN:
+ tv->v_type = VAR_SPECIAL;
+ tv->vval.v_number = (varnumber_T) lua_toboolean(L, pos);
+--- 518,542 ----
+ else
+ lua_pushnil(L);
+ break;
++ case VAR_FUNC:
++ luaV_pushfuncref(L, tv);
++ break;
+ default:
+ lua_pushnil(L);
+ }
+ }
+
+! /*
+! * Converts lua value at 'pos' to typval 'tv'.
+! * Returns OK or FAIL.
+! */
+! static int
+! luaV_totypval(lua_State *L, int pos, typval_T *tv)
+ {
+! int status = OK;
+!
+! switch (lua_type(L, pos))
+! {
+ case LUA_TBOOLEAN:
+ tv->v_type = VAR_SPECIAL;
+ tv->vval.v_number = (varnumber_T) lua_toboolean(L, pos);
+***************
+*** 533,540 ****
+ tv->vval.v_number = (varnumber_T) lua_tointeger(L, pos);
+ #endif
+ break;
+! case LUA_TUSERDATA: {
+ void *p = lua_touserdata(L, pos);
+ if (lua_getmetatable(L, pos)) /* has metatable? */
+ {
+ /* check list */
+--- 554,563 ----
+ tv->vval.v_number = (varnumber_T) lua_tointeger(L, pos);
+ #endif
+ break;
+! case LUA_TUSERDATA:
+! {
+ void *p = lua_touserdata(L, pos);
++
+ if (lua_getmetatable(L, pos)) /* has metatable? */
+ {
+ /* check list */
+***************
+*** 545,551 ****
+ tv->vval.v_list = *((luaV_List *) p);
+ ++tv->vval.v_list->lv_refcount;
+ lua_pop(L, 2); /* MTs */
+! return;
+ }
+ /* check dict */
+ luaV_getfield(L, LUAVIM_DICT);
+--- 568,574 ----
+ tv->vval.v_list = *((luaV_List *) p);
+ ++tv->vval.v_list->lv_refcount;
+ lua_pop(L, 2); /* MTs */
+! break;
+ }
+ /* check dict */
+ luaV_getfield(L, LUAVIM_DICT);
+***************
+*** 555,570 ****
+ tv->vval.v_dict = *((luaV_Dict *) p);
+ ++tv->vval.v_dict->dv_refcount;
+ lua_pop(L, 3); /* MTs */
+! return;
+ }
+! lua_pop(L, 3); /* MTs */
+ }
+- break;
+ }
+ default:
+ tv->v_type = VAR_NUMBER;
+ tv->vval.v_number = 0;
+ }
+ }
+
+ /* similar to luaL_addlstring, but replaces \0 with \n if toline and
+--- 578,604 ----
+ tv->vval.v_dict = *((luaV_Dict *) p);
+ ++tv->vval.v_dict->dv_refcount;
+ lua_pop(L, 3); /* MTs */
+! break;
+ }
+! /* check funcref */
+! luaV_getfield(L, LUAVIM_FUNCREF);
+! if (lua_rawequal(L, -1, -4))
+! {
+! luaV_Funcref *f = (luaV_Funcref *) p;
+! copy_tv(&f->tv, tv);
+! lua_pop(L, 4); /* MTs */
+! break;
+! }
+! lua_pop(L, 4); /* MTs */
+ }
+ }
++ /* FALLTHROUGH */
+ default:
+ tv->v_type = VAR_NUMBER;
+ tv->vval.v_number = 0;
++ status = FAIL;
+ }
++ return status;
+ }
+
+ /* similar to luaL_addlstring, but replaces \0 with \n if toline and
+***************
+*** 646,652 ****
+
+ #define luaV_pushtype(typ,tname,luatyp) \
+ static luatyp * \
+! luaV_push##tname (lua_State *L, typ *obj) \
+ { \
+ luatyp *o = NULL; \
+ if (obj == NULL) \
+--- 680,686 ----
+
+ #define luaV_pushtype(typ,tname,luatyp) \
+ static luatyp * \
+! luaV_push##tname(lua_State *L, typ *obj) \
+ { \
+ luatyp *o = NULL; \
+ if (obj == NULL) \
+***************
+*** 766,772 ****
+ else
+ {
+ typval_T v;
+! luaV_totypval(L, 3, &v);
+ clear_tv(&li->li_tv);
+ copy_tv(&v, &li->li_tv);
+ clear_tv(&v);
+--- 800,806 ----
+ else
+ {
+ typval_T v;
+! luaV_checktypval(L, 3, &v, "setting list item");
+ clear_tv(&li->li_tv);
+ copy_tv(&v, &li->li_tv);
+ clear_tv(&v);
+***************
+*** 783,793 ****
+ if (l->lv_lock)
+ luaL_error(L, "list is locked");
+ lua_settop(L, 2);
+! luaV_totypval(L, 2, &v);
+ if (list_append_tv(l, &v) == FAIL)
+ {
+ clear_tv(&v);
+! luaL_error(L, "Failed to add item to list");
+ }
+ clear_tv(&v);
+ lua_settop(L, 1);
+--- 817,827 ----
+ if (l->lv_lock)
+ luaL_error(L, "list is locked");
+ lua_settop(L, 2);
+! luaV_checktypval(L, 2, &v, "adding list item");
+ if (list_append_tv(l, &v) == FAIL)
+ {
+ clear_tv(&v);
+! luaL_error(L, "failed to add item to list");
+ }
+ clear_tv(&v);
+ lua_settop(L, 1);
+***************
+*** 811,821 ****
+ luaL_error(L, "invalid position");
+ }
+ lua_settop(L, 2);
+! luaV_totypval(L, 2, &v);
+ if (list_insert_tv(l, &v, li) == FAIL)
+ {
+ clear_tv(&v);
+! luaL_error(L, "Failed to add item to list");
+ }
+ clear_tv(&v);
+ lua_settop(L, 1);
+--- 845,855 ----
+ luaL_error(L, "invalid position");
+ }
+ lua_settop(L, 2);
+! luaV_checktypval(L, 2, &v, "inserting list item");
+ if (list_insert_tv(l, &v, li) == FAIL)
+ {
+ clear_tv(&v);
+! luaL_error(L, "failed to add item to list");
+ }
+ clear_tv(&v);
+ lua_settop(L, 1);
+***************
+*** 894,919 ****
+ }
+
+ static int
+! luaV_dict_index (lua_State *L)
+ {
+ dict_T *d = luaV_unbox(L, luaV_Dict, 1);
+ char_u *key = (char_u *) luaL_checkstring(L, 2);
+ dictitem_T *di = dict_find(d, key, -1);
+ if (di == NULL)
+ lua_pushnil(L);
+ else
+ luaV_pushtypval(L, &di->di_tv);
+ return 1;
+ }
+
+ static int
+! luaV_dict_newindex (lua_State *L)
+ {
+ dict_T *d = luaV_unbox(L, luaV_Dict, 1);
+ char_u *key = (char_u *) luaL_checkstring(L, 2);
+ dictitem_T *di;
+ if (d->dv_lock)
+ luaL_error(L, "dict is locked");
+ di = dict_find(d, key, -1);
+ if (di == NULL) /* non-existing key? */
+ {
+--- 928,970 ----
+ }
+
+ static int
+! luaV_dict_index(lua_State *L)
+ {
+ dict_T *d = luaV_unbox(L, luaV_Dict, 1);
+ char_u *key = (char_u *) luaL_checkstring(L, 2);
+ dictitem_T *di = dict_find(d, key, -1);
++
+ if (di == NULL)
+ lua_pushnil(L);
+ else
++ {
+ luaV_pushtypval(L, &di->di_tv);
++ if (di->di_tv.v_type == VAR_FUNC) /* funcref? */
++ {
++ luaV_Funcref *f = (luaV_Funcref *) lua_touserdata(L, -1);
++ f->self = d; /* keep "self" reference */
++ d->dv_refcount++;
++ }
++ }
+ return 1;
+ }
+
+ static int
+! luaV_dict_newindex(lua_State *L)
+ {
+ dict_T *d = luaV_unbox(L, luaV_Dict, 1);
+ char_u *key = (char_u *) luaL_checkstring(L, 2);
+ dictitem_T *di;
++ typval_T v;
+ if (d->dv_lock)
+ luaL_error(L, "dict is locked");
++ if (key != NULL && *key == NUL)
++ luaL_error(L, "empty key");
++ if (!lua_isnil(L, 3)) { /* read value? */
++ luaV_checktypval(L, 3, &v, "setting dict item");
++ if (d->dv_scope == VAR_DEF_SCOPE && v.v_type == VAR_FUNC)
++ luaL_error(L, "cannot assign funcref to builtin scope");
++ }
+ di = dict_find(d, key, -1);
+ if (di == NULL) /* non-existing key? */
+ {
+***************
+*** 934,942 ****
+ hash_remove(&d->dv_hashtab, hi);
+ dictitem_free(di);
+ }
+! else {
+! typval_T v;
+! luaV_totypval(L, 3, &v);
+ copy_tv(&v, &di->di_tv);
+ clear_tv(&v);
+ }
+--- 985,992 ----
+ hash_remove(&d->dv_hashtab, hi);
+ dictitem_free(di);
+ }
+! else
+! {
+ copy_tv(&v, &di->di_tv);
+ clear_tv(&v);
+ }
+***************
+*** 953,958 ****
+--- 1003,1094 ----
+ };
+
+
++ /* ======= Funcref type ======= */
++
++ static luaV_Funcref *
++ luaV_newfuncref(lua_State *L, char_u *name)
++ {
++ luaV_Funcref *f = (luaV_Funcref *)lua_newuserdata(L, sizeof(luaV_Funcref));
++
++ if (name != NULL)
++ {
++ func_ref(name); /* as in copy_tv */
++ f->tv.vval.v_string = vim_strsave(name);
++ }
++ f->tv.v_type = VAR_FUNC;
++ f->args.v_type = VAR_LIST;
++ f->self = NULL;
++ luaV_getfield(L, LUAVIM_FUNCREF);
++ lua_setmetatable(L, -2);
++ return f;
++ }
++
++ static luaV_Funcref *
++ luaV_pushfuncref(lua_State *L, typval_T *tv)
++ {
++ luaV_Funcref *f = luaV_newfuncref(L, NULL);
++ copy_tv(tv, &f->tv);
++ clear_tv(tv);
++ return f;
++ }
++
++
++ luaV_type_tostring(funcref, LUAVIM_FUNCREF)
++
++ static int
++ luaV_funcref_gc(lua_State *L)
++ {
++ luaV_Funcref *f = (luaV_Funcref *) lua_touserdata(L, 1);
++
++ func_unref(f->tv.vval.v_string);
++ vim_free(f->tv.vval.v_string);
++ dict_unref(f->self);
++ return 0;
++ }
++
++ /* equivalent to string(funcref) */
++ static int
++ luaV_funcref_len(lua_State *L)
++ {
++ luaV_Funcref *f = (luaV_Funcref *) lua_touserdata(L, 1);
++
++ lua_pushstring(L, (const char *) f->tv.vval.v_string);
++ return 1;
++ }
++
++ static int
++ luaV_funcref_call(lua_State *L)
++ {
++ luaV_Funcref *f = (luaV_Funcref *) lua_touserdata(L, 1);
++ int i, n = lua_gettop(L) - 1; /* #args */
++ int status;
++ typval_T v, rettv;
++
++ f->args.vval.v_list = list_alloc();
++ rettv.v_type = VAR_UNKNOWN; /* as in clear_tv */
++ for (i = 0; i < n; i++) {
++ luaV_checktypval(L, i + 2, &v, "calling funcref");
++ list_append_tv(f->args.vval.v_list, &v);
++ }
++ status = func_call(f->tv.vval.v_string, &f->args, NULL, f->self, &rettv);
++ if (status == OK)
++ luaV_pushtypval(L, &rettv);
++ clear_tv(&f->args);
++ clear_tv(&rettv);
++ if (status != OK)
++ luaL_error(L, "cannot call funcref");
++ return 1;
++ }
++
++ static const luaL_Reg luaV_Funcref_mt[] = {
++ {"__tostring", luaV_funcref_tostring},
++ {"__gc", luaV_funcref_gc},
++ {"__len", luaV_funcref_len},
++ {"__call", luaV_funcref_call},
++ {NULL, NULL}
++ };
++
++
+ /* ======= Buffer type ======= */
+
+ luaV_newtype(buf_T, buffer, luaV_Buffer, LUAVIM_BUFFER)
+***************
+*** 1033,1039 ****
+ curbuf = buf;
+ luaL_error(L, "cannot delete line");
+ }
+! else {
+ deleted_lines_mark(n, 1L);
+ if (b == curwin->w_buffer) /* fix cursor in current window? */
+ {
+--- 1169,1176 ----
+ curbuf = buf;
+ luaL_error(L, "cannot delete line");
+ }
+! else
+! {
+ deleted_lines_mark(n, 1L);
+ if (b == curwin->w_buffer) /* fix cursor in current window? */
+ {
+***************
+*** 1371,1392 ****
+ static int
+ luaV_list(lua_State *L)
+ {
+! list_T *l = list_alloc();
+ if (l == NULL)
+ lua_pushnil(L);
+ else
+ luaV_newlist(L, l);
+ return 1;
+ }
+
+ static int
+ luaV_dict(lua_State *L)
+ {
+! dict_T *d = dict_alloc();
+ if (d == NULL)
+ lua_pushnil(L);
+ else
+ luaV_newdict(L, d);
+ return 1;
+ }
+
+--- 1508,1591 ----
+ static int
+ luaV_list(lua_State *L)
+ {
+! list_T *l;
+! int initarg = !lua_isnoneornil(L, 1);
+!
+! if (initarg && lua_type(L, 1) != LUA_TTABLE)
+! luaL_error(L, "table expected, got %s", luaL_typename(L, 1));
+! l = list_alloc();
+ if (l == NULL)
+ lua_pushnil(L);
+ else
++ {
+ luaV_newlist(L, l);
++ if (initarg) { /* traverse table to init dict */
++ int notnil, i = 0;
++ typval_T v;
++ do {
++ lua_rawgeti(L, 1, ++i);
++ notnil = !lua_isnil(L, -1);
++ if (notnil) {
++ luaV_checktypval(L, -1, &v, "vim.list");
++ list_append_tv(l, &v);
++ }
++ lua_pop(L, 1); /* value */
++ } while (notnil);
++ }
++ }
+ return 1;
+ }
+
+ static int
+ luaV_dict(lua_State *L)
+ {
+! dict_T *d;
+! int initarg = !lua_isnoneornil(L, 1);
+!
+! if (initarg && lua_type(L, 1) != LUA_TTABLE)
+! luaL_error(L, "table expected, got %s", luaL_typename(L, 1));
+! d = dict_alloc();
+ if (d == NULL)
+ lua_pushnil(L);
+ else
++ {
+ luaV_newdict(L, d);
++ if (initarg) /* traverse table to init dict */
++ {
++ lua_pushnil(L);
++ while (lua_next(L, 1))
++ {
++ char_u *key;
++ dictitem_T *di;
++ typval_T v;
++ lua_pushvalue(L, -2); /* dup key in case it's a number */
++ key = (char_u *) lua_tostring(L, -1);
++ if (key != NULL && *key == NUL)
++ luaL_error(L, "table has empty key");
++ luaV_checktypval(L, -2, &v, "vim.dict"); /* value */
++ di = dictitem_alloc(key);
++ if (di == NULL || dict_add(d, di) == FAIL) {
++ vim_free(di);
++ lua_pushnil(L);
++ return 1;
++ }
++ copy_tv(&v, &di->di_tv);
++ clear_tv(&v);
++ lua_pop(L, 2); /* key copy and value */
++ }
++ }
++ }
++ return 1;
++ }
++
++ static int
++ luaV_funcref(lua_State *L)
++ {
++ const char *name = luaL_checkstring(L, 1);
++ /* note: not checking if function exists (needs function_exists) */
++ if (name == NULL || *name == NUL || VIM_ISDIGIT(*name))
++ luaL_error(L, "invalid function name: %s", name);
++ luaV_newfuncref(L, (char_u *) name);
+ return 1;
+ }
+
+***************
+*** 1402,1408 ****
+ FOR_ALL_BUFFERS(buf)
+ if (buf->b_fnum == n) break;
+ }
+! else { /* by name */
+ size_t l;
+ const char *s = lua_tolstring(L, 1, &l);
+ FOR_ALL_BUFFERS(buf)
+--- 1601,1608 ----
+ FOR_ALL_BUFFERS(buf)
+ if (buf->b_fnum == n) break;
+ }
+! else // by name
+! {
+ size_t l;
+ const char *s = lua_tolstring(L, 1, &l);
+ FOR_ALL_BUFFERS(buf)
+***************
+*** 1472,1477 ****
+--- 1672,1683 ----
+ lua_pushstring(L, "dict");
+ return 1;
+ }
++ luaV_getfield(L, LUAVIM_FUNCREF);
++ if (lua_rawequal(L, -1, 2))
++ {
++ lua_pushstring(L, "funcref");
++ return 1;
++ }
+ luaV_getfield(L, LUAVIM_BUFFER);
+ if (lua_rawequal(L, -1, 2))
+ {
+***************
+*** 1497,1502 ****
+--- 1703,1709 ----
+ {"line", luaV_line},
+ {"list", luaV_list},
+ {"dict", luaV_dict},
++ {"funcref", luaV_funcref},
+ {"buffer", luaV_buffer},
+ {"window", luaV_window},
+ {"open", luaV_open},
+***************
+*** 1537,1543 ****
+ luaV_emsg(L);
+ return 0;
+ }
+! luaV_totypval(L, -1, rettv);
+ return 0;
+ }
+
+--- 1744,1751 ----
+ luaV_emsg(L);
+ return 0;
+ }
+! if (luaV_totypval(L, -1, rettv) == FAIL)
+! EMSG("luaeval: cannot convert value");
+ return 0;
+ }
+
+***************
+*** 1612,1617 ****
+--- 1820,1828 ----
+ luaV_newmetatable(L, LUAVIM_DICT);
+ lua_pushvalue(L, 1);
+ luaV_openlib(L, luaV_Dict_mt, 1);
++ luaV_newmetatable(L, LUAVIM_FUNCREF);
++ lua_pushvalue(L, 1);
++ luaV_openlib(L, luaV_Funcref_mt, 1);
+ luaV_newmetatable(L, LUAVIM_BUFFER);
+ lua_pushvalue(L, 1); /* cache table */
+ luaV_openlib(L, luaV_Buffer_mt, 1);
+*** ../vim-8.1.0133/src/testdir/test_lua.vim 2018-06-30 21:50:16.856674912 +0200
+--- src/testdir/test_lua.vim 2018-07-01 15:00:55.884371772 +0200
+***************
+*** 397,402 ****
+--- 397,425 ----
+ lua str, k, v, d = nil, nil, nil, nil
+ endfunc
+
++ func Test_funcref()
++ function I(x)
++ return a:x
++ endfunction
++ let R = function('I')
++ lua i1 = vim.funcref"I"
++ lua i2 = vim.eval"R"
++ lua msg = "funcref|test|" .. (#i2(i1) == #i1(i2) and "OK" or "FAIL")
++ lua msg = vim.funcref"tr"(msg, "|", " ")
++ call assert_equal("funcref test OK", luaeval('msg'))
++
++ " dict funcref
++ function Mylen() dict
++ return len(self.data)
++ endfunction
++ let l = [0, 1, 2, 3]
++ let mydict = {'data': l}
++ lua d = vim.eval"mydict"
++ lua d.len = vim.funcref"Mylen" -- assign d as 'self'
++ lua res = (d.len() == vim.funcref"len"(vim.eval"l")) and "OK" or "FAIL"
++ call assert_equal("OK", luaeval('res'))
++ endfunc
++
+ " Test vim.type()
+ func Test_type()
+ " The following values are identical to Lua's type function.
+***************
+*** 414,419 ****
+--- 437,443 ----
+ call assert_equal('buffer', luaeval('vim.type(vim.buffer())'))
+ call assert_equal('list', luaeval('vim.type(vim.list())'))
+ call assert_equal('dict', luaeval('vim.type(vim.dict())'))
++ call assert_equal('funcref', luaeval('vim.type(vim.funcref("Test_type"))'))
+ endfunc
+
+ " Test vim.open()
+*** ../vim-8.1.0133/src/version.c 2018-06-30 22:40:39.097551835 +0200
+--- src/version.c 2018-07-01 15:01:56.939951330 +0200
+***************
+*** 791,792 ****
+--- 791,794 ----
+ { /* Add new patch number below this line */
++ /**/
++ 134,
+ /**/
+
+--
+hundred-and-one symptoms of being an internet addict:
+162. You go outside and look for a brightness knob to turn down the sun.
+
+ /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\
+/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
+\\\ an exciting new programming language -- http://www.Zimbu.org ///
+ \\\ help me help AIDS victims -- http://ICCF-Holland.org ///