How to reduce EXE program size? lazarus / 67-Windows ---------------------------------------------------------------------- FlierMate · 2021-04-11 12:16 My simple "Hello World" program is 49,815 bytes. Hmm..., can we strip it of unused libraries / data? The attached picture shows the code section of that size, in which I think the rest of EXE are unrelated to displaying "Hello World" text string on console screen? I thought I want to attempt writing a compress tool for FPC but (1) the output EXE is far more complicated that I thought, (2) it is best if it is done by the developer of the FPC itself (i.e. not outsider like me).  Thank you for your attention. ---------------------------------------------------------------------- winni · 2021-04-11 12:35 Hi! Assuming you got only 4GB Ram then your exe occupies 0.001 % of it. Winni ---------------------------------------------------------------------- marcov · 2021-04-11 12:43 And Windows EXEs are not even always fully loaded into memory Anyway, if you want to obsess over size, you'll need to do it yourself. In the past research by people focussed on size has occasionally been merged back as improvement. But most suggestions are microoptimizations that limit features. Fixes should be real saving of size (e.g. linker improvements), not just cutting the featureset to minimal. If you want that, you'll need to manage it yourself (e.g. maintain your own cut down RTL), since one RTL will never serve all users size requirements optimally So the short answer is: maintain a custom rtl is the easiest for special size requirements. Of course work on improving the smart linking is always welcome. ---------------------------------------------------------------------- Gustavo 'Gus' Carreno · 2021-04-11 12:52 Hey FlierMate, Every once in a while, and lately more often than most(isn't this the 2nd post this last month), someone comes along with this notion that they need to produce a rather small binary. In the current age where hardware minimums are in the 4GB for RAM and half a TERA for HDDs, I really don't understand this chasing of the windmills. The only place where this should be brought up is in embedded environments, where you have very limited RAM/ROM/EPROM. But even there, with the advent of the Arduino(AVR SoC) and the Raspberry Pie(ARM SoC) those limitations are getting smaller every iteration. So, FlierMate, could you please explain to me this urgent quest to make the binary small? Please? I profoundly thank you, in advance, for any light shed into this predicament. Cheers, Gus ---------------------------------------------------------------------- Aidex · 2021-04-11 13:31 Hi! Have you tried the following? Project Settings > Compiler Settings > Debugging > tick "Use external debug symbols file" (-Xg) ---------------------------------------------------------------------- FlierMate · 2021-04-11 13:38 Quote from: winni on April 11, 2021, 02:35:37 pmHi! Assuming you got only 4GB Ram then your exe occupies 0.001 % of it. Winni That is a different perspective to look at it.  Certainly it makes me less worried about the size of EXE.  Quote from: marcov on April 11, 2021, 02:43:59 pmSo the short answer is: maintain a custom rtl is the easiest for special size requirements. Of course work on improving the smart linking is always welcome. FPC is a large project, it would take tremendous effort and time to study the code, let alone working on improving the linker. What I initially thought is a quick fix, but as I said, it is more complicated than that. And thanks for the answer. Quote from: Gustavo 'Gus' Carreno on April 11, 2021, 02:52:00 pmSo, FlierMate, could you please explain to me this urgent quest to make the binary small? Please? I profoundly thank you, in advance, for any light shed into this predicament. I was used to participate in so called "size-optimizing coding contest", so I, for one, is quite obsessed about file size of binary executable.  People are always go for "smaller and faster" or "bigger and faster"(size, depending on the circumstance), or you have heard enough of "shortest path to a solution". All in all, clean code and small binary footprint are often correlated to efficiency.  Hopefully I have answered your question. ---------------------------------------------------------------------- FlierMate · 2021-04-11 13:42 Quote from: Aidex on April 11, 2021, 03:31:24 pmHi! Have you tried the following? Project Settings > Compiler Settings > Debugging > tick "Use external debug symbols file" Hi there.  I think you are talking about Lazarus IDE? Hmm.. ---------------------------------------------------------------------- marcov · 2021-04-11 13:48 Quote from: FlierMate on April 11, 2021, 03:38:37 pmFPC is a large project, it would take tremendous effort and time to study the code, let alone working on improving the linker. What I initially thought is a quick fix, but as I said, it is more complicated than that. That's the quick fix. Commenting some initializations in various standard units and maintain that as a custom RTL. Think about things like localisation, timezone support, thread support etc. Slightly harder is returning the string support back to the pre unicode level. Note that embedded targets of FPC already do some of this. If you need embedded windows, you need to enable/backport such tricks to win32 Most low hanging has mostly been done. ---------------------------------------------------------------------- Aidex · 2021-04-11 13:52 FlierMate, the compiler option I meant is -Xg ---------------------------------------------------------------------- balazsszekely · 2021-04-11 13:57 Quick test: FPC 3.2.0 vs. CodeBlocks 20.3, 32 bit "Hello world" application, both in release mode: 1. FPC 3.2.0:  33,280 bytes 2. CodeBlocks: 18,944 bytes Where is the big difference?  Yes, the binary generated by FPC is slightly larger, but I don't think this is problem, not for me at least. ---------------------------------------------------------------------- Gustavo 'Gus' Carreno · 2021-04-11 14:04 Hey FlierMate, Quote from: FlierMate on April 11, 2021, 03:38:37 pmI was used to participate in so called "size-optimizing coding contest", so I, for one, is quite obsessed about file size of binary executable.  People are always go for "smaller and faster" or "bigger and faster"(size, depending on the circumstance), or you have heard enough of "shortest path to a solution". All in all, clean code and small binary footprint are often correlated to efficiency.  Hopefully I have answered your question.  Yes you have, and frankly I have to admit, and apologise, that I completely forgot about such type of contest that are just for the fun of it. And on that subject, my counter answer is quite simple: In every case of trying to get it to the bone, there's always an effort in cutting away all the things that make it useful for the masses. Or in other words, and already mentioned above, you would have to go and shave down a lot of the stuff in the RTL, FCL and LCL and probably add a lot of other very customized or hand crafted solutions for what you just shaved down due to everything being so intertwined. So, to summarize, it's a rather big effort and it only pays out if you have deep knowledge of the ELF format and/or whatever it's called in Windows the exe format to then go into the RTL, FCL and/or LCL and shave the fat with confidence. Not trivial and not for a one week-end project, I would say. Cheers, Gus ---------------------------------------------------------------------- lainz · 2021-04-11 14:06 QuoteQuick test: FPC 3.2.0 vs. CodeBlocks 20.3, 32 bit "Hello world" application, both in release mode: 1. FPC 3.2.0:  33,280 bytes 2. CodeBlocks: 18,944 bytes Also (usually) CodeBlocks binary is detected as a virus, with all the C stuff we had problems at university and in our homes trying to install something that was free, small and don't get confused with a virus at every compilation. I don't know if it has changed over the years, just commenting my own experience. ---------------------------------------------------------------------- marcov · 2021-04-11 14:09 Is the Code::Blocks binary standalone ? ---------------------------------------------------------------------- lainz · 2021-04-11 14:11 Quote from: marcov on April 11, 2021, 04:09:23 pmIs the Code::Blocks binary standalone ? Yes it's a C program, an exe that just requires the native dll from Windows. Nothing about Net or modern libraries. ---------------------------------------------------------------------- Fred vS · 2021-04-11 14:15 Hello. For info, this, compiled with fpc  -XX -Xs -CX parameters: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program myEmptyProg; beginend. gives: with fpc 3.2.0 Windows 32 bit: 32.5 Kb with fpc 3.2.0 Windows 64 bit: 43.0 Kb with fpc 3.2.0 Linux 32 bit: 29.9 Kb with fpc 3.2.0 Linux 64 bit: 34.0 Kb ---------------------------------------------------------------------- lainz · 2021-04-11 14:21 Yes, FPC is quite small. I tested with Rust x64 and I get a binary of 132 kb in release mode. This is the Rust program I've used. Code: Text  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i fn main() {    } Edit: I know it has nothing to do with file size, but I also tried Kotlin native, and at least with their IDE it never ends compiling  FPC is quite fast as well compiling. ---------------------------------------------------------------------- marcov · 2021-04-11 14:32 Quote from: lainz on April 11, 2021, 04:11:43 pmQuote from: marcov on April 11, 2021, 04:09:23 pmIs the Code::Blocks binary standalone ? Yes it's a C program, an exe that just requires the native dll from Windows. So msvcrt is linked in statically? ---------------------------------------------------------------------- Fred vS · 2021-04-11 14:36 Quote from: lainz on April 11, 2021, 04:21:42 pmYes, FPC is quite small. Hum, not so small as GCC ad clang Code: C  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i int main() {   } with gcc-8 64 bit linux: 16.1 Kb. with clang-7 64 bit linux: 14.0 Kb. But yes, fpc does it small. ---------------------------------------------------------------------- lainz · 2021-04-11 14:49 Quote from: marcov on April 11, 2021, 04:32:50 pmSo msvcrt is linked in statically? Good question =) But I'm not sure, what I know is that it can use different compilers. QuoteMultiple compiler support: GCC (MingW / GNU GCC) MSVC++ clang Digital Mars Borland C++ 5.5 Open Watcom …and more It must depend on the compiler you choose? How I can detect that if I install it? ---------------------------------------------------------------------- alpine · 2021-04-11 14:59 Code: C  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i int main() {} Is actually quite nothing. Include a printf() statement to add some beef. MSVC by default compiles against msvcrt.dll. You can link statically with an option. Can't compare binaries between Win/Linux, the executable format is quite different. Regards, ---------------------------------------------------------------------- lainz · 2021-04-11 15:01 Hey anyways, if I want to install Cyberpunk 2077 it uses 70 GB of disk space, and I can put it together with my less than 100kb dummy program ---------------------------------------------------------------------- marcov · 2021-04-11 15:02 Quote from: lainz on April 11, 2021, 04:49:33 pmQuote from: marcov on April 11, 2021, 04:32:50 pmSo msvcrt is linked in statically? Good question =) But I'm not sure, what I know is that it can use different compilers. But you used only one to create that smaller file. QuoteHow I can detect that if I install it? If you mean how you can detect how it works, check the DLLs that loads. Even if msvcrt comes with Windows, comparing a compiler with a runtime that is packaged with the OS to one that is not is only confusing the picture. ---------------------------------------------------------------------- FlierMate · 2021-04-11 15:04 Quote from: Aidex on April 11, 2021, 03:52:09 pmFlierMate, the compiler option I meant is -Xg It made the EXE larger: 33,811 bytes. If I just type "FPC firstapp.pas" without the "-Xg" then it generates 33,280 bytes. 49KB EXE is a result compiling it in the IDE itself. Quote from: marcov on April 11, 2021, 03:48:27 pmThat's the quick fix. Commenting some initializations in various standard units and maintain that as a custom RTL. Think about things like localisation, timezone support, thread support etc. Slightly harder is returning the string support back to the pre unicode level. Ah, I see. I'll do it if I have special needs. Thanks. BTW, years ago, I remember the EXE was way smaller. Looks like the RTL has grown over the years. Quote from: Gustavo 'Gus' Carreno on April 11, 2021, 04:04:27 pmNot trivial and not for a one week-end project, I would say. True. And I agree with you completely, there is always pros and cons. Usually we could not please everyone. Quote from: Fred vS on April 11, 2021, 04:36:58 pmHum, not so small as GCC Code: C  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i int main() {   } with gcc 64 bit linux: 12.5 Kb. If one coded using Assembler, a "Hello World" EXE as small as 1,024 bytes is possible. But of course it would be a lot more diificult to code in that language. ---------------------------------------------------------------------- Gustavo 'Gus' Carreno · 2021-04-11 15:16 Hey FlierMate, Quote from: FlierMate on April 11, 2021, 05:04:05 pmAnd I agree with you completely, there is always pros and cons. Usually we could not please everyone. Quite right, you can never appease Roman and Trojan(Old Portuguese saying) Quote from: FlierMate on April 11, 2021, 05:04:05 pmIf one coded using Assembler, a "Hello World" EXE as small as 1,024 bytes is possible. But of course it would be a lot more diificult to code in that language. I particularly avoided going here, because it's the low hanging fruit. Nonetheless, from the old day of MS-DOS, there was a guaranteed way that real programmers did it the smallest: Code: DOS  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i COPY CON PROGRAM.EXE Mic drop... And if they needed to distribute: Code: DOS  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i COPY CON PROGRAM.ZIP Cheers, Gus ---------------------------------------------------------------------- Fred vS · 2021-04-11 15:17 Quote from: FlierMate on April 11, 2021, 05:04:05 pmIf one coded using Assembler, a "Hello World" EXE as small as 1,024 bytes is possible. But of course it would be a lot more diificult to code in that language. Of course with Assembler, but imho, Pascal is more comparable with C. And about size, re-imho fpc size of executable are fairly reasonable. It was not the case for libraries, -XX parameters was not enabled for them, but since fpc 3.0.0, it is fixed ( @marcov  ) ---------------------------------------------------------------------- lainz · 2021-04-11 15:18 Quote from: marcov on April 11, 2021, 05:02:40 pmBut you used only one to create that smaller file. .... If you mean how you can detect how it works, check the DLLs that loads. Even if msvcrt comes with Windows, comparing a compiler with a runtime that is packaged with the OS to one that is not is only confusing the picture. Hi, that's ok. Is like the C# executables are even smaller, but they require .NET installed. I understand. But I did not compared the sizes, it was GetMem: Quote from: GetMem on April 11, 2021, 03:57:55 pmQuick test: FPC 3.2.0 vs. CodeBlocks 20.3, 32 bit "Hello world" application, both in release mode: 1. FPC 3.2.0:  33,280 bytes 2. CodeBlocks: 18,944 bytes Where is the big difference?  Yes, the binary generated by FPC is slightly larger, but I don't think this is problem, not for me at least. I did just a Rust comparison on my post, not a C one: Quote from: lainz on April 11, 2021, 04:21:42 pmYes, FPC is quite small. I tested with Rust x64 and I get a binary of 132 kb in release mode. This is the Rust program I've used. Code: Text  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i fn main() {    } Edit: I know it has nothing to do with file size, but I also tried Kotlin native, and at least with their IDE it never ends compiling  FPC is quite fast as well compiling. ---------------------------------------------------------------------- alpine · 2021-04-11 15:38 @lainz Rust? Kotlin? Really? IMHO, nothing can beat C in code compactness. It is made for that! Furthermore, in Linux GCC apps are linked dynamically against all libraries. It is not like MSVC just against a single msvcrt.dll. And, AFAIK, the FPC has the monolithic approach, i.e. to link everything statically. You're comparing oranges with apples. So, what was the intention of the guy who started the topic? I'm lost. Regards, ---------------------------------------------------------------------- lainz · 2021-04-11 15:45 Quote from: y.ivanov on April 11, 2021, 05:38:08 pm@lainz Rust? Kotlin? Really? IMHO, nothing can beat C in code compactness. It is made for that! Furthermore, in Linux GCC apps are linked dynamically against all libraries. It is not like MSVC just against a single msvcrt.dll. And, AFAIK, the FPC has the monolithic approach, i.e. to link everything statically. You're comparing oranges with apples. So, what was the intention of the guy who started the topic? I'm lost. Regards, Hey why not? Comparing a programming language resulting .exe with it's final size. That's it. ---------------------------------------------------------------------- FlierMate · 2021-04-11 15:46 Quote from: y.ivanov on April 11, 2021, 05:38:08 pmSo, what was the intention of the guy who started the topic? I'm lost. It all started when I tried to use "Optimization- Generate smaller code"(see screenshot) in compiler option as well as Smart-linking. But both do not seem to work. So this is what puzzled me. ---------------------------------------------------------------------- Fred vS · 2021-04-11 15:49 Quote from: y.ivanov on April 11, 2021, 05:38:08 pm@lainz Rust? Kotlin? Really? IMHO, nothing can beat C in code compactness. It is made for that! Furthermore, in Linux GCC apps are linked dynamically against all libraries. It is not like MSVC just against a single msvcrt.dll. And, AFAIK, the FPC has the monolithic approach, i.e. to link everything statically. You're comparing oranges with apples. So, what was the intention of the guy who started the topic? I'm lost. Regards, Hello y.ivanov. I think that it is the same for everybody starting with fpc (included me, of course). The size of the executable that is bigger than with their comparable compilers concurrents. This question come back each year, like a wave, but the good news is that in practice, each new fpc release produces smaller exe. And yes, fpc produces bigger exe than his concurrents, but fpc does not have any competitor for cross-compilations, for his huge numbers of targets, his human-pascal-language, his hot forum with mad people and much more. Amen. Fre;D ---------------------------------------------------------------------- FlierMate · 2021-04-11 16:04 Below are some more findings. All are the size of console apps which have dependency. C# .NET - 4,608 bytes EXE. Generate .NET Framework dependent executable. Code: [Select]using System; namespace N {    class Program    {        static void Main(string[] args)        {            Console.Write("Hello World");        }    } } Visual C++ - 10,752 bytes EXE. Generate CRT-dependent executable? Code: [Select]#include int main() {    std::cout << "Hello World\n"; } ---------------------------------------------------------------------- Fred vS · 2021-04-11 16:13 @ FlierMate Yes, we know, fpc generates bigger exe than his comparable Visual C++ friend. And, like marcov explained, it is due to the initialization of some units used by the RTL. If you want to jump into it and make a "light RTL", I am very interested by your work. Fre;D ---------------------------------------------------------------------- alpine · 2021-04-11 16:17 Quote from: Fred vS on April 11, 2021, 05:49:42 pmHello y.ivanov. I think that it is the same for everybody starting with fpc (included me, of course). The size of the executable that is bigger than with their comparable compilers concurrents. This question come back each year, like a wave, but the good news is that in practice, each new fpc release produces smaller exe. And yes, fpc produces bigger exe than his concurrents, but fpc does not have any competitor for cross-compilations, for his huge numbers of targets, his human-pascal-language, his hot forum with mad people and much more. Amen. Fre;D Thanx, Fred! For reminding me that Quote... his hot forum with mad people and much more. is a virtue. I know well the reasons behind the FPC exe bigger sizes. I'm OK with that. The only thing I miss is the lightning compilation speed with Delphi.  Regards, ---------------------------------------------------------------------- balazsszekely · 2021-04-11 16:21 @marcov Yes, it's a standalone application and yes msvcrt.dll is loaded, still the fpc binary is only 1.7x bigger. ---------------------------------------------------------------------- FlierMate · 2021-04-11 16:23 Quote from: Fred vS on April 11, 2021, 06:13:50 pmIf you want to jump into it and make a "light RTL", I am very interested by your work. Yes, and thanks for the encouraging words. I started this topic when I was trying to compress the EXE compiled by FPC. I am wondering is there anyone who is working on a "light RTL" project? ---------------------------------------------------------------------- winni · 2021-04-11 16:29 Quote from: FlierMate on April 11, 2021, 06:23:07 pm Yes, and thanks for the encouraging words. I started this topic when I was trying to compress the EXE compiled by FPC. I am wondering is there anyone who is working on a "light RTL" project?  As far as I know: No. The reason is simple: Today you can't buy a PC with "light RAM" anymore. Winni ---------------------------------------------------------------------- Fred vS · 2021-04-11 16:32 Quote from: winni on April 11, 2021, 06:29:20 pmQuote from: FlierMate on April 11, 2021, 06:23:07 pm Yes, and thanks for the encouraging words. I started this topic when I was trying to compress the EXE compiled by FPC. I am wondering is there anyone who is working on a "light RTL" project?  As far as I know: No. The reason is simple: Today you can't buy a PC with "light RAM" anymore. Winni There are the Rpi and micro-friends that does some effort. ---------------------------------------------------------------------- lainz · 2021-04-11 16:36 Quote from: winni on April 11, 2021, 06:29:20 pmQuote from: FlierMate on April 11, 2021, 06:23:07 pm Yes, and thanks for the encouraging words. I started this topic when I was trying to compress the EXE compiled by FPC. I am wondering is there anyone who is working on a "light RTL" project?  As far as I know: No. The reason is simple: Today you can't buy a PC with "light RAM" anymore. Winni Not PC but specialized hardware like printers with Linux OS. Limited hardware for specific use cases. But some few KB's will do nothing. I mean the hardware I mentioned can run Electron without problems as well. ---------------------------------------------------------------------- Fred vS · 2021-04-11 16:45 Quote from: lainz on April 11, 2021, 06:36:32 pmBut some few KB's will do nothing. I mean the hardware I mentioned can run Electron without problems as well. Hum, for - 32 Kb (and more) for a simple console prog, I am interested by the "Light RTL" fork of FlierMate. ---------------------------------------------------------------------- Gustavo 'Gus' Carreno · 2021-04-11 16:46 Hey all, Quote from: Fred vS on April 11, 2021, 05:49:42 pm[snip] his hot forum with mad people and much more. Mad person in the house. Present and accounted for Cheers, Gus ---------------------------------------------------------------------- marcov · 2021-04-11 17:21 Quote from: Fred vS on April 11, 2021, 06:45:43 pmQuote from: lainz on April 11, 2021, 06:36:32 pmBut some few KB's will do nothing. I mean the hardware I mentioned can run Electron without problems as well. Hum, for - 32 Kb (and more) for a simple console prog,  32KB for a *windows* console prog.   If you want to compare to embedded solutions, your testing must also be for FPC embedded targets like arduino or some Arm Cortext M*. Unless you are still nursing one of those notorious Windows NT4 based printers :-)  (and FPC doesn't support 1 to break even. If you finely divide the packages up into a lot of smaller packages the overhead is lower for small programs, but larger for bigger programs.Some people point out that dynamic linking with massive amount of symbols exported and imported is noticeably slower to startup. This is mostly based on the much faster startup time of bare bones installed D7. It could be the packages initialization more than the dynamic loading aspect though. OTOH KDE also suffered from this on *nix in the past, resorting to a "prelink" scheme, so it is probably a real thing. Besides that there are also extra indirection costs to access global identifiers in packages. Afaik the RTL already got some of those in preparation of packagesQuoteEven if distributing packages with main application partially kills all benefits, unless your program has lots of plug-ins. But overall it's not problem with concept itself - it's problem with it's implementation in Linux. Yes, plugins' as in functionality, (not size savings) are the primary goal of packages I think. As for the Linux problem, it is bigger. Linux simply doesn't value binary interfaces at all beyond the current distribution version iteration. And for non core packages often not even that. ---------------------------------------------------------------------- PascalDragon · 2021-10-27 08:37 Quote from: Alextp on October 26, 2021, 11:33:36 amRuntime packages are ok only on Windows, imagine what problems will have users on Unixes. This won't be a problem, cause like with all good *nix citizens the runtime package libraries will be versioned: librtl.3.2.0.solibrtl.3.2.2.solibrtl.objpas.3.2.0.solibrtl.objpas.3.2. 2.soetc. Using dynamic packages at compile time is in principle already possible for the Windows targets (excluding WinCE), the macOS targets as well as x86_64-linux (for all of them it's disabled inside the compiler and there's also the fact that we don't yet have a way to generate packages from fpmake). ---------------------------------------------------------------------- marcov · 2021-10-27 09:12 I revised my post a bit after reading Pascaldragon's, which reminded me that the exact package division in Delphi is not guaranteed within a future FPC/Lazarus package system. Finer divided packages reduce overhead for programs that only use a few, but increase overhead for larger ones (e.g. lazarus LCL programs) ---------------------------------------------------------------------- FPK · 2021-10-27 18:12 Quote from: marcov on October 26, 2021, 11:06:49 pmYes, plugins' as in functionality, (not size savings) are the primary goal of packages I think. I would expect that plugins work across different releases of a software but this is not going to happen if they are compiled by different versions of FPC.