#exult@irc.freenode.net logs for 29 Sep 2001 (GMT)

Archive Today Yesterday Tomorrow
Exult homepage


[00:18:54] --> matto has joined #Exult
[00:27:35] --> chimera|wookin has joined #exult
[00:57:23] <-- chimera|wookin has left IRC (So many rubes in this world who need to be dealt with ... and I don't have time to do the dealing. http://www.rubecity.com)
[02:14:01] --> chimera|wookin has joined #exult
[03:26:05] --> Waz has joined #exult
[03:26:07] <-- Waz has left IRC ()
[04:12:45] --> Kirben has joined #exult
[06:21:27] <-- matto has left IRC (Client Exiting)
[10:04:29] --> fingolfin has joined #exult
[10:12:20] --> Kefka has joined #exult
[10:12:33] <fingolfin> ho K
[10:12:39] <Kefka> Hi
[10:13:04] <Kefka> my debian box is bascially useless to me (no KDE)
[10:13:15] <Kefka> so i am gonna format it, and put windows 2000 and Debian on it
[10:13:28] <Kefka> i am forced to use a winme machine until i do so
[10:15:33] <Kefka> any idea why char packedStuff[] = {"flower", "shirt", "cup", "bluemarble", "ball"}; is bad?
[10:16:10] <Kefka> error C2078: too many initializers
[10:22:28] <fingolfin> yeah
[10:22:37] <fingolfin> it is an array of arrays, btu you declare it as a simple array
[10:22:47] <fingolfin> try char packedStuff[][] = ...
[10:23:16] <Kefka> ok, but how would i access packedStuff to print out flower?
[10:23:23] <Kefka> as "flower"
[10:23:32] <Kefka> [1][1]?
[10:26:50] <fingolfin> no
[10:27:02] <fingolfin> packedStuff[0]
[10:27:05] <fingolfin> and shirt would be
[10:27:09] <fingolfin> packedStuff[1]
[10:27:15] <fingolfin> arrays start at 0
[10:27:22] <fingolfin> and a C string is an array of chars
[10:27:57] <Kefka> er, i kinda found out what i needed to do in order to accomplish my task, but maybe you could tell me a quick why
[10:28:07] <Kefka> this works
[10:28:19] <Kefka> *char packedStuff[] = {"flower", "shirt", "cup", "bluemarble", "ball"};
[10:28:33] <Kefka> then i do
[10:28:43] <Kefka> for (int i=0; i < 5; i++)
[10:28:43] <Kefka> {
[10:28:43] <Kefka>
[10:28:43] <Kefka> cout << "In my grandmother's trunk, I packed" << endl;
[10:28:43] <Kefka> cout << packedStuff[i];
[10:28:43] <Kefka> }
[10:28:53] <fingolfin> not that arrays and pointers are exchangable in many cases
[10:29:32] <fingolfin> char *foo and char foo[] are *almost* the same, at least when you access foo; one of the differences is that you cannot change the second foo to have a new value
[10:29:52] <fingolfin> char *foo1; char foo2[]: char bar; foo = &bar;
[10:30:03] <fingolfin> foo1 = &bar; // I meant that :) it works
[10:30:11] <fingolfin> foo2 = &bar; // compiler error here
[10:31:17] <Kefka> oh
[10:31:47] <Kefka> ok.. i get it i think
[10:32:39] <Kefka> and what is the c++ equivilent of strcat()?
[10:36:24] <fingolfin> you mean for C++ strings or for C strings in a C program
[10:36:25] <fingolfin> ?
[10:37:18] <Kefka> er
[10:37:54] <Kefka> like i want the output to look like: "flower shirt cup bluemarble ball"
[10:38:07] <Kefka> by throwing 5 separate strings together
[10:38:20] <Kefka> each one being a single word
[10:41:17] <fingolfin> use strcat, if you use C strings (which you are doing)
[10:41:26] <fingolfin> of course in C++ you might consider using C++ strings
[10:41:42] <fingolfin> #include <string> // yeah I left out the .h on purpose
[10:41:47] <fingolfin> void main()
[10:41:48] <fingolfin> {
[10:42:06] <fingolfin> std::string foo("Test"), bar("it!");
[10:42:19] <fingolfin> foo = foo + " " + bar;
[10:42:24] <fingolfin> cout << foo << endl;
[10:42:25] <fingolfin> }
[10:43:28] <Kefka> er heh.. gotta look that over for a minute
[10:54:31] <Kefka> do i have to declare foo and bar?
[10:55:42] <Kefka> void main()
[10:55:42] <Kefka> {
[10:55:42] <Kefka> std::string item1("a flower"), item2("a shirt"), item3("a cup"), item4("a blue marble"), item5("a ball");
[10:55:42] <Kefka>
[10:55:42] <Kefka> for (int i=1; i < 5; i++)
[10:55:53] <Kefka> {
[10:55:53] <Kefka> cout << "In my grandmother's trunk, I packed" << endl;
[10:55:53] <Kefka> cout << item1 << endl;
[10:55:53] <Kefka> }
[10:56:13] <Kefka> even though that doesn't do much, it should still compile right?
[10:56:38] <fingolfin> yeah
[10:56:44] <Kefka> i get this major error
[10:56:59] <Kefka> test.cpp(4) : error C2871: 'std' : does not exist or is not a namespace
[10:57:11] <fingolfin> then drop the std::
[10:57:24] <fingolfin> are you using gcc or VC++ ? :)
[10:57:39] <Kefka> MCVC++
[10:57:42] <fingolfin> bloody damns non-compliant C++ compilers
[10:57:43] <fingolfin> argh
[10:57:45] <Kefka> required by class
[10:57:46] <fingolfin> the worst of them all
[10:57:53] <Kefka> hahah
[10:58:34] <Kefka> test.cpp(26) : error C2065: 'string' : undeclared identifier
[10:58:47] <Kefka> am i doing something very wrong somehow?
[10:58:58] <Kefka> besides using MSVC++
[11:02:00] <fingolfin> do you #include <string>
[11:02:01] <fingolfin> ?
[11:04:28] <Kefka> yes
[11:06:33] <Kefka> ok well, i have decided for now to use C
[11:06:46] <Kefka> char *packedStuff[5] = {"a flower", "a shirt", "a cup", "a blue marble", "a ball"};
[11:06:46] <Kefka>
[11:06:46] <Kefka> for (int i=0; i < 5; i++)
[11:06:46] <Kefka> {
[11:06:46] <Kefka>
[11:06:47] <Kefka> cout << "In my grandmother's trunk, I packed" << endl;
[11:06:49] <Kefka> cout << packedStuff[i] << endl;
[11:06:51] <Kefka> strcat(packedStuff[i],packedStuff[i+1]);
[11:06:53] <Kefka> }
[11:06:58] <Kefka> this compiles, but crashes
[11:07:02] <Kefka> on execution
[11:08:23] <fingolfin> sure it crashes
[11:08:27] <fingolfin> you overwrite memory
[11:08:37] <Kefka> i guess thats a bad thing
[11:08:42] <fingolfin> if you use strcat, you have to make sure you have enough space in the dest buffer
[11:08:55] <fingolfin> so better do this
[11:09:00] <fingolfin> char *packedStuff[5] = {"a flower", "a shirt", "a cup", "a blue marble", "a ball"};
[11:09:13] <fingolfin> char buffer[1000] = "";
[11:09:18] <fingolfin> for (int i=0; i < 5; i++)
[11:09:19] <fingolfin> {
[11:09:37] <fingolfin> strcat(buffer, packedStuff[i]);
[11:09:41] <fingolfin> cout << "In my grandmother's trunk, I packed" << endl;
[11:09:48] <fingolfin> cout << buffer << endl;
[11:10:00] <fingolfin> strcat(buffer, ", ");
[11:10:01] <fingolfin> }
[11:10:05] <fingolfin>
[11:10:11] <fingolfin> something like this; I did not test it :)
[11:11:44] <Kefka> er
[11:11:52] <Kefka> didn't see /msg
[11:11:53] <Kefka> sorry
[11:12:16] <Kefka> jsut noticed
[11:14:35] <Kefka> bingo!
[11:14:37] <Kefka> it worked
[11:14:56] <Kefka> thanks
[11:17:43] <Kefka> one more thing
[11:18:41] <Kefka> is there a way to automatically assign the needed memory to buffer[]?
[11:18:54] <Kefka> you use 1000 as a sure fire way
[11:19:21] <Kefka> but is there an easy way to use only the maximum projected possible memory?
[11:19:28] <Kefka> in the format
[11:19:42] <fingolfin> you could allocate the memory at run time
[11:19:45] <Kefka> buffer[maximum possible amount of memory needed]
[11:19:54] <fingolfin> by using some strlens, and malloc, but that would not be easy
[11:20:18] <fingolfin> or you caluclate the max neeeded memory by hand, but this is errorprone, and you would need to fix it each time you change something
[11:20:30] <fingolfin> using c++ strings takes care of that automatically, though
[11:20:37] <Kefka> so basically, i am stuck with 1000..
[11:20:39] <Kefka> in C
[11:21:06] <fingolfin> yeah, but in fact, you should not use strcat, but strncat, for added security
[11:21:10] <Kefka> i need to understand why this isn't accepting std:string
[11:21:16] <Kefka> er std::string
[11:21:30] <Kefka> strncat?
[11:21:37] <fingolfin> e.g. if the list of items was very big, 1000 might still be to small, and you get again a crash (or worse - no crash but data corruption)
[11:21:51] <fingolfin> strncat takes an additional parameter that gives the max size of the dest buffer
[11:23:02] <Kefka> oh so i would put something like
[11:23:41] <Kefka> strcat(buffer, packedStuff[i], 13);
[11:23:55] <Kefka> reason being 13 is the number of characters in "a blue marble"
[11:24:35] <Kefka> er
[11:24:39] <fingolfin> wrong
[11:24:41] <Kefka> strncat(the above)
[11:24:57] <fingolfin> strncat(buffer, packedStuff[i], sizeof(buffer));
[11:26:54] <Kefka> should i use that in both strcat places?
[11:27:07] <Kefka> referring to that above code you typed out
[11:28:53] <fingolfin> yeah
[11:29:42] <Kefka> now i have to go over the reasoning behind all of this
[11:30:10] <Kefka> this is a problem from chapter 2 of my book.. my teacher will ask me about this code..
[11:31:11] <Kefka> undoubtedly, most people in the class will do the brute force type method of assigning a flower and a ball to separate variables
[11:31:28] <Kefka> then printing them out with " and " inbetween
[11:35:26] <Kefka> would strncat actually prevent the crash of the program?
[11:35:48] <Kefka> if i used buffer[10]
[11:37:14] <fingolfin> yeah, it would prevent the crash; but of course the output would be truncated after 10 chars :)
[11:37:18] <fingolfin> or 9 actually
[11:38:26] <Kefka> strcat(buffer, packedStuff[i]);
[11:38:29] <Kefka> er
[11:38:37] <Kefka> char *packedStuff[5] = {"a flower", "a shirt", "a cup", "a blue marble", "a ball"};
[11:38:37] <Kefka> char buffer[10] = "";
[11:38:37] <Kefka>
[11:38:37] <Kefka> for (int i=0; i < 5; i++)
[11:38:45] <Kefka> {
[11:38:45] <Kefka> strncat(buffer, packedStuff[i], sizeof(buffer));
[11:38:45] <Kefka> cout << "In my grandmother's trunk, I packed" << endl;
[11:38:45] <Kefka> cout << buffer << "." << endl;
[11:38:45] <Kefka> strncat(buffer, " and ", sizeof(buffer));
[11:38:45] <Kefka> }
[11:39:01] <Kefka> this crashes after the 2nd iteration of the for loop
[11:39:15] <Kefka> eg, after it prints out "a flower and a shirt."
[11:41:27] <fingolfin> I think you mean "i.e." not "e.g." ? :)
[11:41:29] <fingolfin> hm
[11:41:29] <Kefka> er
[11:41:31] <Kefka> ie
[11:41:40] <Kefka> what does ie stand for anyways? :)
[11:41:57] <Kefka> something latin i think
[11:42:23] <fingolfin> i.e. means "that is"
[11:42:28] <fingolfin> e.g. means "for example"
[11:42:33] <Kefka> ah
[11:46:04] <fingolfin> for me it just exits, but doesn't crash
[11:46:57] <Kefka> exits after how many loop iterations?
[11:48:54] <fingolfin> one loop iteration; it just silently exits, but not a crash, and no memory overwrite
[11:49:07] <fingolfin> which is good
[11:49:24] <fingolfin> strncat is not a miracle worker; it is simply a means to protect you
[11:49:38] <fingolfin> it is mandatory that this is used in network software to prevent buffer overrun attacks
[11:50:02] <Kefka> so bascially
[11:50:09] <Kefka> all of these errors in IIS
[11:50:17] <Kefka> and viruses
[11:50:35] <Kefka> could have been prevented by someone using strncat instead of strcat?
[11:52:18] <fingolfin> no
[11:52:46] <fingolfin> that would be like saying: if everybody would wear warm clothes in winter, nobody would get ill ever :)
[11:53:04] <Kefka> ah
[11:53:12] <Kefka> so there are other ways to buffer overrun
[11:55:42] <Kefka> this stupid MSVC isn't allowing me to use non .h #includes!
[11:55:46] <Kefka> damn it
[11:56:06] <Kefka> #include <iostream.h> works
[11:56:14] <Kefka> #include <iostream> doesn't
[11:59:20] <fingolfin> these are two different files, you see; and maybe VC++ (the version you have at least) is missing the non-.h versions
[11:59:24] <fingolfin> VC 6 ?
[12:00:03] <Kefka> yeah
[12:00:17] <Kefka> Standard (not professional)
[12:04:49] <-- Kefka has left IRC (Ping timeout for Kefka[cc51780-a.warn1.mi.home.com])
[12:05:20] --> Kefka has joined #exult
[12:05:58] <Kefka> [07:49] <Kefka> yeah
[12:05:58] <Kefka> [07:49] <Kefka> Standard (not professional)
[12:09:21] <fingolfin> VC 6 is bad
[12:09:35] <fingolfin> we had a bad headache trying to run exult in it for a long time
[12:09:47] <fingolfin> and I am not sure if it it ever worked, I think ryan has VC 7 now or so :)
[12:09:55] <Kefka> vc7 is out?
[12:10:04] <Kefka> er
[12:10:07] <Kefka> heh
[12:10:45] <Kefka> well, i wish he said to use gcc 3.0
[12:10:51] <Kefka> (my teacher)
[12:11:22] <Kefka> but i guess he isn't a big linux fan
[12:11:52] <Kefka> char buffer[50] = ""; //provide buffer (to store concatenated strings) larger than the combined size of packedStuff's strings
[12:12:02] <Kefka> is that an accurate comment?
[12:14:03] <fingolfin> sre
[12:14:04] <fingolfin> sure
[12:15:34] <Kefka> ok cool.. another requirement (and i guess good practice) of the class
[12:19:22] <Kefka> do you have a suggestion of something to use other than getch() to pause the output of a program
[12:19:58] <Kefka> basically, if i double click the program in windows, it will run then the window will close before i can read it
[12:21:20] <Kefka> in dos, this wouldn't be a problem since the output would still be on the screen after the program runs, but when running it in windows, its a problem
[12:36:49] <fingolfin> ?logs
[12:36:49] <exultbot> Logs are available at http://www.math.leidenuniv.nl/~wpalenst/exultlog.php3
[12:51:22] <-- fingolfin has left IRC (Client Exiting)
[13:06:48] --> wjp has joined #exult
[13:06:53] <wjp> hi
[13:16:54] <-- Kefka has left IRC (Ping timeout for Kefka[cc51780-a.warn1.mi.home.com])
[13:17:13] --> Kefka has joined #exult
[13:17:29] <Kefka> hi
[13:17:33] <Kefka> wjp
[14:23:34] <-- Kirben has left IRC (System Meltdown)
[14:27:49] --> West-Away has joined #exult
[14:27:54] --- West-Away is now known as West
[14:27:58] <West> heya
[14:28:25] <West> anyone home?
[14:29:27] <West> yello?
[14:32:43] <West> hey what is a snapshot exactly, is it the most up to date but unoffical build of the engine?
[14:34:49] --> Colourless has joined #Exult
[14:34:54] <West> heya
[14:35:10] <Colourless> hi
[14:35:18] <West> I have a question
[14:35:28] <Colourless> ok
[14:35:50] <West> is a snapshot just the latest but unoffical build of the exult engine?
[14:36:05] <Colourless> yes it is
[14:36:10] <West> ah man
[14:36:16] <West> I wish someone would have told me this four weeks ago!
[14:36:17] <West> hehe
[14:36:25] <Colourless> :-)
[14:36:35] <West> I've been stuck in the dream realm because of the bug that occurs that locks up the game
[14:36:54] <West> but I think that's been fixed
[14:37:06] <Colourless> quite possibly it has
[14:37:20] <West> you guys should work on making an engine for U8 too
[14:37:21] <West> hehe
[14:37:54] <West> hey did you hear about the new 3D Ultima engine?
[14:37:56] <wjp> hi
[14:38:03] <wjp> which one?
[14:38:18] <West> this team is going to remake all of the classic Ultimas in 3D
[14:38:27] <Colourless> well, wjp did make a u8 map viewer, but we are not going to make a u8 engine
[14:38:28] <West> they have Richard Garriot's blessing and everything
[14:38:51] <wjp> a very buggy u8 map viewer :-)
[14:38:57] <Colourless> yeah, well we have his blessings as well, but it doesn't mean much
[14:39:09] <West> well it means he won't sue you :-)
[14:39:18] <Colourless> but EA still could
[14:39:18] <West> hehe
[14:39:19] <wjp> he's not the one that will sue, if anyone does
[14:39:36] <West> I thought he held the copyrights to U
[14:39:40] <West> ltima
[14:39:43] <Colourless> nope, EA does
[14:39:45] <wjp> maybe some of the earlier ones?
[14:39:47] <West> sheesh
[14:39:50] <West> well
[14:39:57] <West> definitely U1
[14:40:00] <wjp> RG does hold the LB trademark
[14:40:09] <West> and Aka
[14:40:13] <West> man
[14:40:23] <West> from Xs and +s on a black and white screen to 3D
[14:40:28] <West> that'll take some mental liberty
[14:40:28] <West> hehe
[14:40:42] <Colourless> just a bit
[14:40:56] <West> well I've seen screenshots from them and man
[14:40:59] <West> it's going to be sweet
[14:41:13] <West> not as sweet as U7 and SI from it's original perspective
[14:41:15] <West> but still
[14:41:35] <West> well download is done
[14:41:40] <West> hope you gentlemen have a fine day
[14:41:42] <-- West has left IRC ()
[14:57:11] <wjp> did you see the bug after the test of Ethicality Dominik submitted?
[14:57:24] <wjp> (disappearing objects)
[14:57:25] <Colourless> no i haven't checked out the bugs
[14:58:05] <wjp> after the test, you get some extra gold in your backpack, which causes other objects to disappear if your backpack was full before
[14:59:07] <Colourless> i'm not sure you are meant to keep the gold
[14:59:14] <wjp> I think you are
[14:59:32] <wjp> (IIRC, that is)
[15:00:53] <wjp> we keep having problems with this kind of thing
[15:02:19] <Colourless> i'm pretty sure the original might have actually let you overfill your packpack. It for sure didn't delete objects
[15:02:43] <wjp> we don't delete them either; we add them to the actor itself
[15:02:59] <wjp> (unfortunately, this effectively makes them completely invisible)
[15:03:38] <Colourless> we can't allow that
[15:03:45] <Colourless> it's really screwing things up
[15:03:52] <wjp> some monsters do have items stored there, though
[15:04:08] <wjp> (or that's what it looks like from some debugging messages I added)
[15:04:15] <Colourless> yeah
[15:06:39] <wjp> maybe we should first add them to the backpack with 'dont_check' set, and only add them to the actor itself it that fails
[15:06:44] <wjp> (for the monster case)
[15:07:08] <Colourless> yeah
[15:07:40] <wjp> currently we try to drop the item in the back, belt, lhand and rhand spots
[15:07:54] <wjp> how about trying that entire sequence again with dont_check?
[15:08:33] <Colourless> we could try that
[15:08:34] <wjp> or... we could drop the items on the floor
[15:08:50] <wjp> but that would break the monster case
[15:08:59] <Colourless> i don't think dropping on the floor is such a good idea
[15:10:27] <wjp> that ethicality test is getting annoying
[15:11:03] <Colourless> you think? :-)
[15:11:41] <wjp> do you think it would be ethical to cheat? ;-)
[15:12:09] <Colourless> yes :)
[15:12:15] <Colourless> it's for the good of the universe
[15:12:38] <Colourless> but do not cheat to do evil things
[15:12:54] <wjp> hmm, strange
[15:13:10] <wjp> the extra backpack is still being added to the actor
[15:14:07] <Colourless> take this situation: You fighting an evil person. You can not defend yourself. You know that if you do nothing countless more people will die. Your only option is to cheat and kill the evil person. What do you do?
[15:14:19] <Colourless> :-)
[15:14:26] <wjp> hehe :-)
[15:14:41] <wjp> I save the game and see what happens if I do nothing anyway :-)
[15:14:52] <Colourless> hehe
[15:15:03] <Colourless> some people consider that cheating
[15:15:28] <wjp> yeah
[15:16:32] <Colourless> so you have no choice. The only ethical thing to do is to cheat
[15:18:57] <wjp> but what if cheating causes the fabric of the universe to destabilize, causing countless more people to die?
[15:19:46] <Colourless> then that is unethical
[15:20:50] <Colourless> but if you have the power to restore the state of the universe to that of an earlier time, than you are compelled to do so
[15:30:34] <wjp> ok, now it did work
[15:32:05] <Colourless> what did you do?
[15:32:09] <wjp> recompile :-)
[15:32:10] <Colourless> what was the problem?
[15:32:19] <Colourless> gee
[15:32:24] <wjp> that tends to help :-)
[15:33:28] <wjp> the extra backpack you get is now in your hand (!?)
[15:34:06] <Colourless> as I said, i don't think you are meant to have it
[15:34:36] <wjp> what surprises me is the hand part. Why would it appear there now, but not before?
[15:35:25] <wjp> strange... the extra code doesn't even get executed
[15:35:39] * wjp is confused
[15:39:16] <wjp> ok, seems it doesn't always happen
[15:39:33] <wjp> great... this means I have to do that test again, and again, and again...
[15:42:28] <wjp> oops...
[15:42:36] <Colourless> what?
[15:42:39] <wjp> Container_game_object::add, first line:
[15:42:45] <wjp> if (obj->get_shapenum() == get_shapenum()) return 0;
[15:43:06] <wjp> I wonder what's the point of that
[15:43:31] <wjp> well, except with infinite volume containers, maybe
[15:43:38] <Colourless> quick fail because of volume
[15:43:49] <Colourless> which is most afaik
[15:44:02] <Colourless> if not all
[15:44:03] <wjp> I'll disable it for dont_check
[15:44:36] <Colourless> yeah
[15:45:03] <wjp> brb
[15:45:07] <Colourless> k
[15:52:43] <wjp> b
[15:52:50] <Colourless> wb
[15:53:39] <wjp> you wouldn't happen to have a savegame right before/after the ethicality test in the original? :-)
[15:54:05] <Colourless> i don't think so
[15:54:16] <Colourless> I might
[15:54:23] <wjp> I seem to remember having one
[15:54:24] * wjp checks
[15:54:50] <wjp> I have a game named "Temple of Ethicality"
[16:08:53] --> fingolfin has joined #exult
[16:08:57] <wjp> hi
[16:09:05] <Colourless> hi
[16:09:17] <fingolfin> hi
[16:10:24] * Colourless thinks he'll need to at some stage finish off the SI ending
[18:57:45] --- fingolfin is now known as Fingolfin
[20:16:39] <Colourless> 1h 20 late: whoa, big change you did to your name there
[20:19:02] --- wjp is now known as Wjp
[20:19:23] <Fingolfin> he
[20:19:33] <Fingolfin> Wjp: you look strange like that :)
[20:19:40] --- Wjp is now known as wjp
[20:19:42] <wjp> yeah :-)
[21:30:54] <-- Kefka has left IRC (Ping timeout for Kefka[cc51780-a.warn1.mi.home.com])
[21:35:12] --> Kefka has joined #exult
[22:01:26] <-- Kefka has left IRC (Ping timeout for Kefka[cc51780-a.warn1.mi.home.com])
[22:01:49] --> Kefka has joined #exult
[22:08:19] <wjp> I have to go
[22:08:21] <wjp> g'night
[22:08:22] <-- wjp has left IRC ([x]chat)
[22:18:38] <-- Kefka has left IRC (Ping timeout for Kefka[cc51780-a.warn1.mi.home.com])
[22:20:29] --> Kefka has joined #exult
[22:42:30] <Colourless> time to go
[22:42:34] <-- Colourless has left IRC ([8:16])