Dealing with Hearing Loss: #ShareHear

A few weeks ago I tweeted and posted to Facebook a news story from CNN which I found very intriguing: Can Apple help make hearing aids cool? Based on the article, I’d have to say that the “cool” factor ought to be outweighed by the “I could hear better” factor.

Can Apple help make hearing aids cool?

Image from http://www.cnn.com/2014/03/04/tech/innovation/apple-resound-hearing-aids/

So why this post? It’s hardly in line with my normal SharePointilistic musings. Well, when I tweeted the story, several people got in touch to ask about my hearing aids and hearing loss. One well-respected person in the community pointed out that

…I think sharing anything is our purpose, SharePoint or not. I’d read what you post for sure. What caught my attention was the techy side of iPhone controlling the aids. It went from thinking technology was in the way to it being helpful and cool. Great message and opportunity.

This person has been wondering if it’s time to get his hearing checked, and now maybe he will, having realized that it’s not such a horrible thing. (Neither are colonoscopies, by the way, but that’s a whole other conversation.) If one or two people read this and understand people in their lives with hearing loss a little better or decide to get their own hearing checked, then it was worth writing it. And besides, I’m pretty sure I’m coining the latest #Share- hashtag: #ShareHear.

I’ve been using hearing aids for a little over five years now. Both my maternal Grandfather and my Mother had/have congenital hearing loss over the course of their lives, so I had a decent idea that it was going to happen to me, too. So far, my sister and brother seem to be doing OK, but they are younger.

In the kind of hearing loss I have, it’s a long, slow slide. I noticed probably in my mid-40s that I was having trouble hearing conversations in loud rooms – like bars – but I figured it was more about whether or not I cared enough about the conversation or something. Besides, I was getting older, so who had the energy to hear everything, right? Then a while later I realized that I was watching people’s mouths as they talked rather than their eyes. It took me a while to realize what that meant, but when I did, I figured something might be off.

In my line of work – consulting – I simply have to be able to have clear conversations with people. There aren’t that many professions where there are zero conversations, but I need to be able to hear what people say, internalize and synthesize it, and restate it or react quickly to it all the time. If I can’t hear what people are telling me in a conference room or on a conference call, I’m in trouble.

Even though I knew something was amiss, it wasn’t until I met someone who already had the latest generation of hearing aids that I decided to get my hearing checked out. In my case, they very literally weren’t my Grandfather’s hearing aids. (We actually called him “Grandfather”, just like Heidi in the eponymous movie.) Modern hearing aids are small, nearly unnoticeable, and highly sophisticated.

Here’s a photo of a hearing aid similar to the ones I have:

2014-04-07_14-38-25If you check out the Web page, you’ll see that they can even match the casings to your hair or skin color. As a member of the silver fox, gray-haired society, I think my casings are “Winter Silver”.

Everyone’s hearing loss is different, but as you can see, these things are small. If you’ve talked to me in the past and didn’t notice them, that’s why.

So are hearing aids perfect? No, far from it. As my most excellent audiologist told me early on, we can’t fix hearing, we can just make it better. Our hearing is never going to be as good as it was when we were kids; it’s just a fact of life.

The old style hearing aids were really just amplifiers. Both my Mom and my Grandfather had that kind. The sounds around them were just louder as they were pumped into their ears by ineffective speakers attached to ineffective microphones. Hearing aid technology is a place where improved circuitry and miniaturization makes a *huge* difference. Today’s hearing aids – at least the ones that you pay decent money for – had digital signal processing built into them and they are tuned for exactly your type of hearing loss.

If you do decide to get hearing aids, they are expensive. At least in my case, insurance covered none of it. One would hope that may change at some point, but not to date. Those ads you see in the Sunday paper for free or cheap hearing aids are come-ons, either for crappy hearing aids or ones with hidden costs.

And don’t think that hearing loss is something that only happens to old people like me. It can be a problem for anyone, so if you even have an inkling of a thought that you may have a problem, you owe it to yourself to get your hearing checked. It’s actually sort of fun. You go into a soundproof room – they are usually suspended to reduce vibration – and respond when you hear a bunch of blips and beeps and repeat some words back. It’s all totally painless.

If you’d like to know more about hearing aids or anything I’ve talked about here, feel free to ping me. When I asked my audiologist for good sites to point to, she sent back this:

I was searching thru a few websites for some hearing/ hearing aid information that might interest you.  Instead of sending you lots of different places, I’m just going to point you to the direction of my favorite hearing website – betterhearing.org.  There are some moderately hokey looking pics thru the site, but it’s one of the best places to find lots links for nature of loss, epidemiology, tech updates, current studies, market studies, etc.  I think you may find the kind of things you are looking for there.

but at least for me, it was a conversation with someone I knew about his hearing loss that got me on the right track.

My audiologist is hoping to get her hands on some of the cool Apple connected hearing aids for me to try out sometime soon. If they help me hear better, I’ll seriously consider them.

<UPDATE>

Cigale

Image from http://www.cigale.info/

Kevin Lowe mentioned tinnitus below, which made me realize I didn’t say anything about it.

Ah, tinnitus. The South of France is one of the most beautiful places in the world, at least in my book. The scent of lavender wafting on the breeze of a summer day with the bees droning in the fields is one of my most favorite things. There’s a bug there they call a cigale which sort of like what we call a locust.

Cigales are neat little bugs, and when they are present in the millions, as they are in the South of France, they let off a non-stop chirping sound which melds together into a constant hazy buzz. It’s really lovely.

Here’s a little video on a French farm with the cigales doing their thing.

All very lovely. Now imagine that you hear that sound 24×7, no matter where you are. That’s pretty much what tinnitus is, at least for me. No one fully understands it, but based on what I’ve read it’s our brains trying to fill in the information it’s no longer getting from our ears. Or something like that.

Tinnitus can be one of the worst parts of hearing loss because even though we can’t hear well, we’ve also lost our silence. That tinnitus sound fills it in. It’s subtle for some people, or fades in and out. For me, it’s virtually non-stop. I’m sort of used to it, but it doesn’t help me hear you when I’m talking with you. Unfortunately, hearing aids generally can’t do much about tinnitus. There has been some promising research about using cancelling sounds to controvert tinnitus, but nothing generally useful yet. There. That’s tinnitus.

</UPDATE>

SPServices: What About Deprecation of the SOAP Web Services?

SPServices user JSdream asked a question in the SPServices Discussions on Codeplex the other day that’s worthy of a more prominent response.

Should we, who use SPServices, be concerned at all with Microsoft recommending not to use either the ASMX web services in SharePoint 2013 (http://msdn.microsoft.com/en-us/library/office/jj164060.aspx#DeprecatedAPIs) or the owssvr.dll (I used this one a lot when doing InfoPath stuff) for development purposes?

The Choose the right API set in SharePoint 2013 article is an important one, for sure. In it, there’s pretty clear direction about which API to choose based on the specific requirements of the solution you are building. As with anything, though, there’s a strong dash of “it depends”. It depends on things like your available skills, the device the code will run on, etc.

Figure 1. Selected SharePoint extension types and SharePoint sets of APIs

Figure 1. Selected SharePoint extension types and SharePoint sets of APIs

I would say that we should all be “cautious” rather than “concerned”. The SOAP Web Services are used by many parts of SharePoint still, with the most prominent being SharePoint Designer. If you sniff around in the traffic between processes, you’ll spot other places as well.

That said, deprecated is deprecated. If you build your solutions with the data access layer separated out from the business logic layer, you should be able to replace the calls if and when it becomes necessary.

I am not aware of any official specific time frames for the SOAP services going away, and the Product Group would need to give us a good, long lead time because lots of code depends on it, SPServices or not. Many people have built managed code-based solutions which use the SOAP Web Services as well. GetListItems is a workhorse operation no matter how you build your solutions.

There are many things you simply cannot do with REST yet, though in many cases CSOM may provide better coverage. If you are using SPServices for the operations which aren’t available in REST or CSOM, obviously you’ll want to continue doing so until there is a viable replacement. The REST coverage is improving steadily. (See Overview of SharePoint Conference 2014 and new content for developers for some information.) Keep in mind, though, that the majority of improvements will end up in Office365 first and in the SharePoint Server product at some point later or perhaps not at all. So your time horizons and cloud plans are also critical decision factors.

[If I had to put my money on a horse, it'd be REST over CSOM over the long term.]

All that said, if you are starting a new project on SharePoint 2013 of any significant size, you should be considering using the App Model, CSOM, and REST. SPServices may still fit in there somewhere, so don’t toss it out with the bath water just yet. I’ll continue evolving it as long as it has people wanting to use it. I think I still have plenty of things to do.

Create a Subsite in SharePoint 2013 Using REST Calls

Today I was working on what seemed like a simple little task. I wanted to create a subsite using a REST call in SharePoint 2013. I’m not working in an “app” per se – this is for SharePoint 2013 on premises, and I want to do the subsite creation directly from a call in a plain old aspx page.

Unfortunately, there isn’t a clear example out there, at least not that I could find. It seems as though everyone has simply copied the example from this page on MSDN and quotes it verbatim. (Look for the “Creating a site with REST” example.) Unfortunately, I couldn’t get that example to work for me. Most of the examples are also focused on creating subsites in a workflow rather than directly.

I knew I’d need to have a fresh copy of the Form Digest for the request to work. There’s a great article from Wictor Wilén (@wictor) called SharePoint 2013: How to refresh the Request Digest value in JavaScript that explains several different ways to get this token. You must have the token in order for SharePoint to be willing to accept your requests to do a write to anything; it’s a part of the security features. In the page where I am working, we’re building a full application on top of SharePoint, but without using the out of the box SharePoint UI. Because of this, things like the hidden variable which usually holds the Form Digest token aren’t available in our pages. By making a quick call to the ContextInfo REST API, I can grab the Form Digest token pretty painlessly using the second method from Wictor’s post.

The breakthrough came due to some great suggestions from Matt Gibson (@Gibz) and Rob Windsor (@robwindsor) on Twitter. (You’ve got to love the #SPHelp hashtag!) Both Matt and Rob were sure this should work and gave me tips. The winning idea came from Rob. There’s a comment at the bottom of the MSDN page referenced above that shows slightly different JSON data in the REST call payload, and that did it. Bottom line, the documentation doesn’t seem to be adequate or correct in this case. At the very least, I couldn’t find it if it’s out there.

Here’s the code I ended up with. I’ve built it as a jQuery function for reusability.

// Create a new subsite
$.fn.Site.create = function(options) {

  var opt = $.extend({}, {
    siteUrl: null,
    siteName: null,
    siteDescription: "",
    siteTemplate: "sts",
    uniquePermissions: false
  }, $.fn.ProjectName.defaults, options);

  // Because we don't have the hidden __REQUESTDIGEST variable, we need to ask the server for the FormDigestValue
  var __REQUESTDIGEST;
  var rootUrl = location.protocol + "//" + location.host;

  var contextInfoPromise = $.ajax({
    url: rootUrl + "/_api/contextinfo",
    method: "POST",
    headers: {
      "Accept": "application/json; odata=verbose"
    },
    success: function(data) {
      __REQUESTDIGEST = data.d.GetContextWebInformation.FormDigestValue;
    },
    error: function(data, errorCode, errorMessage) {
      alert(errorMessage);
    }
  });

  // Once we have the form digest value, we can create the subsite
  $.when(contextInfoPromise).done(function() {
    $.ajax({
      url: rootUrl + "/_api/web/webinfos/add",
      type: "POST",
      headers: {
        "accept": "application/json;odata=verbose",
        "content-type": "application/json;odata=verbose",
        "X-RequestDigest": __REQUESTDIGEST
      },
      data: JSON.stringify({
        'parameters': {
          '__metadata': {
            'type': 'SP.WebInfoCreationInformation'
          },
          'Url': opt.siteUrl,
          'Title': opt.siteName,
          'Description': opt.siteDescription,
          'Language': 1033,
          'WebTemplate': opt.siteTemplate,
          'UseUniquePermissions': opt.uniquePermissions
        }
      })
    });
  });

}; // End $.fn.Site.create

With the function set up this way, I can call it something like this:

$().ProjectName.Site.create({
  siteUrl: "mysite",
  siteName: "My Site's Name",
  siteDescription: "This is the description that explains how to use this site.",
  siteTemplate: "sts",
  uniquePermissions: false
});

I like to publish stuff like this when I figure it out. We’re all in this together and we shouldn’t need to figure things out more than once.

Thanks Matt and Rob!

SPServices Stories #21 – Redirect If User Clicked a Button Previously

Introduction

teylynIngeborg Hawighorst (@IngeborgNZ) is a long-time SPServices user who has come up with any number of intriguing uses for the library. I’d recommend her blog anytime if you’d like to learn about interesting things you can do with SharePoint, but even more so if Excel is your bag. Ingeborg has been an Excel MVP for years running (see her profile on the MVP site). Some of the best solutions using SPServices come out of discussions in various SharePoint-oriented forums. In this case, Ingeborg spotted some suggestions from Eric Alexander (@ejaya2 aka PirateEric) and decided to build it out. Without further ado, here is Ingoborg’s article, reposted from her blog cheers, teylyn.

Redirect If User Clicked a Button Previously

I just came across this question in sharepoint.stackexchange.com. When a user visits a SharePoint site, they are presented with a splash screen and need to accept the policy before they can proceed. Upon subsequent visits, the splash screen does not show, because SharePoint will remember the  user. PirateEric outlined a possible solution: Use a SharePoint list to save the user name when the button is clicked. When the page loads, look up the user in the list. If they already exist, redirect the page, if not, show the splash page with the button to accept the policy. If the policy changes and users need to be made aware of that, simply remove all items in the list that tracks the users. All this can be done with jQuery and web services. That intrigued me and I had a go at actually building this, using Marc Anderson’s SPServices.

How to set it up

Create a SharePoint custom list with two fields, Title and UserName. The former is the out of the box field, the latter is a simple text field. Create two pages, the Splash page with the button and the page that is the desired destination page for all visitors. In my sample these are called Splash.aspx and MainContent.aspx On the Splash page the code that you can see below will be loaded before any other web part. If you use a Content Editor Web Part to load the code with a content link, make sure that it’s the first web part on the page. In many cases, JavaScript and jQuery will be placed in the last web part of the page and run after the DOM has loaded. But in this case this would mean that the Splash page appears briefly, even if it is followed by a redirect to a different page. The Splash page provides the policy (or terms and conditions) that the user must accept, and a link or a button that the user can click to accept. This link or button must then trigger a JavaScript function. That is very easy to do. I used a button and put the html straight into a CEWP like this:

<button onclick="PolicyButtonClick()" type="submit">
   I accept the policy
</button>

So the user clicks the button and the JavaScript function PolicyButtonClick() will run. This function can be found in the code below. First, the jQuery library and the SPServices library are loaded. Then the user name of the current user is retrieved with the SPServices call using SPGetCurrentUser. It returns a text string in the format DOMAIN\Account.  Next, the SPServices call uses the GetListItem. In the call, a CAML query is constructed that will return only list items where the column UserName equals the current user.  The items returned by that query are then counted. Since the user account is a unique value, we can safely assume that the query will either return one result or no result at all. If the query returned an item, this means that the user has previously accepted the policy and the script will redirect to the MainContent.aspx page.  If the query did not return anything, the current page will continue to be displayed. When the user clicks the button to accept the policy,  the user name is written into a variable. Then the SPServices operation to UpdateListItem is called and will create a new item in the list “PolicyAccepted”, storing the previously established account name in the column UserName. Then the MainContent.aspx page is loaded. The next time the user opens the Splash page, their account name will be found in the PolicyAccepted list and they will not see the Splash page again, unless the entry in the list is deleted. Here is the complete script:

<script type="text/javascript" src="/path/jquery-1.10.2.min.js" language="javascript"></script><script type="text/javascript" src="/path/jquery.SPServices-2013.02a.min.js" language="javascript"></script><script type="text/javascript">// <![CDATA[
// start the code even before the DOM is loaded, so not waiting for document ready
//$(document).ready( function() {
// get the user name
 var userName= getUserName();
// find the user name in the list
 var userAccepted = matchUserName(userName);
 if (userAccepted == 1 )
 {
 // redirecting page
 window.location.replace("http://path/Documents/MainContent.aspx");
 }
//});

function getUserName() {
 var thisUserAccount= $().SPServices.SPGetCurrentUser({
 fieldName: "Name",
 debug: false
 });
 return(thisUserAccount);
}

function createNewItem(theTitle, theUser) {
 $().SPServices({
 operation: "UpdateListItems",
 async: false,
 batchCmd: "New",
 listName: "PolicyAccepted",
 valuepairs: [["Title", theTitle], ["UserName", theUser]],
 completefunc: function(xData, Status) {
 }
 });
}

function matchUserName(userName) {
 var queryText = "<Query><Where><Eq><FieldRef Name='UserName'/><Value Type='Text'>" + userName + "</Value></Eq></Where></Query>";
 $().SPServices({
 operation: "GetListItems",
 listName: "PolicyAccepted",
 async: false,
 CAMLQuery: queryText,
 completefunc: function (xData, status) {
 itemCount = $(xData.responseXML.xml).find("rs\\:data, data").attr("ItemCount");
 }
 });
 return(itemCount);
}

function PolicyButtonClick() {
 var userName= getUserName();
 var theTitle= "Accepted";
 createNewItem(theTitle, userName);
 window.location.href = "http://path/Documents/MainContent.aspx";
}
// ]]></script>

The MOSS Show SharePoint Podcast: Episode 87 – Talking JavaScript with Marc Anderson

The MOSS ShowBack in late January, I sat down – in the virtual sense, as usual – with Hilton Giesenow (@hiltongiesenow or the slightly more active @TheMossShow) to have a chat about JavaScript for his MOSS Show SharePoint Podcast. At the time, we were in the throes of trying to figure out what had happened on Office365 with some breaking DOM changes. Breaking for us JavaScript folks, anyway. We covered a number of topics like improving the user experience in SharePoint, what’s been going on with JavaScript over the years in the SharePoint community, and more.

From Hilton’s intro to Episode 87 – Talking JavaScript with Marc Anderson:

The entire web development world seems to have had a love-hate-love-hate relationship with JavaScript over the many years of its existence, and it’s no different in the SharePoint world, albeit a few years behind in many cases. In this episode we speak with many-year industry veteran and long time SharePointer Marc Anderson about his experiences with JavaScript and SharePoint over the years, his wildly successful SPServices library, Single-Page Applications (SPAs) and lots more.

Head on over to Episode 87 – Talking JavaScript with Marc Anderson and have a listen.

2014-03-18_22-53-36