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;
      }
   }
}