Monday, July 25, 2016

Multiple Google Hangouts Accounts on Desktop

If you're like me, you have many many google apps accounts, for business, personal, or varying other purposes. For me, this works fine on my android device, where the Hangouts app is designed to support as multiple identities just fine. However, on my desktop, where I spend most of my day, the Hangouts Chrome app lacks this support.

There is an official work around suggested by Google's support team. Until recently, this work around was sufficient. By enabling the Chrome app launcher, I could open the Hangouts app from each account by changing profiles from the hamburger menu in the app launcher. However, Google is deprecating the Chrome app launcher.

Without the app launcher, getting Hangouts open with multiple profiles requires opening a chrome window, opening the app page, and finding and clicking the Hangouts app, then repeat for each profile. This is too many steps to feel efficient for me, and since Hangouts is an integral tool for my daily business, I must have it open at all times, and I need a fast way to get it running.

Enter shortcuts.


Today I finally found the best solution so far. Using Chrome app shortcuts. 

Chrome.exe supports two very useful parameters: profile-directory, and app-id. When you choose "Create shortcuts..." from the right click menu on chrome://apps, the shortcuts created include these two parameters so that the resultant app shortcut is bound to the profile from which you created it.


Choosing this option only offers one place to create the shortcut (Desktop) but fortunately, Chrome is smart enough to save an additional copy of the same shortcut in the Start Menu (specifically: AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Chrome Apps) so there is no need to keep the desktop shortcut around. We can rename these shortcuts to help us quickly find and launch a Hangouts app for each profile.


Incidentally, these shortcuts are profile bound not by any logical account id, but rather by account order. They use --profile-directory="Default" and --profile-directory="Profile 1" arguments to launch the app. So if you find yourself disconnecting and reconnecting your profiles in Chrome, your shortcuts may stop working or start launching the app with the wrong profile.

Wednesday, January 14, 2015

SQL: Convert a Hash to a Varchar

For some reason this task always stumps me, so here is the solution:
CONVERT([varchar](512), hashbytes('sha', col), 2)
Thanks to Basit

Friday, October 12, 2012

JQuery Validate: Change Option Value

In my current project I have a default set of options that every form gets validated with. In fact, .validate(options) is called for every form.

Today I needed to change one of the options that my form validator was initialized with. Sounds pretty simple, but for the life of me I couldn't find anything like setOption() or .validate("option", {}) like other plugins have.

Turns out that Validate actually makes it too simple. Where other plugins give you non-standardized functions to update the options, Validate gives you the options object directly... but they call it settings.

I can disable the auto onsubmit validation by doing the following:
$("#myForm").validate().settings.onsubmit = false;
This works because .validate() returns the current validator for the form, and the validator neatly exposes the settings collection.

Wednesday, April 25, 2012

Extending QueryOver With "Or"

QueryOver (introduced in NHibernate 3.0) offers type safe, Linq-esque, syntax for writing Nhibernate queries in your DAO. However, writing a multiple column disjunction with anything other than simple operators can easily become ugly and unwieldy.

Tuesday, March 13, 2012

T-SQL: Aggregate a column to a comma delimited list

I commonly encounter situations where it is useful to select a comma delimited list as an aggregate in a grouped query. This is a well known problem and yet each time I run across it I have to look something up to solve it.

The following is a detailed breakdown of the solution from the msdn archive.

The scenario I'm covering here is the need to aggregate all the IDs in a joined table into a single column on the master table. We'll use a table structure like this:
CREATE TABLE Parent (
  Id int NOT NULL identity,
  Name varchar(50) NOT NULL,
  Children varchar(256) NULL,
)
CREATE TABLE Child (
  Id int NOT NULL identity,
  ParentId int NOT NULL,
  Name varchar(50) NOT NULL
)
Create some sample data:
INSERT INTO Parent (Name)
VALUES ('Parent 1'), ('Parent 2'), ('Parent 3')
INSERT INTO Child (ParentId, Name)
VALUES (1, 'Child 1'), (1, 'Child 2'), (1, 'Child 3'), (2, 'Child 4'), (2, 'Child 5'), (3, 'Child 6'), (3, 'Child 7'), (3, 'Child 8'), (3, 'Child 9')
Now we can update the Children column on Parent with this:
;
WITH
t AS (SELECT p1.Id, Children = (
    SELECT (',' + convert(varchar, c2.Name ))
    FROM Parent p2
      JOIN Child c2 ON p2.Id = c2.ParentId
    WHERE p2.Id = p1.Id
    ORDER BY c2.Id
    FOR XML PATH( '' )
  ) + ','
  FROM Parent p1
    JOIN Child c1 ON p1.Id = c1.ParentId
  GROUP BY p1.Id)
UPDATE p
SET Children = t.Children
FROM Parent p
  JOIN t ON t.Id = p.Id
And the results look like:
Id | Name | Children
1 | Parent 1 | ,Child 1,Child 2,Child 3,
2 | Parent 2 | ,Child 4,Child 5,
3 | Parent 3 | ,Child 6,Child 7,Child 8,Child 9,

Thursday, June 9, 2011

ActiveReports: Grouping

We've used Grape City's (formerly Data Dynamics) ActiveReports off and on for many years. I'm not truly a fan since personally I've never found it that intuitive, but for flexibility they're pretty good.

Recently I ran into a quirk I've encountered before but had forgotten. I won't call it a bug since we're using it in a manner that is undocumented and most likely not supported.

Since AR uses (or appears to use) DataBinder.Eval to evaluate the DataField on each object in the DataSource of a report, we have always used collections of domain objects for our report sources. This works well for textboxes, however, when you try to do a standard report grouping (with header and footer) you'll get stuck wondering why the report only seems to recognize one group. Specifically this occurs when you use a property path of depth greater than one.

The following works:
myTextbox.DataField = "Property1.Property2";
myGroupheader.DataField = "Property1";
This does not:
myTextbox.DataField = "Property1.Property2";
myGroupheader.DataField = "Property1.Property2";
The textbox will populate correctly but the report will only discover one group of records.

Friday, May 6, 2011

NHibernate: Group By Case Statement

Today I wanted to speed up some statistics tables which had been tossed into our application dashboard awhile back. The queries were originally written quick and dirty to just pull back all of the records in the table then run some linq counts on them. Terrible of course and there was a nice little comment above the section saying something about "TODO: make this better".

The quickest query I could think of to run these statistics looks something like this:
select 
IsJourneyman,
case when Accepted is null then 1 else 0 end,
Count(*)
from
students
group by
IsJourneyman,
case when Accepted is null then 1 else 0 end
My next thought was "Can I implement this in ICriteria?" Well it turns out the answer is Yes!
var cr = Session.CreateCriteria<Student>();

cr.SetProjection(Projections.ProjectionList()
.Add(Projections.RowCount(), "Count")
.Add(Projections.Group<Student>(s => s.IsJourneyman), "IsJourneyman")
.Add(Projections.GroupProperty(
Projections.SqlProjection("case when Accepted is null then 1 else 0 end",
new[] { "IsApplicant" }, new[] { NHibernateUtil.Boolean })),
"IsApplicant")
);

// transform the results into a strong typed object
cr.SetTransformer(Transformers.AliasToBean(typeof(CountResult)));

return cr.List<CountResult>();
For which I created this simple class. The aliases passed to .Add() are used to match up the properties.
public class CountResult
{
public bool IsJourneyman { get; set; }
public bool IsApplicant { get; set; }
public int Count { get; set; }
}
I tried using the Projections.Conditional, but ran into a NHibernate bug on mixing named and ordered parameters.

I'm sure there are faster ways to accomplish this, but since I wanted to do it in NHibernate without adding a calculated field this will work for me.

Thursday, April 21, 2011

Free Reflector Alternatives

If you're like me you were super disappointed when Red Gate reneged on their promise to keep .Net Reflector "free forever". While I don't use Reflector every day, there are numerous times where I've needed to drill into a dll to see how something is accomplished or find some functionality I need.

Fortunately, there are new alternatives appearing for us penny pinchers. Hopefully Red Gate will get the message.

ILSpy - ILSpy is a free, open source replacement for .Net Reflector. Look and feel are modeled on Reflector.

JustDecompile (h/t Assia) - Telerik's foray into the market. Currently in beta but promises regular updates and an integrated auto-updater.

dotPeek - By JetBrains.

Sunday, June 13, 2010

Practical MongoDB Part 3: Fine Tuning

In Part 1 of this series I briefly discussed setting up MongoDB to run as a service. In Part 2 I covered data access objects. In this installment I'd like to touch on embedded documents before reviewing a few configuration changes you should use to improve performance.

Thursday, June 10, 2010

Practical MongoDB Part 2: NoRMalized Data Access

In Part 1 of this series I demonstrated setting up MongoDB to run as a Windows service. In this segment, I'll show you how I setup my data access layers using NoRM.

Practical MongoDB Part 1: Up and Running

Like many others, I've been intrigued by the NoSQL movement and the various alternatives which have appeared in recent years. One of these options which is rapidly growing in popularity is MongoDB, a document oriented database written in C++ with scalability in mind.

This post is the first in a series documenting my attempts to implement MongoDB into a real world project.

MongoDB has garnered a following in the ruby and php communities, but up until recently had little exposure to .Net folks. The earliest .Net driver, mongodb-csharp, was basically a wrapper on Mongo's built in capabilities. While useful, this design did little to provide a strongly typed approach to data access. More recently however, another open source effort led by Andrew Theken and Rob Conery created NoRM: a strongly typed driver (which even has a sweet Linq provider). There are other C# drivers out there, but these are the ones I have experienced. Part 2 and onward of this series will use NoRM.


Thursday, April 15, 2010

MVC 2: JsonRequestBehavior DenyGet

We migrated one of our projects to MVC 2 today, and one of the first things I noticed is that all my ajaxified jsony sweetness had stopped working! A quick look at the XHR revealed the following server error.
This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.
What the heck?

A quick Google turned up a couple articles about MVC 2's new JsonRequestBehavior, and specifically the MSDN article (the link to Haack is dead, so here's a good one). Ok, good to know. I wasn't aware of that vulnerability, but in the mean time I need this project working.

I could modify the actions to call a Json overload which accepts the JsonRequestBehavior.
  return Json(myjson, JsonRequestBehavior.AllowGet);
But since I have somewhere between 50-80 Json actions in this app, that would be a lot of find-replace. Plus, when I finish modifying my client library to use POST requests, I would have to do it all over again. A one stop solution would be much preferable.

If your project already uses a base controller class, you can do one simple override:
protected override JsonResult Json(object data, string contentType,
Encoding contentEncoding, JsonRequestBehavior behavior)
{
// TODO: change all my GET Json request into POST
return base.Json(data, contentType, contentEncoding,
JsonRequestBehavior.AllowGet);
}
Keep in mind this should be a temporary crutch only!

IIS 7 (7.5): Hosting Multiple SSL Sites On One IP

Since I continually find myself Googling this information whenever I add a new site on our wildcard cert, I figured I'd document it here.

Adding a New Binding:

Requirements:
  1. A wild card SSL certificate (of the form *.domain.com). I assume the cert is already installed on your server.
  2. An IP you wish to use on multiple IIS sites.
  3. Two or more IIS sites with no SSL binding (I'll touch on changing a binding at the end).
With these in place, adding an SSL cert is quite simple:
  1. In an elevated command prompt navigate to
    C:\Windows\System32\inetsrv
  2. Enter the following command (replace {SITENAME}, {IP}, and {HOSTHEADER} with the appropriate values).
    appcmd set site /site.name:{SITENAME} /+bindings.[protocol='https',bindingInformation='{IP}:443:{HOSTHEADER}']
  3. Check the selected cert in IIS via the bindings window. You can change the cert here, but you cannot change the host header.
That's it.

Changing an Existing Binding:

Changing a binding is similar to the adding binding with a few alterations to the command
appcmd set site /site.name:{SITENAME} /bindings.[protocol='https',bindingInformation='{IP}:443:{HOSTHEADER}'].bindingInformation:{NEWIP}:443:{NEWHOSTHEADER}

Wednesday, January 20, 2010

NHibernate: Is That Type a Proxy?

One of our applications does some reflection to map customizable content to domain objects. Anyone familiar with NHibernate and lazy loading has probably encountered proxy classes before. My problem: given a Type, I want the domain type.

It's easy to find out that proxy types extend the domain type they represent, so if I know that my Type is a proxy I can call BaseType to get the domain type. But how do I know if my Type is a proxy?

I tried numerous approaches, but the simplest I found was to look for a specific interface. Turns out proxies implement an interface called INHibernateProxy.

if (clazz.GetInterface(typeof(INHibernateProxy).FullName) != null)
clazz = clazz.BaseType;

Now clazz represents the domain type as desired.

There are other solutions of course, such as detecting the namespace (proxies have none), and possibly checking IsAutoClass (which I couldn't confirm in any documentation). This approach seems the most reliable.

Friday, January 8, 2010

NHibernate: Mapping a Generic List of Enum

I recently ran into a case where I wanted to have a collection of an enumeration on one of my domain classes.

E.g.

public class MyDomainClass
{
public List<MyRoleEnum> Roles { get; set; }
}

But how is do we map something like this in an xml mapping? A quick google didn't turn up the answer, so I played around a bit and found the following works as desired.

<bag name="Roles" table="MyDomainClass2Role">    
<key column="MyDomainClassId" />
<element column="Role" type="MyRoleEnum" />
</bag>

To confirm this usage I checked the documentation at hibernate.org. Turns out the <element /> tag was designed for value type bags anyway.

Wednesday, November 4, 2009

Demote 2003 Domain Controller: NETLOGON Timeout

As you may know, I occasionally copy information here which I feel needs better exposure on the web. This is just such a post.

I recently tried to demote a server 2003 domain controller (using dcpromo), and hit the following error message:

The operation failed because:

Failed to configure the service NETLOGON as requested

"The wait operation timed out"
This is a particularly useless message because the actual problem has nothing to do with netlogon.

I corrected this problem by modifying the TCP/IP settings to point DNS at the remaining domain controller (e.g. remove 127.0.0.1 or any other IP which points to the machine being demoted).

Tuesday, September 29, 2009

Running IE6 in Windows 7 with Virtual PC

With the advent of Windows 7 and improved application virtualization, legacy browser testing has been greatly simplified.

Thanks to the XP Mode vmc that Microsoft provides here, it is quite easy to setup an instance of IE6 to run almost seamlessly alongside your native Windows 7 apps.


After installing Windows Virtual PC and the XP Mode vhd, perform the following steps:
  1. In Windows Explorer, navigate to "c:\documents and settings\all users\start menu".
  2. Right-click and select New -> Shortcut.
  3. Type in http://www.google.com or whatever you would like your home page to be.
  4. Give the shortcut a name (I called mine "IE6").
  5. Finish the wizard, log off, and close the virtual PC.
  6. In your Windows 7 start menu you will now find a folder at All Programs -> Windows Virtual PC -> Windows XP Mode Applications which contains the shortcut you just created. Click this shortcut and TADA! IE6 runs in a window of it's own.
One limitation of this approach is that you can only have one instance of any XP Mode application running at one time. You may be able to open multiple IE6 instances by creating more than one shortcut in the xp start menu, but I didn't try it.

Sunday, August 30, 2009

No DVD Sound in Windows 7

I installed Windows 7 on an older (4 years) laptop this past weekend and encountered a rather irksome problem that has a very simple fix.

Symptoms:
  • Audio works fine, until you stick in a DVD and try to play it with WMP12: no sound.
  • WMP12 playing mp3's is fine, but stick in a DVD: no sound.
  • Load a DVD ISO on a virtual drive and try to play: no sound.
Because of some trouble I had with the Realtek drivers for windows 7, and the Sony DVD drive, I was not certain at this point where precisely the problem lay. Searching a bit for Realtek, DVD and Sony's DW-D56A didn't turn anything up, so I started looking more broadly.

Turns out a post on AVForums by Damernath pointed out a very simple solution that worked like a charm. I repeat below for your benefit:
  1. Go to: Control Panel -> Sound
  2. On the "Playback" tab select "Speakers" and click "Properties"
  3. On the "Advanced" tab uncheck "Allow applications to take exclusive control of this device"
That's it. Restart WMP and watch your DVD glory.

Thursday, August 6, 2009

MS Deploy RC1 Install ... Odd!

In upgrading from MS Deploy Beta1 to RC1, I found an undocumented oddity which could stump you for who knows how long.

If you install the RC without first uninstalling the beta, the Web Deployment Agent Service refuses to start. From the command line, "net start msdepsvc" returns

The service did not report an error

And no error is logged in the Event Log either.

The fix? Simple, just go into Programs and Features, select the Web Deployment Tool Release Candidate 1 and choose "Repair".

All fixed.

Thursday, June 18, 2009

Clearing Sql 2008 Management Studio Saved Passwords

In Management Studio 2005, the saved connections, usernames, and passwords could be cleared out by deleting the mru.dat file. However, in SSMS 2008 there is no equivalent data file. A similar effect can be achieved by deleting the SqlStudio.bin file. This will affect other settings, but for now it's the best solution.

In Vista, this file is located at:
C:\Users\{username}\AppData\Roaming\Microsoft\Microsoft SQL Server\100\Tools\Shell\SqlStudio.bin
And for XP:
C:\Documents and Settings\{username}\Application Data\Microsoft\Microsoft SQL Server\100\Tools\Shell\SqlStudio.bin
Aaron Bertrand has blogged a bit more about this here.