Sunday, December 31, 2017

December Queso

  1. uTorrent is KaZaAesque torrent stuff.
  2. authorize.net is a payment gateway.
  3. Zend is another OOP for the web framework.
  4. SparkNotes is some sort of series of study guides like CliffsNotes only online and for free.
  5. The new Honda Accord apparently has a little bin you can just toss your smartphone into to have it charge.
  6. IFTTT stands for "IF This Then That" and is a tool for conditional logic chains to get apps and devices to work together.
  7. "Lorem ipsum" is the name of sorts for a blob of copy that reads "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." if Wikipedia is accurate and obviously the name comes from the first two words. This is Latin and when translated to English has some things to say about pleasure/pain and seeking one and avoiding another and so on. It is used as a dummy blob of copy in Photoshop layouts of what a web page could look like and other similar presentation comps of that ilk.
  8. Image sprites as a concept are pieces of an image. If you have an image file that contains several images you wish to show standalone and then you use CSS tricks to just paint the background of a div with a piece of the bigger image to show only one image... well then you are getting into the art of image sprites. The reason to have four tiny emoji images side by side in one .gif file and then fake it like they are four separate images by cropping what a user sees is for performance. The expensive of an HTTP call could be profoundly greater than any one of the tiny images and you could be cutting download time for the four images together in half with this trick. The way to really make the most of this stuff is to have one big "sheet" of little images that gets downloaded once.
  9. Garmin makes devices for navigation, things you may keep in your car that tell you where to go, etc.
  10. href is hypertext reference abbreviated and rel is relation
  11. The chipset is the integrated circuit managing workflows in a computer. It is the traffic cop waving traffic on in one direction and/or bringing it to a stop in other ways.
  12. SSDs are solid state drives using solid state storage.
  13. In overclocking one runs a processor/CPU faster than is safe and risks overheating! Out of the box NVIDIA graphics cards with a K in their name allow for overclocking. An X in the name just means that this is the latest and greatest, a top end processor.
  14. ERMAHGERD shows up in memes. It's a rednecky "Oh, my God!"
  15. Coinbase when hit by a distributed denial of services attack froze accounts with Litecoin (trading the highest) so that parties could not cash out. This did not happen with other coins. Super shady.
  16. Swapping out a motherboard at your PC means you'll have to reinstall Windows.
  17. MHTML a.k.a. MIME (Multipurpose Internet Mail Extensions) Encapsulation of Aggregate HTML Documents allows for hammering stuff in external links like Java applets and Flash movies right into an HTML page as embedded gunk.
  18. Messenger (or Facebook Messenger) has a rival in GroupMe.
  19. JS Charts is a set of scripts of charting.
  20. Craig's List is like an eBay type forum for selling things online. There are regional markets and if you are buying in Austin from someone in Austin you can probably just go pick whatever-it-is up from the guy in Austin in person without having to go through the hassle of shipping and packaging for the shipping, etc. Freecycle is a comparable network for just giving unwanted stuff away.
  21. Ledger Nano S is a hardware wallet for Bitcoins and the like.
  22. EOS or Entrepreneurial Operating System is a set of tools for the C suite of an organization to measure things and feel good about themselves.
  23. Bluebeam is for editing PDFs.
  24. Splunk lets you do realtime searches of software logs at any device imaginable.
  25. The trophy for the worst thing I've seen professionally goes to Azuma, a company that leases washing machines and driers to apartment renters in Austin, Texas. Instead of using something like QuickBooks for their accounting software they had rolled their own thing in Corel Paradox to tie into their other processes. However, a close second, and certainly the worst thing I've seen in .NET is an application written for EqualLogic before they were acquired by Dell. Developers were allowed to do whatever they wanted and thus this was a web forms app that was hodgepodge of web form code behinds and classes written in both VB.NET and C#! A lot of common functionality was written twice, once in C# and once in VB.NET. A class that did something cornerstone had two files in two languages. Recently, I have been replaying in my head a conversation I recall having with a coworker about this (I explained the situation to another years after the fact.) wherein she suggested that such a circumstance shouldn't be a big deal as both languages compile down to CLR and that a sort of compatibility between VB.NET and C# was the whole point of .NET in general to begin with. Certainly, if you have a project in a solution that can compile and that project then ends up making a .dll, the .dll, without regard to whether it was made by C#, made by VB.NET, or made with a mix of the two should be consumable from another project in a Visual Studio solution with code that is either of C# or of VB.NET. That much is true. I feel compelled to explain the distinction with the EqualLogic project and this model however. In the EqualLogic project there were not multiple projects in the solution or deferments to .dlls. Instead the UI project was the whole app and the whole of the solution. When I attempted to get not yet complied C# to speak to not complied VB I had no luck, and, obviously, no one who came before me could get that working either. IntelliSense wouldn't accommodate, and if you ignored it and just typed in something to get things working, the compiler couldn't compile.
  26. Tile, as an app, helps you sync your phone with a little, well, tile so that your phone can find the tile through geolocation means. You may put the tile in your car and then freely forget where you parked at the mall, etc. You may find your wallet if you get separated from it and what not.
  27. Javadoc makes documentation for Java apps. I think you may use its documentation to drive something akin to IntelliSense too.
  28. StayFocusd is a Chrome plugin that keeps you from browsing beyond one target website for more than fifteen minutes a day. In order to turn it back off you have to retype like a five sentance paragraph perfectly.
  29. Apple has rolled out an update that intentionally makes older phones run slower. Officially, this is to make your battery life last longer, but I can tell you first hand that my battery is draining all the faster. This update is to make you buy a new phone in frustration. There is going to be a class action lawsuit.

Sometimes you can't drill into a FormGroup in Angular 4 without breaking the chain in half midstream. It's corny!

Alright, this code is legit for slurping stuff back out of reactive forms:

submit(): void {
   let presidents:President[] = [];
   let formArray:any = this.presidentsForm.controls['lineItems'];
   formArray.controls.forEach((formGroup:FormGroup):void => {
      let president:President = new President;
      president.Name = formGroup.controls['name'].value;
      president.Party = formGroup.controls['party'].value;
      president.HasNonconsecutiveTerms =
            formGroup.controls['hasNonconsecutiveTerms'].value;
      presidents.push(president);
   });
   this.presidentialContract.setPresidents(presidents).toPromise().then(
      function(data) {
         window.location.href = "/#/list";
      }.bind(this),
      function(error){
         console.log(error);
      });
}

 
 

Why can't the second and third lines of the method be one line like so?

submit(): void {
   let presidents:President[] = [];
   this.presidentsForm.controls['lineItems'].controls.forEach((formGroup:FormGroup):void
         => {
      let president:President = new President;
      president.Name = formGroup.controls['name'].value;
      president.Party = formGroup.controls['party'].value;
      president.HasNonconsecutiveTerms =
            formGroup.controls['hasNonconsecutiveTerms'].value;
      presidents.push(president);
   });
   this.presidentialContract.setPresidents(presidents).toPromise().then(
      function(data) {
         window.location.href = "/#/list";
      }.bind(this),
      function(error){
         console.log(error);
      });
}

 
 

Well, if you don't break the chain midway you'll get an error like this:

Failed to compile.
C:/Apps/GroverClevelandHopscotch/src/GroverClevelandHopscotch.UserInterface/src/app/components/reactiveForms.component.ts (44,51): Property 'controls' does not exist on type 'AbstractControl'.

 
 

If you try to make formArray a FormArray instead of any, which is the type I used to originally create lineItems, you'll similarly get:

Failed to compile.
C:/Apps/GroverClevelandHopscotch/src/GroverClevelandHopscotch.UserInterface/src/app/components/reactiveForms.component.ts (43,13): Type 'AbstractControl' is not assignable to type 'FormArray'. Property 'controls' is missing in type 'AbstractControl'.

 
 

What is more, if you loop in AbstractControl from @angular/forms as an import and try to use it instead of any you get the first error. I don't see any way out of using any save for not declaring a type there which is basically the same thing and I hate using any. I feel dirty whenever I use any and I should. This is some pretty finicky, cantankerous stuff, huh? This won't work either:

submit(): void {
   let presidents:President[] = [];
   this.presidentsForm.controls.lineItems.controls.forEach((formGroup:FormGroup):void
         => {
      let president:President = new President;
      president.Name = formGroup.controls['name'].value;
      president.Party = formGroup.controls['party'].value;
      president.HasNonconsecutiveTerms =
            formGroup.controls['hasNonconsecutiveTerms'].value;
      presidents.push(president);
   });
   this.presidentialContract.setPresidents(presidents).toPromise().then(
      function(data) {
         window.location.href = "/#/list";
      }.bind(this),
      function(error){
         console.log(error);
      });
}

 
 

This will work, but Visual Studio Code 1.8.0 will put a squiggly red line under lineItems like it can't figure out what it is. The code will still compile and work however.

submit(): void {
   let presidents:President[] = [];
   let formArray:any = this.presidentsForm.controls.lineItems;
   formArray.controls.forEach((formGroup:FormGroup):void => {
      let president:President = new President;
      president.Name = formGroup.controls['name'].value;
      president.Party = formGroup.controls['party'].value;
      president.HasNonconsecutiveTerms =
            formGroup.controls['hasNonconsecutiveTerms'].value;
      presidents.push(president);
   });
   this.presidentialContract.setPresidents(presidents).toPromise().then(
      function(data) {
         window.location.href = "/#/list";
      }.bind(this),
      function(error){
         console.log(error);
      });
}

Saturday, December 30, 2017

Error: Cannot find control with unspecified name attribute

Fix this Angular 4 error in reactive forms by removing some brackets. Something like this...

<tr *ngFor="let lineItem of presidentsForm.get('lineItems').controls; let i=index"
      [formGroupName]="i">
   <td><input type="text" [formControlName]="name" /></td>
   <td><input type="text" [formControlName]="party" /></td>
   <td><input type="checkbox" [formControlName]="hasNonconsecutiveTerms" /></td>
</tr>

 
 

...needs to become something like this:

<tr *ngFor="let lineItem of presidentsForm.get('lineItems').controls; let i=index"
      [formGroupName]="i">
   <td><input type="text" formControlName="name" /></td>
   <td><input type="text" formControlName="party" /></td>
   <td><input type="checkbox" formControlName="hasNonconsecutiveTerms" /></td>
</tr>

Friday, December 29, 2017

getting started with generics in TypeScript

where T : Whatever style C# generics have a sister in TypeScript. This will throw up an alert with "ROAR" in it!

class Cat {
   private _speech: string;
   constructor (speech: string) {
      this._speech = speech;
   }
   speak():string{
      return this._speech;
   }
}
class Housecat extends Cat {
   constructor() {
      super("meow");
   }
}
class Lion extends Cat {
   constructor() {
      super("ROAR");
   }
}
class CatOwner<T extends Cat> {
   pet: T;
}
let catOwner: CatOwner<Lion> = new CatOwner<Lion>();
catOwner.pet = new Lion();
alert(catOwner.pet.speak());

How do I create a CanDeactivate guard with conditional logic in an Angular 4 application?

Let's answer the question I posed yesterday here. To do so we are going to make an actual file for our guard and thus the provider in the outermost module may be removed and the reference to 'WhateverGuard' in the routing module should just become WhateverGuard without the surrounding quotes.

import { Injectable, Injector } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { CanDeactivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { WhateverGuardInterface } from './whatever-guard.interface';
import { StupidService } from '../../services/stupid-service';
@Injectable()
export class WhateverGuard implements CanDeactivate<WhateverGuardInterface> {
   private service:StupidService;
   
   constructor(public injector: Injector){
      this.service = injector.get(StupidService);
   }
   
   canDeactivate(component: WhateverGuardInterface, currentRoute:
         ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState?:
         RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
      if(this.service.isToUseGuard){
         return confirm('Are you sure you want to leave?');
      } else {
         return true;
      }
   }
}

 
 

Alright, we are going to need a middleman service that will manage some sort of state to drive the conditional logic seen above. Assuming I have a component, WhateverComponent if you like, wherein there is a form to edit a record and I only want to ask "Are you sure you want to leave?" if one is midstream into editing a record, perhaps the dirty flag on the whole of the form would just serve nicely to drive our conditional logic. That Boolean value needs to unfortunately be communicated into a middleman service (write whatever gunk you need, that is not this lesson) and then the middleman service may also be talked to by our guard. My service is this simple:

import {Injectable} from '@angular/core';
@Injectable()
export class StupidService {
   public isToUseGuard: boolean;
}

 
 

A setting for component at the canDeactivate method is unfortunately mandatory as is some sort of type at the class signature in a shape that reminds one of C# generics. I looked into TypeScript generics some and I guess they are comparable. Anyhow, I don't really understand what to do with this yet and as I turns out I don't have to. I just made a super simple interface to satisfy this requirement that looks like this:

export interface WhateverGuardInterface {}

 
 

What else am I not mentioning? Loop the service and the guard in at Providers in the outermost module! The guard has to be an import at the routing module when you take away the quotes around WhateverGuard as suggested at the very top of this blog posting.

Module '"C:/Users/tom.jaeschke/Documents/Whatever/src/app/components/whatever.model"' has no exported member 'Meh'.

This is literally telling you that the path in one of your import statements is messed up. Nothing more. The path is 'Meh' is jacked.

Thursday, December 28, 2017

What do I do to sanity check the casting of an int to a string in JavaScript if I'm not supposed to use isNaN?

On the other side of the casting you will end up with NaN if something went wrong and of course NaN is falsey, so just do a check to see if they thing you end up with is either truthy or set to zero which would be the one legitimate falsey scenario for a parsed number. I could swear that I've already blogged of this, but I cannot find it at my own blog because it is such a sprawling mess.

var bar = parseInt(foo);
if(bar || bar === 0) {
   alert("It's good!");
} else {
   alert("It's bad!");
}

How do I tell if a particular Input has changed at ngOnChanges at an Angular 4 component?

Great question! I recommend making a private sister variable for the Input variable and setting the private variable equal to the Input variable at ngOnInit. Then at ngOnChanges compare the two for a discrepancy. If there is a discrepancy then it is time to act and in acting you will also want to assign the Input's value to the private sister's value again.

How to set up a super simple "Are you sure you want to leave?" guard in an Angular 4 app!

The CanDeactivate stuff in bullet thirteen here proved hard for me to implement. I ended up going into the outermost module and adding something like this to the providers:

{
   provide: 'WhateverGuard',
   useValue: () => {
      return confirm('Are you sure you want to leave?');
   }
},

 
 

At the routing module, at an applicable route definition, we have an array of canDeactivate guards like so:

{
   path: 'whatever',
   canDeactivate: ['WhateverGuard'],
   component: WhateverComponent
},

 
 

Alright, the good news is that this works and that whenever you try to navigate away from whatever you are gonna be asked "Are you sure you want to leave?" but the bad news is that you will always be asked as much. What if I wanted to inject some conditionally logic and just return true if I don't want to torment the user with an unmerited question? I have not figured out what to do about that yet.

Nan's

I've had this blog afloat for six and a half years now, since the Summer of 2011, and it has mostly been an exposition of my sloppy notes and goofy thoughts on modern coding for line of business apps and CRUD mechanics. That's a good topic too. There are jobs galore in this vein of things, more jobs than there are people to do them, and if you are inclined (It's not for everyone.) this can be your ticket out of working in restaurants and into the middle class. It was for me. As things are so ever-changing it is fun to document it and look back at snapshots. 2011 really was a long time ago, you know? JavaScript was really just taking off back then and now it's all pervasive. Along with modern coding I seem to stray into documenting modernity itself. You'll see movie references all over this blog. I'm obsessed with film. I care a little about what you might think of as modern TV too, stuff you may stream from Netflix and the like. Their prior process of snail-mailing DVDs in little white sleeves around has faded out. I enjoyed the first two seasons of "Stranger Things" and there is another show out now called "Alias Grace" which I would also recommend. It seems music and restaurants play less into my thoughts. I guess I have mentioned them too. I don't drink or do drugs so I can't really tell you what beers I like or what head shop to go to buy a bong. I don't play video games and I don't know anything about fashion. Hmmm...

Another thing that is missing is comic books and roles-playing games and the like. I have a long history of role-playing games under my belt that is a distant past. The last time I participated in a game it was the World of Darkness setting and was with Mark Carroll, Jerry Gutierrez, Richard Gutierrez, Doug Lenat, Bill Mathews, Darin Oehlke, Ryan Thames, and Jessie Thogmorton back in 2009 and 2010 at an apartment I had in Austin. I was fresh off my divorce and this gaming group was another bad experience to boot. World of Darkness, in its second edition watered-down reboot, was still the thing that had Mage and Vampire and Werewolf as other games within it. Mage the game should not be confused with Mage the comic book. I'm into the comic book too, or at least I was. This too, my fascination with Matt Wagner's works, Mage and Grendel, seems so long ago. Anyhow, Mage was originally intended as a set of three comic runs, Mage: The Hero Discovered, Mage: The Hero Defined, and now Mage: The Hero Denied. I didn't really think the final leg, The Hero Denied, would ever show up as this stuff just seemed to get dropped back in the 1990s... but here it is. It's back. This is one example of me caring about comic books. I thought it should make my blog. I stopped by Nan's yesterday and picked up the first four issues and they are good. I recommend this. Oh, I'll end in telling you about another stray thought. I recently went to the dentist for the first time in nineteen years (no cavities) and it was much different than what I remembered. They take your blood pressure now and the dentist also took a bunch of digital photos of my teeth that I saw on a monitor upon my next visit. Half my teeth were cleaned in one sitting, half in a second sitting, and in a third sitting they polished my teeth, etc.

 
 

Addendum 1/22/2018: "Dead Of Winter" is a pretty fun board game.

Wednesday, December 27, 2017

mydatepicker doesn't take a Date

You may see partway down https://github.com/kekeh/mydatepicker that...

public model: any = { date: { year: 2018, month: 10, day: 9 } };

 
 

...is what is expected as a TypeScript type and not Date. Another change is that herein ten really means October and not November. That JavaScript ugliness of the zero to eleven scale for months is replaced with something sane. Unfortunately, this means you may to have translate from the sane to the unsane and back again begging the question of any sanity to begin with. (Forgive the use of the word any.) I wrote a pipe around this stuff today to format the fake dates in a MM/dd/yy shape.

import { Pipe, PipeTransform } from '@angular/core';
import { PseudodateWrapper } from './pseudodate-wrapper.model';
@Pipe({name: 'simplePseudodate'})
export class SimpleDateForPseudodatePipe implements PipeTransform {
   transform(value: PseudodateWrapper): string {
      if(value && value.date){
         let month:string = value.date.month + "/";
         if (value.date.month < 10) month = "0" + month;
         let day:string = value.date.day + "/";
         if (value.date.day < 10) day = "0" + day;
         let year:string = String(value.date.year);
         return month + day + year[2] + year[3]
      }
      return "";
   }
}

 
 

This is kinda cool, huh? What is above also shows off casting a number to a string. PseudodateWrapper looks like this:

import { Pseudodate } from './pseudodate.model';
export class PseudodateWrapper {
   date:Pseudodate;
}

 
 

It may be overkill but I am trying to get away from the overuse of any. Pseudodate in turn looks like:

export class Pseudodate {
   day:number;
   month:number;
   year:number;
}

I can't find it, but I know elsewhere on this blog I describe any in TypeScript as like dynamic in C# and Object in contrast like object in C#.

https://stackoverflow.com/questions/18961203/typescript-any-vs-object This has a better description partway down. It contrasts these three:

  1. var a: any;
  2. var b: Object;
  3. var c: {};

Alright, the third of these is basically just an extension of the second, and if you do .Whatever(); off of the second and third items TypeScript's compiler will lose it because there is an interface, if you will (per diegovilar and Retsam), associated with Object that makes it obvious that there is no .Whatever(); In contrast, the first item will allow for .Whatever(); to be called upon it without a compiler error. Any error, should there be one, will happen at runtime. There is no "interface" at the any and the compiler doesn't impose itself.

Make a video clip start out playing with no sound with the muted keyword.

You'll be able to turn the audio back on as a user with the canned controls along the bottom of the video clip... probably. It worked for me in IE and Chrome. The "muted" keyword goes in the open video HTML tag and should just be free-floating in there like "controls" (hey there are the controls), "loop," and "autoplay."

Tuesday, December 26, 2017

Make rows alternate colors now with CSS!

This at least works in Google Chrome:

#summary tr {
   margin: 0;
   padding: 0;
   background-color: #f8f8f8;
}
#summary tr:first-child {
   background-color: #e5e5e5;
}
#summary tr:nth-child(2n+3) {
   background-color: #FFFFFF;
}

 
 

Not only will this make the rows alternate colors in the table, but the header for the table will moreover be a third color.

text-transform: capitalize;

...in CSS is another text-transform option like lowercase and uppercase. This one only capitalizes the first letter of each word and makes the others "small."

Monday, December 25, 2017

Merry Christmas!

I saw a thing on TV a few days ago in which Richard Quest suggested that the U.S. stock market was soaring at year's end and that he would therefore wish everyone a Merry Christmas without regards to whether or not that was politically correct as that would be keeping with the spirit of Donald Trump and his immediate bubble we are in. I'm join him. Merry Christmas Everyone! Go speculate on Bitcoin! (Maybe that's taking things too far.) I stole this picture of my mother Susan Jaeschke and her boyfriend Gary Kendrick during yesterday's festivities.

 
 

Addendum 1/20/2018: I changed the picture here to use a better picture of my mother. It's my blog and I can do that.

Sunday, December 24, 2017

When you change components with Angular 4's SPAesque routing will ngOnInit and the constructor get run a second time upon a second visit?

Good news! The answer is yes. The components are not kept alive in state or something janky like that. Every time you revisit one it's like you're a virgin anew.

Saturday, December 23, 2017

How do I know what route I am on in the SPA-style Angular 4 routing?

At the component you are using to drive a menu system or whatever where you need to react to this bit of data have this import:

import { Router } from '@angular/router';

 
 

That allows for something like what is seen below, and this trick works both with and without the hash-tag-in-the-route hack.

constructor(router: Router) {
   router.events.subscribe((event: any) => {
      console.log(event);
   });

 
 

event.url herein will have the current piece of the route with a leading slash. Whenever you change routes seven different events seem to get triggered but each has the .url hanging off of their objects in these scenarios. The seven events are:

  1. NavigationStart
  2. RoutesRecognized
  3. GuardsCheckStart
  4. GuardsCheckEnd
  5. ResolveStart
  6. ResolveEnd
  7. NavigationEnd

get the SPA style routing working in an Angular 4 app

In your module for managing the routing....

import { Routes, RouterModule } from '@angular/router';

 
 

...needs to become:

import { Routes, RouterModule, RouterLinkWithHref } from '@angular/router';

 
 

And your menu links like so:

<a href="/reactive">More...</a>

 
 

...need a revamp like so:

<a [routerLink]="['/reactive']">More...</a>

 
 

Yes, that is an array of one thing. That's it however. These two little changes are the only changes you need to make.

{provide: LocationStrategy, useClass: HashLocationStrategy}

 
 

...needs to be at the providers at the outermost module to get the hash tag based routing afloat for servers like IIS which are more cantankerous. Without this change you are just changing out what comes after the slash right after the .com part of the url line. You will need the following import:

import { LocationStrategy, HashLocationStrategy } from '@angular/common';

Thursday, December 21, 2017

novalidate keyword in HTML

W3 schools has this example:

<form action="/action_page.php" novalidate>
   E-mail: <input type="email" name="user_email">
   <input type="submit">
</form>

 
 

...so it goes at the form tag. The description I find online is that this disables the "browser's native form validation" and yes that is a thing even if the W3 schools example explains it poorly. Perhaps a better example would be:

<form action="/action_page.php" novalidate>
   E-mail: <input type="email" name="user_email" required>
   <input type="submit">
</form>

 
 

This touches on the required keyword which might otherwise force you to put something in the user_email field before you may submit the form. In the case of the second example though, the novalidate keyword should sidestep the required keyword. What this does not do is sidestep ASP.NET MVC validations or your validations in JavaScript. My head was about to explode when I first saw this thing because I didn't get how it could possibly work, but now I understand that it is merely of limited scope. I didn't even know about the goofy native validations. Who would rely on those?

Wednesday, December 20, 2017

an opt out for the new UI please?

The Jira interface has gone through two overhauls in the seven months that I've been using it and there is a consensus in our office that it is getting worse not better. Why can't we, as clientele, have the option to use an older version of the UI that we liked? Sure we would be shut out from new features, but if we were OK with that why can't Jira be OK with that? Why isn't this a thing?

Tuesday, December 19, 2017

Why would I use a closure to make an assignment to a Func or Action in C# when I can just use the equals sign?

Well, I am glad that you asked! In looking over this, this, this, and this it became obvious to me today that the gain is one of shapeshifting. Instead of having a Func or Action with one or more inbound properties you may just have an Action without any angle brackets (takes nothing, returns void) and a Func with just one type (the return type). Whatever inbound properties might be are specified right then upon the closure assignment. In effect, the gun is loaded and you'll just pull the trigger later without worrying then about what kind of ammunition it has. Bad analogy? This does not allow you to react to real time conditions with input types later on downstream the way a Func or Action typically might. Instead of making a game plan for how to react to things "tomorrow" you are making a timebomb for "tomorrow" so to speak. I guess you can always stamp overtop of the assignment with another assignment before you use the Func or Action with a terse signature if you need to alter plans. Bonus: Did you know a Func<bool> may have a closure return type like foo==bar or some other form of comparison?

ERROR Error: Cannot find control with unspecified name attribute

<ng-container formArrayName="stuff"></ng-container>

...needs to wrap the div in bullet point twelve here to make this error go away.

Can't bind to 'formControl' since it isn't a known property of 'input'.

ReactiveFormsModule needs to be looped into your imports at your module wrapping your component in an Angular app. That is how you beat this problem.

Monday, December 18, 2017

Ceremity!

The two weeks notice for Ceremity was put in today. Yee-haw! It's been a fun ride with a great consultancy! What a nice seven months I've experienced.

By the way, a good HTML tag for a .mov file like this one is:

<video src="http://www.tomjaeschke.com/blog/TomJaeschke.mov" preload controls>
</video>

Saturday, December 16, 2017

How to find your way back to "My work" in the latest Atlassian Jira user interface shakeup.

  1. As of this week's changes, at left where is says Backlog, Active sprints, Reports, Releases, Issues, Components, Timesheet, and Jira Custom Fields (if you're at the "All sprints" breakdown) click on Timesheet.
  2. Click on your name in the Key column. This changes the left nav to say: Dashboards, Projects, Issues, and Tempo instead.
  3. Click Tempo and the left nav will become: My work, Reports, Teams, Accounts, Getting started, Apps
  4. Click on "My work" next.

How do I make my SSRS report print to a PDF without the content getting cut off?

  1. Open the report in Microsoft SQL Server Report Builder.
  2. Right-click in some dead space and pick: Report Properties...
  3. At the dialog that appears, set the Orientation to Landscape, the Paper size to A4, and the Page units to Centimeters. Obvious, the landscape orientation is what is most important here.

Content that still gets cut off will now wrap onto a second page. Printed pages could be set side by side with each other in a horizontal row to show the big picture.

Did you know there is a little game to play in Google Chrome's browser built around the dinosaur you see when there is no internet connection?

When you see the dinosaur, press the space bar to start the game. The dinosaur will start tearing across the landscape in a sprint. There will be cacti in your way and you must jump them. You may press the space bar to jump and that is the only control over your lot that you have.

Whatever. Supposedly there was a flight simulator built into an older version in Windows. It was something hidden as an Easter egg that you'd have to stumble upon. Meh.

Thursday, December 14, 2017

yay CSS

Did you know that elements with absolute positioning will just sit locked in place within a wrapping element that has the overflow CSS condition demanding a scrollbar when you scroll the scrollbar?

The Obama-era FCC rules for .NET Neutrality have just been thrown away by the modern Trump FCC.

Ajit Pai, who spearheads the Federal Communications Commission, shepherded this through. Pseudosolid .NET Neutrality was on shaky grounds to begin with and it was easy for Mr. Pai to put a pin to the balloon. This is happening the same day that Disney buys Fox. The trend towards a post-Microsoft media/tech oligarchy continues. Remember when everyone badmouthed big evil Microsoft back in the 1990s? They seem so tame anymore.

nav HTML5 tag

I think this is intended to behave like a div wrapping explicitly an unordered list full of links. You would use this instead of menu tag full of menuitem tags though I just today made a nav wrap a menu because I'm an anarchist.

Wednesday, December 13, 2017

How to unhide rows in an Excel sheet.

The hidden rows are kinda represented with two lines tightly close together as shown here. If you bring the cursor over the two lines and it takes the shape seen here of arrows emerging from two lines in lieu of just one line and you line up to bottommost line in the cursor with the bottommost line in the representation of the collapsed rows, then a click will unhide a row, the row adjacent to the unhidden row beneath the two line representation of collapsed rows. If you don't want to unhide oneseys and twoseys like this by going click-click-click you may select the two rows around the hidden rows and then right-click in one of them and pick the option for: "Unhide"

I used the menu HTML5 tag for the first time yesterday.

<menu *ngIf="isNotHome">
   <menuitem><a href="/home">escape away</a></menuitem>
   <menuitem *ngIf="whereAmI != 'list'"><a href="/list">view a list of records</a>
         </menuitem>
   <menuitem *ngIf="whereAmI != 'simple'"><a href="/simple">make simple edits</a>
         </menuitem>
   <menuitem *ngIf="whereAmI != 'reactive'"><a href="/reactive">reactive forms
         experiment</a></menuitem>
</menu>

Tuesday, December 12, 2017

LinqToExcel thuggishness

Cosmetic number formatting in Excel sheets, such as a dress up in which a double quote follows every number to imply "this value is in inches" (a single quote suggests feet in this notation) will not be maintained when the Excel sheet is scrapped with LinqToExcel. Instead, you'll just get the number by itself. If you are ending up with a RowNoHeader object the number will be in string form without any dress up.

negative records for metrics reporting

I have a database table whose records are largely used in SSRS reports and these reports show metrics across a swath of records filtered by things such as date and the like. I just found out today that these records, imported from Excel sheets, can occasionally be "deleted" records whose intent is to offset another record that is a mistake. Shouldn't I just find the dance partner on import and delete it in lieu of adding a wacky offset record? Well, the end client wants a history of everything and has found previous pain in discarding botched records and having no way to reverse-engineer the fact that it they were once there. Alright, well should the offsets just get a flag and then be accounted for in the SSRS reports? Yikes, talk about a spaghetti mess. Do I want to inject yet more logic into T-SQL? Maybe it's best to try to flip digits to negative numbers in writing rows. I don't yet know if I can get away with that.

ObjectResult versus OkResult regarding Observables

return Ok(null); and return Ok(true); differ from return Ok(); in that the later is of OkResult in a .NET Core MVC implementation and the first two are of ObjectResult. As best as I can tell the Angular HttpClient and Observables can't handle the OkResult meaning that you have to hand back something like null or true from REST verbs like PUT or DELETE which should really be fire and forget. (return nothing!) I can't find a way out of this pit and this is exactly the sort of weird minutia that only I care about. Whatever.

Sunday, December 10, 2017

The distinction between .Write and .WriteLine at a C# StreamWriter is bigger than you think.

streamWriter.Write("foo");

 
 

...is going to replace everything in a file with merely "foo" while...

streamWriter.WriteLine("bar");

 
 

...is just going to append "bar" on a separate line following everything else. There is another difference however, all lines written with .WriteLine are followed by a carriage return, like it or not, but a carriage return does not chase a write with .Write. You have to append \r\n to what you write with .Write to put it there. Well, that is if you want it to begin with.

window.location.href = "/whatever";

...kinda needs to be used in TypeScript/Angular in lieu of:

window.location = "/whatever";

InvalidOperationException: The constraint entry 'whatever' - 'string' on the route 'api/Foo/{whatever:string}' could not be resolved by the constraint resolver of type 'DefaultInlineConstraintResolver'.

[HttpPut("{whatever:string}")]

 
 

...needs to become...

[HttpPut("{whatever}")]

 
 

...to fix this error. Specify the type for everything but string. This came up today while I struggled to pass an object to a .NET Core REST Controller. I was missing:

[FromBody]

 
 

...and really the action attribute just needed to be:

[HttpPut]

Error: No provider for Http!

This error comes from not looping in HttpModule at your module in an Angular 2 app. See bullet point five here for the fix.

null values can throw off TypeScript/JavaScript sorting

This can have some funny results if some of what is being sorted has no value. Solve that problem like so:

let presidentsCopy:Array<President> = JSON.parse(JSON.stringify(this.presidents));
presidentsCopy = presidentsCopy.sort((yin, yang) => {
   let yinParty:string = "";
   let yangParty:string = "";
   if (yin.Party){
      yinParty = yin.Party;
   }
   if (yang.Party){
      yangParty = yang.Party;
   }
   if (yinParty > yangParty){
      return 1;
   }
   if (yinParty < yangParty){
      return -1;
   }
   return 0;
});

Make a video clip run in a loop in HTML5!

 
 

...is made with the following HTML and it is the loop keyword that allows for the looping.

<video controls loop>
   <source src="https://vtt.tumblr.com/tumblr_ococjk2Glt1udnceu.mp4"
         type="video/mp4">
   Your browser does not support the video tag.
</video>

 
 

By the way, using the autoplay keyword in the same spot makes the video clip immediate start playing upon page load!

Saturday, December 9, 2017

How may I have .querySelector in a Jasmine unit test select the nth DOM element that matches and not merely the first match?

The answer is to use .querySelectorAll instead. Something like this...

expect(element.querySelector('li').textContent).toContain('foo');

 
 

...may become something like this...

expect(element.querySelectorAll('li')[0].textContent).toContain('foo');

 
 

...which then affords something different altogether like this...

expect(element.querySelectorAll('li')[1].textContent).toContain('bar');

Friday, December 8, 2017

Make a simple generic that basically just wraps another type in C#.

namespace Whatever
{
   public class Wrapper<T>
   {
      public T Data { get; set; }
      public string Metadata { get; set; }
   }
}

 
 

Use it like this:

Wrapper<int> wrapper = new Wrapper<int>();
wrapper.Data = 13;
wrapper.Metadata = "It's lucky!";

Wednesday, December 6, 2017

How do I look at the history of a particular file in Atlassian Bitbucket's paradigm?

Go to https://bitbucket.org/ and click on <> Source beneath the relevant project. Therein switch to the needed branch and drill into the particular folder from the root. Pick a file and then click the "History" button at the upper right.

fatal: Unable to create 'C:/Users/tom.jaeschke/Documents/employee-portal/.git/index.lock': File exists.

This error in Atlassian SourceTree 1.9.13.7 happened when I tried to change branches and I beat the problem by just deleting the file.

Tuesday, December 5, 2017

The action can't be completed because the file is open in devenv.exe

This is a pretty infuriating problem I faced today with Visual Studio 2015. Restarting my laptop and then deleting the .dll file that gets locked up in this error didn't help. Deleting everything and doing a repull from source control didn't fix the problem either. Typing %temp% at the start bar and then destroying all of the temp files at C:\Users\tom.jaeschke\AppData\Local\Temp didn't make anything better too. Eventually I changed the Solutions Configuration dropdown at the top of Visual Studio in the "Standard" toolbar (Views > Toolbars > Standard) to something other than Debug and the problem went away.

Monday, December 4, 2017

SUM and COUNT in Excel programming

=SUM(A1:A75) as the calculation in an Excel field is going to put into that field a sum of all of the numbers in the A column from the first row to the seventy-fifth while on the other hand =COUNT(A1:A75) is just gonna give you the number 75, get it? If you highlight rows 1 to 75 in the A column alone in a selection and then click on the "AutoSum" button of the "Formulas" tab of Excel 2016 then the seventy-sixth row in the A column will get the =SUM(A1:A75) programming. Ways to screw this stuff up include something like =SUM(1,75) which just gives 76 as that is 1+75. Whatever.

when you are in a Skype Audio Meeting and your laptop is blaring the audio instead of your headphones

  1. Click on the "..." at the lower right.
  2. Pick "Meeting Options..." from the little menu that pops up.
  3. Pick "Audio device" under "Options" next.
  4. Click on "Custom Device (Device specified below)" to change your settings.

Sunday, December 3, 2017

What is the type TypeScript equivalent of static classes and static methods in C#?

Call a function in a module like so:

this.presidents = PresidentialSorter.Sort(data);

 
 

The module and the funtion look like this. (This is an over-the-top example.) Note that the export keyword at both the module and the function are allowing the the module and function inside to be "public" if you will and the function without the export keyword is in effect walled off from the outside and encapsulated, accessible only from the other machinery of the module.

import { President } from '../models/president.model';
import { PresidentPlus } from '../models/presidentPlus.model';
export module PresidentialSorter {
   export function Sort(presidents:Array<President>):Array<PresidentPlus> {
      let counter:number = 0;
      let nonconsecutivePresident:PresidentPlus = null;
      let nonconsecutivePresidentBench:PresidentPlus = null;
      let output:Array<PresidentPlus> = new Array<PresidentPlus>();
      let isEvenDeepInNonconsecutiveness: Boolean;
      presidents.forEach((spot:President): void => {
         isEvenDeepInNonconsecutiveness = false;
         let president:PresidentPlus = MapPresidentToPresidentPlus(presidents[counter]);
         counter++;
         if(nonconsecutivePresidentBench) {
            nonconsecutivePresident =
                  JSON.parse(JSON.stringify(nonconsecutivePresidentBench));
         } else {
            nonconsecutivePresident = null;
         }         
         if(president.HasNonconsecutiveTerms) {
            nonconsecutivePresidentBench = JSON.parse(JSON.stringify(president));
         } else {
            nonconsecutivePresidentBench = null;
         }
         if (counter > 2 && presidents[counter-3].HasNonconsecutiveTerms &&
               presidents[counter-2].HasNonconsecutiveTerms){
            let backwardsCounter:number = 3;
            isEvenDeepInNonconsecutiveness = true;
            let isToKeepIncrementing:Boolean = true;
            while (backwardsCounter < counter) {
               backwardsCounter++;
               if (presidents[counter-backwardsCounter].HasNonconsecutiveTerms){
                  if (isToKeepIncrementing) {
                     isEvenDeepInNonconsecutiveness = !isEvenDeepInNonconsecutiveness;
                  }
               } else {
                  isToKeepIncrementing = false;
               }
            }
            if (isEvenDeepInNonconsecutiveness) {
               output.push(nonconsecutivePresident);
            }
         }
         output.push(president);
         if (nonconsecutivePresident && !isEvenDeepInNonconsecutiveness){
            output.push(nonconsecutivePresident);
         }
      });
      output[output.length-1].IsCurrentPresident = true;
      counter = 0;
      output.forEach((spot:PresidentPlus): void => {
         counter++;
         spot.ImmediatePosition = counter;
      });
      return output;
   }
   
   function MapPresidentToPresidentPlus(president:President):PresidentPlus{
      let presidentPlus:PresidentPlus = new PresidentPlus();
      presidentPlus.Name = president.Name;
      presidentPlus.Party = president.Party;
      presidentPlus.HasNonconsecutiveTerms = president.HasNonconsecutiveTerms;
      presidentPlus.IsCurrentPresident = false;
      presidentPlus.ImmediatePosition = 0;
      return presidentPlus;
   }
}

There is now a distinction between .Trim() and .TrimStart() and .TrimEnd() in C#!

The first of these removes BOTH leading and and trailing whitespace at a string, as .trim() will in JavaScript, and with that in mind you can probably guess what the other two things do, huh?

Saturday, December 2, 2017

Can't bind to 'ngFor' since it isn't a known property of 'li'.

This error stems from missing the let keyword. This...

<li *ngFor="president of presidents">

 
 

...needed to become this:

<li *ngFor="let president of presidents">

You may nest media queries inside of media queries. It's legit.

@media (max-height: 475px) {
   #groverClevelandWrapper {
      display: none;
   }
}
@media (min-height: 475px) {
   @media (max-width: 900px) {
      #groverClevelandWrapper {
         display: none;
      }
   }
   @media (min-width: 900px) {
      #groverClevelandWrapper {
         width: 300px;
         height: 180px;
         padding: 235px 10px 0 10px;
         position: absolute;
      }
   }
}

Thursday, November 30, 2017

November Queso

  1. The Iron Yard Academy is closing all shops.
  2. A would be merger between Sprint and T-Mobile has fallen apart.
  3. Log4j is a Java-based logging utility.
  4. "I Am Rich" is an old iPhone app that cost $999.99 and did nothing.
  5. Rover is like Airbnb for pet sitting.
  6. In 2000, SharePoint was orginally WSS or Windows SharePoint Services.
  7. Smartsheet is software as a service kind of like both SharePoint and Excel.
  8. Airtable lets you collaborate in an Excel sheet format "in the air" and then use an API call to save the records off to a database.
  9. Bitcoin is a kind of cryptocurrency and Coinbase is a wallet for cryptocurrency. Litecoin and Ethereum are other types of cryptocurrency.
  10. There is a way to use ref variables with a standalone delegate in C# even if you cannot do so with a Func or an Action.
  11. Tableau Software makes software for buisness intelligence.
  12. There are no semicolons in CoffeeScript!
  13. J2EE (Java 2 Platform Enterprise Edition) is a run anywhere (Mac, Windows, etc.) Java-flavored development thingamabob (platform) for the web with some canned APIs, JavaBeans, and support for HTML and Java applets.
  14. ZeroMQ is a messaging library for distributed/SOA challenges.
  15. Bamboo is a kind of continuous integration server.
  16. @whatever and @.whatever are both equal and equal to this.whatever in CoffeeScript.
  17. Nullable reference types are coming in C# and this means that the regular reference types will cease being nullable breaking a lot of existing code should you turn this on. The idea is that it will be less painful to go forward this way.
  18. White is a tool for testing WPF and WinForms.
  19. Kentico is a CMS.
  20. You may burn a Blu-ray Disc not unlike how you might have burned a CD a dozen years ago.
  21. T-Mobile will flag applicable text messages as "Scam Likely" when appropriate.
  22. GraphQL is a Facebook-made query language not unlike SQL. See how they both have QL in common?
  23. dice.com is a site like monster.com for finding a job. It is, after monster.com, probably the second biggest player in this space.
  24. The OpenAPI Specification is the name for what was Swagger but is now OpenAPI. Stripe is an API for Ruby-with-Sinatra-flavored web sites.
  25. https://www.visualstudio.com/vs/preview/ is an immediate link for a free version of Visual Studio 2017. Get the Community/Professional/Enterprise versions for free.
  26. The IMEI is an International Mobile Station Equipment Identity for a smartphone. This is mundane. The IMSI or International Mobile Subscriber Identity at the SIM card is a more security critical bit of data.

Wednesday, November 29, 2017

How do I get the distinct values from one column in T-SQL while showing the most current value from a second column?

Declare @StatusesFat TABLE
(
   EmployeeId uniqueidentifier NOT NULL,
   WorkStatus varchar(20) NULL
)
INSERT INTO @StatusesFat

...IMAGINE WHATEVER YOU WANT HERE...

Declare @StatusesFlat TABLE
(
   Id uniqueidentifier NOT NULL
)
INSERT INTO @StatusesFlat
SELECT distinct EmployeeId from @StatusesFat
GROUP BY EmployeeId
Declare @Statuses TABLE
(
   EmployeeId uniqueidentifier NOT NULL,
   WorkStatus varchar(20) NULL
)
INSERT INTO @Statuses
SELECT Id as 'EmployeeId', (SELECT top 1 WorkStatus FROM @StatusesFat
      WHERE EmployeeId = Id) as 'WorkStatus'
FROM @StatusesFlat

In convoluted T-SQL mechanics NOT takes precedence over OR and OR takes precedence over AND.

Honestly though, it would be best to just break up your logic with brackets so you don't have to remember these rules.

Add yourself to a channel in Slack.

Click on "Channels" as the title of the list of channels at the left nav. This fills Slack with the "Browse channels" modal of sorts. Type the name of the channel to join at the first fill-in-the-blank field that has a greyed-out magnifying glass in it followed by: "Search channels"

Tuesday, November 28, 2017

Using Pi in T-SQL!

Yes this is a thing. If you have diameter and you need a translation of it to a circumference, well there you go. I never thought I'd use it, but today I have.

SELECT Size * Pi() as 'Foo' FROM Bar

 
 

decimal(22,7) is the type for this, Pi and things multiplied against it.

Thursday, November 23, 2017

How do I get an image to show up in my Angular 4 app?

This is kinda tricky, huh? If you just make a folder somewhere then paths out to stuff in it will be interpreted as routes in the routing right? That won't do. If you look at angular-cli.json you will find a setting called assets that is probably also set to "assets" too. This setting defines a folder to be for images and hence an exception case for the routing rules. The folder (named "assets") needs to live inside the src folder but not a level deeper in the app folder. Look into it like so:

background-image: url("../../assets/GroverCleveland.png");

 
 

I hope everyone is having a Happy Thanksgiving.

Monday, November 20, 2017

How do I make dropdown list controls in SSRS reports?

When creating a parameter at "Parameters" within the "Report Data" pane in Microsoft SQL Server Report Builder as suggested here a dialog with buttons for General, Available Values, Default Values, and Advanced at the upper left will appear dubbed "Report Parameter Properties" and changing the "Data type:" at the General subsection will change the type of control. The options are Text, Boolean, Date/Time, Integer, and Float and Text tends to make a fill-in-the-blank text field while Date/Time is going to create a calendar control of sorts. To make a drop down list, start off with a Text type control and then switch over to Available Views where "Select from one of the following options:" needs to change from "None" to "Get values from a query" in the name of procuring a set of options. You will be prompted to pick a Dataset. When setting up the "Query type:" for the Dataset it may be wise to select the option for "Stored Procedure" in lieu of the option for "Text" where you could just free form some SQL. The reason is that you may find yourself repurposing queries for dropdowns. It is somewhat tricky to have a nullable option for a dropdown. You may solve the problem with a query like so:

Declare @Options TABLE
(
   CompanyId uniqueIdentifier null,
   CompanyName varchar(100) null
)
INSERT INTO @Options (CompanyId, CompanyName) VALUES (null, null)
INSERT INTO @Options
SELECT CompanyId, CompanyName FROM Company
SELECT * FROM @Options

To set up a new Dataset in an existing Data Source in Microsoft SQL Server Report Builder...

...right-click on the data source in the Report Data pane and pick: "Add Dataset..."

Sunday, November 19, 2017

Stub a service in test in an Angular 4 app.

I just got this working today in a GitHub project you may see here. You will want to use basic IoC dependency injection in your outermost wrapper module as suggested here like so:

providers: [
   Configuration,
   {provide: IpContract, useClass: IpService}
]

 
 

The Configuration above is a pseudoWeb.config as suggested here. It is used in my service like so:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Configuration } from '../../configuration';
import { HttpClient } from '@angular/common/http';
import { IpAddress } from '../models/ipAddress.model';
import { IpContract } from '../contracts/ip.contract';
@Injectable()
export class IpService implements IpContract {
   constructor(private httpClient: HttpClient, private configuration: Configuration) { }
   
   getIp():Observable<IpAddress>{
      let route: string = this.configuration.routeToApi + "api/ip";
      return this.httpClient.get<IpAddress>(route,{});
   }
}

 
 

Our contract looks like this:

import { Observable } from 'rxjs/Observable';
import { IpAddress } from '../models/ipAddress.model';
export class IpContract {
   constructor() {}
   public getIp: () => Observable<IpAddress>;
}

 
 

We may just stub our contract like so:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/map';
import { IpAddress } from '../models/ipAddress.model';
import { IpContract } from '../contracts/ip.contract';
@Injectable()
export class IpContractStub implements IpContract {
   constructor() { }
   
   getIp():Observable<IpAddress>{
      let ipAddress:IpAddress = new IpAddress();
      ipAddress.Ip = "127.0.0.1";
      return Observable.of(new IpAddress()).map(o => ipAddress);
   }
}

 
 

We are going to test a component that has a simple template like so:

<section>{{greeting}}</section>

 
 

...and looks like this on the TypeScript side:

import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs/observable';
import { IpAddress } from '../models/ipAddress.model';
import { IpContract } from '../contracts/ip.contract';
@Component({
   selector: 'ip',
   templateUrl: './ip.component.html'
})
export class IpComponent implements OnInit {
   greeting:string;
   ipAddress:IpAddress;
   
   constructor(public ipContract: IpContract) {
   
   }
   
   ngOnInit(): void{
   this.ipContract.getIp().toPromise().then(
      function(data) {
         this.ipAddress = data;
         this.greeting = "Welcome " + this.ipAddress.Ip + " to Grover Cleveland Hopscotch!";
      }.bind(this),
      function(error){
         console.log(error);
      });
   }
}

 
 

Out test:

import { TestBed, fakeAsync, tick, async, ComponentFixture, inject } from '@angular/core/testing';
import { IpComponent } from './ip.component';
import { IpContract } from '../contracts/ip.contract';
import { IpContractStub } from '../contracts/ip.contract.stub';
import { ActivatedRoute } from '@angular/router';
import { FormsModule } from '@angular/forms';
import { Observable } from 'rxjs/Observable';
 
describe('IpComponent (shallow)', () => {
   let fixture: ComponentFixture<IpComponent>;
   let component: IpComponent;
   let element;
   
   beforeEach(() => {
      TestBed.configureTestingModule({
         imports: [
            FormsModule
         ],
         declarations: [
            IpComponent
         ],
         providers: [
            {provide: IpContract, useValue: new IpContractStub()}
         ]
      });
      fixture = TestBed.createComponent(IpComponent);
      component = fixture.componentInstance;
      element = fixture.nativeElement;
   });
   
   describe('greeting', ()=> {
      it('should contain ip address', fakeAsync(()=> {
         
         fixture.detectChanges();
         tick();
         fixture.detectChanges();
         fixture.whenStable().then(() => {
            fixture.detectChanges();
            expect(element.querySelector('section').textContent).toContain('Welcome
                  127.0.0.1 to Grover Cleveland Hopscotch!');
         });
      }));
   });
});

How do I turn off the Pascal case to camel case effect in handing objects back from MVC controllers in a .NET Core application?

I attended a tech talk on this once, and, yes: It's not a bug. It's a feature.

services.AddMvc();

 
 

...in Startup.cs should be replaced with the following, expanded line of code to fix the feature per this.

services.AddMvc().AddJsonOptions(opt => opt.SerializerSettings.ContractResolver =
      new DefaultContractResolver());

 
 

This is what it is assuming that JavaScript should idiomatically have names in camel case while C# POCOs should idiomatically have names in Pascal Case. However, you don't want camel case names at TypeScript objects.

Saturday, November 18, 2017

launchSettings.json

In the "Properties" folder of a .NET Core MVC app there is a file called launchSettings.json which has settings for a default route and the application URL.

return Ok(whatever);

...in a .NET Core Controller action will return an OkObjectResult which is a type of an ObjectResult.

How do I make a .NET Core app spit out the NuGet packages it is using as .dll files in the bin folder upon a build?

Open the .csproj file of a project using the stuff to barf out in Notepad and splice this...

<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

 
 

...just inside this tag:

<PropertyGroup>

Friday, November 17, 2017

How to use the Parameters filter "controls" in Microsoft SQL Server Report Builder's SSRS reports.

Basically, these are going to fill the place the declared variables with leading @ symbols in your T-SQL query. Just write queries that have dummy values for these at the top of the script and then when it is time to copy and paste your script into Microsoft SQL Server Report Builder just leave off the top of the script where the variables are declared and set.

setting dates in T-SQL from magic strings

The dates here represent wide adoption of Gregorian calendar in Sweden and the comet Swift–Tuttle passing close to Earth:

SET @StartDate = (CASE WHEN @StartDate is null THEN '1753-01-01' ELSE
      @StartDate END)
SET @EndDate = (CASE WHEN @EndDate is null THEN '2126-08-05' ELSE
      @EndDate END)

 
 

'1753-01-01 00:00:00.000' is the long form.

Make some controls for a report in Microsoft SQL Server Report Builder.

At the "Report Data" pane in Report Builder where "folders" are titled Built-in Fields, Parameters, Images, Data Sources, and Datasets, the Parameters folder will hold controls. Right-click here and pick "Add Parameter..." to make your own control for filtering.

Thursday, November 16, 2017

How do I cast an IHttpActionResult from a controller to something sane in C#?

IHttpActionResult actionResult = await myController.Whatever();
var result = actionResult as OkNegotiatedContentResult<string>;

loop through the properties on a JSON object in JavaScript

I stole this from here. I can't find my previous blog post on this topic.

var obj = {
   name: "Simon",
   age: "20",
   clothing: {
      style: "simple",
      hipster: false
   }
}
 
for(var propt in obj){
   alert(propt + ': ' + obj[propt]);
}

A struct is going to be mutable not immutable in C#.

This has a way around that. Basically you take in all parameters as settings at the constructor and then make the getsetters only expose getting. Simple types you don't make yourself like int and DateTime are immutable value types even if the structs you roll yourself are not.

Tuesday, November 14, 2017

blanket turn off push notifications in Google Chrome?

Per this:

  1. In Google Chrome, click on that button that looks like three dots in a vertical line at the upper right.
  2. Scroll down to: "Advanced"
  3. Expand: "Advanced"
  4. In the "Privacy and security" subsection click on "Content settings" line item
  5. Click on: "Notifications"
  6. Turn off "Ask before sending (recommended)" so that setting just says: "Blocked"

 
 

Addendum 2/22/2018: Step one and a half above should read: Go to "Settings"

Throw away saved passwords in Microsoft SQL Server Report Builder 3.0.

  1. Click on that circle in the far upper left that has what I might describe as a meshwork triangle bending back upon itself.
  2. Pick: "Options"
  3. Click the button that says: "Clear all recent item lists"

Monday, November 13, 2017

concatenation with plus symbols in T-SQL

Well, it can be easy if you are just working with varchar types:

SELECT FirstName + ' ' + LastName As Name, Birthday
FROM Whatever

 
 

Otherwise you may need to convert to varchar types:

SELECT CONVERT(varchar(10),SuccessPercentage) + '%' As SuccessRate, Birthday
FROM Whatever

Present a true or false conditional as a query column in T-SQL.

SELECT Foo, CASE WHEN Bar = 'Baz' THEN 'Yes' ELSE 'No' END as Qux
FROM Whatever

If you want 'Are you sure?' as a column for query results in a T-SQL query you have to enclose it in single quotes.

Spaces and question marks do not otherwise play nicely with column names.

SELECT Affirmation, SignOff as 'Are you sure?'
FROM Whatever

Make a generic SSRS report in modern times.

  1. Download Microsoft SQL Server 2008 R2 Report Builder 3.0 here. You will use this as the IDE instead of BIDS.
  2. When the app opens and it tries to bring up a wizard, just close the wizard.
  3. Click on the link at the lower left which says "Connect" and feed the dialog box which appears the URL to your SSRS server.
  4. In the "Report Data" pane where there are "folders" for Built-In Fields, Parameters, Images, Data Sources, and Datasets, right-click on Data Sources and pick "Add Data Source..." to set up a data source, i.e. a connection to a database.
  5. Right-click on Datasets next and pick "Add Dataset..." and then walk through the little wizard that appears. (Change the first radio button from "Use a shared dataset" to "Use a dataset embedded in my report." and then pick a data source and finally paste SQL for a query into the Query window before clicking: "OK")
  6. Click on "Table" at the "Insert" tab at the top ribbon and pick "Table Wizard..." to start stepping through another wizard yet. Select your data set and at the "Arrange fields" portion of the wizard move all of the columns for your query at the "Available fields" subsection to the subsection titled "Values" with a Sigma symbol by it.
  7. Click the "Run" button at the upper left of the "Home" tab at the ribbon to see what you've made.
  8. When you close Report Builder it will prompt you to save a file with an .rdl file extension for the thing you have crafted.

Sunday, November 12, 2017

opening up CORS in a .NET Core MVC project

As suggested here, it is different than what is here. Follow these steps:

  1. Install CORS with this NuGet command:
    install-package Microsoft.AspNetCore.Cors
     
  2. services.AddCors();
    ...goes in the ConfigureServices method of Startup.cs just before...
    services.AddMvc();
     
  3. app.UseCors(builder =>
          builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());

    ...goes in the Configure method of Startup.cs just before...
    app.UseMvc();

 
 

I have, this weekend, made a dummy Hello World project that shows off Angular 4 and .NET Core 2.0 playing nicely together complete with tests on both sides of the wire and IoC on both sides of the wire. If you'd like to take a look you may see it here. The CORS thing is one of many challenges I fought with to make this happen.

Saturday, November 11, 2017

ng serve suddenly not working

In setting up .NET Core 2, I seem to have sabotaged the Angular CLI. When I try to run the npm start command to spin up an app I get an error telling me that ng serve ain't there. Following somewhat what is suggested partway down this thread but also doing my own thing a little bit I fixed the problem by destroying outright my node_modules folder and then running these commands:

  1. npm uninstall -g angular-cli @angular/cli
  2. npm install -g @angular/cli
  3. npm install --save-dev @angular/cli
  4. npm install @angular/cli
  5. npm install

upgrading Visual Studio 2017 to use .NET Core 2.0

I undertook the following steps and I cannot say if these had to happen in this order exactly.

  1. I downloaded and installed .NET Core 2.0.
  2. I clicked on the flag in Visual Studio 2017 Professional and then clicked something-er-other to prep an update, though this itself did not update anything.
  3. I closed Visual Studio 2017 Professional.
  4. I typed "Visual Studio Installer" at the start menu to spin up Visual Studio Installer and I let that app do its thing.

Where do I keep the equivalent of Web.config appSettings in an Angular app?

Well, I've made this in the topmost folder side by side with main.ts and index.html:

export class Configuration {
   public routeToApi:string = "http://localhost:61995/";
}

 
 

It has its own file and what you see is the entirety of the file. I loop it in as a provider in my outermost module wrapping everything else and that allows me to pull it in at the constructor line of a service. Is this ghetto?

Friday, November 10, 2017

Flinching paginated lists flinch upon a sort.

The column widths change some don't they? Should we even try to fix this problem or is it normal? A hard fix is going to take the shape of assigning widths to all of the columns and having that which overflows either wrap or get the ellipsis cutoff treatment. There is a happy medium between two extremes however and that entails setting the min-width of the columns allowing them only to collapse only so far. When one column starts to bully the others the change can thus only be so jarring.

integer division versus real division in T-SQL

Dividing integers by integers will give integers for results. In the event of a non-even split in which there is a remainder, an error is not thrown. Instead, SQL just deals with it with rounding to the nearest integer. Surreally, this can produce scenarios is which you may divide not zero by not zero and end up with zero which should be impossible. The fix is to cast the denominator of your "fraction" (that which you will divide by not that which you will divide) to a float just before the cutting like so:

SELECT Foo, Bar, Baz, (Foo + Bar) / CAST(Baz as float) * 100 as Qux
FROM Whatever

Thursday, November 9, 2017

I'm getting more and more comfortable in using Func and Action solutions in C#.

Inside of a Visual Studio solution when project A has some code that reaches into a repository in project B and the method therein has some acrobatics which end up requiring a type from project A even though project B doesn't have the type (in my case I am mapping from a POCO made from consuming Excel sheet gunk and then mapping getsetters from the POCO onto getsetters at an Entity Framework object while casting some string getsetters to getsetters of other types) well the problem may be hacked around by handing in a method from project A to project B as a Func or as an Action. There is a bit of a readability problem with what I have going on stemming from an inability to use ref or out variables. I want to hand in an Entity Framework object and get it back, doctored-up, and then save changes on the context. Well, I shouldn't just get a new variable back from a Func and then attach the new variable to the context in advance of a save as that would be adding something that was already there as the pointer/reference for the object is never broken as it goes into the Func and then back out the other side and even if it was via a deep clone or something the originally object would still be in the context and you still wouldn't want a readd. Since the pointer/reference never breaks. I could get a variable back from the Func, do nothing with it, and then save the context. Well, that is ghetto too. I have settled for handing in the object at the mouth of the method and not returning it at all. Even if an Action returns void a reference type inside of its machinery can get affected and in the next line of code after the call to the Action the object will have the battle scars from the meat grinder it just went through. Not all that readable.

Wednesday, November 8, 2017

bridge tables in Entity Framework's .edmx paradigm and how they behave in code

You could have a many-to-may relationship between clowns and Car with a bridge table made like so. Note that the primary key is a combination of the two primary keys from the Clown table and the Car table and that there is not otherwise a primary key named for the bridge table itself nor any other columns beyond the two that loop in Car and clowns.

CREATE TABLE [dbo].[ClownToCarBridge](
   [ClownID] [uniqueidentifier] NOT NULL,
   [CarID] [uniqueidentifier] NOT NULL,
   CONSTRAINT [PK_ClownToCarBridge] PRIMARY KEY CLUSTERED
   (
      [ClownID] ASC,
      [CarID] ASC
   )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
   IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
   ALLOW_PAGE_LOCKS = ON)
)
GO
ALTER TABLE [dbo].[ClownToCarBridge] WITH CHECK
ADD CONSTRAINT [FK_ClownToCarBridge_ClownID] FOREIGN KEY([ClownID])
REFERENCES [dbo].[Clown] ([ClownID])
GO
ALTER TABLE [dbo].[ClownToCarBridge]
CHECK CONSTRAINT [FK_ClownToCarBridge_ClownID]
GO
ALTER TABLE [dbo].[ClownToCarBridge] WITH CHECK
ADD CONSTRAINT [FK_ClownToCarBridge_CarID] FOREIGN KEY([CarID])
REFERENCES [dbo].[Car] ([CarID])
GO
ALTER TABLE [dbo].[ClownToCarBridge]
CHECK CONSTRAINT [FK_ClownToCarBridge_CarID]
GO

 
 

The way this materializes in code is interesting. There is no ClownToCarBridge C# class. Instead, the Car object will have as a new getsetter an ICollection of Clown objects called "Clowns" and the Clown object will have as a new getsetter, you guessed it, an ICollection of Car objects dubbed: "Cars"

Ternary expressions do not play nicely with nullable types in C#.

DateTime? x = String.IsNullOrWhiteSpace(y) ? null : Convert.ToDateTime(y);

 
 

...cannot compile and must become:

DateTime? x;
if (String.IsNullOrWhiteSpace(y))
{
   x = null;
}
else
{
   x = Convert.ToDateTime(y);
}

The orderBy by pipe which comes with Angular and mfDefaultSorter do not play nicely together.

<tr *ngFor="let person of people | orderBy: 'BirthDate'">

 
 

...probably needs to be replaced by:

<tr *ngFor="let person of people">

 
 

...to fix bust column sorting. Do the initial upfront sort on the TypeScript side like this.

Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.

This has a good fix for this error. In the partial for modifications which has a sister partial class that inherits from DbContext put something like so:

public override int SaveChanges()
{
   try
   {
      return base.SaveChanges();
   }
   catch (DbEntityValidationException ex)
   {
      var x = ex.EntityValidationErrors.SelectMany(y => y.ValidationErrors).Select(z =>
            z.ErrorMessage);
      string message = string.Join(" ", x);
      message = string.Concat(ex.Message, " The validation errors are: ", message);
      throw new DbEntityValidationException(message, ex.EntityValidationErrors);
   }
}

 
 

This will give you much better reporting. In my particular problem I had made a column/getsetter for a varchar/string not nullable when it should have been nullable. I dropped and recreated the database tables and I opened the .edmx as a big blob of XML and found the two places inside where the column was referenced and I set the nullability state from false to true.

Monday, November 6, 2017

Database Diagrams!

In SSMS 17.1 at the pseudofolders beneath a database in the "Object Explorer" which are titled Database Diagrams, Tables, Views, External Resources, Synonyms, Programmability, Query Store, Extended Events, Storage, and Security, right-click on Database Diagrams and pick "New Database Diagram" to make a visual representation of how some database tables interact (you will be able to cherry pick which tables) not unlike an Entity Framework .edmx. You may right-click in the white space around the diagram to find an option for "Zoom" which does what you'd expect.

painful lessons of .NET Core

  1. Make supporting projects for your UI in a solution in Visual Studio 2017 of .NETCoreApp 1.1 and not of .NETStandard 1.4 as there are not test projects for .NETStandard 1.4.
  2. There really are not mocking frameworks yet working for the before mentioned test projects. You will have to stub everything.
  3. The canned MVC projects will require a different approach to CORS, not like this but perhaps like this.

Sunday, November 5, 2017

Property value is not valid.

One or more values are invalid. Mismatched PageRule with the wrong ItemType.

I got this error attempting to set the "Copy to Output Directory" setting of a .txt file to "Copy if newer" in Visual Studio 2017 at the "Properties Window" that one sees when one presses F4. I Googled against this problem and it just is what it is, you know? The IDE has a bug. To hack around it, right-click on the file that you want to alter in the Solution Explorer and pick "Properties" and that will bring up a little dialog box where you may do the same damn thing only successfully so.

Saturday, November 4, 2017

the base tag in HTML

You stick this in the head tag to define what relative paths in href and src parameters are relative to.

<base href="/">

 
 

This suggests that something like this...

<base href="https://www.w3schools.com/images/" target="_blank"">

 
 

...will keep you free of sprinkling target="_blank" everywhere in markup.

named arguments in C# 7.2

...as opposed to positional arguments, these are variables handed in when calling a method that do not necessarily have to correspond sequentially to the variables at the method signature. You lead a variable with its name followed by a colon to make this happen, and beyond that you otherwise just specify variables as separated with commas as you would normally. Named arguments may even be mixed with positional arguments as suggested here. Something newish with C# 7.2 is that you may have a named argument followed by a positional argument followed by another named argument in lieu of having to have named arguments at the end of calling positional arguments. In that scenario, the second positional argument gets hydrated with the second value. optional and reloadOnChange as given here are examples of named arguments.

I am pleased to report that it is easy to get StructureMap working with a .NET Core application.

Steps:

  1. I ran this command in the NuGet Console in Visual Studio 2017...
    install-package StructureMap
    ...which gave me StructureMap 4.5.2.
     
  2. I followed what was suggested at this to add...
    ConfigureIoC(services);
    ...immediately after...
    services.AddMvc();
    ...in the ConfigureServices method inside of Startup.cs.
     
  3. The line of code I added was red/angry as it tried to find a method that wasn't there. I put this method into Startup.cs to fix that:
    public void ConfigureIoC(IServiceCollection services)
    {
       services.AddTransient<IFlatFileMechanics, FlatFileMechanics>();
    }

 
 

Startup.cs ends up looking like so:

using HelloWorld.Core;
using HelloWorld.Infrastructure;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace HelloWorld.RestApi
{
   public class Startup
   {
      public Startup(IHostingEnvironment env)
      {
         var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
            .AddEnvironmentVariables();
         Configuration = builder.Build();
      }
      
      public IConfigurationRoot Configuration { get; }
      
      public void ConfigureServices(IServiceCollection services)
      {
         services.AddMvc();
         ConfigureIoC(services);
      }
      
      public void Configure(IApplicationBuilder app, IHostingEnvironment env,
            ILoggerFactory loggerFactory)
      {
         loggerFactory.AddConsole(Configuration.GetSection("Logging"));
         loggerFactory.AddDebug();
         app.UseMvc();
      }
      
      public void ConfigureIoC(IServiceCollection services)
      {
         services.AddTransient<IFlatFileMechanics, FlatFileMechanics>();
      }
   }
}

 
 

With modern StructureMap we expect dependencies to be hydrated at controller constructor signatures and that is still true. This worked for me:

using HelloWorld.Core;
using Microsoft.AspNetCore.Mvc;
namespace HelloWorld.RestApi.Controllers
{
   [Route("api/[controller]")]
   public class ValuesController : Controller
   {
      public IFlatFileMechanics _flatFileMechanics;
      
      public ValuesController(IFlatFileMechanics flatFileMechanics)
      {
         _flatFileMechanics = flatFileMechanics;
      }
      
      [HttpGet]
      public string Get()
      {
         return _flatFileMechanics.ReadFlatFile();
      }
   }
}

 
 

Addendum 10/3/2018: If you look close we are not using StructureMap at all. The IoC is just a part of .NET Core now. We don't need to explicitly use StructureMap. I was misguided when I typed this up.