Lazarus 1.8.0RC5 + LAMW lazarus / 43-Android ---------------------------------------------------------------------- Handoko · 2017-10-31 17:29 -edit-: This installation tutorial no longer works with the latest version of NDK/SDK. Please use this new installation guide: http://forum.lazarus.freepascal.org/index.php?topic=42527 Hello, I'm back for Android programming. Today I tried to install LAMW on Lazarus 1.8.0RC5 and it succeed! So I write this tutorial, maybe someone will find it useful. Before You Start Remember, you should do proper backup before you start. Linux users can use this script: https://github.com/jmpessoa/lazandroidmodulewizard/tree/master/docs/li nux I tested the script but I prefer my way to install because I don't want multiple versions of Lazarus/FPC put on my computer. More documentations can be found here: https://github.com/jmpessoa/lazandroidmodulewizard/tree/master/docs === Environment === This tutorial should work on other environments with no or some changes but I only tested on: - Ubuntu Mate 17.10 64-bit - Intel x64 - Lazarus 1.8.0RC5 FPC 3.0.4 x86_64-linux-gtk2 This tutorial assume you're using NDK revision 11c. If you're not using this version, you have to change all the texts "4.9" below accordingly. === Install Necessary Libraries & Tools === On my system I only need to use Terminal to install these: 01. sudo apt-get install subversion 02. sudo apt-get install android-tools-adb ant openjdk-8-jdk I saw on other tutorials, they said you may also need to install: 03. sudo apt-get install freeglut3 freeglut3-dev libwxgtk3.0-0v5 04. sudo apt-get install libgtk2-gladexml-perl libgtk2.0-bin libgtk2.0-cil 05. sudo apt-get install make build-essential libncurses5-dev libtinfo-dev 06. sudo apt-get install libcairo2-dev libpango1.0-dev libatk1.0-dev libghc-x11-dev 07. sudo apt-get install libgtk2.0-dev libgdk-pixbuf2.0-dev libgpm-dev fakeroot === Prepare Android NDK & SDK === 08. mkdir ~/Android 09. Extract Android NDK https://developer.android.com/ndk/downloads to ~/Android 10. ln -sf ~/Android/android-ndk-r11c ~/Android/ndk 11. cd /usr/bin 12. sudo ln -sf ~/Android/ndk/toolchains/arm-linux- androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-as arm-linux-androideabi-as 13. sudo ln -sf ~/Android/ndk/toolchains/arm-linux- androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-ld arm-linux-androideabi-ld 14. sudo ln -sf /usr/bin/arm-linux-androideabi-as arm-linux-as 15. sudo ln -sf /usr/bin/arm-linux-androideabi-ld arm-linux-ld 16. Extract Android SDK https://developer.android.com/sdk to ~/Android 17. ln -sf ~/Android/android-sdk-linux ~/Android/sdk 18. Install SDK Packages by running ~/Android/sdk/tools/android Note: The "android" tool has been deprecated by newer version of Android SDK, read more: http://forum.lazarus.freepascal.org/index.php/topic,38777.msg281267.ht ml#msg281267 19. Use a text editor to open ~/.bashrc and add this text below: export PATH=$PATH:~/Android/ndk/toolchains/arm-linux- androideabi-4.9/prebuilt/linux-x86_64/bin Note for #18: I only enable Android 4.4.2 (API 19), you can try other version if you want. === Cross Compile Android ARM === 20. cd /usr/share/fpcsrc/3.0.4 21. sudo make clean crossall OS_TARGET=android CPU_TARGET=arm 22. sudo make crossinstall OS_TARGET=android CPU_TARGET=arm INSTALL_PREFIX=/usr 23. sudo ln -sf /usr/lib/fpc/3.0.4/ppcrossarm /usr/bin/ppcrossarm 24. sudo ln -sf /usr/bin/ppcrossarm /usr/bin/ppcarm 25. Add these blue lines below to /etc/fpc.cfg: #IFDEF ANDROID #IFDEF CPUARM -Fu/usr/lib/fpc/$fpcversion/units/$fpctarget -Fu/usr/lib/fpc/$fpcversion/units/$fpctarget/* -Fu/usr/lib/fpc/$fpcversion/units/$fpctarget/rtl #ENDIF #ENDIF === Cross Compile Android i386 === You can skip this section if you do not need to target Android Intel CPU. 26. cd /usr/bin 27. sudo ln -sf ~/Android/ndk/toolchains/x86-4.9/prebuilt/linux-x86_64/bin/i686-linux- android-as i686-linux-android-as 28. sudo ln -sf ~/Android/ndk/toolchains/x86-4.9/prebuilt/linux-x86_64/bin/i686-linux- android-ld i686-linux-android-ld 29. sudo ln -sf /usr/bin/i686-linux-android-as i686-linux-as 30. sudo ln -sf /usr/bin/i686-linux-android-ld i686-linux-ld 31. cd /usr/share/fpcsrc/3.0.4 32. sudo make clean crossall OS_TARGET=android CPU_TARGET=i386 33. sudo make crossinstall OS_TARGET=android CPU_TARGET=i386 INSTALL_PREFIX=/usr 34. sudo ln -sf /usr/lib/fpc/3.0.4/ppcross386 /usr/bin/ppcross386 === Lazarus Android Module Wizard Installation === 35. cd ~/Android 36. svn co https://github.com/jmpessoa/lazandroidmodulewizard.git 37. ln -sf ~/Android/lazandroidmodulewizard.git ~/Android/lazandroidmodulewizard 38. Start Lazarus IDE 39. menu > Package > Open Package (.lpk) > "tfpandroidbride_pack.lpk" 40. Compile, then and Use > Install 41. menu > Package > Open Package (.lpk) > "lazandroidwizardpack.lpk" 42. Compile, then and Use > Install 43. menu > Package > Open Package (.lpk) > "amw_ide_tools.lpk" 44. Compile, then and Use > Install 45. menu > Tools > [Lamw] Android Module Wizard > Paths Settings: [Jdk, Sdk, Ndk, ...]: Path to Java JDK: /usr/lib/jvm/java-8-openjdk-amd64 Path to Ant bin: /usr/bin Path to Android SDK: /home/[handoko]/Android/sdk Path to Android NDK: /home/[handoko]/Android/ndk NDK Version: 11c Note for #39, #41, #43: Those lpk files can be found inside "lazandroidmodulewizard.git" folder. Note for #45: You should change the name "[handoko]" to the user name on your computer. === How To Start A LAMW Project === Lazarus main menu > New > Project > choose one of these: - Android [NoGUI] JNI Module [Lamw] - Android [GUI] JNI Module [Lamw] - Android Console App [Lamw] The components you can use in LAMW Projects are limited on the those inside "Android Bridges" and "Android Bridges Extras" tabs only. The pascal source code will be saved in: [projectname]\jni. The compiled binary (*.so) will be saved in: [projectname]\libs (inside armeabi or x86) The Android binary (*.apk) will be saved in: [projectname]\bin To produce the apk file (from *.so), you need to run "build-debug.sh" or "build-release.sh", which can be found on the project folder. Alternatively, you can you use LATE (Lazarus Apk Expert Tools): Lazarus main menu > Tools > [Lamw] Android Module Wizard > LATE: Apk Expert Tools [Build, Install, ...] Below I provided an apk sample compiled to target ARMV7A, it should run correctly on Intel CPU too. It shows some moving rectangles drawn using OpenGL ES 2 (jCanvasES2). The source code can be downloaded here: http://forum.lazarus.freepascal.org/index.php/topic,38777.msg264878.ht ml#msg264878 Note: LATE does not work correctly on Linux. === Setting For Android i386 Target === You need to make some changes if you want to target on Android i386. 46. Lazarus main menu > Project > Project Options > Paths > Libraries (-Fl): /home/[handoko]/Android/ndk/platforms/android-21/arch-x86/usr/lib/ 47. Lazarus main menu > Project > Project Options > Paths > Target file name (-o): ../libs/x86/libcontrols 48. Lazarus main menu > Project > Project Options > Config and Target > Target file name (-P): i386 49. Lazarus main menu > Project > Project Options > Custom Options: -Xd -XPi686-linux-android- -FD/home/[handoko]/Android/ndk/toolchains/x 86-4.9/prebuilt/linux-x86_64/bin Note: To make fat binary (https://en.wikipedia.org/wiki/Fat_binary), compile as much target as you want before running that build debug/release script. To cancel fat binary producing, delete all things inside [projectname]\libs folder before compiling. ---Edited--- 04-Nov-17:  Cross Compile Android i386 section, sample-apk.zip and screenshot. 31-Mar-18:  Step #18 - info about depreciation of "android" tool. ---------------------------------------------------------------------- mai · 2017-10-31 19:13 what the heck is LAMW? ---------------------------------------------------------------------- Handoko · 2017-10-31 19:21 LAMW (Lazarus Android Module Wizard) is one of the way to create Android app using Lazarus. So far, there are several ways to do Android programming in Lazarus, LAMW is the easiest I think. There other options are: - FPC JVM http://wiki.lazarus.freepascal.org/FPC_JVM_Android_Development - Laz4Android This package uses Custom Drawn Interface. https://sourceforge.net/projects/laz4android/ - LazToApk This tool will help you automatically download Laz4Android, Android SDK & NDK, configure and perform cross compiling. https://sourceforge.net/projects/laztoapk/ - LazSDL2Design Package Similar to LAMW, it has its own Form Designer and components. http://forum.lazarus.freepascal.org/index.php/topic,33008.0.html ---------------------------------------------------------------------- jmpessoa · 2017-10-31 22:16 QuoteSo I write this tutorial, maybe someone will find it useful. Hello Handoko! Great! I wil add your tutorial to LAMW repo... Laz4Android + LAMW  is good, too! Thank you! ---------------------------------------------------------------------- Mike.Cornflake · 2017-10-31 22:45 Quote from: mai on October 31, 2017, 08:13:36 pmwhat the heck is LAMW? http://wiki.lazarus.freepascal.org/LAMW ---------------------------------------------------------------------- mai · 2017-11-01 10:38 Quote from: Mike.Cornflake on October 31, 2017, 11:45:38 pmQuote from: mai on October 31, 2017, 08:13:36 pmwhat the heck is LAMW? http://wiki.lazarus.freepascal.org/LAMW But what the heck does a complete Adroid app then look like? Most important screenshot is missing from your link ! ---------------------------------------------------------------------- DonAlfredo · 2017-11-01 10:55 For your info, I have included two screenshots of a simple Android app that I am currently working at. It scans barcodes and stored them in a mORMot database (local and remote). ---------------------------------------------------------------------- jmpessoa · 2017-11-02 00:00 QuoteBut what the heck does a complete Adroid app then look like? LAMW "maps" allmost all native Android GUI controls APIs. So, the "look" will depend on the design skills... ---------------------------------------------------------------------- Handoko · 2017-11-03 20:30 I added Cross Compile Android i386 section,  sample-apk.zip and screenshot on the first post. ---------------------------------------------------------------------- jmpessoa · 2017-11-03 20:40 Ok. I will update github repo... [Can you post hole project, so I will put in demos folder!] Thank you! ---------------------------------------------------------------------- Handoko · 2017-11-04 14:42 I modified the code a bit, adding more rectangles and change the background color when jButton2 clicked. I wrote the code originally to test jCanvasES2 can or not to handle deep test (glEnable(GL_DEPTH_TEST)) because I found some things not working correctly. The big rectangle will slowly move to the back, it starts at its z position above the small rectangles and when it reached the middle of the screen, the big rectangles will be behind the small rectangles. I don't need this code anymore. It is free, I put it in CC0. You can do anything you like with the code. 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 {Hint: save all files to location: /home/handoko/Projects/Project Software/Android Test/glTest1/jni }unit unit1; {$mode delphi} interface uses  Classes, SysUtils, AndroidWidget, Laz_And_Controls, Laz_And_GLESv2_Canvas,  Laz_And_GLESv2_Canvas_h;  type   { TAndroidModule1 }   TAndroidModule1 = class(jForm)    jButton1: jButton;    jButton2: jButton;    jButton3: jButton;    jCanvasES2_1: jCanvasES2;    jTimer1: jTimer;  procedure AndroidModule1JNIPrompt(Sender: TObject);    procedure jButton1Click(Sender: TObject);    procedure jButton2Click(Sender: TObject);    procedure jButton3Click(Sender: TObject);    procedure jCanvasES2_1GLCreate(Sender: TObject);    procedure jCanvasES2_1GLDown(Sender: TObject; Touch: TMouch);    procedure jCanvasES2_1GLDraw(Sender: TObject);    procedure jTimer1Timer(Sender: TObject);  private    ResHalfX, ResHalfY, ResHalfZ, ResScaleX, ResScaleY, ResScaleZ: Single;    ColorFill, ColorBorder: TRGBA;    procedure SetColorBorderRGBA(const R, G, B: single; const A: Single = 1);    procedure SetColorFillRGBA(const R, G, B: single; const A: Single = 1);    procedure DrawRectHV(const X, Y, sX, sY, W: Single; const Z: Single = 0);  end; var  AndroidModule1: TAndroidModule1; implementation  {$R *.lfm} const  Total             = 100;  ButtonClicked: Byte = 1; var  Xpos:   array[1..Total] of Single;  Ypos:   array[1..Total] of Single;  Xspeed: array[1..Total] of Single;  Yspeed: array[1..Total] of Single; { TAndroidModule1 } procedure TAndroidModule1.AndroidModule1JNIPrompt(Sender: TObject);const  SizeX = 910;  SizeY = 1358;  SizeZ = 1000;var  i: Integer;begin  // Setup screen  SetScreenOrientationStyle(ssPortrait);  ResHalfX := SizeX * 0.5;  ResHalfY := SizeY * 0.5;  ResHalfZ := SizeZ * 0.5;  ResScaleX := 1/ResHalfX;  ResScaleY := 1/ResHalfY;  ResScaleZ := 1/ResHalfZ;  jCanvasES2_1.Screen_Setup(jCanvasES2_1.Width, jCanvasES2_1.Height, xp2D);  SetColorBorderRGBA(0, 0, 0);  // Setup rectangles  for i := 1 to Total do begin    Xpos[i] := Random(770)-385;    Ypos[i] := Random(1000)-500;    Xspeed[i] := Random(7)-3;    Yspeed[i] := Random(7)-3;    if (Xspeed[i] = 0) then Xspeed[i] := 1;    if (Yspeed[i] = 0) then Yspeed[i] := 1;    Xspeed[i] := 3;  end;  // Start timer  jTimer1.Enabled := True;end; procedure TAndroidModule1.jButton1Click(Sender: TObject);begin  ButtonClicked := 1;end; procedure TAndroidModule1.jButton2Click(Sender: TObject);begin  ButtonClicked := 2;end; procedure TAndroidModule1.jButton3Click(Sender: TObject);begin  ButtonClicked := 3;end; procedure TAndroidModule1.jCanvasES2_1GLCreate(Sender: TObject);begin//  jCanvasES2_1.Texture_Load_All;  jCanvasES2_1.Shader_Compile('simon_Vert', 'simon_Frag');  jCanvasES2_1.Shader_Link;end; procedure TAndroidModule1.jCanvasES2_1GLDown(Sender: TObject; Touch: TMouch);begin  // Show touched X, Y  ShowMessage(FormatFloat('0.00', Touch.Pt.X)+', '+FormatFloat('0.00', Touch.Pt.Y));end; procedure TAndroidModule1.jCanvasES2_1GLDraw(Sender: TObject);const  Z: Integer = -500;var  XYs: TXYs;  i:   Integer;begin  glClear(GL_DEPTH_BUFFER_BIT);  glEnable(GL_DEPTH_TEST);  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  glEnable(GL_BLEND);  jCanvasES2_1.MVP:= cID4x4;  jCanvasES2_1.SetMVP(jCanvasES2_1.MVP);   XYs.Cnt := 4;  XYs.Pt[0] := _XY(-1, -1);  XYs.Pt[1] := _XY(-1,  1);  XYs.Pt[2] := _XY( 1,  1);  XYs.Pt[3] := _XY( 1, -1);  jCanvasES2_1.DrawPolyFill(XYs, 0.9, _RGBA(0.5, 1, 0.8, 1), _RGBA(1, 0, 0, 1), 0.05);   XYs.Pt[0] := _XY(-435*ResScaleX, -550*ResScaleY);  XYs.Pt[1] := _XY(-435*ResScaleX,  550*ResScaleY);  XYs.Pt[2] := _XY( 435*ResScaleX,  550*ResScaleY);  XYs.Pt[3] := _XY( 435*ResScaleX, -550*ResScaleY);  if (ButtonClicked = 2) then    jCanvasES2_1.DrawPolyFill(XYs, 0.8, _RGBA(0.5, 0.2, 1, 1), _RGBA(1, 0, 0, 1), 0)  else    jCanvasES2_1.DrawPolyFill(XYs, 0.8, _RGBA(0, 0, 0, 1), _RGBA(1, 0, 0, 1), 0);   Inc(Z);  If (Z > 500) then Z := -500;  SetColorFillRGBA(0, 1, 0);  DrawRectHV(-100, Z, 200, 200, 30, Z);   SetColorFillRGBA(1, 1, 0);  for i := 1 to Total do begin    Xpos[i] := Xpos[i] + Xspeed[i];    Ypos[i] := Ypos[i] + Yspeed[i];    if (Xpos[i] < -400) and (Xspeed[i] <= 0) then Xspeed[i] := 3;    if (Xpos[i] >  370) and (Xspeed[i] >= 0) then Xspeed[i] := -3;    if (Ypos[i] < -600) and (Yspeed[i] <= 0) then Yspeed[i] := Random(3)+1;  if (Ypos[i] >  550) and (Yspeed[i] >= 0) then Yspeed[i] := Random(3)-4;    case ButtonClicked of      1: begin           SetColorFillRGBA(1, 1, 0);           DrawRectHV(Xpos[i], Ypos[i], 50, 50, 5, 50);         end;      2: begin           SetColorFillRGBA(0, 0, 0);           DrawRectHV(Xpos[i], Ypos[i], 50, 50, 5, 50);         end;      3: begin          SetColorFillRGBA(0, 0, 1);          DrawRectHV(Xpos[i], Ypos[i], 50, 50, 5, -100);          end;    end;  end;end; procedure TAndroidModule1.jTimer1Timer(Sender: TObject);begin  jCanvasES2_1.Refresh;end; procedure TAndroidModule1.SetColorBorderRGBA(const R, G, B: single;  const A: Single);begin  ColorBorder.R := R;  ColorBorder.G := G;  ColorBorder.B := B;  ColorBorder.A := A;end; procedure TAndroidModule1.SetColorFillRGBA(const R, G, B: single;  const A: Single);begin  ColorFill.R := R;  ColorFill.G := G;  ColorFill.B := B;  ColorFill.A := A;end; procedure TAndroidModule1.DrawRectHV(const X, Y, sX, sY, W: Single;  const Z: Single);var  X1, Y1, X2, Y2, W2: Single;  X1small, Y1small, X2small, Y2small, X1big, Y1big, X2big, Y2big: Single;  XYs: TXYs;begin  // Make sure (X1, Y1) is the bottom leftmost, to produce clockwise winding  if (sX >= 0) and (sY >= 0) then begin    X1 := X;    Y1 := Y;    X2 := X+sX;    Y2 := Y+sY;  end else    if (sX < 0) and (sY >= 0) then begin      X1 := X+sX;      Y1 := Y;      X2 := X;      Y2 := Y+sY;    end else      if (sX < 0) and (sY < 0) then begin        X1 := X+sX;        Y1 := Y+sY;        X2 := X;        Y2 := Y;      end else        if (sX >= 0) and (sY < 0) then begin          X1 := X;          Y1 := Y+sY;          X2 := X+sX;        Y2 := Y;        end;  // Map the points  W2 := W * 0.5;  X1small := (X1-W2) * ResScaleX;  Y1small := (Y1-W2) * ResScaleY;  X2small := (X2-W2) * ResScaleX;  Y2small := (Y2-W2) * ResScaleY;  X1big := (X1+W2) * ResScaleX;  Y1big := (Y1+W2) * ResScaleY;  X2big := (X2+W2) * ResScaleX;  Y2big := (Y2+W2) * ResScaleY;  XYs.Cnt := 10;  XYs.Pt[0].X := X1big;   XYs.Pt[0].Y := Y1big;  XYs.Pt[1].X := X2small; XYs.Pt[1].Y := Y1big;  XYs.Pt[2].X := X2small; XYs.Pt[2].Y := Y2small;  XYs.Pt[3].X := X2big;   XYs.Pt[3].Y := Y2big;  XYs.Pt[4].X := X2big;   XYs.Pt[4].Y := Y1small;  XYs.Pt[5].X := X1small; XYs.Pt[5].Y := Y1small;  XYs.Pt[6].X := X1small; XYs.Pt[6].Y := Y2big;  XYs.Pt[7].X := X2big;   XYs.Pt[7].Y := Y2big;  XYs.Pt[8].X := X2small; XYs.Pt[8].Y := Y2small;  XYs.Pt[9].X := X1big;   XYs.Pt[9].Y := Y2small;  // Draw it  jCanvasES2_1.DrawPolyFill(XYs, Z*ResScaleZ, ColorFill, ColorBorder, 0);end; end. Although I set the compiling parameters to target ARM devices, it still working correctly on my Intel-based mobile phone. Some maybe interested to know, I done a massive benchmark on my Intel-based phone using this rectangle code (with some modifications) and this is the result: Target CPU (-P)    Method 1     Method 2 i386               980 frames   984 frames arm                740 frames   739 frames It is 20-30% slower running ARM codes on Intel machine. Below are the settings I used to compile the code: QuoteNDK version: r11c NDK API level: 21 (Android 5.0, 5.1) SDK: Android 4.4.2 - API 19 Java: java-8-openjdk-amd64 Path to Workspace: /home/handoko/Projects/Project Software/Android Test Libraries (-Fl): /home/handoko/Android/ndk/platforms/android-21/arch- arm/usr/lib/ Target file name (-o): ../libs/armeabi/libcontrols Target OS (-T): Android Target CPU family (-T): arm Custom options: -Xd -CfSoft -CpARMV7A -XParm-linux-androideabi- -FD/home/handoko/Android/ndk/toolchains/arm-linux- androideabi-4.9/prebuilt/linux-x86/bin ---------------------------------------------------------------------- WayneSherman · 2018-03-31 01:34 Thanks for the installation help. Regarding step #18: Quote from: Handoko on October 31, 2017, 06:29:05 pm18. Install SDK Packages by running ~/Android/sdk/tools/android Note for #18:  I only enable Android 4.4.2 (API 19), you can try other version if you want. The "android" tool has been deprecated and instead this tool should be used: ~/android/sdk/android/bin/sdkmanager BTW, I used this to get a list with full package names yet compact (from here): ./sdkmanager --list --verbose | grep -vP "^Info:|^\s|^$|^done$" I have attached the list of packages.  Which packages do I need to install at a minimum? (platforms;android-19 ?) Thank you. ---------------------------------------------------------------------- Handoko · 2018-03-31 03:22 I admit I'm lazy when things already work so I haven't updated my Android SDK/NDK for a long time. Thank you for the information about the depreciation of "android" tool. I have added some note on the step #18. ---------------------------------------------------------------------- jmpessoa · 2018-03-31 03:36 QuoteWhich packages do I need to install at a minimum? (platforms;android-19 ?) What about "Android-25" + "Buil-Tools" 25.0.3 + Gradle 4.1....  so, you can stay prepared to incoming LAMW 0.8 !! ---------------------------------------------------------------------- WayneSherman · 2018-03-31 04:45 Quote from: jmpessoa on March 31, 2018, 05:36:13 amWhat about "Android-25" + "Buil-Tools" 25.0.3 + Gradle 4.1....  so, you can stay prepared to incoming LAMW 0.8 !! Based on the list provided by "sdkmanager", installation would be like this: ./sdkmanager "platforms;android-25" "build-tools;25.0.3" Some questions please: 1) sdkmanager doesn't list anything with "Gradle" in the name.  Is that installed with the build-tools package? 2) If I install android-25, will my compiled app still work on earlier versions of Android? 3) Does LAMW 0.7 work with android-25? Thanks for your assistance ---------------------------------------------------------------------- jmpessoa · 2018-03-31 04:55 1) No!  And you do not "must have" gradle in LAMW 0.7 ... but,  for LAWW 0.8  "material design" support, yes! for gradle:  https://gradle.org/next-steps/?version=4.1&format=bin 2) Yes! 3) Yes!