Disclaimer: this is an automatic aggregator which pulls feeds and comments from many blogs of contributors that have contributed to the Mono project. The contents of these blog entries do not necessarily reflect Xamarin's position.

December 8

Vehicle Smart Solves an Everyday Problem with Five-Star Xamarin Apps

From life-saving technology to small daily conveniences, mobile developers everywhere are creating apps that make our lives easier, better, and safer. Vehicle Smart, for example, allows UK residents to quickly check annual vehicle safety and emissions permit status, view upcoming tax deadlines, verify vehicle history, store insurance information, and more. Prior to launch, individuals often purchased vehicles that were out of compliance, potentially emitting hazardous chemicals and damaging the environment or, at the very least, incurring fines for past-due fees.

Born out of their own frustration with market offerings, the Vehicle Smart team, comprised of just three developers, recognized a need and shipped their apps in only two months. Since launch, the apps have been wildly successful, and the team created a corporate entity (Vehicle Smart Ltd.) to continue to add more features and generate revenue.

Today, we’ve invited Rob Wilson, co-founder of Devology, Ltd. and passionate Xamarin developer, to share how Vehicle Smart went from idea to five-star app.

Tell us a little bit about your company and role. Have you always been a developer?

I’ve been a developer since my teens, when I wrote 8-bit MSX computer games. From there, I joined General Dynamics and spent 18 years in the defense sector. These days, I develop websites, web apps, web services, and mobile apps for all use cases, from social sharing to team safety.

I co-founded Devology Ltd. with my cousin, Michael Glazebrook, to write our own software products. In our second year of business, we connected with James English, who was in the process of transitioning from 17 years in government software development to commercial web and mobile apps.

Initially, James focused on iOS using Swift, but found development frustrating and slow. After a couple of weeks, James asked me for some C# and Xamarin training and support, and he quickly saw Xamarin’s huge potential and the benefits of cross-platform development, especially with Xamarin.Forms. From there, we formed Vehicle Smart Ltd, a 50/50 split between Devology Ltd. and JVE Ltd., James’ company.

Due to my experiences developing mobile apps, I was able to offer advice, consultancy, and pair-programming (working side-by-side), utilizing Xamarin.Forms. James, a Certified Usability Analyst, spent his years in the defense industry crafting and fine-tuning highly nuanced jet weapon displays. With my technical knowledge and his ability to create powerful and clean UIs, we’ve attracted positive praise from our users. Vehicle Smart is now our number one performing app, with only a few months’ part-time development!

Vehicle Smart app on iPhone

Tell us about your app and what prompted you to build it.

Vehicle Smart (available on Android and iOS) is the smart way to check MOT and TAX information for any UK vehicle. Vehicle Smart provides free, up-to-date data for all UK vehicles, allows users to manage their vehicles through the “My Garage” and “My Services” features, and performs mileage analysis to spot mileage discrepancies between dealer reports and the MOT database. In our latest update, users can set important date reminders, such as MOT and tax expiry, insurance renewals, and service dates, as well as save vehicle-specific details, like oil type, tire sizes, and more, for easy access.

We also expose our JSON web-service API to allow other developers to access UK vehicle and driver agency (the DVLA and DVSA) data in an easy-to-consume JSON format, rather than scraping the HTML themselves. The agencies hold all vehicle and driver information and record every single vehicle test, so this is a vast amount of data.

Vehicle Smart was born out of James’ frustration with the current market offering and burning desire to create a product. He’s passionate about cars and bikes, and had used many mobile apps over the years, often two or three at a time, to manage and obtain the vehicle information that he needed. There wasn’t a single app that could do everything he was looking for and do it well.

Little did we know how popular our app would be! In under four months, we had over 100,000 users and more than 1,000 five-star reviews. We’ve had lots of feedback, ranging from how intuitive and simple we’ve made the user interface to amazement at how much data we provide. Numerous users thank us after they’ve discovered their tax or MOT has expired, letting us know that we’ve saved them from driving illegally, and avoiding hefty fines, with our app!

Why did you choose Xamarin?

Due to my previous mobile experiences, I was confident that Xamarin.Forms would be the ideal solution, allowing us to reuse our UI layer and business logic across platforms. I considered Xamarin.iOS and Xamarin.Android, but determined that Xamarin.Forms could easily handle our user interface needs.

I had used C# for some time, so when I started using Xamarin, I just extended that knowledge as I went on.

What do you think about when you hear “native app”? How did Xamarin help you accomplish your definition of “native”?

To me, native means hooking into all of the low-level platform SDK libraries, without restriction, which allows the UI to look and feel native. This is very important to me. I’ve had arguments with colleagues that felt HTML5 provided excellent UI support, but I saw glitchy animations and weird behaviors that yanked me out of the typical phone user experience, especially with iOS 7’s big look-and-feel update, aging the supposedly ‘native’ HTML5 implementations overnight.

Xamarin gives developers the right mix. You can use Xamarin.iOS / Xamarin.Android or Xamarin.Forms, and call through to the native libraries. Xamarin.Forms has gotten better and better, including improved support for native user interface controls, without needing custom renderers. My biggest problem right now is finding time to keep up with its evolution!

How long did it take to ship your app, from design to deploy?

From initial concept through to market, it took us eight weeks. James and I poured our spare hours into the design, development, testing, and deployment to the Google Play Store. A few days later, we deployed to iOS.

I’d estimate that we’ve reused 95% code across platforms, including UI and business logic. A shared services folder defines our UI on both platforms, including local notifications, persistence, and logging.

Since our launch, we’ve continued to release updates, including In-App Purchases and premium upgrades, expiration reminder notifications (7 days for freemium users, 14 and 30 days for paid users), saving vehicle information and overall improvements based on users’ feedback. We’re also actively working on our Windows app.

Without Xamarin, you could easily triple the amount of time it would have taken us to get to market, perhaps more. We would have needed to learn the Android Studio tooling, as well as all the Activity stuff that Xamarin.Forms shields you from. Plus, we’d then have to develop in Java for Android, Swift for iOS, and C# for Windows.

Why is mobile quality important?

We lose sleep over this regularly! An app’s ability to perform will defines its success, and delivering a high quality product has been key to our success so far. Apps that are full of bugs and crash often tend to be dismissed very quickly, and winning a user back becomes twice as hard, if not impossible. When you’re a new app on the market, it’s imperative your product is 99% stable. First impressions count for everything.

How do you use HockeyApp?

HockeyApp has been invaluable. It helps us capture crash logs, see stack traces, helping us track down a number of bugs that our users were experiencing, but we hadn’t seen ourselves.

We can see crash frequency, which determines the priority that they should be fixed. Based on impact, we decide whether we hold back for another beta test, or whether we need to go live with an urgent fix.

We also like the idea of adding analytics to see what features people are using the most and to get insights about which features the haven’t yet discovered.

What have your users said about your app?

We said this before, but the response has been amazing. Our friends and family love it, but they’re biased so we rely on the amazing reviews we’ve received for both Android and iOS.

We’ve learned that users sometimes struggle to leave feedback in the App Store, so, while our iOS version has only 47 reviews, all have been five-stars!

What advice do you have for developers who are just starting out or investigating mobile development? Any best resources?

Personally, I learn a little, code a little, learn a little more, write tons… refactor.

My main resource is the official Xamarin documentation, and I find the Xamarin Forums invaluable. The community is fantastic, and I contribute when I have time. Xamarin’s blog post are great for keeping up-to-date about new features, the Charles Petzold book is also good, and StackOverflow is always an amazing resource. With these options, my questions are always answered.

If you’re an enterprise, be careful not to over-analyze or over-design. Avoid the waterfall model in exchange for an agile approach. For us, we try to have a sprint that captures a large feature and some bug fixes. We avoid unnecessary documentation like the plague, using Trello as our go-to place to capture all project details.

Be warned: users can be fussy and you’ll need to be on top of their reviews. Don’t assume you know all of the answers. Get a version out early, and get feedback from your customers.

In summary, just start. Don’t get paralyzed, trying to find the perfect way of doing things from the outset. Make mistakes and learn from them.

To learn how our customers around the world are building amazing apps, visit xamarin.com/customers, and start building your own today at xamarin.com/download.

The post Vehicle Smart Solves an Everyday Problem with Five-Star Xamarin Apps appeared first on Xamarin Blog.

December 7

Google Awareness API for Android: Query and React to Signals

awareness-apiGoogle Play services offers a plethora of amazing APIs for developers to integrate into their iOS and Android applications. For Android developers, specifically, there are several more APIs available that can give you even more power and integration with the Android OS when developing apps for the platform. One of the newest APIs, Awareness, brings together seven different location and context signals into a single easy to use API, including time, location, places, beacons, headphones, activity, and even weather. The NuGet package for the Awareness API launches alongside our release of Google Play services 9.6.1 (32.961.0) for Xamarin.

The Awareness API offers two different ways to get insight to these signals, the Fence and the Snapshot APIs. The Fence API allows you to react to changes in the user’s environment and the signals. You can create multiple conditions that need to be met and when they occur, you receive a callback to react to them. The Snapshot API on the other hand, which we’ll look at today, gives you direct access to the signals from one simple asynchronous API. In addition to being a simple API, the Awareness API delivers better battery performance and memory usage due to its intelligent caching and cross-app optimizations.

snapshotandfence

Install the Awareness NuGet

The first step to accessing the Awareness APIs is to add the Google Play services – Awareness NuGet to your Xamarin.Android application. As of this blog post, the current version is 32.961.0. The easiest way to find the NuGet is to directly enter the package name Xamarin.GooglePlayServices.Awareness. The additional dependencies of Google Play services Places, Location, Base packages, and required Support Packages will also come along when the NuGet is added.

addnuget

Register for API Keys

Google Play services often require a unique API key for each application using them. These are created and enabled in the Google API Developer Console. First create a new project:
1-new-project

Once it is created, you’ll want to enable three different APIs:

  • Awareness API
  • Google Places API for Android (for Places API)
  • Nearby Messages API (for Beacons API)

2-add-apis

You’ll need to enter your application’s package name and the keystore’s SHA1 you’re using for debug and release when ready to deploy to the app store to register these. You can read through Obtaining your Signing Key Fingerprint in our Android documentation.

Simply create new credentials using these keys.
3-credentials

Add Keys to the Android Manifest

Once you have registered for the APIs, you’ll receive a unique API Key that needs to be added to your Android Manifest file. It’s the same API Key for each of the meta-data tags that we’ll add to the application node, which will look like this:


    
    
    

Create GoogleAPIClient

With all of the API Key registration out of the way, it’s now time to actually start using the Awareness API. To use any Google Play service API, we’ll need to create a GoogleApiClient. First let’s bring in a few namespaces:

using Android.Gms.Common.Apis;
using Android.Gms.Awareness;
using Android.Gms.Awareness.State;
using Android.Gms.Extensions;

Now, in our Activity, we can create and connect to the GoogleApiClient:

public class MainActivity : Activity
{
  GoogleApiClient client;
  protected async override void OnCreate(Bundle bundle)
  {
    base.OnCreate(bundle);
    client = await new GoogleApiClient.Builder(this)
                       .AddApi(Awareness.Api)
                       .AddConnectionCallbacks(() =>
                        {
                          //Connected Successful
                        })
                        .BuildAndConnectAsync((i) =>{ });
  }
}

Query Signals

We can now start using the API to query signals, such as headphones.

var headPhones = await Awareness.SnapshotApi.GetHeadphoneStateAsync(client);
if (headPhones?.Status?.IsSuccess ?? false)
{
  if(headPhones.HeadphoneState.State == HeadphoneState.PluggedIn)
    Debug.WriteLine(Headphones plugged in");
  else
    Debug.WriteLine(Headphones not plugged in");
}
else
{
  Debug.WriteLine("Could not get headphone state");
}

Other signals besides headphones require additional permissions such as location and activity recognition. We must add two specific permissions to the Android Manifest:


To check and request permissions, we can use the Permissions Plugin that helps abstract the functionality into a simple call. If we want to query the location and weather, we can use the Permissions Plugin along side the Awareness API:

//Check and request permissions
var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Location);
if (status != PermissionStatus.Granted)
{
  var results = await CrossPermissions.Current.RequestPermissionsAsync(Permission.Location);
  if (results[Permission.Location] != PermissionStatus.Granted)
    return; //handle rejection
}
//Get current location
var location = await Awareness.SnapshotApi.GetLocationAsync(client);
if (location?.Status?.IsSuccess ?? false)
  Debug.WriteLine($"Location: {location.Location.Latitude},{location.Location.Longitude}");
//Get weather information
var weather = await Awareness.SnapshotApi.GetWeatherAsync(client);
if (weather?.Status?.IsSuccess ?? false && weather.Weather != null)
{
  Debug.WriteLine($"Temperature: {weather.Weather.GetTemperature(1)} ";
  Debug.WriteLine($"Humidity: {weather.Weather.Humidity}%";
  Debug.WriteLine($"Feels Like: {weather.Weather.GetFeelsLikeTemperature(1)} ";
  Debug.WriteLine($"Dew Point: {weather.Weather.GetDewPoint(1)} ";
}

We can even take it a step further and detect the user’s current activity, such as running or cycling, by requesting the Detected Activity:

var detectedActivity= await Awareness.SnapshotApi  .GetDetectedActivityAsync(client);
if (detectedActivity?.Status?.IsSuccess ?? false)
{
  var probablyActivity = detectedActivity?.ActivityRecognitionResult ?.MostProbableActivity;
  Debug.WriteLine(probablyActivity?.ToString() ?? "No activity");
}

Learn More

The Awareness API is extremely powerful and at the same time extremely energy efficient when querying signals on the device. You can download a full source code example from my GitHub page that walks through using each of the Snapshot APIs, and you can also learn more about the Awareness API from the Google Developer portal.

The post Google Awareness API for Android: Query and React to Signals appeared first on Xamarin Blog.

December 6

Webinar Recording | Get Started with Xamarin and Microsoft Azure

Whether you’re a new mobile developer or an experienced enterprise team lead, Microsoft’s Azure App Service and Xamarin can provide you with everything you need to build engaging Android, iOS, and Windows apps.

In this previously recorded webinar, Microsoft Program Manager Mike James shows you how to easily add powerful web services and mobile essential features to your Xamarin apps by leveraging the power of Azure App Service and your existing .NET skills.

In the webinar recording, you will:

  • Learn how to deploy your first App Service
  • See the .NET Client SDK in action
  • Integrate with data and business systems, on-premises and in the cloud
  • Enhance your apps with push notifications, user authentication, and more
  • Add data and intelligence APIs to deepen user engagement
  • Get the sample app code and documentation you need to get started

 

The post Webinar Recording | Get Started with Xamarin and Microsoft Azure appeared first on Xamarin Blog.

Secure USB boot with Debian

Foreword

The moment you leave your laptop, say in a hotel room, you can no longer trust your system as it could have been modified while you were away. Think you are safe because you have a crypted disk? Well, if the boot partition is on the laptop itself, it can be manipulated and you will not notice because the boot partition can't be encrypted. The BIOS needs to access the MBR and boot loader and that loads the Linux kernel, all unencrypted. There has been some reports lately that the Linux cryptsetup is insecure because you can spawn a root shell by hitting the enter key for 70 seconds. This is not the real threat to your system, really. If someone has physical access to your hardware, he can get a root shell in less than a second by passing init=/bin/bash as parameter to the Linux kernel in the boot loader regardless if cryptsetup is used or not! The attacker can also use other ways like booting a live system from CD/USB etc. The real insecurity here is the unencrypted boot partition and not some script that gets executed from it. So how to prevent this physical access attack vector? Just keep reading this guide.

This guide explains how to install Debian securely on your laptop with using an external USB boot disk. The disk inside the laptop should not contain your /boot partition since that is an easy target for manipulation. An attacker could for example change the boot scripts inside the initrd image to capture your passphrase of your crypted volume. With an USB boot partition, you can unplug the USB stick after the operating system has booted. Best practice here is to have the USB stick together with your bunch of keys. That way you will disconnect your USB stick early after the boot as finished so you can put it back into your pocket.

Secure Hardware Assumptions

We have to assume here that the hardware you are using to download and verify the install media is safe to use. Same applies with the hardware where you are doing the fresh Debian install. Say the hardware does not contain any malware in the form of code in EFI or other manipulation attempts that influence the behavior of the operating system we are going to install.

Download Debian Install ISO

Feel free to use any Debian mirror and install flavor. For this guide I am using the download mirror in Germany and the DVD install flavor.

wget http://ftp.de.debian.org/debian-cd/current/amd64/iso-dvd/debian-8.6.0-amd64-DVD-1.iso

Verify hashsum of ISO file

To know if the ISO file was downloaded without modification we have to check the hashsum of the file. The hashsum file can be found in the same directory as the ISO file on the download mirror. With hashsums if a single bit differs in the file, the resulting SHA512 sum will be completely different.

Obtain the hashsum file using:

wget http://ftp.de.debian.org/debian-cd/current/amd64/iso-dvd/SHA512SUMS

Calculate a local hashsum from the downloaded ISO file:

sha512sum debian-8.6.0-amd64-DVD-1.iso

Now you need to compare the hashsum with that is in the SHA512SUMS file. Since the SHA512SUMS file contains the hashsums of all files that are in the same directory you need to find the right one first. grep can do this for you:

grep debian-8.6.0-amd64-DVD-1.iso SHA512SUMS

Both commands executed after each other should show following output:

$ sha512sum debian-8.6.0-amd64-DVD-1.iso
c3883edfc95e3b09152d46ce29a032eed1de71531549aee86bb98dab1528088a16f0b4d628aee8ac6cc420364e208d3d5e19d0dea3576f53b904c18e8f604d8c  debian-8.6.0-amd64-DVD-1.iso
$ grep debian-8.6.0-amd64-DVD-1.iso SHA512SUMS
c3883edfc95e3b09152d46ce29a032eed1de71531549aee86bb98dab1528088a16f0b4d628aee8ac6cc420364e208d3d5e19d0dea3576f53b904c18e8f604d8c  debian-8.6.0-amd64-DVD-1.iso

As you can see the hashsum found in the SHA512SUMS file matches with the locally generated hashsum using the sha512sum command.

At this point we are not finished yet. These 2 matching hashsums just means whatever was on the download server matches what we have received and stored locally on your disk. The ISO file and SHA512SUM file could still be a modified version!

And this is where GPG signatures chime in, covered in the next section.

Download GPG Signature File

GPG signature files usually have the .sign file name extension but could also be named .asc. Download the signature file using wget:

wget http://ftp.de.debian.org/debian-cd/current/amd64/iso-dvd/SHA512SUMS.sign

Obtain GPG Key of Signer

Letting gpg verify the signature will fail at this point as we don't have the public key of the signer:

$ gpg --verify SHA512SUMS.sign
gpg: assuming signed data in 'SHA512SUMS'
gpg: Signature made Mon 19 Sep 2016 12:23:47 AM HKT
gpg:                using RSA key DA87E80D6294BE9B
gpg: Can't check signature: No public key

Downloading a key is trivial with gpg, but more importantly we need to verify that this key (DA87E80D6294BE9B) is trustworthy, as it could also be a key of the infamous man-in-the-middle.

Here you can find the GPG fingerprints of the official signing keys used by Debian. The ending of the "Key fingerprint" line should match the key id we found in the signature file from above.

gpg:                using RSA key DA87E80D6294BE9B

Key fingerprint = DF9B 9C49 EAA9 2984 3258  9D76 DA87 E80D 6294 BE9B

DA87E80D6294BE9B matches Key fingerprint = DF9B 9C49 EAA9 2984 3258 9D76 DA87 E80D 6294 BE9B

To download and import this key run:

$ gpg --keyserver keyring.debian.org --recv-keys DA87E80D6294BE9B

Verify GPG Signature of Hashsum File

Ok, we are almost there. Now we can run the command which checks if the signature of the hashsum file we have, was not modified by anyone and matches what Debian has generated and signed.

gpg: assuming signed data in 'SHA512SUMS'
gpg: Signature made Mon 19 Sep 2016 12:23:47 AM HKT
gpg:                using RSA key DA87E80D6294BE9B
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: Good signature from "Debian CD signing key <debian-cd@lists.debian.org>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: DF9B 9C49 EAA9 2984 3258  9D76 DA87 E80D 6294 BE9B

The important line in this output is the "Good signature from ..." one. It still shows a warning since we never certified (signed) that Debian key. This can be ignored at this point though.

Write ISO Image to Install Media

With a verified pristine ISO file we can finally start the install by writing it to an USB stick or blank DVD. So use your favorite tool to write the ISO to your install media and boot from it. I have used dd and a USB stick attached as /dev/sdb.

dd if=debian-8.6.0-amd64-DVD-1.iso of=/dev/sdb bs=1M oflag=sync

Install Debian on Crypted Volume with USB boot partition

I am not explaining each step of the Debian install here. The Debian handbook is a good resource for covering each install step.

Follow the steps until the installers wants to partition your disk.

There you need to select the "Guided, use entire disk and set up encrypted LVM" option. After that select the built-in disk of your laptop, which usually is sda but double check this before you go ahead, as it will overwrite the data! The 137 GB disk in this case is the built-in disk and the 8 GB is the USB stick.

It makes no difference at this point if you select "All files in one partition" or "Separate /home partition". The USB boot partition can be selected a later step.

Confirm that you want to overwrite your built-in disk shown as sda. It will take a while as it will write random data to the disk to ensure there is no unencrypted data left on the disk from previous installations for example.

Now you need to enter your passphrase that will be used to protect the private key of the crypt volume. Choose something long enough like a sentence and don't forget the passphrase else you can no longer access your data! Don't save the passphrase on any computer, smartphone or password manager. If you want to make a backup of your passphrase then use a ball pen and paper and store the paper backup in a secure location.

The installer will show you a summary of the partitioning as shown above but we need to make the change for the USB boot disk. At the moment it wants to put /boot on sda which is the built-in disk, while our USB stick is sdb. Select /boot and hit enter, after that select "Delete this partition".

After /boot was deleted we can create /boot on the USB stick shown as sdb. Select sdb and hit enter. It will ask if you want to create an empty partition table. Confirm that question with yes.

The partition summary shows sdb with no partitions on it. Select FREE SPACE and select "Create a new partition". Confirm the suggested partition size. Confirm the partition type to be "Primary".

It is time to tell the installer to use this new partition on the USB stick (sdb1) as /boot partition. Select "Mount point: /home" and in the next dialog select "/boot - static files of the boot loader" as shown below:

Confirm the made changes by selecting "Done setting up the partition".

The final partitioning should look now like the following screenshot:

If the partition summary looks good, go ahead with the installation by selecting "Finish partitioning and write changes to disk".

When the installer asks if it should force EFI, then select no, as EFI is not going to protect you.

Finish the installation as usual, select your preferred desktop environment etc.

GRUB Boot Loader

Confirm the dialog that wants to install GRUB to the master boot record. Here it is important to install it to the USB stick and not your built-in SATA/SSD disk! So select sdb (the USB stick) in the next dialog.

First Boot from USB

Once everything is installed, you can boot from your USB stick. As simple test you can unplug your USB stick and the boot should fail with "no operating system found" or similar error message from the BIOS. If it doesn't boot even though the USB stick is connected, then most likely your BIOS is not configured to boot from USB media. Also a blank screen and nothing happening is usually meaning the BIOS can't find a boot device. You need to change the boot setting in your BIOS. As the steps are very different for each BIOS, I can't provide a detailed step-by-step list here.

Usually you can enter the BIOS using F1, F2 or F12 after powering on your computer. In the BIOS there is a menu to configure the boot order. In that list it should show USB disk/storage as the first position. After you have made the changes save and exit the BIOS. Now it will boot from your USB stick first and GRUB will show up and proceeds with the boot process till it will ask for your passphrase to unlock the crypt volume.

Unmount /boot partition after Boot

If you boot your laptop from the USB stick, we want to remove the stick after it has finished booting. This will prevent an attacker to make modifications to your USB stick. To avoid data loss, we should not simply unplug the USB stick but unmount /boot first and then unplug the stick. Good news is that we can automate this unmounting and you just need to unplug the stick after the laptop has finished booting to your login screen.

Just add this line to your /etc/rc.local file:

umount /boot

After boot you can once verify that it automatically unmounts /boot for you by running:

mount | grep /boot

If that command produces no output, then /boot is not mounted and you can safely unplug the USB stick.

Final Words

From time to time you need to upgrade your Linux kernel of course which is on the /boot partition. This can still be done the regular way using apt-get upgrade, except that you need to mount /boot before that and unmount it again after the kernel upgrade.

Enjoy your secured laptop. Now you can leave it in a hotel room without the possibility of someone trying you obtain your passphrase by putting a key logger in your boot partition. All the attacker will see is a fully encrypted harddisk. If he tries to mess with your crypted disk, you will notice as the decryption will fail.

Disclaimer: there are still other attack vectors possible, but they are much harder to do. Your hardware or BIOS can still be modified. But not by holding down the enter key for 70 seconds or by booting a live system.

December 5

Join us for the Xamarin Dev Days Live Virtual Event

Xamarin Dev Days has been a huge hit over the past couple of years. Thousands of developers at over 100 events around the globe have joined in for a Xamarin hands on learn experience, and we can’t thank our amazing community of MVPs, User Group Leaders, and Developers that helped organize, present, and run each of the events enough. We could think of no better way to end this year’s Xamarin Dev Days events than with a huge LIVE virtual Xamarin Devs Days event that everyone can attend!

Join us online on Wednesday, December 14 starting at 9:00 am PT / 12:00 pm ET / 4:00 pm GMT for the last Xamarin Dev Days of the year streamed live on Channel 9. Xamarin Dev Days Live will kick off with several sessions covering native cross-platform development for iOS, Android, and Windows in C# with Xamarin from Xamarin experts, followed by an afternoon immersed in code as attendees follow along at home for a walkthrough of building your first app.

960-x299

Learn more and register at the link below to join us on December 14, 2016 at 9:00 am PT / 12:00 pm ET / 4:00 pm GMT!
 

Register

The post Join us for the Xamarin Dev Days Live Virtual Event appeared first on Xamarin Blog.

December 4

A quick introduction to Flatpak

Releasing ISV applications on Linux is often hard. The ABI of all the libraries you need changes seemingly weekly. Hence you have the option of bundling the world, or building a thousand releases to cover a thousand distribution versions. As a case in point, when MonoDevelop started bundling a C Git library instead of using a C# git implementation, it gained dependencies on all sorts of fairly weak ABI libraries whose exact ABI mix was not consistent across any given pair of distro releases. This broke our policy of releasing “works on anything” .deb and .rpm packages. As a result, I pretty much gave up on packaging MonoDevelop upstream with version 5.10.

Around the 6.1 release window, I decided to take re-evaluate question. I took a closer look at some of the fancy-pants new distribution methods that get a lot of coverage in the Linux press: Snap, AppImage, and Flatpak.

I started with AppImage. It’s very good and appealing for its specialist areas (no external requirements for end users), but it’s kinda useless at solving some of our big areas (the ABI-vs-bundling problem, updating in general).

Next, I looked at Flatpak (once xdg-app). I liked the concept a whole lot. There’s a simple 3-tier dependency hierarchy: Applications, Runtimes, and Extensions. An application depends on exactly one runtime.  Runtimes are root-level images with no dependencies of their own. Extensions are optional add-ons for applications. Anything not provided in your target runtime, you bundle. And an integrated updates mechanism allows for multiple branches and multiple releases parallel-installed (e.g. alpha & stable, easily switched).

There’s also security-related sandboxing features, but my main concerns on a first examination were with the dependency and distribution questions. That said, some users might be happier running Microsoft software on their Linux desktop if that software is locked up inside a sandbox, so I’ve decided to embrace that functionality rather than seek to avoid it.

I basically stopped looking at this point (sorry Snap!). Flatpak provided me with all the functionality I wanted, with an extremely helpful and responsive upstream. I got to work on trying to package up MonoDevelop.

Flatpak (optionally!) uses a JSON manifest for building stuff. Because Mono is still largely stuck in a Gtk+2 world, I opted for the simplest runtime, org.freedesktop.Runtime, and bundled stuff like Gtk+ into the application itself.

Some gentle patching here & there resulted in this repository. Every time I came up with an exciting new edge case, upstream would suggest a workaround within hours – or failing that, added new features to Flatpak just to support my needs (e.g. allowing /dev/kvm to optionally pass through the sandbox).

The end result is, as of the upcoming 0.8.0 release of Flatpak, from a clean install of the flatpak package to having a working MonoDevelop is a single command: flatpak install --user --from https://download.mono-project.com/repo/monodevelop.flatpakref 

For the current 0.6.x versions of Flatpak, the user also needs to flatpak remote-add --user --from gnome https://sdk.gnome.org/gnome.flatpakrepo first – this step will be automated in 0.8.0. This will download org.freedesktop.Runtime, then com.xamarin.MonoDevelop; export icons ‘n’ stuff into your user environment so you can just click to start.

There’s some lingering experience issues due the sandbox which are on my radar. “Run on external console” doesn’t work, for example, or “open containing folder”. There are people working on that (a missing DBus# feature to allow breaking out of the sandbox). But overall, I’m pretty happy. I won’t be entirely satisfied until I have something approximating feature equivalence to the old .debs.  I don’t think that will ever quite be there, since there’s just no rational way to allow arbitrary /usr stuff into the sandbox, but it should provide a decent basis for a QA-able, supportable Linux MonoDevelop. And we can use this work as a starting point for any further fancy features on Linux.

Gtk# app development in Flatpak MonoDevelop

Editing MonoDevelop in MonoDevelop. *Inception noise*

December 2

Optimizing Android Apps for Multi-Window Mode

One of my favorite features in Android 7.0 Nougat is support for multiple applications running at the same time with the new Multi-Window mode. When the user has an application open and long presses on the app switcher button, they can select a second application to put side by side, which opens up new scenarios, such as dragging and dropping content. On tablets and other larger devices, this also enables a new freeform mode that allows applications to be fully re-sized. Out of the box applications should be able to take advantage of this new mode, as Android Activities will automatically re-size to the correct proportions when the app enters this mode. Here are two Xamarin.Android applications in the new Multi-Windows mode, one built with Xamarin.Forms and the other built with traditional Xamarin.Android.

f3399082-eeef-432f-b9e4-3a6bb4f344df

As you can see, out of the box Multi-Window mode should be supported in your app, however, there are a lot of other optimizations that you can add that will delight your users.

Application Configuration

There are a few easy settings to enable and disable Multi-Window mode for your entire application for a single Activity when you compile against API 24.

If you’re using a sub-classed Application, you can add the ResizeableActivity attribute:

//Entire application does not support split mode
[Application (ResizeableActivity = false)]

//Main activity support split
[Activity(Label = "Monkeys",
        ResizeableActivity = true,
        Name="com.refractored.monkeysapp.MainActivity",
        MainLauncher = true,
        LaunchMode = LaunchMode.SingleTop,
        Icon = "@drawable/ic_launcher")]
//Detail activity does not support split
[Activity(Label = "Details",
        Name = "com.refractored.monkeysapp.DetailsActivity",
        ResizeableActivity = false,
        LaunchMode = LaunchMode.SingleTop,
        ParentActivity = typeof(MainActivity))]

If this is set to true, the activity and application can be launched into split-screen and freeform modes. If you specify this on a single Activity and the user navigates to it, then the new activity will go back into full screen mode. If you’re targeting API 24 and don’t set this attribute, the default will be true.

Launching Activities Side-by-Side

Another neat feature is the ability to launch side-by-side if the user is already in a split-screen session by adding a few flags to your intent before starting the new Activity:

var intent = new Intent(this, typeof(DetailsActivity));
//Request that the new Activity launches adjacent if possible
intent.AddFlags(ActivityFlags.LaunchAdjacent);
//Required for adjacent activity mode
intent.AddFlags(ActivityFlags.NewTask);
//If you would like a new instance of an existing activity to be created.
intent.AddFlags(ActivityFlags.MultipleTask);
StartActivity(intent);

8d34720d-75c9-4ecb-9d6f-a753b5a42a07

Activity Configuration

Starting with Android 7.0, there’s a new Layout attribute that you can add to any Activity class that specifies additional parameters when the Activity is in Multi-Window mode. Here’s an example of specifying location along with the minimum and default dimensions when the Activity is launched into freeform mode:

[Activity(Label = "Monkeys",
        ResizeableActivity = true,
        Name="com.refractored.monkeysapp.MainActivity",
        MainLauncher = true,
        LaunchMode = LaunchMode.SingleTop,
        Icon = "@drawable/ic_launcher")]
    [Layout (DefaultHeight = "500dp",
             DefaultWidth = "600dp",
             Gravity ="top|end",
             MinHeight = "450dp",
             MinWidth="300dp")]

Detecting Multi-Window Mode

Sometimes you may want to enable or disable parts of your user interface or functionality when the user enters Multi-Window mode. You can easily detect the new IsInMultiWindowMode boolean on any Activity.

if(IsInMultiWindowMode)
{
  //Enable or disable functionality
}

Additionally, you can be notified when the user enters or exits Multi-Window mode by overriding the OnMultiWindowModeChanged method:

public override void OnMultiWindowModeChanged(bool isInMultiWindowMode)
{
  base.OnMultiWindowModeChanged(isInMultiWindowMode);
}

Learn More

When optimizing for Multi-Window mode, there are a few other considerations to keep in mind, such as supporting drag and drop and all of the different types of configurations that users may attempt to launch your app in. Be sure to read through the official Android documentation on Multi-Window mode for a full testing check-list.

The post Optimizing Android Apps for Multi-Window Mode appeared first on Xamarin Blog.

Driving a PITA merge conflict to the release branch

Everything was green and working automatically while merging a feature branch to our latest release branch. In fact, I was about to meet my colleagues in the coffee room for a break, but... Ouch! A big red conflict involving a lot of lines appeared. At first glance, I have no idea what happened to the conflicting file. Cancel the coffee break? Hold on, not yet, not today!

Let me show you the steps I followed to solve a non-trivial merge conflict with Plastic SCM and have the feature branch integrate and checked-in into the release branch. For this purpose, I used some 2nd-class-citizen features in Plastic that definitively I have to promote to 1st class after this experience.

December 1

Xamarin Developer Events in December

It’s been a fantastic year for the Xamarin Community, with over 100 user groups globally organizing more than 1,100 meetups and 136 Xamarin Dev Days, and after all of the awesome announcements at Microsoft Connect(); 2016, it’s no wonder Xamarin user groups around the world are getting together for a look at all of the new and improved tools for Xamarin developers! The end of the year is in sight, but there’s still plenty of events happening before we ring in the New Year. If you’re interested in diving into mobile development in C#, be sure to check out some of these great community events below.

xdd-auckland-blog-photo

Here are some of the Xamarin events happening around the world in December:

Xamarin Dev Days

  • Around the World! December
  • Join your local developer community for a free, full day of Xamarin and Azure mobile development training

North Florida Xamarin User Group 🇺🇸

  • Jacksonville, FL, December 5
  • Connect(); //2016 Recap for Mobile Developers

Boston Mobile C# Developers 🇺🇸

  • Cambridge, MA, December 8
  • Microsoft Connect Redux

//AzureReady gb

  • London, UK, December 12
  • Azure showcase featuring keynote speakers, technical sessions, and hands-on environments

Las Vegas Xamarin Developers 🇺🇸

  • Las Vegas, NV, December 14
  • Data Binding in Xamarin Forms Part 2

São Paulo Developers br

  • São Paulo, Brazil, December 14
  • Xamarin.Android and Material Design

Munich Mobile Xamarin & .NET Developers Group za

  • Munich, Germany, December 15
  • Xamarin Pizza & Beer – Connect(); Recap

Nashville .Net Developers 🇺🇸

  • Nashville, TN, December 15
  • Connect(); 2016 Recap for Mobile Developers

Find a Xamarin Developer Group in Your Area

If you don’t see an event above in your town or city, you can also use this map of Xamarin User Groups to find one near you.

Interested in starting your own Xamarin developer group?

We’re here to help! Take a look at a few of these useful resources:

Visit the Xamarin events page for even more Xamarin meetups, conferences, hackathons, and other events happening near you this month.

The post Xamarin Developer Events in December appeared first on Xamarin Blog.

November 30

Creating Platform-Specifics in Xamarin.Forms

Recently on the blog, Pierce introduced Platform-Specifics, which allow you to consume functionality that’s only available on a specific platform without having to implementing custom renderers or effects. With the use of a simple Fluent API, you can make platform-specific tweaks from shared code in Xamarin.Forms.

At the time of writing, Xamarin.Forms includes the following Platform-Specifics:

  • Blur support for any VisualElement on iOS.
  • A translucent navigation bar on iOS.
  • The ability to set the operating mode for a soft keyboard input area on Android.
  • Toolbar placement options on Windows.
  • A partially collapsible MasterDetailPage navigation bar on Windows.

In addition, vendors can create their own Platform-Specifics with Effects. An Effect provides the desired functionality, which is then exposed through a Platform-Specific. The result is an Effect that can more easily be consumed through XAML and a fluent code API.

In this blog post, I’m going to demonstrate how to expose an Effect through a Platform-Specific that adds a shadow to the text displayed by a Label. All the code can be found in a sample application. However, the blog post will focus on the implementation for the iOS platform.

Creating a Platform-Specific

The process for creating a Platform-Specific is:

  1. Implement the desired functionality as an Effect.
  2. Create a Platform-Specific class that will expose the Effect.
  3. Add an attached property to the Platform-Specific class to allow the Platform-Specific to be consumed through XAML.
  4. Add extension methods in the Platform-Specific class to allow it to be consumed through a fluent code API.
  5. Modify the Effect implementation so that the Effect is only applied if the Platform-Specific has been invoked on the same platform as the Effect.

Each item will now be considered in turn.

Implement the Desired Functionality as an Effect

In the sample application, the iOS project provides the LabelShadowEffect class, which adds a shadow to a Label by setting the following properties:

Control.Layer.CornerRadius = 5;
Control.Layer.ShadowColor = UIColor.Black.CGColor;
Control.Layer.ShadowOffset = new CGSize(5, 5);
Control.Layer.ShadowOpacity = 1.0f;

For more information about creating this Effect, see Creating an Effect and Passing Effect Parameters as Attached Properties.

Create a Platform-Specific Class

A Platform-Specific is created as a public static class:

namespace MyCompany.Forms.PlatformConfiguration.iOS
{
	using System.Linq;
	using Xamarin.Forms;
	using Xamarin.Forms.PlatformConfiguration;
	using FormsElement = Xamarin.Forms.Label;
	public static class Shadow
	{
		const string EffectName = "MyCompany.LabelShadowEffect";
        ...
		static void AttachEffect(FormsElement element)
		{
			IElementController controller = element;
			if (controller == null || controller.EffectIsAttached(EffectName))
			{
				return;
			}
			element.Effects.Add(Effect.Resolve(EffectName));
		}
		static void DetachEffect(FormsElement element)
		{
			IElementController controller = element;
			if (controller == null || !controller.EffectIsAttached(EffectName))
			{
				return;
			}
			var toRemove = element.Effects.FirstOrDefault(e => e.ResolveId == Effect.Resolve(EffectName).ResolveId);
			if (toRemove != null)
			{
				element.Effects.Remove(toRemove);
			}
		}
	}
}

The AttachEffect and DetachEffect methods will be used to add or remove the Effect, and will be invoked by additional code that’s added to the Shadow class.

Add an Attached Property

An attached property must be added to the Platform-Specific class to allow consumption through XAML:

public static class Shadow
{
    ...
	public static readonly BindableProperty IsShadowedProperty =
       BindableProperty.CreateAttached("IsShadowed", typeof(bool), typeof(Shadow), false, propertyChanged: OnIsShadowedPropertyChanged);
	public static bool GetIsShadowed(BindableObject element)
	{
		return (bool)element.GetValue(IsShadowedProperty);
	}
	public static void SetIsShadowed(BindableObject element, bool value)
	{
		element.SetValue(IsShadowedProperty, value);
	}
	static void OnIsShadowedPropertyChanged(BindableObject element, object oldValue, object newValue)
	{
		if ((bool)newValue)
		{
			AttachEffect(element as FormsElement);
		}
		else
		{
			DetachEffect(element as FormsElement);
		}
	}
        ...
}

The IsShadowed attached property is used to add the effect to, and remove it from, the control that the Shadow class is attached to. The attached property registers the OnIsShadowedPropertyChanged method that will be executed when the value of the property changes. In turn, this method calls the AttachEffect or DetachEffect method.

Add Extension Methods

Extension methods must be added to the Platform-Specific to allow consumption through a fluent code API:

public static class Shadow
{
    ...
	public static bool IsShadowed(this IPlatformElementConfiguration<iOS, FormsElement> config)
	{
		return GetIsShadowed(config.Element);
	}
	public static IPlatformElementConfiguration<iOS, FormsElement> SetIsShadowed(this IPlatformElementConfiguration<iOS, FormsElement> config, bool value)
	{
		SetIsShadowed(config.Element, value);
		return config;
	}
    ...
}

The IsShadowed and SetIsShadowed extension methods invoke the get and set accessors for the IsShadowed attached property, respectively. Each extension method operates on the IPlatformElementConfiguration<iOS, FormsElement> type, which specifies that the Platform-Specific can only be invoked on Label instances from iOS.

Modify the Effect Implementation

The Effect implementation must be modified so that it can only be invoked from the same platform the Platform-Specific is implemented for:

if (((Label)Element).OnThisPlatform().IsShadowed())
{
	Control.Layer.CornerRadius = 5;
	Control.Layer.ShadowColor = UIColor.Black.CGColor;
	Control.Layer.ShadowOffset = new CGSize(5, 5);
	Control.Layer.ShadowOpacity = 1.0f;
}
else if (!((Label)Element).OnThisPlatform().IsShadowed())
{
	Control.Layer.ShadowOpacity = 0;
}

A shadow is added to the Label text provided that the IsShadowed attached property is set to true, and provided that the Shadow Platform-Specific has been invoked on the same platform that the Effect is implemented for. This check is performed with the OnThisPlatform method.

Consuming the Platform-Specific

The Shadow Platform-Specific can be consumed in XAML by setting the Shadow.IsShadowed attached property to a boolean value:

<ContentPage xmlns:ios="clr-namespace:MyCompany.Forms.PlatformConfiguration.iOS" ...>
  ...
  <Label Text="Label Shadow Effect" ios:Shadow.IsShadowed="true" ... />
  ...
</ContentPage>

Alternatively, the Shadow platform-specific can be consumed through the fluent code API:

using Xamarin.Forms.PlatformConfiguration;
using MyCompany.Forms.PlatformConfiguration.iOS;
...
shadowLabel.On<iOS>().SetIsShadowed(true);

This results in a shadow being applied to the text displayed by a Label:

screenshot

Wrapping Up

The result of exposing an Effect as a Platform-Specific is that the Effect can be more easily consumed through XAML and through a fluent code API.

For more information about consuming Platform-Specifics, see Consuming Platform-Specifics. For more information about creating Platform-Specifics, see Creating Platform-Specifics.

The post Creating Platform-Specifics in Xamarin.Forms appeared first on Xamarin Blog.

November 29

Live Webinar | Getting the Most out of iOS 10 and Android N

The newly released iOS 10 and Android N(ougat) operating system updates are great opportunities for mobile developers to add new features to their mobile apps that make them stand out. Join Mike James and James Montemagno, Microsoft Program Managers of Mobile Developer Tools, for a webinar on December 8, 2016 at 10:00 am PT / 1:00 pm ET / 5:00 pm GMT as they guide you through the latest enhancements in these releases.

Mike will discuss iOS 10’s new features, including new App Extensions, CallKit, iMessage Apps, and the new SiriKit. For Android Developers, James has you covered with Android N’s notification enhancements, multi-window support, important environment changes, and the latest revisions of the Android Support Libraries and Google Play services to add to your app.

ios and android n

During this webinar you will:

  • Discover new iOS 10 and Android N features, and how they impact your apps.
  • Review code samples and hear best practices for accessing the new APIs.
  • Explore how to maximize code-sharing between projects and ensure backward compatibility while leveraging platform-specific APIs.

Register at the link below to join us on December 8, 2016 at 10:00 am PT / 1:00 pm ET / 5:00 pm GMT.
 

Register

The post Live Webinar | Getting the Most out of iOS 10 and Android N appeared first on Xamarin Blog.

November 28

Say Hello to the Xamarin Profiler

As developers, we have many tools at our disposal to help catch problems in our code (and protect our sanity); for example, IDE features such as IntelliSense find errors as we type, a debugger gives us a window into the app when it’s running, and a profiler, in turn, shows us how our app is using resources and where it could be more effective. The Xamarin Profiler is currently the only way to profile managed (C#) code and find memory and performance issues in Xamarin applications. It can also be paired with native profilers, like Xcode Instruments and Android Monitor, to ensure better app behavior and performance.

Last week at Microsoft Connect(); we announced the first stable release of the Xamarin Profiler, available today from the Xamarin download page as part of the full Xamarin installation for MSDN Enterprise subscribers or download the standalone installer here. We have designed beautiful, native Profiler apps for both Mac and Windows to help collect and interpret profiling data.

Profiler on Windows

Profiler on Windows

Launching the Profiler

To start a profiling session, launch an application on device or simulator with the Xamarin Profiler attached. In Visual Studio, open your Xamarin project and choose Analyze > Xamarin Profiler to begin the session. In Xamarin Studio and Visual Studio for Mac, choose Run > Start Profiling.

Xamarin Profiler sessions can also be saved in the mlpd format (Mono Log Profiler Data). Double-clicking on an mlpd file will open it in the Xamarin Profiler. These files can be moved between Windows and Mac.

Instruments

When Xamarin Profiler launches, it will ask you to select an instrument or group of instruments to gather data about your app. Each instrument gathers certain information about an application to help diagnose different types of problems. The Xamarin Profiler comes with three instruments: Allocations, Time Profiler, and Cycles. Let’s dive into each one to learn how it can help us build better apps.

Allocations

The Allocations instrument shows us how much memory our app is using and what it’s using it for. The allocations tab has a list of all of the objects created during the lifetime of the app, with the details panel on the right providing additional filters, statistics, and a chart on the overall breakdown of memory usage:

Profiler on Mac

Profiler on Mac

We can further filter the list of Allocations to find objects useful to us. For example, we can search for objects from our code by searching for our namespace. The Xamarin Profiler marks our objects in blue:

Profiler on Mac

Profiler on Mac

Another way to filter Allocation data is to limit the information to a particular segment with the selection tool. The selection tool lets us highlight a section of data to focus on. This will limit the Allocations list to the objects allocated during the selected time interval:

Profiler on Mac

Profiler on Mac

The Allocations instrument also features a call tree, which displays memory usage grouped by method call. We have the option to view the call tree separated by thread as well as inverted, which shows memory usage at the most granular level first and works its way up the call stack:

Profiler on Mac

Profiler on Mac

Snapshots

A nice feature of the Allocations instruments is snapshots, the ability to list all of the objects in our app at a point in time. We can take a snapshot at any point during the profiling session by clicking on the camera icon in the Profiler controls on the top left. The red lines in the console mark the snapshots in the profiling session:

Profiler on Windows

Profiler on Windows

Double-clicking on a snapshot reveals the objects that are in memory at the time. Choosing Only New Objects in the display options limits the objects displayed to the delta between the previous snapshot and this one. This gives us a sense of what was created between two points in time:

Profiler on Windows

Profiler on Windows

Time Profiler

The Time Profiler uses sampling to determine where our app is spending the most time. Sampling is a lightweight performance profiling method that polls the application at regular intervals to determine what code is being executed and then forms a hypothesis for how long different parts of our program take to execute.

Inside the Xamarin Profiler, the call tree in the first tab is the same call tree as the Allocations tab, but instead of breaking down memory usage by method, it shows how much time was spent in each method.

In the second tab, the sample list gives us a breakdown of the sampling results:

Profiler on Mac

Profiler on Mac

Cycles

The Cycles instrument gives a written and visual representation of circular references between objects, making it particularly useful for detecting native reference cycles, or circular references between objects that cross the boundary between the native and managed world. These types of cycles are important, because they prevent the objects involved from being picked up by the garbage collector.

The Xamarin Profiler provides a list of cycles under the Roots & Cycles tab. We are primarily concerned with cycles involving objects in our own code. If a cycle is detected, Xamarin Profiler will list the root object in the list on the left and draw a graph on the right of all the objects involved in the cycle. The root of the cycle is pictured in purple, with the dependencies between objects represented by arrows:

Profiler on Windows

Profiler on Windows

For more information on Cycles, refer to our simple example app for native reference cycles, and James Clancey’s Guide to Cross-Platform Performance with Xamarin, which provides details on how cycles form and how to fix them.

Resources

 

The post Say Hello to the Xamarin Profiler appeared first on Xamarin Blog.

November 26

OS X Branch Explorer learns to filter branches

BL793 comes with another great feature for OS X users: now you can filter branches in the Branch Explorer! It is an added capability on top of the “inclusion/exclusion rules”. It works as follows:

Monologue

Monologue is a window into the world, work, and lives of the community members and developers that make up the Mono Project, which is a free cross-platform development environment used primarily on Linux.

If you would rather follow Monologue using a newsreader, we provide the following feed:

RSS 2.0 Feed

Monologue is powered by Mono and the Monologue software.

Bloggers