Scott Hanselman

Integrating Visual Studio Code with dnx-watch to develop ASP.NET 5 applications

October 20, '15 Comments [20] Posted in ASP.NET | Open Source
Sponsored By

Visual Studio Code is a great cross platform code editor that is also free. You can get it at code.visualstudio.com for Mac, Windows, or Linux. It's great for web development, and particularly shines with node.js. Since ASP.NET 5 is still in active beta and moving very fast, some of the features I want when VSCode is used with ASP.NET aren't there yet. Fortunately VSCode is very configurable and I was able to get it to do what I wanted in about 10 minutes of messing around.

dnx-watch in VSCode

One of the promises of ASP.NET is the ability to write code, hit Ctrl-S (Save) in your editor and then hit F5 (refresh) in your browser to see the results. Rinse, repeat. Any "build" step should be basically hidden.

After you've got .NET Core and ASP.NET 5 with the DNX (for now, the "dotnet execution engine") you should take a look at the dnx-watcher command. It's a command you can install in one line:

dnu commands install Microsoft.Dnx.Watcher

This convenience command wraps dnx, so when you want to run your app rather than "dnx web" you'll say "dnx-watch web." It will watch your source files directory for changes. When you make a change, be it in VSCode or in Notepad, dnx-watch will kick the process and start it again so you can hit F5 in your browser.

Visual Studio Code doesn't have a Build or Debug menu for ASP.NET today, but I wanted to be able to "Ctrl-Shift-B" and build/start my web application. Specifically I wanted to run dnx-web on the current app.

Here's how you do that today. First, install dnx-watch as above.

This next part with tasks.js is totally optional, but I like it because it makes VSCode and the Ctrl-Shift-B hotkey I'm used to work the way I want.

Make a folder at the top of your project called ".vscode" and put a file called "tasks.json" inside it. This is a special file that lets you tell Visual Studio Code what gulp tasks it should know about.

Here I'm saying there's a task (that we'll create in a second) called "watch" (I decide on the name) and it's the Build command for this project. I could make a Test command if I wanted, as well. I want to see the output.

{
"version": "0.1.0",
"command": "gulp",
"isShellCommand": true,
"tasks": [
{
"taskName": "watch",
"isBuildCommand": true,
"showOutput": "always",
"isWatching": true
}
]
}

Now where does this "watch" task go? Well it goes in my project's gulpfile.js! It's a gulp task like any other.

I want to shell out and run dnx-watch, so I'll have to bring in a small library called gulp-shell by adding it to my package.json, then running npm.install. That will give me the ability to shell out to arbitrary command line apps like dnx-watch. Visual Studio Code will capture and stream the output as seen in the screenshot above.

Then I just add one line to my gulpfile after adding the appropriate require at the top.

gulp.task('watch', shell.task(['dnx-watch web']))

ASIDE: There is the beginnings of a gulp plugin for ASP.NET called "gulp-dnx" that knows about DNX and ASP.NET 5 but since I just wanted this one feature, this was easier. When gulp-dnx knows about dnx-watch, it might be easier, but the general flow would remain the same.

At this point, I can code all I want, press Save and dnx-watch will automatically restart my application. I can put Visual Studio Code side by side with my browser and Save/Refresh over and over.

Now you can always add your own keybindings by editing keybindings.js from File | Preferences | Keyboard Shortcuts. For example, here Ctrl-Q is bound to Terminate Task (that will let me stop dnx-watch). However, because we said "isBuildCommand: true" in the tasks.js file, we've told Visual Studio Code that our "watch" gulp command IS our project's command to build. You could add test commands, make your gulp file more sophisticated; the sky's the limit.

Give it a try!


Sponsor: Many thanks to Atalasoft for sponsoring the feed this week. If your project requires image viewing, format freedom, scanning, or other document-centric workflows, Atalasoft’s document imaging experts can help. Evaluate their developer tools for 30 days with remarkable human support.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Control how your bower packages are installed with a gulpfile in ASP.NET 5

October 16, '15 Comments [29] Posted in ASP.NET | Javascript | Open Source
Sponsored By

ASP.NET 5 beta 8 is out. Yes, that's a lot of betas, but it's important to get things right when you're doing something new like this. You can find instructions in our documentation for installing ASP.NET 5 beta8 on Windows, Mac and Linux.

ASP.NET 5 uses the NuGet package manager to get server-side libraries but for client-side things we recommend folks use Bower. The most popular JavaScript and CSS libraries are there, and there's no need for us to duplicate them in NuGet. This means ASP.NET 5 folks get to use the same great client-side libraries that other open web technologies enjoy.

In very early builds of ASP.NET 5 we put those libraries in a folder outside the web root (wwwroot) into bower_components or npm_components and then used a gulp/grunt (think MSBuild for JavaScript) task to copy the files you want to deploy into wwwroot in preparation for deployment. However this confused a LOT of folks who weren't familiar with these tools. It also meant another step after installing a new JavaScript library. For example, you'd install angular with bower, then manually edit the gulp file to copy the .js you wanted into the folder of your choice, then run gulp to actually move it. These are common tasks for many of today's open web developers, but have been confusing for ASP.NET 5 users who don't usually work on the command line. So, this was changed a while back and your bower libraries show up right in your wwwroot.

bower stuff under wwwroot

While this is convenient change and great to starters, at some point you'll want to graduate to a more formal process and want to move your bower client libraries back out, and then setup a task to move in just a files you want. Let's take a moment and switch it back the way it was.

Here's how.

Update your .bowerrc and project.json

In the root of your project is a .bowerrc file. It looks like this:

{
"directory": "wwwroot/lib"
}

Change it to something like this, and delete your actual wwwroot/lib folder.

{
"directory": "bower_components"
}

Exclude your source bower folder from your project.json

You'll also want to go into your project.json file for ASP.NET 5 and make sure that your source bower_components folder is excluded from the project and any packing and publishing process.

"exclude": [
"wwwroot",
"node_modules",
"bower_components"
],

Update your gulpfile.js

In your gulpfile, make sure that path is present in paths. There are totally other ways to do this, including having gulp install bower and figure out the path. It's up to you how sophisticated you want your gulpfile to get as long as the result is that production ready .js ends up in your wwwroot ready to be served to the customer. Also include a lib or destination for where your resulting JavaScript gets copied. Could be scripts, could be js, could be lib as in my case.

var paths = {
webroot: "./" + project.webroot + "/",
bower: "./bower_components/",
lib: "./" + project.webroot + "/lib/"
};

Add a copy task to your Gulpfile

Now open your Gulpfile and note all the tasks. You're going to add a copy task to copy in just the files you want for deployment with your web app.

Here is an example copy task:

gulp.task("copy", ["clean"], function () {
var bower = {
"bootstrap": "bootstrap/dist/**/*.{js,map,css,ttf,svg,woff,eot}",
"bootstrap-touch-carousel": "bootstrap-touch-carousel/dist/**/*.{js,css}",
"hammer.js": "hammer.js/hammer*.{js,map}",
"jquery": "jquery/jquery*.{js,map}",
"jquery-validation": "jquery-validation/jquery.validate.js",
"jquery-validation-unobtrusive": "jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"
}

for (var destinationDir in bower) {
gulp.src(paths.bower + bower[destinationDir])
.pipe(gulp.dest(paths.lib + destinationDir));
}
});

Do note this is a very simple and very explicit copy tasks. Others might just copy more or less, or even use a globbing wildcard. It's up to you. The point is, if you don't like a behavior in ASP.NET 5 or in the general build flow of your web application you have more power than ever before.

Right click the Bower node in the Solution Explorer and "Restore Packages." You can also do this in the command line or just let it happen at build time.

image

Looking in this simplified screenshot, you can see the bower dependencies that come down into the ~/bower_components folder. Just the parts I want are moved into the ~/wwwroot/lib/** folder when the gulpfile runs the copy task.

A new flow for my JavaScript

Feel free to share in the comments links to your blog posts on how YOU like your gulpfiles and build process to work!


Sponsor: Thanks to Infragistics for sponsoring the feed this week! Responsive web design on any browser, any platform and any device with Infragistics jQuery/HTML5 Controls.  Get super-charged performance with the world’s fastest HTML5 Grid - Download for free now!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Diabetes Technology: Dexcom G5 CGM Review - So much wasted potential

October 13, '15 Comments [56] Posted in Diabetes
Sponsored By

Dexcom G5 for iPhoneAs you may know, I'm a Type 1 Diabetic and have been for well over 20 years. I wear a Medtronic Insulin Pump 24 hours a day and use a Dexcom CGM (Continuous Glucose Meter) to monitor my blood sugar, also 24 hours a day.

This post won't explain how diabetes works to you, so check these posts out (or this video) first if you're not familiar.

Moving from a Dexcom G4 to a Dexcom G5

A CGM (Continuous Glucose Meter) doesn't keep you from pricking your fingers. You'll still do finger sticks in order to calibrate a CGM, at least twice a day.

The Dexcom G4 "with Share" worked like this. There was a small transmitter that is attached to me, and it talks a proprietary RF wireless format to a Receiver and then the Receiver talks Bluetooth LE to your iPhone, like this picture below.

Once the sugar number got to my iPhone it's then optionally uploaded to  the Dexcom Share Cloud. My wife can install the Dexcom Follow application on her iPhone and see my sugar on her phone. She also gets the same notifications and warnings I get.

How the Dexcom G4 system works

When you "upgrade" to the G5 from the G4, you'll likely do what I did. I called Dexcom support to see if I was eligible. They had a US$199 upgrade fee which I paid, and the G5 transmitter showed up a week later. I then called them back to get an "upgrade code" which was a 12 digit unique number (GUID) that I had to enter into their Dexcom Studio application on my Windows machine. I plugged in my Dexcom G4 with Share Receiver to my Windows machine using Microsoft USB and ran the upgrader. I needed that upgrade key. Then about 20 minutes later the G4 receiver (remember it talked RF to the G4 transmitter) is now a G5 and only speaks Bluetooth directly to the Bluetooth-enabled G5 transmitter. That means it works like this now:

How the Dexcom G5 system works

The G5 software that runs on the iPhone can also upload to the same Dexcom Cloud which means my wife's Dexcom Follow app *works unchanged*. This was a relief.

The Good

  • If I forget my Receiver device at home I can still see my sugars on my phone. This is huge if you're someone who didn't want to get a Dexcom CGM simply because you didn't want another device in your pocket. That is no longer a blocker.
    • You can carry and use either or both of them. However, if a family member is "Following" you and needs to see your numbers, only the phone is uploading them.
    • You can calibrate on either device and they'll both stay in sync. This was a nice touch as I was concerned I'd have to treat the iPhone as a "Virtual Receiver" and calibrate on both devices twice. Just calibrate on either device and the other sees it.

 

The Bad

First I want to say that I REALLY appreciate Dexcom, the company, the product, and the people, and I appreciate what you've done for myself and for Diabetics everywhere. The Dexcom sensor technology is unparalleled and a fundamental life changer. I can't imagine living without my CGM and I wholly and completely recommend a Dexcom CGM for ANY and ALL Type 1 Diabetics who want to get a real clear view of what's happening inside your body.

That said, I'm going to be very honest here, so if you work for Dexcom, please take my feedback as what it is. It's firm, crisp, actionable feedback. You should fix these things. They are bad and wrong.

There's no gap filling.

With the G4, if I had the receiver in my pocket but my phone was elsewhere, the phone would "fill the gaps" and load in missed readings that might have happened while the phone and receiver were apart. This doesn't happen anymore and it sucks. Sometimes the phone misses readings and sometimes the receiver misses them and I don't get a complete smooth curve even though the data seems to be available in the ether. As a techie, I'm assuming this means that the new Transmitter has no memory and just yells out the last reading over Bluetooth until a new reading shows up. IMHO it should remember maybe 5 to 10 and sync up gaps when possible. And if the receiver has records the phone doesn't or vice versus, for goodness sake, close the gaps.

IMG_1738

The phone just isn't a reliable receiver.

Remember when I said that having the G5 means you don't need the phone with you all the time? Well, kind of. I'm not sure that's 100% true. Here's 3+ hours of data that was completely missed this morning. The phone was 3 feet from my transmitter at all times, sitting on my night stand. My physical receiver was under my pillow and picked up the whole nights numbers, but the fact is, numbers were missed.

Yes, Bluetooth is a troublesome thing, but my Tile BT devices NEVER lose a connection. My Apple Watch never loses connection. My Microsoft Band doesn't lose connections. My car doesn't lose connections. You get the idea. I don't trust the Dexcom G5 software to use only my phone to view my data. I just can't avoid a lost hour.

Also, it's unclear to me how this data gets over the the iPhone from a software perspective. Is it a background task? Can the Dexcom software get ejected from memory when playing high memory pressure games? I need these answers.

I'd like to have a Dexcom engineer tell me/us that this is a transmitter/phone/software/hardware/radio/whatever problem, but who knows. They must know it's not as reliable as the physical device.

IMG_1735  

The Missed Opportunities

Please, Dexcom Engineer who must be reading this post, read these and explain.

  • There's no Watch app? The Dexcom G4 has an Apple Watch app, but this "upgrade" doesn't include one. Not cool. Don't remove functionality. I don't want to  pick up my iPhone and run an app every time I want to see my sugar. Glance-able data, people. 
    • complications_explained_2xWatch OS2 has the idea of "complications" which are AMAZING. Dexcom needs to let me put my sugar in an active area on my watch screen. To not to do this hurts. It hurts every day as I glance at my numbers hundreds of times a  day.
  • There's a HUGE amount of wasted whitespace in the chart. Huge. Notice that my goal area (the gray area) is less than 10% of my screen space. The area that I'm NOT supposed to be in (from 150 and up is huge). Please let us change the Y-Axis. Please. 300 to 400 mg/dl is far too much Y-axis for many folks. Give us a logarithmic scale. Let me change it to 200 or 250 until I get higher.
  • The app scales on iPhone 6+. If you want to play in the Apple App Store then play correctly. Make nice scalable graphics, and make it look pleasant everywhere.
  • No interactive graph until I landscape the device. The main screen is static. I can't change the axes (Y or X!) and I can't touch existing records. This is a dumb app on a pocket super-computer. Not being able to explore my data is unacceptable.
    • That said, I can flip the device into landscape and look at up to 24 hours in the past, and run my fingers over the results. Why not portrait?
  • No "iOS widgets." iOS has the notion of Widgets. Little active areas of contact for data like my calendar or the weather. I need to see my Glucose here. Again, this is a huge missed opportunity. Huge. Do it now.

Net net, was it a good upgrade? I'm not sure yet. The sensor tech is amazing. The accuracy remains amazing. I like having the option to not take my receiver with me, but the fact that I can't trust the phone not to disconnect when it's in my pocket on the same side the transmitter is remains a serious concern. Buy the G5 if you like Tech and new Stuff, but know that the G4 is still a great device, it's just one you have to carry with you no matter what.


Sponsor: Thanks to Infragistics for sponsoring the feed this week! Responsive web design on any browser, any platform and any device with Infragistics jQuery/HTML5 Controls.  Get super-charged performance with the world’s fastest HTML5 Grid - Download for free now!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Moving beyond Beginner when 3D Printing and becoming a Handy Person

October 9, '15 Comments [12] Posted in
Sponsored By

OK, let's just say it. I'm not that handy and I'll never be handy. I'm consistently impressed with all my friends and family members who put up pictures of their amazing dining room tables made from scratch. "Ya, I raised this tree from a sapling, cut it down, and made this table with tools from the 1700s. #diy."

Every time I pick up a saw or a drill I feel like I'm faking it. But I try.

The most important thing when making, I think, is to identify your comfort zone and then push past it a little bit.

I've been doing some 3D Printing lately. In fact I'm being teased by people at work who say the printer is always going whenever they call. I say, if I'm going to make a big purchase like this, it needs to be used all the time or non-technical spouse will tell me that buying it was a mistake.

Here's some of my 3D Printing posts so far:

I'm still a beginner, but I think I'm quickly moving into intermediate skills when printing things on a 3D Printer.  Here's some lessons I've learned.

Making a Minecraft Chess Set

3D Printers are marketed wrong.

Listen up, 3D Printer makers, you're selling these things wrong. I was over at Home Depot recently, it's a lumber/tools/fixit shop here in the states (where Handy People go to cut wood, I guess) and they had a Dremel 3D Printer on the end of the aisle. I have a Dremel, so asked a few questions and pretended to be a new customer. They had setup a bunch of little colorful plastic toys. You've seen these demonstrations, right? It's all the little crap like Yoda heads and stuff. It has its place, but at some point you're like "OK, but what can I make that I can use?"

It's a Home Improvement Store where Handy People go, not a Hobby Shop. Show me stuff I can make that will fix my house!

3D Printed stuff and a yoda head

The first thing I printed was a wall bracket for my Dyson Handheld Vacuum. (Again, the goal here is to have non-technical spouse appreciate that I, too, am a Handy Person.)

Making a dyson vaccum bracket

3D Printer manufacturers should showcase all the cool utilitarian stuff you can make. Which leads me to...

Material/Filament - There's more than just vanilla PLA and ABS

When you print, you use filament which are spools of plastic spaghetti. There's lots of materials but the first one we all use is PLA, which is a plant-based biodegradable plastic. Later folks move on to ABS Plastic, which is what LEGO bricks are made of. I haven't gotten that far yet and have only printed PLA...however.

There is a company called Proto-Pasta that makes and sells "exotic filaments" including PLAs that include Carbon Fiber, Magnetic Iron, like a Conductive PLA, or High Temp PLA. The High Temp PLA can be head treated (put them in the oven) and they'll then become very heat resistant AND a lot stiffer and stronger.

On the left in this pic is a clear High Temp PLA print of a bracket I wanted. Then I put it in the Oven for 20 min at 230F. The one on the right has crystalized and changed from translucent to opaque and it's VERY STRONG.

Proto Pasta's High Temp PLA

I mention this because discovering and using this High Temp PLA opened up a whole world to me. Now I can try printing simple circuit boards with Conductive PLA! The point is, I was playing it safe, but now my possibilities have multiplied. 

Software - Way more important than I thought

As I mentioned in my post on The Basics of 3D Printing in 2015 there is a lot of great open source software that you can use to 3D Print with. In fact, you can make your own 3D printer using off the shelf parts and open source design, so there's no real need for you to spend any money on software.

But. I was talking with a 3D Printing expert at a MakerFaire and they gushed about Simplify3D. It's an all in one 3D Printing software that can take in 3D models, arrange them, slice them (slicing means turn the 3D model into x-y-z movements for the printer) and so much more.

Before I was using multiple apps, constantly tinkering, fighting with the built-in software, moving files from app to app in a disjoint workflow. With Simplify3D not only is it easier, but the parts are better. How? It is just that much smarter software, IMHO.

Simplify3D is amazing

I love this view below. I've got a bracket I'm going to print, and the have colored the "moves" of the print head intelligently showing how many mm per min (mm/min) the print head will move. See how the software is smart about the speed of the supports versus the walls versus the parts that stick up?

Simplify3D made the Minecraft Chess set possible when other systems were creating weird supports or moving too fast and tipping over the fragile parts.

Simplify3D is amazing

Seriously, if you're moving to intermediate like I am, pay the money and buy Simplify3D. I don't say that lightly. I'm just scratching the surface and learning what it can do, but so far it's already been worth the money. I have no relationship with the company and there's no affiliate code on the link.

Fear - I was still afraid of the device...until I took it apart

For the most part I've been using my Dremel and Printrbot 3D Printers without issue or incident. However after a few hundred hours of successful printing a snag in the filament spool as it unraveled somehow caused a clog in the Dremel. I was kind of freaking out. 3D Printers are somewhat persnickety and when you have one well-calibrated you don't usually want to mess with it. I thought.  

Taking apart a Dremel

I called Dremel Tech Support and let me tell you, someone give Adrian Malone at Dremel Consumer Services a raise. I called them up and Adrian was in the middle of a print. First, I love that, folks that use their products. He say he had over 1000 hours on that machine (the machines keep track) and he talked my courage up until I felt prepared to take about the whole head and unclog it. His instructions were crystal clear, he was patient and kind. All the things Tech Support should be. Gave me his extension but told me anyone could help...and I have a feeling they could. I've heard tales of Dremel Tech Support being amazing for these printers before this cemented it.

Keep Printing - If you're not using it, you're not learning

My 7 year old and I are printing a quadcopter from places called "CrossFire 2" as a (many) weekend project. We printed a money clip for his allowance last week. We just finished the Minecraft Chess Set today. We're always making, but more importantly, we're always learning. \

3D printing a Quadcopter

Are you 3D Printing? What kinds of stuff do you make? What tips did I miss? Sound off in the comments.


Sponsor: Thanks to my friends at Accusoft for sponsoring the feed this week. Just a few lines of code lets you add HTML5 document viewing, redaction, annotation, and more to your apps and websites.Download a free trial now!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Penny Pinching in the Cloud: Your web app doesn't need 64-bit

October 6, '15 Comments [21] Posted in Azure
Sponsored By

Often times I hear folks say that they need (or want) 64-bit support when they deploy to the cloud. They'll deploy their modest application to Azure, for example, as a Web Application, then immediately go to the settings and set it to 64-bit. So many years later and it's "do I need 64-bit" is still confusing to a lot of people.

Change your Azure bitness settings here

I made basic Hello World ASP.NET app and deployed it. Now, I go to that Web Apps "blade" in the Azure Portal, click Tools, then Process Explorer (after exercising the app a little.) I'm running 32-bit here. The K is the Kudu "sidecar" deployment site (for things like Git deploy and diagnostics), and the other icon is the production site.

30 meg working set for IIS in 32 bit mode

Now, I'll swap it to 64-bit and exercise the web app again. Remember, this app is just a super basic app.

102 meg working set in IIS in 64-bit mode

See how the working set (memory) jump? It's a little extreme in a hello world example, but it's always going to be bigger than 32-bit. Always. 64-bit'll do that. Does your site need to address more than 4 gigabytes of memory from any single process? No? Then your web app probably doesn't need to be 64-bit. Don't believe me? Test it for yourself.

I'll go even further. Most web apps don't need 64-bit, but here's the real reason. If you stay 32-bit when putting your Web Application in the cloud you can fit more applications into a limited space. Maybe your Medium App Service Plan can actually be a Small and save you money.

Until 64-bit only is the default in things like Nano Server, today you can fit more Web Apps into limited memory if you stick with 32-bit.

I personally have 18 web apps in a Standard Small App Service in my personal Microsoft Azure account. They are sites like my podcast Hanselminutes and they get decent traffic. But most never get over 300-600 megs of memory and there's literally no reason for them to be 64-bit today. As such, I can fit more in the Small App Service Plan I've chosen.

18 web apps in a single app service plan

Remember that the Azure Pricing Calculator isn't totally obvious when it comes to Web Applications. It's not ~$55 per Basic Web Site. There's a Virtual Machine under there, they call the whole thing an "App Service Plan" and your Web Apps sit on top of that plan/VM. It's really $55 for a plan that supports as many web applications you can comfortably fit in there.

The cloud is a great deal when you're smart about the resources you've been given. If you're using Azure and you're not using most of the the resources in your service plan, you're possibly wasting money.

What Penny Pinching in the Cloud tips do you have? Disagree with this advice? Sound off in the comments.

Related Links


Sponsor: Thanks to my friends at Accusoft for sponsoring the feed this week. Just a few lines of code lets you add HTML5 document viewing, redaction, annotation, and more to your apps and websites. Download a free trial now!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.