Open stsp opened 4 years ago
Oh... So is it correct to assume that the intermediate target support - I mean, the proper one, without disabling parallel build, adding custom clean hooks and so on - is not something to ever expect?
without disabling parallel build
This policy does not completely disable parallel builds; source compilation inside the target is still parallel.
https://github.com/xmake-io/xmake/discussions/2831 I think this tells something similar to what I get, complaining about set_kind(). But I think he misses the fact that secondary targets are not supported, so allowing user-defined kinds is likely still not enough to solve the problem.
$ xmake f
note: the following packages were not found in any repository (check if they are spelled correctly):
-> nasm-segelf
$ dpkg-query -s nasm-segelf
Package: nasm-segelf
Status: install ok installed
Why doesn't it see the installed package?
$ xmake f note: the following packages were not found in any repository (check if they are spelled correctly): -> nasm-segelf $ dpkg-query -s nasm-segelf Package: nasm-segelf Status: install ok installed
Why doesn't it see the installed package?
Since this package was not added to xmake-repo and apt::nasm-segelf
was not specified, xmake can only treat it as unknown and run nasm-segelf --version
to try to detect it, which is unreliable.
To detect it more reliably, you need to add it to the xmake-repo, or define package("nasm-segelf")
in your own repository, and then provide the on_fetch script, for example:
package("nasm-segelf")
set_kind("toolchain")
on_fetch(function (package, opt)
if opt.system then
return package:find_tool("nasm")
end
end)
--[[ optional, if you want to install from source url
on_install(function (package)
end)]]
package_end()
add_requires("nasm-segelf")
target("test")
add_files("src/*.S")
set_toolchains("nasm@nasm-segelf")
BTW, Currently, xmake's nasm toolchain does not support automatic binding of custom nasm packages. It will always use the system's nasm, and the xmake nasm toolchain needs to be improved if you want the above configuration to work completely and reliably.
Currently, only the llvm/mingw/zig toolchains support automatic package binding and switching at compile time.
Since this package was not added to xmake-repo and apt::nasm-segelf was not specified
Even doing add_requires("apt::nasm-segelf", {system = true})
still gives this:
note: the following packages were not found on your system, try again after installing them:
-> apt::nasm-segelf latest
xmake can only treat it as unknown and run nasm-segelf --version to try to detect it, which is unreliable.
But for me it could work.
If I could tell xmake an alias name to do
alias-name --version
, then things will
work, because it will then do nasm --version
and get "nasm-segelf" in a version string.
Although of course it should just detect
it via native package manager.
To detect it more reliably, you need to add it to the xmake-repo, or define package("nasm-segelf")
No, you said, it can detect it locally on a system. If this wasn't said, I wouldn't be trying xmake now.
Also: how can I disable this silly
updating repositories .. ok
at the first
start, that takes quite a lot of time?
Well, if I can't stop xmake from always
going to the internet over my back, I'll
just delete it and will advice everyone to
do the same. :) This is completely
intolerable, so I hope you can just tell
me how to disable that behavior forever. :)
It will always use the system's nasm
I don't care, because, until it supports intermediate targets, I won't port the build system to it. I will just use it as a supplement, to get and build custom nasm. But the parent build system will use it. So this is not a problem.
No, you said, it can detect it locally on a system. If this wasn't said, I wouldn't be trying xmake now.
in your xmake.lua
package("nasm-segelf")
set_kind("toolchain")
on_fetch(function (package, opt)
if opt.system then
return package:find_tool("nasm")
end
end)
package_end()
add_requires("nasm-segelf", {system = true})
It only detect it from local system, and your package configuration is in your local project.
This is completely intolerable, so I hope you can just tell me how to disable that behavior forever. :)updating repositories .. ok
xmake g --network=private
$ xmake g --network=private
configure
{
proxy_pac = pac.lua
theme = default
network = private
}
Why does it say that? Anyway, works as expected. Also the initial delay in unsupported sources is now gone. Can I include such behavior into the project, so that even when building it on another machine, it won't go to the internet until I explicitly ask to download the nasm sources?
in your xmake.lua
No, this way it also finds regular nasm. It doesn't look for "nasm-segelf" in a "--version" output, neither does it look via the apt/dpkg. So... what is this all about?
Can I include such behavior into the project, so that even when building it on another machine, it won't go to the internet until I explicitly ask to download the nasm sources?
you need use dev version, set_policy("network.mode", "private")
in your xmake.lua
xmake update dev
source ~/.xmake/profile
you need use dev version
I am using PPA version, is this a dev version?
No, this way it also finds regular nasm. It doesn't look for "nasm-segelf" in a "--version" output, neither does it look via the apt/dpkg.
you can run custom command to check.
package("nasm-segelf")
set_kind("toolchain")
on_fetch(function (package, opt)
if opt.system then
local ok = try {function () os.run("dpkg-query -s nasm-segelf"); return true end}
if ok then
return {name = "nasm-segelf", program = "<binary path>", version = "1.0"}
end
end
end)
BTw , It tried --version
after installing nasm-segelf. it's not found.
$ nasm-segelf --version
bash: nasm-segelf: command not found
you need use dev version
I am using PPA version, is this a dev version?
no, dev branch version, because I just added it today.
you can run custom command to check.
So is this what you "meant" saying it supports querying the native package manager?
BTw , It tried --version after installing nasm-segelf. it's not found.
Yes, but if it checked the actual
version string returned by
nasm --version
, it could find
"nasm-segelf" there. But for that
it needs to get a tool name and a
string to grep, which probably can't
be provided now.
no, dev branch version, because I just added it today.
Will wait for PPA, not a problem.
local ok = try {function () os.run("dpkg-query -s nasm-segelf"); return true end}
Of course you realize this is not the way to query "native package manager", as it may be rpm or whatever else.
local ok = try {function () os.run("dpkg-query -s nasm-segelf"); return true end}
Of course you realize this is not the way to query "native package manager", as it may be rpm or whatever else.
it's only a example, you can run any commands to detect it.
os.run("dpkg-query -s nasm-segelf")
os.run("nasm-segelf --version")
os.run("nasm-segelf --help")
-- find it from rpm
-- and more if it exists
....
Is this what you "meant" saying it supports querying the native package manager?
Is this what you "meant" saying it supports querying the native package manager?
If it is a library, then add_requires("fmt", {system = true})
will automatically call pkg-config to look up the system libraries, and if its package is configured with apt's extsources, it will also look it up from apt/pacman.
But if it's only a binary program, like your nasm-pkgself
We just need to try running nasm-segself --version
to detect it from the system. Or go further and detect it from apt/rpm in the on_fetch custom script.
In the current version, there is no support for natively looking up binaries from apt/rpm.
In the current version, there is no support for natively looking up binaries from apt/rpm.
Any plans?
In the current version, there is no support for natively looking up binaries from apt/rpm.
Any plans?
you can open a feature request first, I'll consider improvements in the future, but there's no guarantee that I will be supported in the next version. I still have a lot of issues to deal with.
You can try runing the custom command approach first I mentioned earlier to detect it. Or keep waiting.
Well, I can work around the problem by adding a nasm-segelf symlink into a package. So lets do just that for now...
Didn't help!
$ nasm-segelf --version
nasm-segelf version 2.17rc0
$ xmake f
note: the following packages were not found in any repository (check if they are spelled correctly):
-> nasm-segelf
... with add_requires("nasm-segelf")
in xmake.lua.
OK, since xmake failed to automate basically every task I tried to put on it, I resorted to the classical "plug existing holes one-by-one" approach. I slimmed down nasm-segelf packaging to not conflict with nasm, added a homebrew recipe for it, and will probably just add autoconf to patch up the remaining holes. ... like those that homebrew is mostly for Mac, and therefore of course also doesn't talk to the native package managers... But at least it works, and almost looks like the only workable solution among the currently existing abundance of package managers. I only had to submit just a couple of pull requests to its repo to get it running, and they are already approved, so let's say it took just 1 day.
The xmake package has been in Fedora official repository. https://src.fedoraproject.org/rpms/xmake
And I have supported to pack NSIS package. https://github.com/xmake-io/xmake/issues/1433
I will continue to pack deb/rpm packages in the future.
This is good to know.
But w/o the intermediate target support
it has little use at porting the existing
complex build system on. Plus its intention
to always go to the internet "to read some
news and watch youtube" is unacceptable
for me personally, and produces the
multi-seconds delays on start up.
And this is besides the fact that I wasn't
able to get it to detect nasm-segelf, even
after providing such symlink, so that
nasm-segelf --version
could work.
In contrast, I was quite impressed with the homebrew manager (but I can't say I tried the xmake's package management already, so can't really compare). So I think it would be best if I return to xmake a few years later to see if its all still the same, and then decide.
This is to add that, according to you, custom nasm replacement is not yet supported, native package manager query is not yet supported, native package build is not yet supported...
But I don't think I'll easily find some other build system that allows me to gradually port the project, target-by-target. I think most of the existing build systems are not designed to co-exist in another build system and cooperate with it. When our project at work faced the same problem, they did a research and found that only bazel was adequate for their porting needs. Then they spent a few man-years porting to bazel... But I do have neither bazel, nor a few man-years to spend on this.
It appears that meson supports intermediate targets, generators and any weird dependency propagation. Or maybe it doesn't: it just gives you an OOP DSL, on top of which you can code up most of anything... But the cost is huge. Took me 2 full weeks to just get to the barely working POC. Given that dosemu2 is much larger than fdpp, it will likely never be ported. The amount of work is ridiculously high.
meson support got the lucky hash commit though: a999999 Perhaps this means, it worth the troubles after all. :)
Hi Andrew, I am hesitating to switch
the build system just yet.
Would you like to play with it a bit and
let me know what you think?
If it works for you locally, then CI can
be the next step.
I added the configure.meson
script
that should get you started.
Would you like to play with it a bit and let me know what you think?
Sure. I never used meson before myself, so how should I test the build?
Just use configure.meson, it tells you everything.
Yes, thanks I found that but I get
ajb@calypso:/clients/common/fdpp.git/build$ ../configure.meson
Directory does not contain a valid build tree:
/clients/common/fdpp.git/build
What command does it execute?
Can you add set -x
to a script?
ajb@calypso:/clients/common/fdpp.git/build$ git diff
diff --git a/configure.meson b/configure.meson
index ab4d8666..ddd8b895 100755
--- a/configure.meson
+++ b/configure.meson
@@ -1,3 +1,8 @@
+#!/bin/sh
+
+
+set -xv
+
if [ -f meson.build ]; then
echo -e "Create a build dir first:"
echo -e "\tmkdir build"
if [ -f meson.build ]; then
echo -e "Create a build dir first:"
echo -e "\tmkdir build"
echo -e "\tcd build"
echo -e "\t../$(basename $0)"
echo "Bye!"
exit 0
fi
+ [ -f meson.build ]
TOP=$(dirname "$0")
+ dirname ../configure.meson
+ TOP=..
meson setup --native-file $TOP/fdpp/toolchain.ini \
--cross-file $TOP/fdpp/toolchain.ini \
--cross-file $TOP/fdpp/kernel/toolchain.ini \
--native-file $TOP/fdpp/kernel/toolchain.ini . $TOP --reconfigure
+ meson setup --native-file ../fdpp/toolchain.ini --cross-file ../fdpp/toolchain.ini --cross-file ../fdpp/kernel/toolchain.ini --native-file ../fdpp/kernel/toolchain.ini . .. --reconfigure
Directory does not contain a valid build tree:
/clients/common/fdpp.git/build
[ "$?" == "0" ] || exit 1
+ [ 1 == 0 ]
../configure.meson: 20: [: 1: unexpected operator
+ exit 1
so I think line 20 should be [ "$?" = "0" ] || exit 1
i.e. single =
, but that's after the error
Ok, not sure what does this mean. From that build dir you can do:
$ find .. -name meson.build
../fdpp/thunk_gen/meson.build
../fdpp/kernel/meson.build
../fdpp/loader/meson.build
../fdpp/meson.build
../meson.build
Do you see the same?
ajb@calypso:/clients/common/fdpp.git/build$ find .. -name meson.build
../fdpp/thunk_gen/meson.build
../fdpp/kernel/meson.build
../fdpp/loader/meson.build
../fdpp/meson.build
../meson.build
this page https://mesonbuild.com/Configuring-a-build-directory.html suggests there's a step called meson configure
Please try to remove --reconfigure
from script. Maybe in your version it
requires configured build tree.
yes that got further
ajb@calypso:/clients/common/fdpp.git/build$ ../configure.meson
if [ -f meson.build ]; then
echo -e "Create a build dir first:"
echo -e "\tmkdir build"
echo -e "\tcd build"
echo -e "\t../$(basename $0)"
echo "Bye!"
exit 0
fi
+ [ -f meson.build ]
TOP=$(dirname "$0")
+ dirname ../configure.meson
+ TOP=..
meson setup --native-file $TOP/fdpp/toolchain.ini \
--cross-file $TOP/fdpp/toolchain.ini \
--cross-file $TOP/fdpp/kernel/toolchain.ini \
--native-file $TOP/fdpp/kernel/toolchain.ini . $TOP
+ meson setup --native-file ../fdpp/toolchain.ini --cross-file ../fdpp/toolchain.ini --cross-file ../fdpp/kernel/toolchain.ini --native-file ../fdpp/kernel/toolchain.ini . ..
The Meson build system
Version: 0.61.2
Source dir: /clients/common/fdpp.git
Build dir: /clients/common/fdpp.git/build
Build type: cross build
Project name: fdpp
Project version: 0.1
C compiler for the host machine: gcc (gcc 11.4.0 "gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0")
C linker for the host machine: gcc ld.bfd 2.38
C++ compiler for the host machine: clang++ (clang 14.0.0-1ubuntu1 "Ubuntu clang version 14.0.0-1ubuntu1.1")
C++ linker for the host machine: clang++ ld.bfd 2.38
../meson.build:1:0: ERROR: Tried to use unknown language "nasm".
A full log can be found at /clients/common/fdpp.git/build/meson-logs/meson-log.txt
[ "$?" = "0" ] || exit 1
+ [ 1 = 0 ]
+ exit 1
Added patch, can you please re-check?
Well that's the Jammy build stuffed then
ajb@calypso:/clients/common/fdpp.git/build$ ../configure.meson
The Meson build system
Version: 0.61.2
Source dir: /clients/common/fdpp.git
Build dir: /clients/common/fdpp.git/build
Build type: cross build
../meson.build:1:0: ERROR: Meson version is 0.61.2 but project requires >= 0.64
A full log can be found at /clients/common/fdpp.git/build/meson-logs/meson-log.txt
Sigh. Your meson is just 2 years old, but there is no nasm yet. And in fact I suspect we'll fsck on anything before 1.0, which is dated dec 2022, so 1 year old... I didn't know meson have just emerged. Hmm, unsure what to do now.
I tend to follow the Ubuntu LTS series, so come April all will be good!
I am not quite sure things will improve much... unless we want to drop everything but 2024 LTS? :( I guess we'll be able to switch CI to meson at April, but seems like makefiles will have to be supported in parallel for quite a years to come. Which puts a big question mark on this entire work.
is there an updated meson in a PPA we could use?
That's an interesting question. In fact, as its written on python, we probably can just use the Noble's packages on any ubuntu. Let me tell you secretly that I have actually done exactly that. :) Just forgot in 2 weeks of porting.
So... can you try to just to update to the Noble build? IIRC there was no such PPA, or why would I otherwise use the Noble build myself.
ajb@calypso:/clients/common/fdpp.git/build$ sudo apt remove meson
ajb@calypso:/clients/common/fdpp.git/build$ sudo apt install ninja-build
[sudo] password for ajb:
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following NEW packages will be installed
ninja-build
0 to upgrade, 1 to newly install, 0 to remove and 0 not to upgrade.
Need to get 111 kB of archives.
After this operation, 358 kB of additional disk space will be used.
Get:1 http://gb.archive.ubuntu.com/ubuntu jammy/universe amd64 ninja-build amd64 1.10.1-1 [111 kB]
Fetched 111 kB in 0s (301 kB/s)
Selecting previously unselected package ninja-build.
(Reading database ... 328447 files and directories currently installed.)
Preparing to unpack .../ninja-build_1.10.1-1_amd64.deb ...
Unpacking ninja-build (1.10.1-1) ...
Setting up ninja-build (1.10.1-1) ...
Processing triggers for man-db (2.10.2-1) ...
Processing triggers for doc-base (0.11.1) ...
Processing 1 added doc-base file...
ajb@calypso:/clients/common/fdpp.git/build$ pip3 install meson
Defaulting to user installation because normal site-packages is not writeable
Collecting meson
Downloading meson-1.3.0-py3-none-any.whl (976 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 976.4/976.4 KB 5.0 MB/s eta 0:00:00
Installing collected packages: meson
WARNING: The script meson is installed in '/home/ajb/.local/bin' which is not on PATH.
Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed meson-1.3.0
ajb@calypso:/clients/common/fdpp.git/build$ export PATH=/home/ajb/.local/bin:${PATH}
ajb@calypso:/clients/common/fdpp.git/build$ ../configure.meson
The Meson build system
Version: 1.3.0
Source dir: /clients/common/fdpp.git
Build dir: /clients/common/fdpp.git/build
Build type: cross build
Project name: fdpp
Project version: 0.1
Nasm compiler for the host machine: nasm-segelf (nasm 2.17)
Nasm linker for the host machine: gcc ld.bfd 2.38
C compiler for the host machine: gcc (gcc 11.4.0 "gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0")
C linker for the host machine: gcc ld.bfd 2.38
C++ compiler for the host machine: clang++ (clang 14.0.0-1ubuntu1 "Ubuntu clang version 14.0.0-1ubuntu1.1")
C++ linker for the host machine: clang++ ld.bfd 2.38
Nasm compiler for the build machine: nasm-segelf (nasm 2.17)
Nasm linker for the build machine: gcc ld.bfd 2.38
C compiler for the build machine: gcc (gcc 11.4.0 "gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0")
C linker for the build machine: gcc ld.bfd 2.38
C++ compiler for the build machine: clang++ (clang 14.0.0-1ubuntu1 "Ubuntu clang version 14.0.0-1ubuntu1.1")
C++ linker for the build machine: clang++ ld.bfd 2.38
Build machine cpu family: x86_64
Build machine cpu: x86_64
Host machine cpu family: x86
Host machine cpu: i386
Target machine cpu family: x86
Target machine cpu: i386
Executing subproject libfdpp
libfdpp| Project name: libfdpp
libfdpp| Project version: 0.1
libfdpp| C compiler for the host machine: gcc (gcc 11.4.0 "gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0")
libfdpp| C linker for the host machine: gcc ld.bfd 2.38
libfdpp| C++ compiler for the host machine: clang++ (clang 14.0.0-1ubuntu1 "Ubuntu clang version 14.0.0-1ubuntu1.1")
libfdpp| C++ linker for the host machine: clang++ ld.bfd 2.38
libfdpp| C compiler for the build machine: gcc (gcc 11.4.0 "gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0")
libfdpp| C linker for the build machine: gcc ld.bfd 2.38
libfdpp| C++ compiler for the build machine: clang++ (clang 14.0.0-1ubuntu1 "Ubuntu clang version 14.0.0-1ubuntu1.1")
libfdpp| C++ linker for the build machine: clang++ ld.bfd 2.38
Executing subproject libfdpp:thunk_gen
thunk_gen| Project name: thunk_gen
thunk_gen| Project version: 0.1
thunk_gen| C compiler for the host machine: gcc (gcc 11.4.0 "gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0")
thunk_gen| C linker for the host machine: gcc ld.bfd 2.38
thunk_gen| C compiler for the build machine: gcc (gcc 11.4.0 "gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0")
thunk_gen| C linker for the build machine: gcc ld.bfd 2.38
thunk_gen| Program flex found: YES (/usr/bin/flex)
thunk_gen| Program bison found: YES (/usr/bin/bison)
thunk_gen| Build targets in project: 1
thunk_gen| Subproject thunk_gen finished.
libfdpp| Fetching value of define "FDPP_API_VER" : 35
libfdpp| Fetching value of define "BPRM_VER" : 10
libfdpp| Program /clients/common/fdpp.git/subprojects/libfdpp/parsers/mkfar.sh found: YES (/clients/common/fdpp.git/subprojects/libfdpp/parsers/mkfar.sh)
libfdpp| Program /clients/common/fdpp.git/subprojects/libfdpp/parsers/parse_decls.sh found: YES (/clients/common/fdpp.git/subprojects/libfdpp/parsers/parse_decls.sh)
libfdpp| Program autom4te found: YES (/usr/bin/autom4te)
libfdpp| Program echo found: YES (/usr/bin/echo)
libfdpp| Build targets in project: 9
libfdpp| Subproject libfdpp finished.
Executing subproject loader
loader| Project name: loader
loader| Project version: 0.1
loader| C compiler for the host machine: gcc (gcc 11.4.0 "gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0")
loader| C linker for the host machine: gcc ld.bfd 2.38
loader| C compiler for the build machine: gcc (gcc 11.4.0 "gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0")
loader| C linker for the build machine: gcc ld.bfd 2.38
loader| Found pkg-config: YES (/usr/bin/pkg-config) 1.8.0
loader| Run-time dependency libelf found: YES 0.186
loader| Fetching value of define "FDPP_API_VER" : 35
loader| Fetching value of define "BPRM_VER" : 10
loader| Build targets in project: 10
loader| Subproject loader finished.
Executing subproject kernel
kernel| Project name: kernel
kernel| Project version: 1.7
kernel| Nasm compiler for the host machine: nasm-segelf (nasm 2.17)
kernel| Nasm linker for the host machine: gcc ld.bfd 2.38
kernel| C compiler for the host machine: gcc (gcc 11.4.0 "gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0")
kernel| C linker for the host machine: gcc ld.bfd 2.38
kernel| Nasm compiler for the build machine: nasm-segelf (nasm 2.17)
kernel| Nasm linker for the build machine: gcc ld.bfd 2.38
kernel| C compiler for the build machine: gcc (gcc 11.4.0 "gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0")
kernel| C linker for the build machine: gcc ld.bfd 2.38
kernel| Fetching value of define "FDPP_API_VER" : 35
kernel| Fetching value of define "BPRM_VER" : 10
kernel| Program i686-linux-gnu-ld found: YES (/usr/bin/i686-linux-gnu-ld)
kernel| Build targets in project: 15
kernel| Subproject kernel finished.
Build targets in project: 15
fdpp 0.1
Subprojects
kernel : YES
libfdpp : YES
loader : YES
thunk_gen : YES (from libfdpp)
User defined options
Cross files : ../fdpp/toolchain.ini
../fdpp/kernel/toolchain.ini
Native files: ../fdpp/toolchain.ini
../fdpp/kernel/toolchain.ini
Found ninja-1.10.1 at /usr/bin/ninja
Done configure
Now run "meson build --verbose" to build
After that you can do "sudo meson install" to install
ajb@calypso:/clients/common/fdpp.git/build$ meson build --verbose
usage: meson [-h] {setup,configure,dist,install,introspect,init,test,wrap,subprojects,rewrite,compile,devenv,env2mfile,help} ...
meson: error: unrecognized arguments: --verbose
ajb@calypso:/clients/common/fdpp.git/build$ meson build
ERROR: Neither source directory 'build' nor build directory None contain a build file meson.build.
WARNING: Running the setup command as `meson [options]` instead of `meson setup [options]` is ambiguous and deprecated.
Wow! Let me do just that...
Currently (in master) fdpp is only buildable on focal and groovy. Bionic misses llvm-objcopy so that binutils is needed, and Xenial misses lld, so binutils is needed. There are a few ways to solve that:
Case 3 can only work if you can, as @andrewbird suggests, say "lld | binutils" in Build-Depends.
I would personally think I'd go for 1 unless @jschwartzenberg moves things to 3. :)