From 193f1b94bf23cb901c38adf1ea70bd5117143f71 Mon Sep 17 00:00:00 2001 From: Jared Adams Date: Sun, 8 Mar 2009 23:11:14 -0600 Subject: Fix error in sqlite 2 to 3 update script --- src/sql/sqlite/updates/update_2_to_3.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sql/sqlite/updates/update_2_to_3.sql b/src/sql/sqlite/updates/update_2_to_3.sql index f8fdfc91..55441eb5 100644 --- a/src/sql/sqlite/updates/update_2_to_3.sql +++ b/src/sql/sqlite/updates/update_2_to_3.sql @@ -6,7 +6,7 @@ CREATE TABLE tmw_transactions char_id INTEGER NOT NULL, action INTEGER NOT NULL, message TEXT, - time INTEGER NOT NULL, + time INTEGER NOT NULL ); -- update the database version, and set date of update -- cgit v1.2.3-70-g09d2 From 9c85904b24a5fa72c096f023e3deaa96b85dd52c Mon Sep 17 00:00:00 2001 From: Jared Adams Date: Sun, 8 Mar 2009 23:23:50 -0600 Subject: Fix a bug in the sqlite db creation file --- src/sql/sqlite/createTables.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sql/sqlite/createTables.sql b/src/sql/sqlite/createTables.sql index 11478d9b..42a884db 100644 --- a/src/sql/sqlite/createTables.sql +++ b/src/sql/sqlite/createTables.sql @@ -218,7 +218,7 @@ CREATE TABLE tmw_transactions char_id INTEGER NOT NULL, action INTEGER NOT NULL, message TEXT, - time INTEGER NOT NULL, + time INTEGER NOT NULL ); CREATE TABLE tmw_online_list -- cgit v1.2.3-70-g09d2 From 39dd791921e94ffb55e3005e5c131c46c8929a78 Mon Sep 17 00:00:00 2001 From: Jared Adams Date: Sun, 8 Mar 2009 23:26:56 -0600 Subject: Fix database version in sqlite db creation file --- src/sql/sqlite/createTables.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sql/sqlite/createTables.sql b/src/sql/sqlite/createTables.sql index 42a884db..1831c45a 100644 --- a/src/sql/sqlite/createTables.sql +++ b/src/sql/sqlite/createTables.sql @@ -142,7 +142,7 @@ CREATE TABLE tmw_world_states INSERT INTO tmw_world_states VALUES('accountserver_startup',NULL,NULL, strftime('%s','now')); INSERT INTO tmw_world_states VALUES('accountserver_version',NULL,NULL, strftime('%s','now')); -INSERT INTO tmw_world_states VALUES('database_version', NULL,'2', strftime('%s','now')); +INSERT INTO tmw_world_states VALUES('database_version', NULL,'3', strftime('%s','now')); CREATE TABLE tmw_auctions ( -- cgit v1.2.3-70-g09d2 From 1ac059d0b7ab18c3723336f6e2ac8012732a5570 Mon Sep 17 00:00:00 2001 From: Bjørn Lindeijer Date: Tue, 10 Mar 2009 15:19:50 +0100 Subject: Fixes for some compile warnings Mostly comparisons between signed and unsigned integers --- src/account-server/dalstorage.cpp | 2 +- src/chat-server/post.cpp | 6 ++++-- src/common/transaction.hpp | 2 +- src/utils/stringfilter.cpp | 8 +++++--- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/account-server/dalstorage.cpp b/src/account-server/dalstorage.cpp index eac9f409..086487f3 100644 --- a/src/account-server/dalstorage.cpp +++ b/src/account-server/dalstorage.cpp @@ -1688,7 +1688,7 @@ std::vector DALStorage::getTransactions(time_t date) << date; dal::RecordSet const &rec = mDb->execSql(sql.str()); - for (int i = 0; i < rec.rows(); ++i) + for (unsigned int i = 0; i < rec.rows(); ++i) { Transaction trans; trans.mCharacterId = toUint(rec(i, 1)); diff --git a/src/chat-server/post.cpp b/src/chat-server/post.cpp index e3f4c4f0..ba829c02 100644 --- a/src/chat-server/post.cpp +++ b/src/chat-server/post.cpp @@ -62,7 +62,8 @@ std::string Letter::getContents() bool Letter::addAttachment(InventoryItem item) { - if (mAttachments.size() > Configuration::getValue("mail_maxAttachments", 3)) + unsigned int max = Configuration::getValue("mail_maxAttachments", 3); + if (mAttachments.size() > max) { return false; } @@ -102,7 +103,8 @@ Post::~Post() bool Post::addLetter(Letter *letter) { - if (mLetters.size() > Configuration::getValue("mail_maxLetters", 10)) + unsigned int max = Configuration::getValue("mail_maxLetters", 10); + if (mLetters.size() > max) { return false; } diff --git a/src/common/transaction.hpp b/src/common/transaction.hpp index 21a00de8..3cdb4d58 100644 --- a/src/common/transaction.hpp +++ b/src/common/transaction.hpp @@ -61,7 +61,7 @@ enum TRANS_TRADE_MONEY, TRANS_TRADE_ITEM, TRANS_ATTR_INCREASE, - TRANS_ATTR_DECREASE, + TRANS_ATTR_DECREASE }; #endif diff --git a/src/utils/stringfilter.cpp b/src/utils/stringfilter.cpp index 93be8b3e..1e2eaa54 100644 --- a/src/utils/stringfilter.cpp +++ b/src/utils/stringfilter.cpp @@ -103,9 +103,11 @@ bool StringFilter::filterContent(const std::string& text) bool StringFilter::isEmailValid(const std::string& email) { - // Testing Email validity - if ((email.length() < Configuration::getValue("account_minEmailLength", 7)) || - (email.length() > Configuration::getValue("account_maxEmailLength", 128))) + unsigned int min = Configuration::getValue("account_minEmailLength", 7); + unsigned int max = Configuration::getValue("account_maxEmailLength", 128); + + // Testing email validity + if (email.length() < min || email.length() > max) { return false; } -- cgit v1.2.3-70-g09d2 From 53cde41db10d69120cdc46f278178fc5667744a1 Mon Sep 17 00:00:00 2001 From: Bjørn Lindeijer Date: Tue, 10 Mar 2009 15:23:17 +0100 Subject: Updated INSTALL file --- INSTALL | 143 ++++++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 99 insertions(+), 44 deletions(-) diff --git a/INSTALL b/INSTALL index 23e5f25d..8b82ade0 100644 --- a/INSTALL +++ b/INSTALL @@ -1,16 +1,19 @@ Installation Instructions ************************* -Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free -Software Foundation, Inc. +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, +2006, 2007, 2008 Free Software Foundation, Inc. -This file is free documentation; the Free Software Foundation gives + This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Basic Installation ================== -These are generic installation instructions. + Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses @@ -23,9 +26,9 @@ debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves -the results of its tests to speed up reconfiguring. (Caching is +the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale -cache files.) +cache files. If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail @@ -35,20 +38,17 @@ some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create -`configure' by a program called `autoconf'. You only need -`configure.ac' if you want to change it or regenerate `configure' using -a newer version of `autoconf'. +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type - `./configure' to configure the package for your system. If you're - using `csh' on an old version of System V, you might need to type - `sh ./configure' instead to prevent `csh' from trying to execute - `configure' itself. + `./configure' to configure the package for your system. - Running `configure' takes awhile. While running, it prints some - messages telling which features it is checking for. + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. 2. Type `make' to compile the package. @@ -67,42 +67,57 @@ The simplest way to compile this package is: all sorts of other programs in order to regenerate files that came with the distribution. + 6. Often, you can also type `make uninstall' to remove the installed + files again. + Compilers and Options ===================== -Some systems require unusual options for compilation or linking that the -`configure' script does not know about. Run `./configure --help' for -details on some of the pertinent environment variables. + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: - ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== -You can compile the package for more than one kind of computer at the + You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their -own directory. To do this, you must use a version of `make' that -supports the `VPATH' variable, such as GNU `make'. `cd' to the +own directory. To do this, you can use GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. - If you have to use a `make' that does not support the `VPATH' -variable, you have to compile the package for one architecture at a -time in the source code directory. After you have installed the -package for one architecture, use `make distclean' before reconfiguring -for another architecture. + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. Installation Names ================== -By default, `make install' installs the package's commands under + By default, `make install' installs the package's commands under `/usr/local/bin', include files under `/usr/local/include', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX'. @@ -125,7 +140,7 @@ option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= -Some packages pay attention to `--enable-FEATURE' options to + Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The @@ -137,14 +152,36 @@ find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + Specifying the System Type ========================== -There may be some features `configure' cannot figure out automatically, -but needs to determine by the type of machine the package will run on. -Usually, assuming the package is built to be run on the _same_ -architectures, `configure' can figure that out, but if it prints a -message saying it cannot guess the machine type, give it the + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: @@ -170,9 +207,9 @@ eventually be run) with `--host=TYPE'. Sharing Defaults ================ -If you want to set default values for `configure' scripts to share, you -can create a site shell script called `config.site' that gives default -values for variables like `CC', `cache_file', and `prefix'. + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. @@ -181,7 +218,7 @@ A warning: not all `configure' scripts look for a site script. Defining Variables ================== -Variables not defined in a site shell script can be set in the + Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set @@ -190,21 +227,29 @@ them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is -overridden in the site shell script). Here is a another example: +overridden in the site shell script). - /bin/bash ./configure CONFIG_SHELL=/bin/bash +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: -Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent -configuration-related scripts to be executed by `/bin/bash'. + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash `configure' Invocation ====================== -`configure' recognizes the following options to control how it operates. + `configure' recognizes the following options to control how it +operates. `--help' `-h' - Print a summary of the options to `configure', and exit. + Print a summary of all of the options to `configure', and exit. + +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. `--version' `-V' @@ -231,6 +276,16 @@ configuration-related scripts to be executed by `/bin/bash'. Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. +`--prefix=DIR' + Use DIR as the installation prefix. *Note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. -- cgit v1.2.3-70-g09d2 From 3dec609dc5f343547fad87dbbd3d7c7e2c59dde5 Mon Sep 17 00:00:00 2001 From: Philipp Sehmisch Date: Thu, 19 Mar 2009 20:10:27 +0100 Subject: Implemented the possibility to have maps with or without PvP combat. PvP is governed by the map property "pvp". Currently it can be either "none" for no PvP combat or "free" for unrestricted PvP combat. "none" is the default value which is used when pvp is undefined. Later addition of more sophisticated PvP modes is possible. --- src/game-server/being.cpp | 5 +++++ src/game-server/map.cpp | 8 ++++++++ src/game-server/map.hpp | 16 +++++++++++++++- src/game-server/mapcomposite.cpp | 6 ++++++ src/game-server/mapcomposite.hpp | 13 +++++++++++++ src/game-server/mapreader.cpp | 19 ++++++++++++++++--- 6 files changed, 63 insertions(+), 4 deletions(-) diff --git a/src/game-server/being.cpp b/src/game-server/being.cpp index cec2c4e6..ace30861 100644 --- a/src/game-server/being.cpp +++ b/src/game-server/being.cpp @@ -190,6 +190,11 @@ void Being::performAttack(Damage const &damage, AttackZone const *attackZone) int type = o->getType(); if (type != OBJECT_CHARACTER && type != OBJECT_MONSTER) continue; + if (getMap()->getPvP() == PVP_NONE && + type == OBJECT_CHARACTER && + getType() == OBJECT_CHARACTER) + continue; + LOG_DEBUG("Attack Zone:"<< attPos.x<<":"<::const_iterator i; + i = mProperties.find(key); + if (i == mProperties.end()) return ""; + return i->second; +} + void Map::blockTile(int x, int y, BlockType type) { if (type == BLOCKTYPE_NONE || x < 0 || y < 0 || x >= mWidth || y >= mHeight) diff --git a/src/game-server/map.hpp b/src/game-server/map.hpp index 3a9badf9..bbc33fea 100644 --- a/src/game-server/map.hpp +++ b/src/game-server/map.hpp @@ -154,6 +154,17 @@ class Map int getTileHeight() const { return tileHeight; } + /** + * Returns a general map property defined in the map file + */ + const std::string &getProperty(const std::string &key) const; + + /** + * Sets a map property + */ + void setProperty(const std::string& key, const std::string& val) + { mProperties[key] = val; } + /** * Find a path from one location to the next. */ @@ -170,11 +181,14 @@ class Map static const unsigned char BLOCKMASK_CHARACTER = 0x01;// = bin 0000 0001 static const unsigned char BLOCKMASK_MONSTER = 0x02; // = bin 0000 0010 int *mOccupation[NB_BLOCKTYPES]; + + // map properties int mWidth, mHeight; int tileWidth, tileHeight; - MetaTile *mMetaTiles; + std::map mProperties; // Pathfinding members + MetaTile *mMetaTiles; int onClosedList, onOpenList; }; diff --git a/src/game-server/mapcomposite.cpp b/src/game-server/mapcomposite.cpp index b9e4b863..e7267d08 100644 --- a/src/game-server/mapcomposite.cpp +++ b/src/game-server/mapcomposite.cpp @@ -532,6 +532,12 @@ void MapComposite::setMap(Map *m) assert(!mMap && m); mMap = m; mContent = new MapContent(m); + + std::string sPvP = m->getProperty ("pvp"); + if (sPvP == "free") mPvPRules = PVP_FREE; + else if (sPvP == "none") mPvPRules = PVP_NONE; + else mPvPRules = PVP_NONE; + } void MapComposite::update() diff --git a/src/game-server/mapcomposite.hpp b/src/game-server/mapcomposite.hpp index 078842d6..7242fad6 100644 --- a/src/game-server/mapcomposite.hpp +++ b/src/game-server/mapcomposite.hpp @@ -38,6 +38,12 @@ class Thing; struct MapContent; struct MapZone; +enum PvPRules +{ + PVP_NONE, // no PvP on this map + PVP_FREE // unrestricted PvP on this map + // [space for additional PvP modes] +}; /** * Ordered sets of zones of a map. */ @@ -289,6 +295,11 @@ class MapComposite */ void update(); + /** + * Gets the PvP rules on the map + */ + PvPRules getPvP() const { return mPvPRules; } + /** * Gets an iterator on the objects of the whole map. */ @@ -329,6 +340,8 @@ class MapComposite Script *mScript; /**< Script associated to this map. */ std::string mName; /**< Name of the map. */ unsigned short mID; /**< ID of the map. */ + + PvPRules mPvPRules; }; #endif diff --git a/src/game-server/mapreader.cpp b/src/game-server/mapreader.cpp index 9caddc24..758b37ee 100644 --- a/src/game-server/mapreader.cpp +++ b/src/game-server/mapreader.cpp @@ -114,7 +114,7 @@ void MapReader::readMap(const std::string &filename, MapComposite *composite) } } -Map* MapReader::readMap(xmlNodePtr node, std::string const &path, +Map* MapReader::readMap(xmlNodePtr node, std::string const &path, MapComposite *composite, std::vector &things) { // Take the filename off the path @@ -140,6 +140,19 @@ Map* MapReader::readMap(xmlNodePtr node, std::string const &path, ::tilesetFirstGids.push_back(XML::getProperty(node, "firstgid", 0)); } } + else if (xmlStrEqual(node->name, BAD_CAST "properties")) + { + for_each_xml_child_node(propNode, node) + { + if (xmlStrEqual(propNode->name, BAD_CAST "property")) + { + std::string key = XML::getProperty(propNode, "name", ""); + std::string val = XML::getProperty(propNode, "value", ""); + LOG_DEBUG(" "<setProperty(key, val); + } + } + } else if (xmlStrEqual(node->name, BAD_CAST "layer")) { // Layer 3 is collision layer. @@ -166,7 +179,7 @@ Map* MapReader::readMap(xmlNodePtr node, std::string const &path, int objW = XML::getProperty(objectNode, "width", 0); int objH = XML::getProperty(objectNode, "height", 0); Rectangle rect = { objX, objY, objW, objH }; - + if (objType == "WARP") { @@ -236,7 +249,7 @@ Map* MapReader::readMap(xmlNodePtr node, std::string const &path, { if (xmlStrEqual(propertyNode->name, BAD_CAST "property")) { - std::string value = XML::getProperty(propertyNode, "name", std::string()); + std::string value = XML::getProperty(propertyNode, "name", std::string()); value = utils::toupper(value); if (value == "MONSTER_ID") { -- cgit v1.2.3-70-g09d2 From caa35916909ca81defbc03f8825eb582f68c0238 Mon Sep 17 00:00:00 2001 From: Philipp Sehmisch Date: Tue, 24 Mar 2009 00:39:29 +0100 Subject: Added config option to set default PvP mode --- src/game-server/mapcomposite.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/game-server/mapcomposite.cpp b/src/game-server/mapcomposite.cpp index e7267d08..6145ecc1 100644 --- a/src/game-server/mapcomposite.cpp +++ b/src/game-server/mapcomposite.cpp @@ -23,6 +23,7 @@ #include #include "point.h" +#include "common/configuration.hpp" #include "game-server/map.hpp" #include "game-server/mapcomposite.hpp" #include "game-server/character.hpp" @@ -534,6 +535,8 @@ void MapComposite::setMap(Map *m) mContent = new MapContent(m); std::string sPvP = m->getProperty ("pvp"); + if (sPvP == "") sPvP = Configuration::getValue("defaultPvp", ""); + if (sPvP == "free") mPvPRules = PVP_FREE; else if (sPvP == "none") mPvPRules = PVP_NONE; else mPvPRules = PVP_NONE; -- cgit v1.2.3-70-g09d2 From 3a54fb903f9cc2cc47a852dab6569848d19c6dad Mon Sep 17 00:00:00 2001 From: Bjørn Lindeijer Date: Fri, 27 Mar 2009 17:48:55 +0100 Subject: Fixed compile warning --- src/game-server/map.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/game-server/map.cpp b/src/game-server/map.cpp index f66f8876..3821b0a8 100644 --- a/src/game-server/map.cpp +++ b/src/game-server/map.cpp @@ -65,8 +65,7 @@ Map::~Map() } } -void -Map::setSize(int width, int height) +void Map::setSize(int width, int height) { this->mWidth = width; this->mHeight = height; @@ -83,9 +82,11 @@ Map::setSize(int width, int height) const std::string &Map::getProperty(const std::string &key) const { + static std::string empty; std::map::const_iterator i; i = mProperties.find(key); - if (i == mProperties.end()) return ""; + if (i == mProperties.end()) + return empty; return i->second; } @@ -159,8 +160,7 @@ bool Map::getWalk(int x, int y, char walkmask) const return !(mMetaTiles[x + y * mWidth].blockmask & walkmask); } -MetaTile* -Map::getMetaTile(int x, int y) +MetaTile *Map::getMetaTile(int x, int y) { return &mMetaTiles[x + y * mWidth]; } -- cgit v1.2.3-70-g09d2