Etymotic mc5 Earphones – Review

At the time of this writing, I’ve been using the Etymotic mc5 Earphones almost every day for 2 years, 3 months.  I wear glasses, so using over-the-ear style headphones is out of the question.  Over the years, I’ve tried many different types and styles of in-ear Earphones.  A little more than two years ago, I made the decision it was time to do some research, get some recommendations, and spend some money on a quality product.  On a friends recommendation, I turned to the Etymotic mc5.

They sell for $59 and you can purchase them from their website, or from Amazon.

What I Like

I’m a programmer.  And, like many programmers, I listen to music a lot while I work.  Because of that, comfort is a must when considering a pair of in-ear earphones.  Especially when shelling out more than $5 or $10 dollars.  These particular in-ear earphones are, by far, the most comfortable I have ever owned.  They come with a few tips to choose from,  I chose the gel tips, which themselves come in three different sizes.  Speaking of ear-tips, they also offer a service where you can get ear tips made, custom to your ear.  I have not done this.

When I purchased these, I hadn’t caught the fact that they were noise isolating, but they are.  So much so, that when I plug them into my computer, I have to turn my volume down to 4, and I still can’t hear my wife when she comes up behind me.

When I’ve had to call customer service, they have been great, every time.

What I Don’t Like

Honestly, there are only three things I don’t like about this product.  And, one of those is a small inconvenience, which I’ll start with.

They are only 4′ long.  Which isn’t all that bad, but I tend to adjust in my seat often, and for my office setup, it’s just barely long enough.  A 6′ cord would go a long way for these earphones.

The product only has a two-year warranty.  For a product as expensive as this, and one I’ve heard should last for several years, a two-year warranty just seems too small.  Which brings me to my third issue.

In my 27 months of use, I’ve had to send it in for replacement twice, so I’m already on my third pair.  The problem has been the same with each pair.  The adhesive that holds the two main pieces together, wears down.  Don’t get me wrong.  I know that earphones don’t last forever.  But, for the price-tag, and such a high-quality earphone, I would expect the quality of the construction would be the same.  It should also be noted, that both times I called Etymotic to initiate the exchange process, and they were nothing but helpful and friendly, which I find hard to find these days.

Conclusion

As company that has it’s roots in designing and manufacturing hearing products, I had high expectations for my Etymotic earphones.  And they met those expectations.  I would recommend these earphones to anyone who is looking for a quality earphone at a reasonable price.

Technical Specifications

Frequency Response: 20 Hz – 15 kHz
Accuracy Score: 85%
Transducers: High-output 8mm neodymium moving coil driver
Noise Isolation: 35-42 dB
Impedance (@1kHz): 16 Ohms
Sensitivity (@1 kHz) SPL at 0.1v: 100dB
Maximum Output (SPL): 120 dB
Cable: 4 ft.
User Replaceable ACCU-Filters: Yes
Warranty : 2 Years
Custom-Fit Option: Yes

Advertisements

Das Keyboard Prime 13 – Review

Das Keyboard sent me the Prime 13 about a month ago, and I’ve been using it ever since. As a software engineer, the keyboard plays in important role in the ability to complete my job functions as a software engineer.  Beyond the hours spent typing code, I also look for features to make my job easier.  I was excited to try this one.

This keyboard sells for $149.00 and is available at www.daskeyboard.com.

You can read my review below, skip to my conclusion, or visit the technical specifications.

Initial Reaction

Weighing in at nearly 3 pounds (2.9 to be exact) and featuring an anodized aluminum top panel, this keyboard is both extremely sturdy and stylish.

If you’re interested in the detailed technical specifications, click here, or just keep reading for the review.

What I Like

As I mentioned in my initial reaction, this is a hefty keyboard.  Whether intended or not, the weight is an important feature and the more I use it the more I notice it doesn’t slide around on my desk like other keyboards do.

As a coder, I use my function keys much more often than the average typist. The fact that these function keys are full-size is a major bonus. Many keyboards out there don’t have full-size function keys, making them a pain to use. Along those lines, this keyboard doesn’t have a “special key row” above the function keys, which my old keyboard had. I don’t miss this. Since using the Das Keyboard, I’ve not once opened outlook, or a chat window while trying to press a function key.

I’ve wanted to use a mechanical keyboard with Cherry switches for a while, and this was my first experience with one. Not only did I like Cherry switches much more than I thought I would, after only 5 minutes of typing I already started seeing an improvement in my typing speed and accuracy which was quite surprising to me.

As with any new keyboard, I did have to get adjusted to the new travel spacing, but it was very intuitive, and I adjusted quite nicely.

I’ve noticed that many keyboards either don’t have indicators on the actual keyboard, ordaskeyboard-logo-on-prime13-mechanical-keybaord they don’t have notifications on screen (it’s either/or). The Prime 13 has both lights for Caps/Num/Scroll Lock, and toast notifications. I like this very much. I want to have the toast notification when I get in a hurry and turn off NumLock, and I want to see that NumLock is on when I come back to my computer after walking away.

Being able to adjust the keyboard backlighting is nice, although I never do.

The aluminum plate adds a nice look to the keyboard. Just looking at the thing you know it’s going to be a good typing experience.

I don’t need keyboard backlighting, nor do I need a USB pass-through, and I like a clean desk, so I was initially disappointed that this wasn’t a wireless keyboard (though, good luck finding a decent wireless mechanical keyboard). Having said that, because the weight of the keyboard keeps it in place well, the cable doesn’t move around, which keeps my papers behind the keyboard nice and neat. Though I would still prefer a wireless keyboard for cleanliness, this isn’t a con for me since it hasn’t had any negative effect.

What I Don’t Like

As for things that I would change, there aren’t very many, but here they are.

mechanical-switches-prime13The keyboard backlighting has 7 levels of brightness, including off. This is great. However, there are some inconsistencies in the brightness level of some of the keys.  This could be by design, or it could be a small oversight.  Either way, I’m not a fan of it. Without getting into specifics of why, the end result is that the Function keys, which share media controls, have lighting for the Function and the media control, for example, “F5” and “Previous” are the same key, and both symbols have the same level of brightness.  However, the number row keys don’t share brightness with the character it represents, for example, “2” is bright, but “@” is dim.

The thing I would change the most about this keyboard is the media controls which are embedded with the Function keys.  This means simple functions like mute, volume down, volume up, etc. are accessed via two keystrokes, which is more than a little annoying. If this keyboard had designated media buttons, that would be a major bonus.

It’s not a big factor for me because I don’t use the USB Pass-through, however it is a little disappointing that a keyboard as new as the Prime 13 has USB 2.0 instead of 3.0.

I was also disappointed that not all keys sound the same. As I got used to typing on the keyboard, it became less noticeable to me and it hasn’t affected my typing any, but it was still an initial disappoint that a keyboard with this quality would have those inconsistencies. The following keys have a different sound than the main keys:

  • The spacebar is more “hollow”
  • The backspace key has a “tinny” sound
  • The enter key has a “blunt” sound
  • The shift key has a “tinny” sound, though not as noticeable as the backspace

Conclusion

It has been an absolute joy to type on this keyboard over the last several weeks, and it lives up to the reputation that comes with the Das Keyboard brand.  I would recommend this keyboard to anyone who is looking for a quality mechanical keyboard.

Technical Specifications

Keyboard Layout

  • Standard 104-Key: US layout with n-key rollover
  • Standard 105-Key: UK, DE, and NO layouts with n-key rollover

Switches

  • Cherry MX Brown (Soft Tactile) mechanical key switches
    • Feel: Soft Tactile
    • Actuation Force: 45g
    • Tactile Force: 55g
    • Lifetime: 50 million actuations
    • Total travel distance: 4mm
    • Pre-travel distance: 2mm
    • Operating Point: 2mm
    • Reset point: 2mm
    • Keycap stem: MX (Cross)

Key Caps

  • Black thermoplastic key caps with white laser-marked inscriptions

Interface and Connectivity

  • One USB 2.0 pass-through
  • 2m (6.5ft) USB braided Y cable with dual USB type-A connectors, gold plated (fixed, not detachable)

Backlighting

  • 1 Zone: entire keyboard
  • Color modes: 1 color, White
  • Brightness: 7 modes/levels which include off
  • Lighting Mode Memory
    • When keyboard is plugged into the computer and upon a power down/powering off of the computer, the keyboard will remember and return to the last used lighting mode/brightness level.
    • Default brightness level: 3
  • Keyboard will auto-dim after 10 minutes of inactivity

Compatibility

  • Compatible with Windows, Mac OS, ChromeOS, and Linux Operating Systems
  • Compatible with USB 1.1 and 2.0 standards
  • Compatible with USB KVM switches

System Requirements

  • One USB 1.1 or 2.0 port (for keyboard)
  • One USB 2.0 port (for USB pass-through port)
  • No custom driver required

Product Dimensions

  • Length: 45.80 cm (18.03 in)
  • Width: 17.20 cm (6.77 in)
  • Height: 3.11 cm (1.22 in)
  • Weight: 1.32 KG (2.9 lbs)

Wildcard Subdomains in MVC5 and Azure WebApp

If you’re here, I’m going to assume you already know what Wildcard Subdomains are.  The point of this post is to teach you how to get them to work in your MVC application, both on your dev machine, and on Azure WebApps.

First step is to get it working on your local machine.  Ben Cull does a great job of getting this working over at his blog: http://benjii.me/2015/02/subdomain-routing-in-asp-net-mvc/  I highly recommend watching his short video on the topic also: https://youtu.be/dMFOo0__rm0

The only problem I ran into at this point was that I would get an exception that the controller wasn’t defined if the URL looked like “subdomain.localhost:4353”.  So, I just added an IF blocks to his SubdomainRoute class to make ‘controller’ “Home” if it is an empty string, and an IF block to make ‘action’ “Index” if it is an empty string.

After this, everything works perfect locally.

To get this to work in Azure WebApps, however; you need to complete a couple more steps.

First, you’ll need to go to your domains DNS management and add the following CNAME record:

*.YourDomain.Com

This gets a Value which looks something like this (Azure will tell you what it needs to be)

YourDomain.azurewebsites.net

Next, in Azure, go to your WebApp and click “Configure” and then scroll down and click “Manage Domains”.  Here, you’ll add the following domain name:

*.YourDomain.com

Note: This is where Azure will tell you what to put in your CNAME record.

You’re all set.  Now you can go to “AnySubdomainThatYouWant.YourDomain.Com” and it should work!

 

MVC 5 T4 Templates and View Model Property Attributes


Yesterday, I published a blog post demonstrating how to modify your T4 templates for your single project.  Today, I’m going to show you how to access an attribute from your Model in your T4 template.  Beginning with MVC 5, the T4 templates no longer use ModelProperty class to iterate over the properties in your Model.  ModelProperty has direct access to Attributes, and there are plenty of resources on the web on how to read the attributes in your T4 using that.  In MVC 5, however, ModelProperty has been replaced with PropertyMetaData, which does not have access to the attributes of your properties.  Further, I found it very difficult to find a solution for MVC5 on the web, until finally I came across an old MSDN Magazine article, which was only helpful because I could download the sample project and take a look inside.  The article itself is missing referenced images and code samples.  So, I’m taking what I learned, and am creating this, hopefully simple, post to demonstrate.

For our purposes today, we will be extending our project from yesterday to make the Biography property on the Person model a RichText field.  So, for a reminder, here is our Person model:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
 
namespace CustomViewTemplate.Models
{     
     [Table("Person")]
     public class Person
     {
         [Key]
         public int PersonId { get; set;}

         [MaxLength(5)]
         public string Salutation { get; set; }

         [MaxLength(50)]
         public string FirstName { get; set; }

         [MaxLength(50)]
         public string LastName { get; set; }

         [MaxLength(50)]
         public string Title { get; set; }

         [DataType(DataType.EmailAddress)]
         [MaxLength(254)]
         public string EmailAddress { get; set; }

         [DataType(DataType.MultilineText)]
         public string Biography { get; set; }     
     }
}

To demonstrate that we can also use a custom attribute, let’s create one.  Create a class called RichTextAttribute in the project root directory:

namespace CustomViewTemplate
{
     [AttributeUsage(AttributeTargets.Property)]
     public class RichTextAttribute : Attribute
     {
         public RichTextAttribute() { }
     }
}

Then, back to PersonModel, add the RichText attribute to the Biography property:

[RichText]
[DataType(DataType.MultilineText)]
public string Biography { get; set; }

Now, copy the following global template files from

C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\Extensions\Microsoft\Web\Mvc\Scaffolding\Templates\MvcView\

to a folder called

CodeTemplates\MvcView\

  • Create.cs.t4 (OR Create.vb.t4)
  • Imports.include.t4
  • ModelMetaDataFunctions.cs.include.t4 (OR ModelMetaDataFunctions.vb.t4)

Now, remember the PropertyMetaData, doesn’t have access to the attributes, so we need to create a new class with a function that does the work for us, so let’s create a class called T4Helpers, with a public function called IsRichText.

using System; 

namespace CustomViewTemplate
{
     public static class T4Helpers
     {
         public static bool IsRichText(string viewDataTypeName, string propertyName)
         {
             bool isRichText = false;
             Attribute richText = null;
             Type typeModel = Type.GetType(viewDataTypeName);

             if (typeModel != null)
             {
                 richText = (RichTextAttribute)Attribute.GetCustomAttribute(typeModel.GetProperty(propertyName), typeof(RichTextAttribute));
                 return richText != null;
             }

             return isRichText;
         }
     }
}

We are using our custom RichTextAttribute here, but you could use any Attribute you would like.  What we are doing is returning true or false; indicating that the given property either does or does not have the attribute we are checking for.

Before we can use this function in our T4 template, we’ll need to Build our project and then add a reference to our assembly in the imports file.

Open your projects copy of Imports.include.t4 and add a reference to your assembly as line 4.  For me, it looks like this:

<#@ assembly name="C:\My Applications\Playground\CustomViewTemplate\CustomViewTemplate\bin\CustomViewTemplate.dll" #>

As you are typing the line of code above, if you are using tangible T4 Editor, you might see an inellisense option like so:

image

and you might be tempted to use it, but there is a bug that will prevent this form working.

Okay, now we can modify our T4 template.  Open Create.cs.t4 and look for the foreach loop that iterates over our list of properties.  You’ll find this around like 96:

<# foreach (PropertyMetadata property in ModelMetadata.Properties) {      if (property.Scaffold && !property.IsAutoGenerated && !property.IsReadOnly && !property.IsAssociation) {          // If the property is a primary key and Guid, then the Guid is generated in the controller. Hence, this property is not displayed on the view.          if (property.IsPrimaryKey && IsPropertyGuid(property)) {              continue;          } #>

To avoid unnecessary calls to our new method, we’ll only check for the RichText attribute against properties that we will actually be rendering, so after the inner If statement (the one that checks for primary key’s and Guid’s), we can add this line:

bool isRichText = CustomViewTemplate.T4Helpers.IsRichText(ViewDataTypeName, property.PropertyName);

Now, the tricky part is using our new variable and finding the correct place for it.  For our purposes, we will put it inside the nested if statement that is checking for a checkbox.  So, that entire if block would look like this with our new code added:

             if (isCheckbox) {
#>


<div class="checkbox">
<#                  PushIndent("    "); #>
                 @Html.EditorFor(model => model.<#= property.PropertyName #>)
<#              } else if (property.IsEnum && !property.IsEnumFlags) { #>
                 @Html.EnumDropDownListFor(model => model.<#= property.PropertyName #>, htmlAttributes: new { @class = "form-control" })
<#              } else if (isRichText) { #>
                 // TODO: Place RichTextBox HTML here
<# } else { #>
                 @Html.EditorFor(model =>; model.<#= property.PropertyName #>, new { htmlAttributes = new { @class = "form-control" } })
<#              }           } else { #>
                 @Html.EditorFor(model => model.<#= property.PropertyName #>) 
<#          } #>

Now, you can see that I just put some generic text instead of an @Html helper, because the implementation details of RichText aren’t important for the purposes of this tutorial.

To verify everything is working properly, we can save changes, go to our PersonController and add a Create action, Right-Click inside to Add View, and add a Create view.

Inside the generated Create.cshtml, you can scroll down and see that our Biography field has our placeholder text, instead of a @Html helper function.



<div class="form-group">
    @Html.LabelFor(model => model.Biography, htmlAttributes: new { @class = "control-label col-md-2" })


<div class="col-md-10">
        // TODO: Place RichTextBox HTML here
        @Html.ValidationMessageFor(model => model.Biography, "", new { @class = "text-danger" })
    </div>


</div>


If you’ve found this tutorial helpful, please leave a comment below!

MVC 5 Custom View Templates

The out-of-the-box template that comes with Visual Studio has improved a great deal since I first started building ASP.Net Web Pages several years ago. But, as nice as the new template is, it’s still nice to be able to adjust the T4 templates that are used to generate the Views. I’ve known for a long time that I could modify these templates globally, by modifying them directly in the Visual Studio folder, but, it wasn’t until earlier this week that I learned you can customize them for just your single project. This post will demonstrate how to do that. In my next post, I’ll demonstrate how to access the attributes on your Model’s properties, from inside the T4 templates.

For the purpose of this demo, I will be using Visual Studio 2013, MVC 5, EF 6, and .net 4.5.1.

For our sample, we will create a simple application that allows for basic CRUD of a person object. So, fire up NuGet and install EF 6 and add a calls called PersonModel to Models folder:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace CustomViewTemplate.Models
{
    [Table("Person")]
    public class Person
    {
        [Key]
        public int PersonId { get; set;}

        [MaxLength(5)]
        public string Salutation { get; set; }
        
        [MaxLength(50)]
        public string FirstName { get; set; }
        
        [MaxLength(50)]
        public string LastName { get; set; }
        
        [MaxLength(50)]
        public string Title { get; set; }
        
        [DataType(DataType.EmailAddress)]
        [MaxLength(254)]
        public string EmailAddress { get; set; }
        
        [DataType(DataType.MultilineText)]
        public string Biography { get; set; }
    }
}

Now, add a basic Person controller, an Empty one so that only the Index Get method is created:

image

namespace CustomViewTemplate.Controllers
{
    public class PersonController : Controller
    {
        // GET: Person
        public ActionResult Index()
        {
            return View();
        }
    }
}

If you right-click inside Index() and choose Add View, use scaffolding to add a List view.

image

Now, the view will open and you’ll see the default List view, which just happens to be a table.

Take special notice to lines 9-11:

<p>
    @Html.ActionLink("Create New", "Create")
</p>

Now, of course this will create a standard issue hyperlink, but what if, for the sake of this example, we want it to be a button instead. Well, we could just change the HTML, but if we wanted this to be a button by default, we would have to change the button. So, first things first, we need to identify the location of the global template files. That location is

C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\Extensions\Microsoft\Web\Mvc\Scaffolding\Templates\

Now, you can modify the .t4 files in this directory, but ONLY do that if you want the changes to be global. To make changes only to the project you are working in, copy the direct to a new folder in your project’s root, called “CodeTemplates”. You only need to copy down the files you will want to change, but it is important that you copy the folder structure down. That is, we want to modify a file called List.cs.t4, so we need to copy our file to “~ProjectFolder~\CodeTemplates\MvcView\List.cs.t4”. So for me, that looks like this:

C:\My Applications\Playground\CustomViewTemplate\CustomViewTemplate\CodeTemplates\MvcView\List.cs.t4

Note, if you are using VB, you’ll want List.vb.t4.

IMPORTANT NOTE
You also need to copy over MvcView\Imports.include.t4 and MvcView\ModelMetadataFunctions.cs.include.t4

Back in Visual Studio, in Solution Explorer, you’ll need to “Show all files”, and do a refresh, but you should see your CodeTemplates folder now. Of course, you won’t need the templates for deployment, but if you are modifying them, you should add to source control, so go ahead and right-click and “Include in project”.

Now, you can open the t4 file, but beware, VS doesn’t come with a T4 editor out-of-the-box. That means, no styling and no intellisense. There are, however, some good T4 editor’s in the VS extensions. I use tangible T4 Editor 2.2.5 plus modeling tools for VS 2013 (free edition). Of course, you’ll need Visual Studio to be closed before you can run the installer.

Remember our hyperlink we want to change to a button, well, there’s no special t4 stuff going on with that, and this isn’t a tutorial on the basics of t4, so with List.cs.t4 open, look for our HTML snippet above and change it to:

<p>
    <button type="button" onclick="addNewPerson();">Create New Person</button>
</p>

Now save the file. Now, back to the controller and right-click inside the Index method, and select AddView and add a new List View, but overwrite the existing one.

Now, when you look at the new version of Index.cshtml, you’ll see that instead of a hyperlink, you now have a button!

Happy Templating!

Serializing a Dictionary

For better or for worse, dictionaries are not allowed in .net Web API’s.  List’s are allowed, and what’s a dictionary, if not a list of key, value pairs?  So, I wrote this extension method to “serialize” a dictionary.

public static class ExtensionMethods
{
     public static List<KeyValuePair<T1, T2>> Serialize<T1, T2> (this Dictionary<T1, T2>)
     {
          List<KeyValuePair<T1, T2>> list = new List<KeyValuePair<T1, T2>>();
          list.AddRange(dictionary);
          return list;
     }
}

Then, you call it like this:

Dictionary<int, string> wordsThatStartWithB = new Dictionary<int, string>()
{
     { 1, "Bob" },
     { 2, "Blue" },
     { 3, "Bone" },
     { 4, "Bow" }
};

return wordsThatStartWithB.Serialize();

Of course, there are probably better ways of doing this, which is why I will be open sourcing my extensions library in the coming weeks, and will have a blog post about each one. Do you have any recommendations on improving this?

Windows Phone Error code: 85010014

The Short Version

My phone suddenly began reporting Error Code: 85010014 when attempting to sync my work email.

The Fix

It turns out I had a calendar event with a status of “Meeting Elsewhere”.  Changing the status to “Free/Busy/Tentative/Out Of Office” fixed the problem immediately.

The Long Story

Four days ago, my work email suddenly refused to sync on my phone, giving me error code 85010014.  I searched the web, over and over and over and over, to no avail (which is why I’m posting this), so figuring it out was up to me.

What made it look like a device issue:

Because my Outlook and my Web Access functioned properly, from the business side anyway, it looked as though the problem was on my device somehow.  The first thing I attempted was to change my password, but that didn’t fix the problem.

Why a device issue just didn’t feel right:

There were several reasons why I was sure it wasn’t a problem on my device.  I observed the following:

  • Restarting device didn’t fix
  • Removing and Re-Adding the account didn’t fix
  • Removing and Restarting and Re-Adding the account didn’t fix
  • Outlook.com address was working
  • School email (exchange also) was working

Then, I started reading a forum post I came across, which linked to another post, which linked to another post….anyway, I eventually made my way to a post from a problem someone experienced several years ago on their WP7 device with similar symptoms.  They fixed it by unchecking all the boxes for “Content to sync”, then syncing, then adding “Email”, then syncing, then “Contacts”, sync, “Calendar”, sync, “Tasks”, sync.  He observed that by adding the services back one-by-one, the sync was successful and his problem went away.  So I did the same thing, and noticed the same thing…until I checked the box next to Calendar.  The sync failed.  So, I was able to observe that my account would sync, as long as I didn’t attempt to sync the calendar.  So, I pulled out my old WP 7 device and sure enough, I was able to duplicate this behavior.  So, this helped me narrow down the problem, and eliminate my device. 

I kept reading about “try refreshing your cache”, and I wasn’t sure if that was IE cache, or some special device cache or what, but the Microsoft support folks in the forums kept saying, “contact your device manufacture for instructions to clear the cache”.  So, I updated to Windows Phone 8.1.  I’ve been wanting it anyway, and it was released to developers that day, so I downloaded it.  I assumed it would clear my cache, but whether it did or not, the problem persisted.

So, I added my account to my co-workers phone (another WP8, different manufacturer), and was able to duplicate the behavior.  All the while, his account continued to function properly.

So, now I’m convinced that there is a problem with my account, or my calendar or something, but no one knows what to do, and officially, my employer doesn’t support email on devices.  So, I’ve been dealing with this for four days, and tonight I decided to really dig in and try to get this figured out.

I started by looking at the properties of my calendar in Outlook.  I noticed that I’ve never cleaned my calendar since I started with the company two years ago, so it had well over 400 items.  I thought surely not, but maybe-just-maybe, I’ve reached some sort of threshold and the sync process can’t handle so many calendar items.  So, I performed an archive and removed all events older than 90 days.  Still nothing.

So, I started looking through my upcoming events and found one that had my status as “Meeting Elsewhere”, because I’m trying anything and everything I can think of at this point, I change it to “Free” and try syncing on my phone, success!  I thought maybe it just took a while for the clean-up to take effect, so I changed the status back to “Meeting Elsewhere” and sure enough, it broke again, and to fix it, just switch it back to “Free”.