Commit Graph
100 Commits
Author SHA1 Message Date
Jiri Denemark 984c01ba5c qemu: Emit VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED events 2013-07-18 15:28:45 +02:00
Jiri Denemark 3fbf78bdf3 qemu: Remove devices only after DEVICE_DELETED event 2013-07-18 15:28:45 +02:00
Jiri Denemark ab47cc9bf9 qemu: Add support for DEVICE_DELETED event 2013-07-18 15:28:45 +02:00
Jiri Denemark ae951e724c Add virDomainDefFindDevice for looking up a device by its alias 2013-07-18 15:28:45 +02:00
Jiri Denemark 1f71de59f6 Clarify virDomainDetachDeviceFlags documentation 2013-07-18 15:28:45 +02:00
Jiri Denemark ee023f6c1f examples: Handle VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED event 2013-07-18 15:28:45 +02:00
Jiri Denemark 4421e257dd Add VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED event 2013-07-18 15:28:45 +02:00
Jiri Denemark d077cda4e9 qemu: Separate char device removal into a standalone function 2013-07-18 15:18:04 +02:00
Jiri Denemark d9301a9ae3 maint: Make ctags work out of the box
The .ctags file specifies default options for ctags so that it does not
ignore libvirt.h.in and ignores uninteresting files. As a result, you
can just run "ctags" and navigating to a public API won't get you to a
useless entry in api.html.
2013-07-18 08:47:21 +02:00
Jiri Denemark 53f3739afe qemu: Separate host device removal into a standalone function 2013-07-16 20:29:04 +02:00
Jiri Denemark ac68a785cc qemu: Separate net device removal into a standalone function 2013-07-16 20:29:04 +02:00
Jiri Denemark 92758a71d8 qemu: Separate controller removal into a standalone function 2013-07-16 20:29:04 +02:00
Jiri Denemark a22ae222ee qemu: Separate disk device removal into a standalone function 2013-07-16 20:29:04 +02:00
Jiri Denemark 89b7bb75d7 qemu: Add qemuDomainReleaseDeviceAddress to remove any address 2013-07-16 20:29:04 +02:00
Jiri Denemark f24e90d542 qemu: Slightly increase memory limit
For low-memory domains (roughly under 400MB) our automatic memory limit
computation comes up with a limit that's too low. This is because the
0.5 multiplication does not add enough for such small values. Let's
increase the constant part of the computation to fix this.
2013-07-11 11:17:47 +02:00
Jiri Denemark 59cc0fe5aa qemu: Set RLIMIT_MEMLOCK when memoryBacking/locked is used
If a domain is configured to have all its memory locked, we need to set
RLIMIT_MEMLOCK so that QEMU is actually allowed to lock the memory.
2013-07-08 12:35:28 +02:00
Jiri Denemark 6d8ebc7538 qemu: Use qemuDomainMemoryLimit when computing memory for VFIO 2013-07-08 12:35:27 +02:00
Jiri Denemark e0e438af00 qemu: Move memory limit computation to a reusable function 2013-07-08 12:35:27 +02:00
Jiri Denemark 86dba8f3de Don't spam logs with "port 0 must be in range" errors
Whenever virPortAllocatorRelease is called with port == 0, it complains
that the port is not in an allowed range, which is expectable as the
port was never allocated. Let's make virPortAllocatorRelease ignore 0
ports in a similar way free() ignores NULL pointers.
2013-07-08 12:27:58 +02:00
Jiri Denemark 0d7dc70824 qemu: Release correct websocket port 2013-07-08 12:27:58 +02:00
Jiri Denemark d4ce75ba76 Paused domain should remain paused after migration
https://bugzilla.redhat.com/show_bug.cgi?id=981139

If a domain is paused before migration starts, we need to tell that to
the destination libvirtd to prevent it from resuming the domain at the
end of migration. This regression was introduced by commit 5379bb0.
2013-07-08 12:27:58 +02:00
Jiri Denemark db0a18a165 Fix NULL dereference caused by ACL filtering of domains
Caused by 763973607d.
2013-07-04 16:55:53 +02:00
Jiri Denemark d2664daf1b qemu: Implement support for VIR_MIGRATE_PARAM_GRAPHICS_URI 2013-06-25 16:41:58 +02:00
Jiri Denemark 35461438cb Implement extensible migration APIs in qemu driver 2013-06-25 16:41:58 +02:00
Jiri Denemark 1004d6323a qemu: Move internals of Confirm phase to qemu_migration.c 2013-06-25 16:41:57 +02:00
Jiri Denemark ecd811310c qemu: Move common parts of Prepare phase to qemu_migration.c 2013-06-25 16:41:57 +02:00
Jiri Denemark d3ce7363f3 qemu: Move internals of Begin phase to qemu_migration.c 2013-06-25 16:41:57 +02:00
Jiri Denemark 83b43717a6 Fix possible NULL dereference during migration 2013-06-25 16:10:09 +02:00
Jiri Denemark 4669543cb8 Introduce VIR_MIGRATE_PARAM_GRAPHICS_URI parameter
The parameter specifies connection parameters to use for migrating
client's connection to domain's graphical console.
2013-06-25 01:33:47 +02:00
Jiri Denemark bdb6578a42 virsh: Use extensible migration APIs 2013-06-25 01:31:07 +02:00
Jiri Denemark 6f4c6af6ed python: Add bindings for extensible migration APIs
The patch implements wrappers for virDomainMigrate3 and
virDomainMigrateToURI3.
2013-06-25 01:28:39 +02:00
Jiri Denemark 4bf62f44a9 Extensible migration APIs
This patch introduces two new APIs virDomainMigrate3 and
virDomainMigrateToURI3 that may be used in place of their older
variants. These new APIs take optional migration parameters (such as
bandwidth, domain XML, ...) in an array of virTypedParameters, which
makes adding new parameters easier as there's no need to introduce new
APIs whenever a new migration parameter needs to be added. Both APIs are
backward compatible and will automatically use older migration calls in
case the new calls are not supported as long as the typed parameters
array does not contain any parameter which was not supported by the
older calls.
2013-06-25 01:24:53 +02:00
Jiri Denemark 35820ad543 Adapt virDomainMigratePeer2Peer for extensible migration APIs 2013-06-25 01:21:16 +02:00
Jiri Denemark fa8b7c6aed Adapt virDomainMigrateVersion3 for extensible migration APIs 2013-06-25 01:18:13 +02:00
Jiri Denemark cca4d10d82 Implement extensible migration APIs in remote driver 2013-06-25 01:16:15 +02:00
Jiri Denemark c0762b6518 New internal migration APIs with extensible parameters
This patch implements extensible variants of all internal migration APIs
used for v3 migration.
2013-06-25 01:13:16 +02:00
Jiri Denemark 81709832ab Introduce migration parameters
To be used by new migration APIs with extensible set of parameters.
2013-06-25 00:38:25 +02:00
Jiri Denemark d0d5acb511 Introduce virTypedParamsCopy internal API 2013-06-25 00:38:25 +02:00
Jiri Denemark 173a14ec0b Log input type parameters in API entry points 2013-06-25 00:38:25 +02:00
Jiri Denemark fefb0d5464 Introduce VIR_TYPED_PARAMS_DEBUG macro for dumping typed params
All APIs that take typed parameters are only using params address in
their entry point debug messages. With the new VIR_TYPED_PARAMS_DEBUG
macro, all functions can easily log all individual typed parameters
passed to them.
2013-06-25 00:38:24 +02:00
Jiri Denemark 8a7f1166e1 Introduce virTypedParamsReplaceString internal API 2013-06-25 00:38:24 +02:00
Jiri Denemark 637a7c865a Introduce virTypedParamsCheck internal API
This API is useful for checking whether only a specific subset of
supported typed parameters were passed.
2013-06-25 00:38:24 +02:00
Jiri Denemark 40369ea674 util: Emit proper error code in virTypedParamsValidate
When unsupported parameter is passed to virTypedParamsValidate,
VIR_ERR_ARGUMENT_UNSUPPORTED should be returned rather than
VIR_ERR_INVALID_ARG, which is more appropriate for supported parameters
used incorrectly.
2013-06-25 00:38:24 +02:00
Jiri Denemark c40ed4168a Rename virTypedParameterArrayValidate as virTypedParamsValidate 2013-06-25 00:38:24 +02:00
Jiri Denemark 2ebd847924 build: Fix check-aclrules in VPATH build 2013-06-25 00:38:23 +02:00
Jiri Denemark adb7b0b562 qemu: Make probing for commands declarative 2013-06-21 09:32:42 +02:00
Jiri Denemark 61a2841493 qemu: Make probing for events declarative 2013-06-21 09:32:42 +02:00
Jiri Denemark ddf8ad82eb qemu: Avoid leaking uri in qemuMigrationPrepareDirect 2013-06-18 14:49:20 +02:00
Jiri Denemark 9313a6a7fc qemu: Fix memory leak in Prepare phase
Avoid leaking virDomainDef if Prepare phase fails before it gets to
qemuMigrationPrepareAny.
2013-06-11 13:27:52 +02:00
Jiri Denemark 634096536c virsh: Obey pool-or-uuid spec when creating volumes
Our documentation says a pool may be referenced by its name or UUID
anywhere if it makes sense (pool-name and pool-uuid are the only
exceptions). However, vol-create and vol-create-as commands did not obey
this.
2013-06-04 10:16:02 +02:00
Jiri Denemark 3b50a711f0 spec: Explicitly require libgcrypt-devel
Our configure.ac says:

    Not all versions of gnutls include -lgcrypt, and so we add
    it explicitly for the calls to gcry_control/check_version

Thus we cannot rely on gnutls-devel to bring grcypt-devel as a
dependency.
2013-06-03 15:15:44 +02:00
Jiri Denemark a923865a0e virsh iface-bridge: Ignore delay if stp is turned off
Delay only makes sense with STP enabled.
2013-06-03 15:15:44 +02:00
Jiri Denemark 4db39e3fee Fix warning about using an uninitialized next_unit value
Using an uninitialized value and a bool saying if the value is valid may
confuse compilators.
2013-06-03 15:15:44 +02:00
Jiri Denemark fae2505eee Document that runtime changes may be lost after S4 suspend 2013-05-31 18:03:20 +02:00
Jiri Denemark c6f2523fb1 qemu: Fix build without gnutls
"error" label in qemuMigrationCookieGraphicsAlloc is now used
unconditionally thanks to VIR_STRDUP.
2013-05-27 10:19:36 +02:00
Jiri Denemark fd74f74fe6 qemu: Implement support for locking domain's memory pages 2013-05-16 23:21:58 +02:00
Jiri Denemark 555866389c Add support for locking domain's memory pages
The following XML configuration can be used to request all domain's
memory pages to be kept locked in host's memory (i.e., domain's memory
pages will not be swapped out):

      <memoryBacking>
        <locked/>
      </memoryBacking>
2013-05-16 23:03:08 +02:00
Jiri Denemark 4734f1f53b Fix build with VirtualBox
Commit ba5f3c7c moved vbox driver into libvirtd but forgot to adapt
daemon's Makefile.am.
2013-05-16 23:01:43 +02:00
Jiri Denemark e13e548fc2 build: Fix check-driverimpls in VPATH
DRIVER_SOURCE_FILES mixes files with absolute path (inherited from
REMOTE_DRIVER_GENERATED) with file paths that are relative to srcdir but
check-driverimpls.pl needs full paths.
2013-05-16 15:45:43 +02:00
Jiri Denemark c431f06587 util: Fix build without devmapper
stdlib.h header file needed for getenv was only transitively included
through libdevmapper.h.
2013-05-16 12:15:38 +02:00
Jiri Denemark 6d4804858e qemu: Use -machine accel=tcg|kvm when available
This is a better interface to choose accelerator than guessing whether
we should enable or disable kvm to get the right one.
2013-04-23 21:19:35 +02:00
Jiri Denemark cfe24c1a18 qemu: Move -enable-kvm and friends earlier in the command line 2013-04-23 21:19:35 +02:00
Jiri Denemark fd2e55302b logging: Make log regexp more compact (and readable) 2013-04-22 20:13:40 +02:00
Jiri Denemark 6d1b3edc6e qemu: Ignore libvirt logs when reading QEMU error output
When QEMU fails to start, libvirt read its error output and reports it
back in an error message. However, when libvirtd is configured to log
debug messages, one would get the following unhelpful garbage:

    virsh # start cd
    error: Failed to start domain cd
    error: internal error process exited while connecting to monitor: \
      2013-04-22 14:24:54.214+0000: 2194219: debug : virFileClose:72 : \
      Closed fd 21
    2013-04-22 14:24:54.214+0000: 2194219: debug : virFileClose:72 : \
      Closed fd 27
    2013-04-22 14:24:54.215+0000: 2194219: debug : virFileClose:72 : \
      Closed fd 3
    2013-04-22 14:24:54.215+0000: 2194220: debug : virExec:602 : Run \
      hook 0x7feb8f600bf0 0x7feb86ef9300
    2013-04-22 14:24:54.215+0000: 2194220: debug : qemuProcessHook:2507 \
      : Obtaining domain lock
    2013-04-22 14:24:54.216+0000: 2194220: debug : \
      virDomainLockProcessStart:170 : plugin=0x7feb780261f0 \
      dom=0x7feb7802a360 paused=1 fd=0x7feb86ef8ec4
    2013-04-22 14:24:54.216+0000: 2194220: debug : \
      virDomainLockManagerNew:128 : plugin=0x7feb780261f0 \
      dom=0x7feb7802a360 withResources=1
    2013-04-22 14:24:54.216+0000: 2194220: debug : \
      virLockManagerPluginGetDriver:297 : plugin=0x7feb780261f0
    2013-04-22 14:24:54.216+0000: 2194220: debug : \
      virLockManagerNew:321 : driver=0x7feb8ef08640 type=0 nparams=5 \
      params=0x7feb86ef8d60 flags=0
    2013-04-22 14:24:54.216+000

instead of (the output with this patch applied):

    virsh # start cd
    error: Reconnected to the hypervisor
    error: Failed to start domain cd
    error: internal error process exited while connecting to monitor: \
      char device redirected to /dev/pts/33 (label charserial0)
    qemu-system-x86_64: -drive file=/home/vm/systemrescuecd-x86-1.2.0.\
      iso,if=none,id=drive-ide0-1-0,readonly=on,format=raw,cache=none: \
      could not open disk image /home/vm/systemrescuecd-x86-1.2.0.iso: \
      Permission denied
2013-04-22 20:13:40 +02:00
Jiri Denemark e4bdba8d7f qemu: Move QEMU log reading into a separate function 2013-04-22 20:13:40 +02:00
Jiri Denemark f1a1ebf19d cpu: Rename PowerPCUpdate and PowerPCDataFree functions
For consistency with other functions in PowerPC CPU driver, the two
functions are renamed as ppcUpdate and ppcDataFree, respectively.
2013-04-19 14:33:16 +02:00
Jiri Denemark 7a4f12381c cpu: Remove hardcoded list of PowerPC models
The cpu_map.xml file is there to separate CPU model definitions from the
code. Having the only interesting data for PowerPC models only in the
source code. This patch moves this data to the XML file and removes the
hardcoded list completely.
2013-04-19 14:33:16 +02:00
Jiri Denemark f42ecaf12b cpu: Reimplement PowerPCDecode
PowerPC CPUs are either identical or incompatible and thus we just need
to look up the right model for given PVR without pretending we have
several candidates which we may choose from.

The function is also renamed as ppcDecode to match other functions in
PowerPC CPU driver.
2013-04-19 14:33:16 +02:00
Jiri Denemark fdf6efde27 cpu: Reimplement PowerPCBaseline
Baseline API is supposed to return guest CPU definition that can be used
on any of the provided host CPUs. Since PowerPC CPUs are either
identical or incompatible, the API just needs to check that all provided
CPUs are identical. Previous implementation was completely bogus.

The function is also renamed as ppcBaseline to match other functions in
PowerPC CPU driver.
2013-04-19 14:33:16 +02:00
Jiri Denemark ba8ba24711 cpu: Fix loading PowerPC vendor from cpu_map.xml
When ppcVendorLoad fails to parse the vendor element for whatever
reason, it is supposed to ignore it and return 0 rather than -1. The
patch also removes PowerPC vendor string from the XML as it is not
actually used for anything.
2013-04-19 14:33:16 +02:00
Jiri Denemark 70349cb90d cpu: Fix PowerPCNodeData
Make getting node CPU data for PowerPC unsupported on other
architectures. The function is also renamed as ppcNodeData to match
other functions in PowerPC CPU driver.
2013-04-19 14:33:16 +02:00
Jiri Denemark 6af5a06275 cpu: Make comparing PowerPC CPUs easier to read
Revert the condition to make it easier to read. The function is also
renamed as ppcCompare to match other functions in PowerPC CPU driver.
2013-04-19 14:33:15 +02:00
Jiri Denemark 16c6b60cbd cpu: Introduce cpuModelIsAllowed internal API
The API can be used to check if the model is on the supported models
list, which needs to be done in several places.
2013-04-19 14:33:15 +02:00
Jiri Denemark 88624b5d4c qemu: Do not report unsafe migration for local files
When migrating a domain with disk images stored locally (and using
storage migration), we should not complain about unsafe migration no
matter what cache policy is used for that disk.
2013-04-11 21:57:50 +02:00
Jiri Denemark 6f1b9c8d2a spec: Require pod2man when running autoreconf
Since commit b8a32e0e94, all man pages
depend on configure.ac so that they are properly regenerated whenever
libvirt version changes. Thus libvirt.spec needs to have a build
dependency on pod2man when %{enable_autotools} is set.
2013-04-08 16:11:16 +02:00
Jiri Denemark d8d4aa01d8 rpc: Fix client crash when server drops connection
Despite the comment stating virNetClientIncomingEvent handler should
never be called with either client->haveTheBuck or client->wantClose
set, there is a sequence of events that may lead to both booleans being
true when virNetClientIncomingEvent is called. However, when that
happens, we must not immediately close the socket as there are other
threads waiting for the buck and they would cause SIGSEGV once they are
woken up after the socket was closed. Another thing is we should clear
all remaining calls in the queue after closing the socket.

The situation that can lead to the crash involves three threads, one of
them running event loop and the other two calling libvirt APIs. The
event loop thread detects an event on client->sock and calls
virNetClientIncomingEvent handler. But before the handler gets a chance
to lock client, the other two threads (T1 and T2) start calling some
APIs. T1 gets the buck and detects EOF on client->sock while processing
its RPC call. Since T2 is waiting for its own call, T1 passes the buck
on to it and unlocks client. But before T2 gets the signal, the event
loop thread wakes up, does its job and closes client->sock. The crash
happens when T2 actually wakes up and tries to do its job using a closed
client->sock.
2013-03-27 09:00:38 +01:00
Jiri Denemark a1fe02f0e9 log: Separate thread ID from timestemp in ring buffer
When we write a log message into a log, we separate thread ID from
timestamp using ": ". However, when storing the message into the ring
buffer, we omitted the separator, e.g.:

    2013-02-27 11:49:11.852+00003745: ...
2013-03-27 09:00:35 +01:00
Jiri Denemark ef3cd6473f qemu: Fix startupPolicy regression
Commit 82d5fe5437

    qemu: check backing chains even when cgroup is omitted

added backing file checks just before the code that removes optional
disks if they are not present. However, the backing chain code fails in
case the disk file does not exist, which makes qemuProcessStart fail
regardless on configured startupPolicy.

Note that startupPolicy implementation is still wrong after this patch
since it only check the first file in a possible chain. It should rather
check the complete backing chain. But this is an existing limitation
that can be solved later. After all, startupPolicy is most useful for
CDROM images and they won't make use of backing files in most cases.
2013-03-18 14:11:58 +01:00
Jiri Denemark 57bb725aca qemu: Avoid NULL dereference in qemuSharedDiskEntryFree
At least one caller may call qemuSharedDiskEntryFree with NULL as the
first argument. Let's make the function similar to other *Free functions
and do nothing in such case.
2013-03-12 09:10:41 +01:00
Jiri Denemark 11677e081b docs: Clarify semantics of sparse storage volumes
Sparse LVM volumes do not behave in the way one would naively expect.
The allocation does not automatically increase (which is different from
how sparse files work).
2013-03-12 09:03:14 +01:00
Jiri Denemark 4b0cb4a745 storage: Cleanup logical volume creation code
This patch plugs two memory leaks, removes some useless and confusing
constructs and renames renames "cleanup" label as "error" since it is
only used for error path rather then being common for both success and
error paths.
2013-03-06 14:53:00 +01:00
Jiri Denemark e4e28220b5 qemu: Make sure qemuProcessStart is run within a job
qemuProcessStart expects to be run with a job already set and every
caller except for qemuMigrationPrepareAny use it correctly. This bug can
be observed in libvirtd logs during incoming migration as

    warning : qemuDomainObjEnterMonitorInternal:979 : This thread seems
    to be the async job owner; entering monitor without asking for a
    nested job is dangerous
2013-03-01 08:32:08 +01:00
Jiri Denemark 492afb8202 qemu: Implement virDomainMigrate*CompressionCache 2013-02-22 17:36:00 +01:00
Jiri Denemark e94aeb1428 virsh: Add migrate-compcache command
This is a command wrapping virDomainMigrateGetCompressionCache and
virDomainMigrateSetCompressionCache.
2013-02-22 17:35:59 +01:00
Jiri Denemark be80186732 remote: Implement virDomainMigrate*CompressionCache 2013-02-22 17:35:59 +01:00
Jiri Denemark 4802d59e6a python: Implement virDomainMigrateGetCompressionCache wrapper 2013-02-22 17:35:59 +01:00
Jiri Denemark 34f44e911f Introduce virDomainMigrate*CompressionCache APIs
Introduce virDomainMigrateGetCompressionCache and
virDomainMigrateSetCompressionCache APIs.
2013-02-22 17:35:59 +01:00
Jiri Denemark 8def32916d qemu: Implement virDomainGetJobStats 2013-02-22 17:35:59 +01:00
Jiri Denemark 4121a77c1a qemu: Parse more fields from query-migrate QMP command
As a side effect, this also fixes reporting disk migration process.
It was added to memory migration progress, which was wrong. Disk
progress has dedicated fields in virDomainJobInfo structure.
2013-02-22 17:35:59 +01:00
Jiri Denemark 38ab12251e virsh: Use virDomainGetJobStats in domjobinfo if available 2013-02-22 17:35:58 +01:00
Jiri Denemark 34fd94278a remote: Implement virDomainGetJobStats 2013-02-22 17:35:58 +01:00
Jiri Denemark 98b9acf5aa remote: Auto-allocate params in remoteDeserializeTypedParameters
remoteDeserializeTypedParameters can now be called with either
preallocated params array (size of which is announced by nparams) or it
can allocate params array according to the number of parameters received
from the server.
2013-02-22 17:35:58 +01:00
Jiri Denemark 8eb7ab95c2 python: Implement virDomainGetJobStats wrapper 2013-02-22 17:35:58 +01:00
Jiri Denemark 4dd00f4238 Introduce virDomainGetJobStats API
This is an extensible version of virDomainGetJobInfo.
2013-02-22 17:35:58 +01:00
Jiri Denemark 94f59b9ece qemu: Add support for compressed migration 2013-02-22 17:35:58 +01:00
Jiri Denemark ecfff1dab3 Introduce VIR_MIGRATE_COMPRESSED flag
This flag may be used with migration APIs to request compression of
migration data.
2013-02-22 17:35:58 +01:00
Jiri Denemark d3d5920181 docs: Fix HTML errors
<pre> is forbidden inside <p>
2013-02-21 10:38:28 +01:00
Jiri Denemark 568a6cda27 qemu: Avoid deadlock in autodestroy
Since closeCallbacks were turned into virObjectLockable, we can no
longer call virQEMUCloseCallbacks APIs from within a registered close
callback.
2013-02-21 10:38:28 +01:00
Jiri Denemark 3898ba7f2c qemu: Turn closeCallbacks into virObjectLockable
To avoid having to hold the qemu driver lock while iterating through
close callbacks and calling them. This fixes a real deadlock when a
domain which is being migrated from another host gets autodestoyed as a
result of broken connection to the other host.
2013-02-21 10:27:24 +01:00
Jiri Denemark 69660042fb qemu: Do not ignore mandatory features in migration cookie
Due to "feature"/"features" nasty typo, any features marked as mandatory
by one side of a migration are silently considered optional by the other
side. The following is the code that formats mandatory features in
migration cookie:

    for (i = 0 ; i < QEMU_MIGRATION_COOKIE_FLAG_LAST ; i++) {
        if (mig->flagsMandatory & (1 << i))
            virBufferAsprintf(buf, "  <feature name='%s'/>\n",
                              qemuMigrationCookieFlagTypeToString(i));
    }
2013-02-20 15:24:01 +01:00