| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
| |
stringValue() already checks isString(). We don't have to do it twice.
Coverity-Id: 486710
Change-Id: I074228f9a120c3bbfe6d4a65f05fe11322fbd07b
Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
|
| |
|
|
|
|
|
|
| |
Coverity-Id: 486699
Coverity-Id: 486697
Coverity-Id: 486715
Change-Id: Icdd15ff578f8be55fe9db3ffc38e893f667edc40
Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
|
| |
|
|
|
|
|
|
|
| |
The propertyList is an array allocated on the JavaScript stack. None of
it can be null.
Coverity-Id: 486709
Change-Id: I3178181aa89bfff86fb5aa469660a912b4f1691c
Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
When using namespaced Qt, we need to prevent symbol clashes with symbols
of the same name.
* namespace some publicly visible classes
* hide classes in implementation in an anonymous namespace
* rename read/write to readValue/writeValue to avoid name clash with c
functions.
Task-number: QTBUG-138543
Pick-to: 6.10
Change-Id: Ica77462c1f81f1e01cc60477e5b56ecfe3c1abb4
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
`Scope` provides a mean of performing uninitialized scoped allocations
on the JS stack.
This can generally be unsafe as this form of allocation temporarily
leaves an element representing garbage memory on the JS stack, which
could be accessed by other parts of the program.
Indeed, a set of bugs related to this kind of behavior was recently
solved.
Hence, to reduce the surface of those kind of bugs, the usages of
uninitialized scoped allocations were reduced to a minimum.
The solution to the recent set of bugs related to uninitialized scoped
allocations introduced a series of `construct` methods that ensure that
the uninitialized allocation and the initialization of the allocated
elements are performed as a single step of computation, reducing the
surface for incorrect usages of those kind of allocations.
The solution was expanded by the introduction of new `construct` methods
that cover initialization from other types and some different means of
initialization that were used around the code-base to work with
uninitialized scoped allocations.
Similarly, the various allocation methods in `Scope` were subsumed by
the new `construct` methods, with the only remaining means of allocation
being the uninitialized one that is used as a building block for the
`construct` methods.
In particular, `Scope` provided three forms of allocation under the
various `alloc` methods.
The aforementioned uninitialized allocation and an allocation that
performed initialization to either the Undefined or the Empty value.
The latter two forms of allocation were converted to forms of
`construct`.
Since they directly map to the same concept of allocation plus
initialization, the conversion avoids having two names for the same
concept.
More specifically, the form of allocation that initialized to the
Undefined value was converted to the new `constructUndefined` which
keeps the same behavior.
The different naming from the basic `construct` methods is justified by
the different interface, which doesn't require choosing a initial value,
and the different implementation which is built on the more general
`construct` methods rather than the lower level allocation routines.
The form of allocation that initialized to the Empty value was removed
as it was found to be unused in the code-base.
The converted allocation methods generally provides the same interface
and behavior with the exception of always requiring the user to specify
the amount of allocate objects.
This is a change compared to the previous interface which allowed a
zero-argument version that allocated a single element.
The writer of the patch considered the additional terseness
inconsequential compared to the required additional code so that the
possibility was not preserved.
The code related to the converted allocation forms was removed as a
consequence of the conversion.
The remaining uninitialized allocation form was made private, to avoid
general usage outside of `Scope`, and favoring usages of the substitute
`construct` methods.
A comment that was related to usages of uninitialized scoped allocations
was moved to the lower level `jsAlloca`, which forms the basis for those
allocations and creates the abovementioned issues, where it was expanded
upon.
Usages of the non-uninitialized allocation forms around the code-base
were modified to use the new `constructUndefined` method.
Most usages of the uninitialized allocation form were modified to use
the new `construct` methods that were added to replace them.
Exceptions were made for those cases where the initialization routine is
either very complex or depends on details that shouldn't belong to
`Scope` such that they cannot be trivially encapsulated in a `construct`
method.
Instead, the relevant function or object was friended by `Scope` to
allow accesses to the now private form of allocation.
Those usages were previously checked and are supposed to be safe but
should be scrutinized if they are modified or the code around them is
modified.
One of the friended functions, `callDatafromJs`, previously offered a
default argument that was not made use of in the code-base.
The default value for the argument was removed to simplify friending the
function, considering the difficulty the language has with friended
function with default arguments and considering that it would have
required the default value to be moved out of the function definition
into a forward declaration in the unrelated header that defines `Scope`.
It is expected that the changes will reduce the surface of usage of
uninitialized scoped allocations in favor of a slightly safer approach,
make the issue that those usages can produce more apparent and generally
centralize the usages as much as possible to make them easier to
evaluate and keep track of.
Change-Id: I351329f2c139201e0728791df6da297698170f55
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
| |
We're doing fully custom parsing here, and external JSON must not cause
security issues.
Pick-to: 6.10 6.9 6.8
QUIP: 23
Task-number: QTBUG-136970
Change-Id: I43f8280a31ebc170382485e6f5f3e7c06aa7db1a
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
| |
We usually have to do some handling in this case, but here we return
anyway.
Coverity-Id: 468063
Change-Id: Ie2ced36322a28d0c68c6c8618eb4f7890ae0f7ab
Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
Reviewed-by: Luca Di Sera <luca.disera@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Commit b9bfdea0e2c6721d2306af0ecc44f88da9988957 removed specialized
code for QVariantList conversions by relying on sequences instead.
Some checks for sequences and other array-like containers were missed.
Add those and perform all calls to QJsonObject::toJsonArray through a
common QV4::Object interface.
Amends b9bfdea0e2c6721d2306af0ecc44f88da9988957
Pick-to: 6.7
Fixes: QTBUG-123993
Change-Id: Ia671d556af4f2b4d44f652fa93182977d88621f2
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
|
| |
|
|
|
|
|
|
|
| |
Unlike gcc, clang warns about implicit fallthrough even if the following
label only contains a `break` statement
Pick-to: 6.7
Change-Id: If7fb15b5e2e1a8fb80668087e4497efb8d3d30d4
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Long story short, JSON.stringify takes optional second argument which
can be a replacer function. It is supposed to be called for each
encountered key-value during serialization. While replacer's second
argument is already serialized (so you could just return it), just in
case you are not satisfied with default serialization — the original
value is still passed in together with the whole object as a value of
JavaScript `this`.
Sadly, there is no test in the whole ECMA test suite to catch this bug.
This is quite a breaking change for code which already uses Qt-specific
workarounds, so it would be better not to cherry-pick it as a hot-fix
onto existing (released) branches.
Sample use case: serialize dates as a number of seconds since epoch.
function replacer(k, v) {
if (this[k] instanceof Date) {
return Math.floor(this[k].getTime() / 1000.0);
}
return v;
}
const str = JSON.stringify(obj, replacer);
[ChangeLog][QML][Important Behavior Changes] Set correct `this` value in
JSON.stringify replacer scope, so that the value for current key in
current object is no longer pre-stringified, and can actually be used to
implement custom object serialization logic.
Fixes: QTBUG-95324
Pick-to: 6.5
Change-Id: I618a533e8eba7999d5416aca14f4971093a83f7a
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
|
| |
|
|
|
|
|
|
| |
Pick-to: 5.15 6.2 6.4
Fixes: QTBUG-106875
Change-Id: I3b0abda6948b79a9e3cf263f27885037fff1804c
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Calling alloc with a qint64 parameter is a good indicator that we got
that value from Object::getLength. In that case, the value needs to be
sanitized with safeForAllocLength.
As a consequence, we notice that method_stringify did indeed use alloc
in an usasafe way; this is now fixed.
In a few other places, variables had to be changed from unsigned to
signed int (as the conversion is now ambiguous).
An even stricter check would be to only accepd a value of (not yet
existing) "sanitized_size_t" type. However, that requires more effort,
at it would each and every call-site, and is thus left as an exercise
for later.
Pick-to: 6.4 6.2 5.15
Fixes: QTBUG-107619
Change-Id: I3bba9be1e0aea72e11ccb6c168219b4591eb8f5b
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This is a semantic patch using ClangTidyTransformator as in
qtbase/df9d882d41b741fef7c5beeddb0abe9d904443d8:
auto QtContainerClass = anyOf(
expr(hasType(cxxRecordDecl(isSameOrDerivedFrom(hasAnyName(classes))))).bind(o),
expr(hasType(namedDecl(hasAnyName(<classes>)))).bind(o));
makeRule(cxxMemberCallExpr(on(QtContainerClass),
callee(cxxMethodDecl(hasAnyName({"count", "length"),
parameterCountIs(0))))),
changeTo(cat(access(o, cat("size"), "()"))),
cat("use 'size()' instead of 'count()/length()'"))
a.k.a qt-port-to-std-compatible-api with config Scope: 'Container',
with the extended set of container classes recognized.
Change-Id: Idb1f75dfe2323bd1d9e8b4d58d54f1b4b80c7ed7
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Drop unnecessary includes detected by clangd-iwyu.
Add new includes due to the transitive includes. Also, some of the
includes were detected as unused even if they were actually in use.
In those cases, use angular brackets instead of "" which deceives
the tool not to complain.
Affected subfolders: Debugger, Compiler, JsApi, JsRuntime, Memory,
Parser
Task-number: QTBUG-106473
Change-Id: I01d996a2a2ba31cbbc5f60f5454c8f850298f528
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
| |
|
|
|
|
|
|
|
| |
Amends commit af1ef35fa00a466d3af04c17b59fcb4ea38f396a.
Pick-to: 6.4 6.3
Task-number: QTBUG-92192
Change-Id: I7523b9294d543eaaf2c37f4d2d4456758cdb6e3e
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
For objects with circular structures we generate a proper error message
and fail earlier. For objects with excessive recursion we throw a range
error rather than crashing.
This behavior is modeled after node's behavior in such circumstances.
We use the existing stack overflow detection to determine when to throw
the range error. Testing shows that on windows the limit was
insufficient. Lower it.
Pick-to: 6.2 6.3 6.4
Fixes: QTBUG-92192
Change-Id: I25dd302f65f359111e42492df3c71549c4ed7157
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Replace the current license disclaimer in files by
a SPDX-License-Identifier.
Files that have to be modified by hand are modified.
License files are organized under LICENSES directory.
Pick-to: 6.4
Task-number: QTBUG-67283
Change-Id: I63563bbeb6f60f89d2c99660400dca7fab78a294
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
|
| |
|
|
|
|
|
| |
It is shorter and encapsulates the exception handling a bit.
Change-Id: I8e2dc0eb3b930e222b8cb4852b73d99ca18a0379
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
We either have pre-populated arguments and thisObject, then we can just
use them and keep them const. Or, we want to allocate and populate the
arguments and the thisObject. Then, do allocate them in a separate
object, and transform that into JSCallData afterwards if necessary.
Furthermore, avoid alloc(0) as that just returns the current stack top.
Writing to it will clobber other data. Rather, just use nullptr and
crash if it's written to.
Also, remove the useless operator-> from JSCallData. That one just
confuses the reader.
Change-Id: I8310911fcfe005b05a07b78fcb3791d991a0c2ce
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
| |
|
|
|
| |
Change-Id: Idb26e2df6d4fe8940db57066a30fa8c243f6d2c9
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
|
| |
|
|
|
|
|
| |
This avoids the warnings on conversion to QChar.
Change-Id: Ib774f24592d6f09a531c60bb6fa6e5bdbec88120
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
| |
|
|
|
|
|
|
| |
If the call resulted in an exception the return value is undefined.
Task-number: QTBUG-81581
Change-Id: Ibfdd5e1229cf5437f270232d3b1a91308adeec72
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
| |
|
|
|
|
|
|
|
|
| |
A string representation of those is unlikely to be actual JSON, and even
if it is, we don't want to use it as such.
Fixes: QTBUG-72674
Change-Id: I6815366a0176d9725ff4840d3fc545792ce00535
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Reviewed-by: Robin Burchell <robin.burchell@crimson.no>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Get rid of Primitive and move the corresponding methods
directly into Value. Mark many methods in Value as
constexpr and turn Value into a POD type again.
Keep Primitive as a pure alias to Value for source
compatibility of other modules that might be using it.
Change-Id: Icb47458947dd3482c8852e95782123ea4346f5ec
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
Get rid of makeIdentifier(), as toPropertyKey() will take
care of it.
Rename identifier() to propertyKey() and check that the
key is valid.
Remove String/StringOrSymbol::asArrayIndex(), we don't need it
anymore.
Change-Id: I3c490fabc1475c9ea288b49b1638b6fa1bc237b7
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
|
| |
|
|
|
|
|
|
| |
This finalizes the refactoring of Object's vtable API. Also added
the receiver argument to the method as required by the ES7 spec.
Change-Id: I36f9989211c47458788fe9f7e929862bcfe7b845
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
|
| |
|
|
|
|
|
|
|
|
| |
Pass an Identifier through those virtual methods to unify
the string and integer based versions.
Also add the receiver that's required in ES7
Change-Id: I4e7f01b4c97cc80bcb3c485f6343f28213dc9e6b
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
|
| |
|
|
|
| |
Change-Id: I33c29cc4d023be4ee996a4dc1fb4356da59e60d6
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
|
| |
|
|
|
|
|
|
|
|
| |
The output should be the same as if we were printing an array, with
brackets.
Task-number: QTBUG-67776
Change-Id: I942df66a2908f82ea8ba1ce65676413569cf6f02
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
|
| |
|
|
|
|
|
|
|
|
| |
Stringify::JA takes an ArrayObject* but it merely gets the length
property and does indexed get calls. Those work also on array-like
objects such as our sequence wrappers.
Task-number: QTBUG-45018
Change-Id: I4ec4f89a2e09c918fbc2ff1d48ae5915e67ce280
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
From now on we prefer nullptr instead of 0 to clarify cases where
we are assigning or testing a pointer rather than a numeric zero.
Also, replaced cases where 0 was passed as Qt::KeyboardModifiers
with Qt::NoModifier (clang-tidy replaced them with nullptr, which
waas wrong, so it was just as well to make the tests more readable
rather than to revert those lines).
Change-Id: I4735d35e4d9f42db5216862ce091429eadc6e65d
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
|
| |
|
|
|
|
|
|
| |
Convert most of the methods used QML objects to the new calling
convention. Converted IndexedBuiltinFunction to do the same.
Change-Id: I41b26042c2f56f24988485b06e8ccd214e2573c0
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
|
| |
|
|
|
|
|
| |
Avoid allocations on the JS stack if possible
Change-Id: I344cd6dceb6264314f9d22c94db22b22d1d24d14
Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
|
| |
|
|
|
| |
Change-Id: Ic53532edae9a209aa7125af6f00a9d993d74f1a3
Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
|
| |
|
|
|
| |
Change-Id: I6b99e9a7102b3dcb6a7699f54b6456eba6248699
Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
|
| |
|
|
|
|
|
|
| |
As, this is going to change in a simple stack based structure
to keep pointers to the data to pass to calls.
Change-Id: Ia9aa3f81ee3eeba36affd16aac7b2fe97d59aea9
Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
| |
Instead of mimicking a Value. This makes sure that argc now stays
correct even when anything on Value changes.
Most of the change is mechanical: replace callData->argc by
callData->argc().
Change-Id: I521831ae1ffb3966bad6589c18d7a373e13439d7
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
|
| |
|
|
|
|
|
|
|
| |
Renamed ScopedCallData to JSCall, enforced passing a JS
FunctionObject to it, and added call() and callAsConstructor()
methods to it.
Change-Id: I30db65c9765c2896b5909fe2105c0934c6dad861
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
|
| |
|
|
|
| |
Change-Id: I9ae42aa7a811aa93fe0950725e9d253a0c5e8dba
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
|
| |
|
|
|
|
|
|
| |
Allow for faster calling of builtins, and completely avoid
scope creation in many cases.
Change-Id: I0f1681e19e9908db10def85a74e134a87fc2e44c
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
|
| |
|
|
|
|
|
|
| |
Change those back again to return a value. This will be required
to avoid creation of Scope objects between JS function calls.
Change-Id: I05cb5cf8fd0c13dcefa60d213ccd5983fab57ea3
Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
|
| |
|
|
|
|
|
|
|
| |
This isn't used much, and we can do a bit of a better job by doing it by
hand. In the case of jsonobject, we can reuse the empty string, and in
the other uses, we can avoid allocating multiple values on the JS stack.
Change-Id: I1f02cd86e3969c1471981978d18ce8512412123b
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
|
| |
|
|
|
| |
Change-Id: I2dc8797e2240fcfc4176cb08b982e3e98b879646
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
|
| |
|
|
|
|
|
|
| |
It's enough to just call stringValue(), as that already
does the isString() check.
Change-Id: I7be0e643a7975c0704b4c9c43b337deb8db9fce0
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
|
| |
|
|
|
| |
Change-Id: Iad64dd2c330ca85a28f8f5c776b0ede623203558
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
|
| |\
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Conflicts:
examples/quick/quickwidgets/quickwidget/main.cpp
src/qml/jsruntime/qv4jsonobject.cpp
src/qml/jsruntime/qv4qobjectwrapper.cpp
src/qml/jsruntime/qv4qobjectwrapper_p.h
src/qml/qml/qqmlengine.cpp
src/qml/qml/qqmlpropertycache.cpp
src/qml/qml/qqmlpropertycache_p.h
src/quick/items/qquickanimatedsprite.cpp
src/quick/items/qquickitem.cpp
src/quick/items/qquickitem.h
src/quick/items/qquickitem_p.h
src/quick/items/qquickview_p.h
src/quick/scenegraph/qsgcontext.cpp
src/quick/scenegraph/qsgdefaultrendercontext.cpp
Change-Id: I172c6fbff97208f21ed4c8b6db3d1747a889f22b
|
| | |\
| | |
| | |
| | | |
Change-Id: I48764527fa1ab6d8d59c24552394459b1cdc58ee
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
This covers a whole host of missing cases, notably QUrl stored in a QV4::Value.
Task-number: QTBUG-50592
Change-Id: I8afd772046c7bfbbcf916a7e90a57be5257b9df8
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
GCC6 might dead-store-eliminate out our secret write to Base::mmdata,
because it expects all memory content to be "undefined" before
constructor calls. Clang might take the same approach if the constructor
of Heap::Object is removed.
By making these structs trivial, it also makes them memcpy-able.
Change-Id: I055b2ad28311b997fbe059849ebda4d5894eaa9b
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
... or with QL1C in such cases:
- if there is overloaded function
- in QStringBuilder expressions
Saves ~1.5 KB in text size.
Build config: ubuntu 16.04 x64, gcc 5.3
Change-Id: Icc0789f1c244ce20a3182494b0c7f35c9d77e41d
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
|