Setting up a Xamarin build with Cake

There are a lot of different ways for setting up your continuous delivery pipeline these days. Platforms like Mobile Center and Bitrise offer a complete solution that can be configured very easily. Another solution that’s gaining more popularity is Cake Build. Cake Build also has a lot to offer, but in quite a different way.

Cake is cross-platform build automation system, based on C#.  It’s open source (on GitHub) and became part of the .NET foundation last year. The possibilities with Cake are endless because you can use all the features that C# has to offer. You can even consume NuGet packages in your build script. Cake also has a few siblings called Jake, Make, Rake and Fake which are similar, but use other languages.

When setting up your build with Cake, you need to create a build file which contains your build steps, written in C#. Cake comes with a lot of default build tasks for you to use in your pipeline. A great advantage of having your configuration in a file, is that you can easily move to an other system or environment without having to reconfigure your entire pipeline. Adding this file to your source repository will also enable versioning on your build script, awesome! Cake build tools work on Windows, Linux and on Mac OS X.

To make the writing of your build scripts a lot more pleasant, there is a Visual Studio Code add-in and an Visual Studio add-in. The add-ins integrate Cake in your IDE and allow you to create the required files with a few clicks. Code completion, Intellisense (recently announced) and syntax highlighting are also great features that the add-in has to offer. If that’s not enough, and your build is still failing for some vague reason, you can even debug your build script to find the issue!

Getting started

When setting up your first Cake build, there are 3 files of importance:

  • Bootstrapper file: will download Cake.exe and all it’s dependencies using a PowerShell script for Windows (build.ps1) or a bash script for Mac OS X/ Linux (build.sh). When Cake is already installed with all it’s dependencies, the Cake.exe can also be called directly.
  • Build steps: This file (by default called “build.cake“) contains all the steps that need to be executed for the build to succeed. The build script can be written in a C# Domain-specific language. Because it’s written in C#, you are able to use all the C# features in your script!
    The execution order of the steps can be manipulated by making steps depend on each other, or by setting criteria. This can be achieved by using extensions methods.
  • NuGet packages: All the dependency required for the build to run are defined in a packages config file (tools/packages.config). The listed dependencies will be installed in the tools folder. An example dependency might for example be a unit test runner.

After specifying your build steps and dependencies, you can kick off the build by running the bootstrapper file:

Mac & Linux:

sh build.sh

Windows:

PS> .\build.ps1

Don’t hesitate to give Cake Build a try, you can run it side by side with your current build without modifying your project! My working example is also available on GitHub.

Cake.Recipe
To ease the re-use of build scripts, Cake.Recipe was introduced. Cake.Recipe is a set of build tasks which can be consumed through NuGet. For more info, please visit their website.

Related links:

Code sharing with GIT submodules

When developing software, sharing your code can save up a lot of time and decrease redundancy. To really make this work for your team, it is of great essence to choose a fitting code sharing strategy.

One way to achieve this is by using NuGet to distribute and consume the code in packages. NuGet makes publishing, consuming (a specific version), updating and managing dependencies easy. Although NuGet publishing can be automated, you still need to publish every time when you make a small change in your shared code. When your code is still heavily under construction, this might be less efficient.

These inconveniences were taken in consideration by GIT, and therefor GIT submodules were developed. With GIT submodules it’s possible to clone a (sub)repository in your working repository. This will create a subfolder in your repository where you can use the code from the external repository. Changes made in the submodule are not tracked to the working repository, only to the submodule repository. GIT submodules are especially useful when sharing code across multiple applications. If you only want to share code across platforms, it’s probably more efficient to work in the same repository.

With GIT submodules you’re able to specify in what directory your submodule lives and what version (points to a specific commit) of the shared code you want to use. To explain this in more detail, I will use an example where the (Xamarin) “SubmoduleApp” wants to make use of a “Shared” GIT repository.

  1. First, you need to clone the repository which contains the app (git clone https://github.com/basdecort/SubmoduleApp.git):
  2. After you cloned the source code of the app you are working on, you can add your submodule. Make sure you navigated to the correct folder (and switched to the correct branch) before adding the submodule, then run “git submodule add {repoUrl}”:
  3. When this operation finishes, you probably notice that the submodule was cloned into the specified subdirectory. Although this process created a lot of files in our working directory, GIT only detected 2 file changes. We can verify this by running “git status”: All of the cloned files are tracked to the shared repository and therefor aren’t labeled as new. The two files (.gitmodules & Shared) that are added to the SubmoduleApp repository contain information about the submodule:
    • .gitmodule : information about the remote repository of the module.
    • Shared : this file will point to a specific commit of the submodule. The name of the file depends on the name of the directory of your submodule.By changing the hash, you will point to a different version (commit) of the shared repository.
  4. To make sure everyone uses the submodules in the same way, you should make sure to commit and push these files to the root repository.
  5. At this point you’ve successfully created a submodule! If you followed the exact steps as mentioned above, you end up with the following folder structure:With this folder structure it’s fairly easy to create a reference from the TodoPCL.sln to your Shared project and keep your code completely separated.
  6. After making some changes, just navigate to the correct repository folder (Shared or Todo) and commit your changes from there like you did before. Changes will be applied to the correct repository.

You can find this example on GitHub as well. If you don’t like to work in a terminal, I’d recommend SourceTree. SourceTree is a great tool for working with GIT submodules and is available for Windows and Mac.

Related links:

Symbolicating iOS crashes

Sometimes when your app crashes it can be pretty hard to determine what went wrong, especially when you are unable to reproduce and/or debug the crash. Luckily the device also stores crash logs!

Getting the device logs
There are 2 ways to get your crash log: with xCode or with iTunes. Because not every tester has xCode installed I will also list the steps required for iTunes:

iTunes

  1. Connect device to pc/mac.
  2. Open your device in iTunes and make sure iTunes is synced. This will also transfer your crash logs.
  3. Open the crash log folder:
    1. Windows: %appdata%/Roaming/Apple computer/Logs/CrashReporter/Mobile Device/{your devicename}
    2. Mac: ~/Library/Logs/CrashReporter/MobileDevice/{your devicename}
  4. In this folder you can find the crash logs with the following format “{appname}.crash”.

    xCode

  5. Connect your device to your Mac.
  6. Open xCode and launch the organizer (Window->Devices or Window->Organizer)
  7. Select your device from the list and click “View device logs”.
  8. Find the crash log based on creation time and right click the entry to export. Click export and save the log to your filesystem.

After pulling the logs from the device, you’ll probably notice that these log files on itself don’t contain a lot of useful information. Bummer!

The logs you pulled from the device are unsymbolicated. This means a lot of technical information isn’t included. You can recognize an unsymbolicated crash log when the function names are missing. Fortunately you are able to add this information by symbolicating your log.

Symbolicating
xCode offers tooling to symbolicate your crashes. The location of this tool depends on your version of xCode.

  • xCode 7 & 8:/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash
  • xCode6: Applications/Xcode.app/Contents/SharedFrameworks/DTDeviceKitBase.framework/Versions/A/Resources/symbolicatecrash
  • xCode5: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/PrivateFrameworks/DTDeviceKitBase.framework/Versions/A/Resources/symbolicatecrash

Before you can execute the symbolicatecrash command, you need to set your Developer_Dir enviroment variable:

export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer"

To symbolicate your file, you need to run the “symbolicatecrash” command and pass the previous mentioned files as params. The -o parameter indicates where to write the symbolicated file to.

symbolicate -o "symbolicatedCrash.txt" "MyAppName 2-12-14, 9-44 PM.crash" "MyAppName.app"

Services
Because symbolicating your log requires the exact .app and .DSYM file from the build in which the crash occurred, it’s common to use a crash reporting service. Most of the crash reporting services allow you to upload your app and .DSYM manually or from your continuous delivery pipeline. These services also offer an SDK to catch and log unhandled exceptions (crashes) to their system. Normally you can enable this with one line of code in your app. For example, initializing crash reporting for a Xamarin app with Mobile Center can be done with the following code:


MobileCenter.Start("{Your App Secret}", typeof(Crashes));

In addition to this article, you might also want to check out John Miller’s blogpost on Symbolicating iOS crashes. Great post!

Related links:

HockeyApp: Creating a bridge to the cloud

HockeyApp is an awesome tool when it comes to crash reporting, user metrics, beta app distribution and collecting user feedback. The SDK is very easy to integrate and there also is tooling available to integrate HockeyApp in your CI/CD pipeline.

In 2016, when Microsoft announced (Visual Studio) Mobile Center, it also became clear that HockeyApp will become part of this new full-fledged platform for mobile development. Therefor Microsoft is now focussing on integrating HockeyApp in Mobile Center and HockeyApp itself isn’t getting new features.

If you are currently at the point where you need to choose a tool for crash reporting and user metrics, and you don’t want to use the preview of Mobile Center, HockeyApp is probably still the way to go. One great advantage of HockeyApp is that when Mobile Center becomes general available, the migration will be seamless. Also if you want to analyze and visualize your event data in ways other than are currently available in HockeyApp, you are able to create a bridge to Azure Application Insights. This will allow you to create your own dashboards and get fine-grained control of your data and metrics. You can even export to your own data storage through Application Insights! For now it’s only possible to export events and traces, but exporting crashes is on the roadmap for Mobile Center.

Application Insights
Application Insights is an extensible analytics platform that helps you monitoring your performance and metrics. When connecting HockeyApp to Azure Application Insights the raw data of logged events and traces will become available for querying. Based on these queries you’ll be able to create your own dashboards!

Setting up the connection between HockeyApp and Application Insights is pretty straightforward:

  1. First, create a API in your HockeyApp account settings:
  2. When the API key is created, you need to create a resource in the Azure portal. The Application Insights resource can be found in the Developer Tools category. After selecting Application Insights, the form will show up and ASP.net web application will be selected as default application type. After selecting “HockeyApp bridge app”, the form will change and show the required fields for a HockeyApp bridge. First of all you need to paste the (previously created) API key in the “Token” field. Azure will automatically load your apps from HockeyApp, so you only have to choose an app and fill in the other fields. If you ever created an Azure resource this should be fairly easy.
  3. After clicking Create, you’re all set! Yes, it’s really that easy!
    To see your data you can simply open Application Insights from the Azure portal or navigate directly to https://analytics.applicationinsights.io/ and log in with your Microsoft account.

When your bridge app collected some data, you will be able to start analyzing and visualizing by creating queries. Queries can be created with the Analytics query language, which might be a bit tricky in the beginning, but the documentation will help you get started. To give you a feeling of what it looks like, this query will return all events from the US:

 customEvents | where client_CountryOrRegion == "United States" 

By default the data is visualized in a table, but with a few clicks you can transform this into a beautiful chart. You can even customize these visualizations to suit your needs!

Related links:

Talking Bluetooth (Low Energy) with Xamarin

With the rising popularity of IoT (Internet of Things), it becomes more common that you need to communicate with hardware. In most cases you can accomplish this with network connectivity, but you might want to consider Bluetooth Low Energy (BLE) as well. As the name suggests, BLE uses a lot less energy in comparison to classic Bluetooth. Less energy consumption means that it’s possible to use smaller (and portable) batteries what might be very useful for IoT devices. When deciding if BLE suites your needs, you should take a few things in consideration:

  • Bandwidth: Bluetooth is less suitable for transmitting large sets of data, especially BLE.
  • Costs: in comparison to network adapters, bluetooth is more affordable.
  • Range: the range of your device really depends on the bluetooth device and version that is used by the hardware and the smartphone/tablet. The environment might also impact the range. At a maximum you can reach 100 meters, but the average will be around 15 meters.
  • Power consumption: you can use BLE to save energy, but this will limit the throughput. If you are transferring small packages this might be interesting. The classic way of bluetooth communication is also less consuming than network connectivity.

Instead of writing the bluetooth code for every platform, you can choose to use a plugin that provides an abstraction layer so it’s possible to access BLE from shared code. At the time of writing, I find Bluetooth LE Plugin for Xamarin the best pick for the job. The plug-in is easy to implement and is continuously getting updates. If you want to use classic bluetooth you might want to look into some other plugins. in this post I will focus on Bluetooth LE Plugin for Xamarin.

When working with BLE, there are 3 (most important) different bluetooth abstraction layers:

  • Services: A service contains one or more characteristics. For example, you could have a service called “Heart Rate service” that includes characteristics such as “heart rate measurement.” Each service has it’s unique pre-defined 16-bit or 128-bit UUID.
  • Characteristics: A characteristic is some kind of endpoint for a specific part of the service. Just like a service, the characteristic also has a UUID. Characteristics support a range of different interactions: read, write, notify, indicate, signedWrite, writableAuxilliaries, broadcast.
  • DescriptorsDescriptors are defined attributes that describe a characteristic value. For example, a descriptor might specify a human-readable description, an acceptable range for a characteristic’s value, or a unit of measure that is specific to a characteristic’s value.

Now, let’s dive into some code samples! To give you a taste of what the plugin has in store for you, some snippets:

Scan for BLE devices (advertisements)
The Adapter class makes it possible to detect devices in the surrounding area. You can simply get an instance of the adapter and start scanning with the following code:

 var adapter = CrossBluetoothLE.Current.Adapter;
adapter.DeviceDiscovered += (s,a) =+ deviceList.Add(a.Device);
await adapter.StartScanningForDevicesAsync(); 

Connect to device
When you’ve found the device you want to connect to, you are able to initiate a connection with the device. After connecting successfully to a device you are able to get the available characteristics and start sending requests or start retrieving notifications from the device. When the bluetooth device doesn’t receive any requests for a specific period (may differ per device), it will disconnect to save battery power. After getting a device instance (with the previous sample), it’s fairly easy to setup a connection:

 try
{
    await _adapter.ConnectToDeviceAsync(device);
}
catch(DeviceConnectionException e)
{
// ... could not connect to device
}

Note: a device scan is only necessary when connecting to the device for the first time. It’s also possible to initiate a connection based on the UUID of the device.

Get services, characteristics, descriptors
As described above, a service is the first abstraction layer. When an instance of a service is resolved, the characteristics of this specific service can be requested. The same goes for a characteristic and his descriptors. On a characteristic you can request the descriptors.

The different abstraction layers can be requested in a similar way, GetAll or GetById:

// Get All services and getting a specific service
var services = await connectedDevice.GetServicesAsync();
var service = await connectedDevice.GetServiceAsync(Guid.Parse("ffe0ecd2-3d16-4f8d-90de-e89e7fc396a5"));

// Get All characteristics and getting a specific characteristic
var characteristics = await service.GetCharacteristicsAsync();
var characteristic = await service.GetCharacteristicAsync(Guid.Parse("37f97614-f7f7-4ae5-9db8-0023fb4215ca"));

// Get All descriptors and getting a specific descriptor
var descriptors = await characteristic.GetDescriptorsAsync();
var descriptor = await characteristic.GetDescriptorAsync(Guid.Parse("6f361a84-eeac-404c-ae48-e65b9cba6af8"));

Send write command
After retrieving an instance of the characteristic you’re able to interact with it. Writing bytes for example:

await characteristic.WriteAsync(bytes);

Send read command
You can also request information from a characteristic:

var bytes = await characteristic.ReadAsync();

Pretty easy, right? To get you started, you can find an example project on the Bluetooth LE Plugin GitHub page. Although this seems pretty simple,  I’ve experienced some difficulties in making it rock solid. Some tips to improve your code:

  • Run bluetooth code on main thread.
  • Don’t scan for devices and send commands simultaneously, also don’t send multiple commands simultaneously. A characteristic can only execute one request at a time.
  • Adjust ScanMode to suit your use case.
  • Don’t store instances of characteristics or services.

Related links:

Microsoft Build: The future of Xamarin

On the second day of the Microsoft Build conference, during the Keynote, Microsoft had some awesome announcements related to Mobile development. In a following session James Montemagno and Miguel De Icaza got into more detail and even showed more epic new features. As always to two put on a great show while presenting!

Together with my colleague Marco, I’ll cover announcements made at the Microsoft Build conference in a series of blogposts. You can also read these posts on his blog.

Xamarin Live Player
When Xamarin Live Player (XLP) was announced during the Build keynote, most of the audience was pleasantly surprised. Until now developing on Windows for iOS was a serious hassle because it required a Mac to compile the app. This setup works well when you have an expensive Mac and a fast and reliable network, but in a lot of scenarios these builds take up a lot of time.

With XLP you don’t need a Mac build host anymore! You just install the Xamarin Live Player app from the App Store or Play Store, pair your device in Visual Studio and boom! You’re ready to debug on the device. Just select your device (annotated with “Player”) en hit run:

Besides the build improvements XLP has more to offer! You can also modify your Xamarin.Forms or Xamarin.Classic app while debugging so you can easily test changes to your app without stopping and restarting the debug process.
This will really speed up the development! To achieve this you first have to open the view you want to debug live. For now a Xamarin.Forms Xaml and iOS storyboards are supported, when XLP becomes GA all types of views should be supported. After opening your view file, you can run the with Visual Studio by clicking “Run -> Live Run Current View” on Mac or “Tools -> Xamarin Live Player -> Live Run Current View” on Windows.

XLP is still in preview and after some testing we are still experiencing a few difficulties. If you want to give XLP a try, you’re probably best of using the examples provided by James Montemagno.

Fastlane
If you’ve ever developed an app for iOS you probably felt the pain of having to provision your app in the Apple Developer Portal. Although there is a good (and very long) read on how to accomplish this, you don’t want to waste any time on this. This is where Fastlane comes to the rescue. With Fastlane tools installed you are able to provision your app with a few clicks in Visual Studio! Fastlane also comes in handy when releasing your app to the Stores. It handles all tedious tasks, like generating screenshots, dealing with code signing, and releasing your application.

Xaml standard 1.0
During the Build Conference Microsoft also introduced a new standard for XAML, called XAML Standard 1.0. The standard will describe a specification for cross-platform user interfaces for both UWP and Xamarin.Forms. As for now, XAML Standard is in a very early stage and Microsoft encourages developers to contribute to their specification. 1.0 should become available later this year.

Bindings simplified
Xamarin was already supporting usage of native libraries with Android binding and iOS binding projects. Because of the complex nature of binding projects, Xamarin released the CocoaPods Importer which will simplify importing CocoaPods with a few clicks. With this importer you can easily transform a CocoaPods library to a .NET library.

iOS Extensions
When you’ve created extensions for your app, these extensions will run in a separate process. Therefor the Xamarin runtime was included for every extension. With the latest version of Xamarin, the runtime is only included once for all your extensions. This will result in a smaller app size and improved performance. The latest version of Visual Studio also allows multi-process debugging, that will come in handy when debugging your app combined with your extensions.

AOT for Mac and Android, Hybrid mode
The compilation process of Xamarin.Android and Xamarin.iOS apps was quite different until now. One big difference was that Android was compiled Just In Time, iOS was compiled Ahead Of Time. After the compilation of iOS apps, the LVVM optimizes the generated code to get high performance. Xamarin announced to also start supporting AOT for Android and Mac apps, that will result in better performance. When you compile AOT you might lose some flexibility (for example: no dynamic code loading), and therefor Xamarin also introduced an Hybrid mode. The Hybrid mode will work for platforms that support AOT as well as JIT. It will compile AOT, but also add the bits needed for JIT.

Embedinator-4000

Embedinator-4000​
While the Xamarin platform mostly focuses on writing code in C# and compiling this to a native application, the Embedinator takes a bit of a different approach. The Embedinator makes it possible to write your code in C# and then compile this into a framework library for Java, Swift, Objective-C or C/C++. Therefor you can easily share your C# code with truly native apps. Miguel De Icaza promised that more languages will be added. As for now, the Embedinator can be used from command line, in the future this will be integrated in Visual Studio.

SkiaSharp
SkiaSharp is a cross-platform 2D graphics API for .NET platforms based on Google’s Skia Graphics Library (which is used by apps like Google Chrome). Xamarin announced that it will be supporting Android, iOS, Mac, UWP, tvOS and Windows. Also support for SVG files is added in the latest release. James showed an awesome demo of The Kimono designer which is build on top of SkiaSharp.

Xamarin.IoT
The latest alpha of Xamarin also contains support for Linux based IoT devices! It will add a new project template for Xamarin.IoT and allow you to deploy and debug your IoT app remotely. Debugging will work similar to debugging Xamarin applications. The IoT Hub SDK will make it easy to communicate with your Azure IoT Hub. The library supports communication with MQTT and AMQP message queues.

Mobile Center
Microsoft is putting a lot of effort in making Mobile Center a full fletched CI/CD solution. With the latest release they added support for UWP and the ability to send push notifications to Android or iOS applications. Mobile Center is still in preview, but is expected to become GA later this year.

Project Rome for iOS
Last year Microsoft announced Project Rome SDK for Android. This year at the Build conference Microsoft also announced the iOS SDK. Project Rome creates a bridge between the different platforms for a seamless user experience. The SDK allows developers to start and control apps over platforms and devices.

If you have any comments or want to share your experience, don’t hesitate to contact me on Twitter.

Related links:

 

Microsoft Build: VS4Mac

Last week I travelled to Seattle to attend the Microsoft Build conference. On the first day of the conference there were a lot of cool announcements related to AI, IoT, Azure and more, but Xamarin wasn’t mentioned at all. Slightly related to Xamarin development was the release of Visual Studio for Mac.

Together with my colleague Marco, I’ll cover announcements made at the Microsoft Build conference in a series of blogpost. You can also read these posts on his blog.

In november Microsoft announced the availability of Visual Studio for Mac (VS4Mac) at Microsoft Connect();-event. In the beginning, MonoDevelop was the IDE to develop C# on a Mac, which later converted to Xamarin Studio (XS). But since the Build-conference this week, VS4Mac has gone GA which made it the prime IDE for C# developers on MacOS. Because of this, XS is discontinued and VS4Mac is the way to go. Awesome!

VS4Mac isn’t just a rebrand of XS, is has tons of new features added. When it was Xamarin Studio, you would be able to build apps, games & services for mobile using the technology from Xamarin. Now that it has turned into Visual Studio, you can even make Web and Cloud applications that you can deploy on Microsoft Azure. But that’s not all: VS4Mac also has C# 7.0 support! You’ll now be able to create stuff like Local functions and more of the great stuff C# 7.0 brings us (all running on Mono 5.0).

When creating a Native Mobile App in VS4Mac, you’ll now have the option to add a Mobile Backend, which adds a ASP.NET Core Web API project to the solution as well. You’ll get three different heads in the solution: The .Droid and .iOS projects (for Android and iOS respectively) and a new, .MobileAppService backend.

Visual Studio for Mac

The project template already comes with a small example to show you on how the projects work together. When running the .MobileAppService project, a web server will start on a certain port (in my example: 52599) which will cause Swagger UI to start up. And now the awesome part: VS4Mac supports Multi-process debugging as well! This means that you can debug the .iOS (or .Droid.) project and .MobileAppService project at the same time, jumping back and forth from front-end to back-end code.

By default, the Mobile projects use a MockDataStore that doesn’t make a connection to the .MobileAppService project. Luckily, it’s pretty simple to connect them to eachother and see the multi-process debugging in action. Take the following steps:

  1. Open up the App.cs file in the Shared project
  2. Set the UseMockDataStore boolean to false
  3. Make sure the BackendUrl has the correct port number

Now both the front- & back-end solutions are communicating with eachother, which you can simply prove by setting breakpoints in both solutions and checking the data. Now you’ll be able to create a full solution with a front- and back-end in the same IDE!

Visual Studio for Mac

In the example above you’ll see the ItemsViewModel , a class within the .iOS solution trying to retrieve the data. It jumps to the ItemController, a class within the .MobileAppService project to provide that data back to iOS. Being able to debug across these different threads allows developers to debug solutions quickly.

Other than an ASP.NET Web API, we’re also able to create a website with ASP.NET MVC or Web Forms. Since VS4Mac is running on Roslyn, syntax highlights for HTML and CSS is available. Even the Razor Syntax is supported, making VS4Mac your one-stop shop for Mobile and Web development as well!

Visual Studio for Mac

But it doesn’t stop there – there’s even support for Docker (in Preview) for those that like to play around with Containers. If you’re using Azure Functions to create a Serverless Architecture, you’re covered. If you’re a user of Unity, selecting a *.cs file now automatically opens up VS4Mac as well. With all this functionality already in VS4Mac, it doesn’t matter if you’re using Windows or MacOS!

As far as we know now, it won’t have an exact feature parity with Visual Studio on Windows. Developing UWP on MacOS wouldn’t make much sense as well as developing MacOS apps on Windows doesn’t make sense. But more and more functionality (especially Azure support) will be ported to VS4Mac soon, making it possible to have all the functionality you need to develop C# on MacOS. Go ahead and try it out yourself!

Related links: