Saturday, February 25, 2017

fun features in TypeScript!

On the 13th of this moth I saw Chander Dhall speak on "TypeScript and Angular 2" at the Austin .NET User Group. The first half of the talk was just on TypeScript and he said some things I had not heard before! What is below will return two alerts. The first has 13 in it and the second has undefined in it.

class Product {
   public id: number;
   constructor(id: number) {
      alert(id);
   }
}
let product = new Product(13);
alert(product.id);

 
 

Tuples are for beating the Thunderdome problem. When you start bolting stuff onto a tuple it has to be one of the predefined types already there, but beyond that you may just bolt stuff on. Lists may be cast to tuples. The following will throw three alerts saying iOS then Android then Windows at the end.

let list = ["iOS", "Android", "Windows"];
let [first, second, third] = list;
alert(first);
alert(second);
alert(third);

 
 

This throws the same three alerts.

let list = ["iOS", "Android", "Windows"];
let [first, ...rest] = list;
alert(first);
alert(rest[0]);
alert(rest[1]);

 
 

Suck out the parameters from a type out to variables! The following throws two alerts that say first 123 and then: Product Model 123

let product = {
   id: 123,
   address: {},
   model: "Product Model 123"
}
let { id, model } = product;
alert(id);
alert(model);

 
 

This throws two alerts with Joshua and Cazton being the values:

function setDefault(obj: { empName: string, companyName?: string }) {
   let { empName, companyName = "Cazton" } = obj;
   alert(empName);
   alert(companyName);
}
setDefault({empName:"Joshua"});

 
 

This does the same thing more or less, but now the second alert will say Whatever.

function setDefault(obj: { empName: string, companyName?: string }) {
   let { empName, companyName = "Cazton" } = obj;
   alert(empName);
   alert(companyName);
}
setDefault({empName:"Joshua", companyName: "Whatever"});

 
 

This allows for the value handed in to be one of two things.

function unionTypes(value: number | number[]) {

 
 

interface IDivide {
   (n: number, d: number): number;
}

...is like...

let divide : (n: number, d: number) => number;

 
 

The following was given as an example of how to do generics, but I wonder if this is going to work given how the very first example above behaves.

class Model{
   model: T;
   constructor(model: T) {
   }
}

 
 

Getting into Angular2 another thing I learned that was new had to do with the distinction between Observable, Promise, and Callback. To illuminate let's explain what Observable is firstly, revamping the app I describe here and here by making, to begin with, a "models" folder in the "app" folder with two new, badly named objects in it. ;) The first is in a file dubbed "outer.model.ts" and it looks like this:

import {Observable} from 'rxjs/observable';
import {Inner} from './inner.model';
export class Outer {
   isbn: string;
   characters: Array<string>;
   contentDrugInFromOtherEndpoints: Array<Observable<Inner>>;
   contentKeptInFromOtherEndpoints: Array<Inner>;
}

 
 

The other is "inner.model.ts" and it looks like this:

export class Inner {
   name: string;
}

 
 

The models above will be used to catch calls that come back from an API. Outer has some extra state bolted on to it too. It'll make sense. Patience! Next make a "services" folder in the "app" folder and put "api-service.service.ts" in it. It will hold the following code:

import {Injectable} from '@angular/core';
import {Http, Response} from '@angular/http';
import {Outer} from '../models/outer.model';
import {Inner} from '../models/inner.model';
import {Observable} from 'rxjs/observable';
import {ApiContract} from '../contracts/api-contract.contract';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';
@Injectable()
export class ApiService implements ApiContract {
   public api:string;
   constructor(private http: Http) {
      this.api = "http://www.anapioficeandfire.com/api/books";
   }
   public getOuter(): Observable<Outer[]>{
      return this.http.get(this.api).map((response: Response) => <Outer[]>response.json());
   }
   public getInner(url: string): Observable<Inner> {
      return this.http.get(url).map((response: Response) => <Inner>response.json());
   }
}

 
 

Alright, I'm going to use the dependency injection trick at the providers for my template so therefore I also have to have an inheritance trick for my service above. It needs to be upcastable to something like an interface that just holds signatures for its methods. In going through a learning curve it turned out that you cannot make a contract for a service that is an interface and get it to play nicely with the "providers dependency injection thing" but instead the class you are to use needs to implement a class you are to use for a contract. Note that I used the word implement. Typically in inheritance in TypeScript a class implements and interface and a class extends another class, but herein, in this wackiness, a class must implement a class. This means that a line reading super(); at the first line inside of the constructor of the service needs to be removed as not only is it no longer mandatory, it won't compile. You'll notice this as one of the big changes when you switch implements to extends in these scenarios. Just below is the last of the four new files. Make a "contracts" folder and put "api-contract.contract.ts" inside of it holding the following code.

import {Outer} from '../models/outer.model';
import {Inner} from '../models/inner.model';
import {Observable} from 'rxjs/observable';
export class ApiContract {
   constructor() {}
   public getOuter: () => Observable<Outer[]>;
   public getInner: (url: string) => Observable<Inner>;
}

 
 

Our original starting-point-component.ts needs love anew:

import { Component, Input } from '@angular/core';
import {Http, Headers} from '@angular/http';
import {Observable} from 'rxjs/observable';
import {Outer} from '../models/outer.model';
import {Inner} from '../models/inner.model';
import {ApiContract} from '../contracts/api-contract.contract';
import {ApiService} from '../services/api-service.service';
@Component({
   selector: 'entry-point',
   templateUrl: '/Partial/SomethingErOther',
   providers: [{provide: ApiContract, useClass: ApiService}]
})
export class StartingPoint {
   private welcome: string;
   private outers: Observable<Outer[]>;
   constructor(private apiContract: ApiContract) {
   this.welcome = "Hey, look at this!";
   this.outers = apiContract.getOuter();
   }
   act(outer: Outer) {
      if (!outer.contentKeptInFromOtherEndpoints) {
         outer.contentKeptInFromOtherEndpoints = new Array<Inner>();
         let counter = 0;
         while (counter < outer.characters.length){
            outer.contentKeptInFromOtherEndpoints.push(new Inner())
            counter++;
         }
      }
      outer.characters.forEach(url => {
         let inner = this.apiContract.getInner(url);
         if (!outer.contentDrugInFromOtherEndpoints) {
            outer.contentDrugInFromOtherEndpoints = new Array<Observable<Inner>>();
         }
         outer.contentDrugInFromOtherEndpoints.push(inner);
      });
   }
   react(inner: Inner, outer: Outer, counter: number){
      if(outer.contentKeptInFromOtherEndpoints[counter]){
         if (!outer.contentKeptInFromOtherEndpoints[counter].name){
            if (inner && inner.name){
               outer.contentKeptInFromOtherEndpoints[counter] = inner;
            }
         }
      }
   }
}

 
 

Let's make the HTML for the view starting-point-component.ts end up using look like this:

<ol>
   {{welcome}}
   <li *ngFor="let outer of outers | async">
      {{outer.isbn}}
      <ng-container *ngIf="!outer.contentDrugInFromOtherEndpoints">
         <a style="cursor:pointer; color:blue" (click)="act(outer)">more?</a>
      </ng-container>
      <ng-container *ngIf="outer.contentDrugInFromOtherEndpoints">
         <ng-container *ngFor="let inner of outer.contentDrugInFromOtherEndpoints;
               let i = index;">
            {{react(inner | async, outer, i)}}
         </ng-container>
      </ng-container>
      <ul *ngIf="outer.contentDrugInFromOtherEndpoints">
         <li *ngFor="let inner of outer.contentKeptInFromOtherEndpoints">
            {{inner.name}}
         </li>
      </ul>
   </li>
</ol>

 
 

Alright, this all works. There is a way to use Promise<Outer[]> instead of Observable<Outer[]> above (with a little bit different syntax) and Promise is native to Angular 2 and does not require you to use rxjs as Observable does. Also you can just use Callback by which I mean plain Jane JavaScript asynchronous implementations that have existed since the beginning of AJAX. TypeScript 2 supports the Promise API so you can do its .done stuff, so why go to Observable at all and loop in rxjs? Observable is good for talking to a web socket more so than an API endpoint, where there is a buffer. You can get back a collection one item at a time in a progressing stream and then manhandle/repurpose/use the array asynchronously as it fills in. One last thing on Angular 2: An $event from a keyup event may be caught as a KeyboardEvent at a TypeScript method and then cast to a HTMLInputElement if desired.

Friday, February 24, 2017

hacks to extend insight

When you need a paginated list of records in a web application it's probably best to use a third party library. The grids that DevExpress has are, for example, pretty robust and have enough whistles and bells to do mostly anything you might need. The other alternative is to roll your own. You rationalize it like this: "Well, those DevExpress grids are really overkill. We don't need to do all that! We are just going to have a table layout with pagination, oh and just a few more easy features." That works great all the way until the end of that story, but then, a sprint away, the grid needs to be tweaked so that it can do just a little bit more. Soon your monster will be growing more and more tentacles. I don't recommend this, but if you have the opportunity to work on something like this I think you'll find that it's a lot of fun to build something like this out even if it doesn't make a lot of sense. I've learned a lot. If a column in a grid has hyperlinks for all of its data points and the links all do something row specific, you have to find a way for the grid (assuming you are building something repurposable across all comparable scenarios and you’re not tying your creation to one need and one shape of recordset) to allow a user to hand in a method that can be run upon "hyperlink" (i.e. button) click. In TypeScript this takes the shape of having an interface (at the grid mechanics) that has a property for a method signature allowing JSON objects to be handed in from the outside to match against it that have a function hanging off of them to hydrate this need case by case. Once I actually built something like this I realized that if I were to build something comparable in C# that this would be one of the elusive use cases for a Func! An interface in C# would take a Func for what to defer to to do upon the click of a button at a row. Again, the goofy puzzle is also an interesting one and a lot of fun. What if you have an n+1 problem in which nine out of ten columns are hydrated by an initial query but all of the line items in the grid each require an independent call to hydrate the data point for the tenth column? Well, fortunately if you are using a canned solution like DevExpress you will not be allowed to do anything too stupid and you'll just be damned to deal with the data aggregation issue upstream or have the extra data points hydrate at expandable areas for each row as they are expanded by the user. If you are doing your own thing you can get silly. The items in the tenth column can just start appearing one at a time sequentially and asynchronously. If there is a search box at the top of each column for filtering then the filter for the tenth column starts out greyed-out and unlocks once you have all of the records! Now that's ghetto fabulous! Things can get really strange. You'll have to restrain yourself to keep the UX under control and not make something that obviously smells to users as dysfunctional and Mickey Mouse. The proverbial "You have enough rope to hang yourself." saying applies here. Try to use good judgment. Get others to nod their heads at your bad ideas, etc. Good luck!

Friday, February 17, 2017

wireframe versus mockup

The mockup is the Photoshop layout of how a web page should look and the wireframe is on par with a digital version of a whiteboard drawing of it, showing where buttons sit and what is important and what not.

Wednesday, February 15, 2017

When I am viewing a PDF on the web with Google Chrome, how may I save it locally?

  1. mouse over the guts of the content
  2. a black bar will appear at the upper edge below the browser's top navigation
  3. at the right side of the black bar, click the icon that looks like an arrow pointing down at a little horizontal line

Tuesday, February 14, 2017

The date input type doesn't work in IE11! I'm serious!

<!DOCTYPE html>
<html lang="en">
   <body>
      <form action="#">
         look at this:
         <div>         
            <input type="date" id="whatever" />
         </div>
         <input type="submit" value="go" />
      </form>
   </body>
</html>

Monday, February 13, 2017

How do I get the URL for a tab in Microsoft OneNote to share with the team?

Right-click on the tab and pick: "Copy Link to Section"

Turn off External Web Tools in Visual Studio 2015

at:

  1. Tools
  2. Options...
  3. Projects and Solutions
  4. External Web Tools

Uncheck everything here!

When you want to make a async API endpoint and stub it out to just return canned data in the short term, what does the await part look like?

[HttpGet, Route("widgets/{customerId:long}")
public async Task<IHttpActionResult> GetWidgets(long customerId)
{
   List<OrderNumber> widgets = new List<OrderNumber>()
   {
      new Widget()
      {
         PartNumber = 4534,
         Name = "FlapTrapWackyWonk"
      },
      new Widget()
      {
         PartNumber = 346456346,
         Name = "GusGuffGunkGooey"
      }
   };
   return Json(widgets);
}

 
 

becomes...

[HttpGet, Route("widgets/{customerId:long}")
public async Task<IHttpActionResult> GetWidgets(long customerId)
{
   List<OrderNumber> widgets = new List<OrderNumber>()
   {
      new Widget()
      {
         PartNumber = 4534,
         Name = "FlapTrapWackyWonk"
      },
      new Widget()
      {
         PartNumber = 346456346,
         Name = "GusGuffGunkGooey"
      }
   };
   return Json(await Task.FromResult(widgets));
}

Sunday, February 12, 2017

handlebars.js

...is really simple to use. You can learn all there is to know in an hour. You can get it here and then, after looping in this one library, make a template inside a script tag like so:

<script id="myTemplate" type="text/x-handlebars-template">
   <table>
      <tr>
         <th>Foo</th>
         <th>Bar</th>
         <th>Baz</th>
         <th>Qux</th>
      </tr>
      {{#myCollection}}
         <tr>
            <td>{{foo}}</td>
            <td>{{bar}}</td>
            <td>{{baz}}</td>
            <td>{{#calculateQux foo bar baz}}{{/calculateQux}}</td>
         </tr>
      {{/myCollection}}
   </table>
</script>

 
 

Let's talk about how we could use this to fill in records in a div called someDivSomewhere with jQuery. The markup is pretty simple and it stays simple and if you are going to anything complicated at all you have to defer to a function in JavaScript to do so. In this example that function will be a calculateQux. To get this to work, you would need to make a function that takes in three variables at the signature to represent the foo, the bar, and the baz suggested in the markup above. Let's say that we just assign that function to a variable dubbed calculateQux also. Alright, with all of that in mind, the following code will get our div hydrated with our template.

var json = { myCollection: [ {foo:true,bar:"cat",baz:13}, {foo:false,bar:"dog",baz:42} ] };
Handlebars.registerHelper('calculateQux', calculateQux);
var stepOne = $("#myTemplate").html();
var stepTwo = Handlebars.compile(stepOne);
$("#someDivSomewhere").html(stepTwo(json));

 
 

Alright, the rest of what is happening should be easy to reverse engineer just by staring at it. We are handing in an object with a property called myCollection that is an array of objects which each have a foo, a bar, and a baz. We loop through them in the template while building a table. A fourth column for "Qux" has calculated values based on some other hijinks we have going on upstream in code. Yay! Bonus: The template in the stepOne variable may be pushed to and taken from localStorage!

Plaza

This is an iPhone app by Chatous. You punch in your locale and you can see garbage knickknacks being sold locally. Someone I don't really know recommended the app over Facebook just now. It turns out that you log in with Facebook and the first time you do it tries to spam all of the friends in your friends list about itself so he probably didn't even mean to give me this. Awesome!

Saturday, February 11, 2017

Using MVC views within Angular 2!

Assuming this application and this incorporation into MVC, one may obviously change up starting-point.component.ts like so to have a template in the form of an .html file, in this case starting-point.template.html sitting in the same folder as starting-point.component.

import { Component, Input } from '@angular/core';
import {Http, Headers} from '@angular/http';
import {Observable} from 'rxjs/observable';
@Component({
   selector: 'entry-point',
   templateUrl: '/Whatever/app/components/starting-point.template.html',
   providers: []
})
export class StartingPoint {}

 
 

Similarly, a change up like so...

import { Component, Input } from '@angular/core';
import {Http, Headers} from '@angular/http';
import {Observable} from 'rxjs/observable';
@Component({
   selector: 'entry-point',
   templateUrl: '/Partial/SomethingErOther',
   providers: []
})
export class StartingPoint {}

 
 

...is going to give you back the view from a controller action assuming a controller like so:

using System.Web.Mvc;
namespace MyApp.Controllers
{
   public class PartialController : Controller
   {
      public ActionResult SomethingErOther() => PartialView();
   }
}

 
 

Inside of the view, a .cshtml file at /Views/Partial/SomethingErOther.cshtml, you may use the familiar Razor markup. I had some heartache in trying to put something in the ViewBag and then pull it out again in the view that the Angular stuff uses. If I set something in HomeController or WhateverController it cannot be surfaced in the view. I guess it just reads as null. If I set the same property in the PartialController's action like so...

using System.Web.Mvc;
namespace MpApp.Controllers
{
   public class PartialController : Controller
   {
      public ActionResult SomethingErOther()
      {
         ViewBag.Message = "huh?";
         return PartialView();
      }
   }
}

 
 

...well, that works but also clobbers the same ViewBag setting back in the regular context of HomeController and WhateverController and views associated with them, making it behave nullesque therein. This is strange behavior, but it is also not the end of the world. If you just see this divide you should be able to tiptoe around it and get what you need working.

The folder structure requirements for Angular 2 in a C# MVC application are a little finicky.

Do not put the Angular stuff in the Scripts folder with all of the other random JS stuff. It needs its own folder at the root of the UI project and this folder cannot just be named anything. The folder needs to be named after the Controller that will cough up a view that uses it! That means in the case of HomeController your Angular app will go in a "Home" folder in the root of your UI project with the "app" and "node_modules" folders immediately inside of it and in the case of WhateverController your Angular app will go in a "Whatever" folder in the root of your UI project with the "app" and "node_modules" folders immediately inside of that folder. It might be best NOT to use the HomeController and to instead make something new honestly. Consider these three URLs:

  1. http://localhost:60892/Home/Index
  2. http://localhost:60892/Home
  3. http://localhost:60892

Alright, the first two will work great with an Angular app in a "Home" folder and the third will barf red up to Google Chrome's console instead of behaving itself. That's frustrating! I hacked around this problem by making the HomeController automatically redirect to a different controller and then using that controller to fish for the view for the Angular 2 mechanics. The Home Controller just looks like this now:

using System.Web.Mvc;
namespace MyApp.Controllers
{
   public class HomeController : Controller
   {
      public ActionResult Index()
      {
         return RedirectToAction("Index", "Whatever");
      }
   }
}

 
 

In the view that actually summons the .js files for Angular code you should craft URLs like so:

<script src="~/Whatever/node_modules/core-js/client/shim.min.js"></script>

I don't know what to do with the elephant in the room.

By elephant I mean: big heavy thing. Here some thoughts on the fatso node_modules folder which for this little project holds 89.9 MB and 10,559 files. But these are just thoughts and not solutions. I'm trying to figure out what is best to do. If you add this sort of thing to source control or add it to a Visual Studio 2017 RC solution you will see the proverbial spinner spinning a little bit. In the case of including in it a .csproj file, you will quickly find that you can't compile as there will be one hundred and one things (well, twenty-four without hyperbole) nested in third party gunk the TypeScript compiler hates. Putting <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked> inside the first <PropertyGroup> in the .csproj file will stop TypeScript compilation when you build. This means no TypeScript compilation from within Visual Studio, but maybe that's not the end of the world. I don't see why I can't build (and thus sanity check) TypeScript at the command line. Why does everything work there and not in Visual Studio? Well, I suppose that is another puzzle. I guess it's trendy to have an Angular 2 frontend that one just works with in Visual Studio Code that merely talks to C# through REST calls effectively putting the C# and the TypeScript in two entirely different applications. And yet, that begs the question: "What if you want to mix Angular 2 into a traditional MVC app?" With regards to source control, it's gonna be painful to tuck node_modules away if it actually gets updates regularly. I guess you would start out hoping that such isn't the case. Not keeping a copy in source control could lead to some terrible, terrible surprises when you pull the code two years later and try to rehydrate the folder only to find that newer versions of libraries introduce devastating changes. I don't know what to do about any of this.

It's a gamble either way, right?

Friday, February 10, 2017

Just what does type in TypeScript do exactly?

Alight kids, this TypeScript...

enum ColorPattern {
   Solid,
   Splotchy,
   Striped
}
 
class Snake {
   commonName: string;
   genusAndSpecies: [string,string];
   lengthInMeters: number;
   appearance: ColorPattern;
}
 
class Constrictor extends Snake {
   poundsPerSquareInchPressureFromSqueeze: number;
   shouldYouRunIfYouSeeOne: boolean;
}
 
class HarmlessSnake extends Snake {
   recommendedAsPet: boolean;
}
 
class Viper extends Snake {
   lethalDoseFiftyScaleRating: number;
   milligramsOfVenomPerBite: number;
   shouldYouRunIfYouSeeOne: boolean;
}
 
type DangerousSnake = Constrictor | Viper;
 
interface AdviceDangerousSnake {
   give: (serpent: DangerousSnake) => string;
}
 
let advice = <AdviceDangerousSnake>{
   give: (serpent: DangerousSnake): string => {
      if (serpent.shouldYouRunIfYouSeeOne) {
         return `Run if you see a ${serpent.commonName}.`;
      } else {
         return `Freeze if you see a ${serpent.commonName}.`;
      }
   }
}
 
let tuple: [string, string] = ["Eunectes", "murinus"];
 
let anaconda = new Constrictor();
anaconda.commonName = "Green Anaconda";
anaconda.genusAndSpecies = tuple;
anaconda.lengthInMeters = 5;
anaconda.appearance = ColorPattern.Splotchy;
anaconda.shouldYouRunIfYouSeeOne = true;
anaconda.poundsPerSquareInchPressureFromSqueeze = 65;
 
alert(advice.give(anaconda));

 
 

...is pretty verbose considering that all it does is throw an alert with "Run if you see a Green Anaconda." in it, but, well, it's an excuse to show off TypeScript! TypeScript compiles to JavaScript and per https://www.typescriptlang.org/play/index.html it will ultimately make this JavaScript if the above is given...

var __extends = (this && this.__extends) || function (d, b) {
   for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
   function __() { this.constructor = d; }
   d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var ColorPattern;
(function (ColorPattern) {
   ColorPattern[ColorPattern["Solid"] = 0] = "Solid";
   ColorPattern[ColorPattern["Splotchy"] = 1] = "Splotchy";
   ColorPattern[ColorPattern["Striped"] = 2] = "Striped";
})(ColorPattern || (ColorPattern = {}));
var Snake = (function () {
   function Snake() {
   }
   return Snake;
}());
var Constrictor = (function (_super) {
   __extends(Constrictor, _super);
   function Constrictor() {
      return _super.apply(this, arguments) || this;
   }
   return Constrictor;
}(Snake));
var HarmlessSnake = (function (_super) {
   __extends(HarmlessSnake, _super);
   function HarmlessSnake() {
      return _super.apply(this, arguments) || this;
   }
   return HarmlessSnake;
}(Snake));
var Viper = (function (_super) {
   __extends(Viper, _super);
   function Viper() {
      return _super.apply(this, arguments) || this;
   }
   return Viper;
}(Snake));
var advice = {
   give: function (serpent) {
      if (serpent.shouldYouRunIfYouSeeOne) {
         return "Run if you see a " + serpent.commonName + ".";
      }
      else {
         return "Freeze if you see a " + serpent.commonName + ".";
      }
   }
};
var tuple = ["Eunectes", "murinus"];
var anaconda = new Constrictor();
anaconda.commonName = "Green Anaconda";
anaconda.genusAndSpecies = tuple;
anaconda.lengthInMeters = 5;
anaconda.appearance = ColorPattern.Splotchy;
anaconda.shouldYouRunIfYouSeeOne = true;
anaconda.poundsPerSquareInchPressureFromSqueeze = 65;
alert(advice.give(anaconda));

 
 

So there are few supertypes, if you will, in C#: class, interface, struct ...and TypeScript has a few supertypes too: class, interface, type ...a class being like a class in C# more or less, but an interface being very different. You can just make a variable from an interface as you can a class. The only differences are:

  1. that interfaces must be instantiated with a bit different syntax and at that moment all of the required fields must be hydrated and that's any field that doesn't have a question mark both immediately after its name (no space) and before the colon before its type
  2. a class can have methods but an interface only may have signatures for methods making them comparatively anemic

Classes may implement interfaces and what is more interfaces, yes, may implement classes. This will make your head want to explode until you eventually get used to the idea that "interfaces" are just a very different thing in TypeScript than they are in C#. An interface can be a contract to upcast a class to, but then again you don't really need a class to use them so don't think that's what they are for, all in all. There is no inheritance for type. You can just make a type like so:

type DangerousSnake = {
   commonName: string;
   genusAndSpecies: [string,string];
   lengthInMeters: number;
   appearance: ColorPattern;
   shouldYouRunIfYouSeeOne: boolean;
};

 
 

But the real intent of type seems to be to alias classes like so:

type DangerousSnake = Constrictor;

 
 

Both of the versions of DangerousSnake immediately above could replace this line of code at the beginning of our blog posting...

type DangerousSnake = Constrictor | Viper;

 
 

...and the code would still successfully compile to JavaScript and the "Run if you see a Green Anaconda." alert would still fire when JavaScript code was generated, but things get a little more interesting when we introduce a pipe symbol to alias two classes. This allows for something on par with "where T" in C#'s generics. The pipe means intersection and our type will have fields common across the two classes that hydrate it as seen at this screen grab from the TypeScript playground:

 
 

Replacing the pipe symbol with an ampersand allows for a union instead of an intersection and all fields across all classes are available. You will need to be a little more careful with these, obviously.

 
 

Addendum 10/4/2018: An interface in TypeScript will make nothing when compiled to JavaScript. It provides type safety in TypeScript and nothing more. Notice above that AdviceDangerousSnake does not exist in the JavaScript.

how to make a photo for yourself in the Outlook-2013-with-Exchange paradigm

  1. open Outlook 2013
  2. click "People" at the bottom where it says "Mail Calendar People Tasks"
  3. at the list of People, Business Card, Card, Phone, List at the top nav go to People and search for yourself
  4. add yourself to your People list
  5. go to Business Card and open your own Business Card
  6. click on the photo within the Business Card to change it up
  7. you'll upload a new photo

when your iPhone asks if you want to switch to low power mode and you accidentally say yes

To turn this back off on a phone like mine, an iPhone 45 with iOS 9.1 (13B143):

  1. go to: Settings > Battery > Low Power Mode
  2. uncheck

Thursday, February 9, 2017

what the "Controller As" pattern is and what it's not

$scope in the old AngularJS 1.58 paradigm may seem at first glance like a guiding light, a beacon to gravitate towards, a thing to stray towards by default in lieu of straying off elsewhere...

...but once you get a closer look it's a little scary!

You are being drawn into a dangerous web with its overuse. I was originally under the misimpression that the "Controller As" pattern would restrain $scope to the scope of a controller rather than letting it be application-wide, but that is not the reality. The pattern just gives you convenience names to use in markup and the as keyword does not really even have to be restrained to a controller either.

<div ng-controller="ArachnidController as spiderWeb">
   {{ spiderWeb.intro }}
   <div ng-repeat="spider in spiderWeb.arachnids as spiders">
      {{ spiders.$index }} - {{ spider.name }}
   </div>
</div>

 
 

Above $scope.intro gets replaced with spiderWeb.intro but who cares? This actually does not reduce the scope of $scope. I was confused to think that there was an application-level $scope above what $scope means at any one controller. Indeed there may be such an animal, but it is at the controller level where $scope grows fat (as a controller grows fat and gets dozens of variables hanging off of $scope) and this a big enough problem by itself, a major performance pain in the first version of Angular, to raise alarm. It is not something you can fix with the "Controller As" pattern. Angular 2 deals with this well by more modularly breaking things up in components instead of having a controller approach that turns into a spaghetti mess as an app grows significantly not trivial. It does help a little that controllers are isolated from each other and if you want crosstalk data between controllers you need to do it through a service. Similarly, if some things on a controller's $scope are not strictly needed maybe they could be nested in a directive that is only conditionally brought to life. The really painful thing is that every variable in $scope has a watcher associated with it running in the background as an agent for reacting to change detection. $scope is basically like this+ with the plus part being that all the items hanging off of the "this" each get a watch, so in a controller $scope is scoped like this for the controller, and down at a directive there is some isolated $scope restricted to the bounds of just the directive. I guess you can see how $scope.intro and spiderWeb.intro and, for that matter, this.intro are comparable in ArachnidController, no? The watchers alone distinguish the first two from the third item. The anti-pattern of just packing things on $scope will lead to lag and what is more there may be digest cycles in which items on $scope update other items on $scope that are calculated values, exasperating things exponentially. Changing something like this...

$scope.foo = 13;
$scope.bar = 42;
$scope.baz = 69;

 
 

...to something like this...

$scope.qux = {
   foo: 13,
   bar: 42,
   baz: 69
};

 
 

...is a good way to make an optimization. Now three watches have been reduced to one. A flag at the qux object, such as changing the baz to 86, will get caught by the watchers. The watchers do not just watch to see if a pointer is similar or different on a JSON object. They are somehow crawling the object for all alterations. That said, this is still an optimization and/as it's less expensive to have a complex object on $scope than to have all of the similar fields as differing properties directly hanging off of $scope.

random things from a second dinner discussion

I guess this is the sequel blog posting for this.

  • An exploded view drawing is the formal name for those drawings where you see a mechanical device comprised of many parts in a manner in which the parts are separated apart and labeled.
  • Will artificial intelligence go anywhere? To date in a 1980s model it has had the shape of data analytics and "Expert Systems" wherein the later has to do with making the AI a SME (subject matter expert) that may be queried about a topic. NLP (natural language processing) is newer and allows for English (or other language) voice communications between people and machines and should also allow a translator to always be present when two human beings talk to each other in different tounges as a side effect bonus.

Wednesday, February 8, 2017

I learned that whenever a third party has to view a company's intranet through Citrix as they are otherwise off the LAN that they do not have the common browser controls.

There is no forward or back button.

PyCharm

It's an IDE for Python from JetBrains.

disrepair FTW!

https://vine.co/u/906778719690043392 has been offline for days since the last Anonymous hack and now that it is back, it is messed up and missing some of my Vines! Others are repeated! Is this a deliberate hack or a side effect of the bigger hack and a bad recovery from it? I am glad I scraped everything to here. The funny thing is that Twitter just dropped the support of Vine down to a skeleton crew and thus it was in no position to deal with Vine being messed with as it does not want to think about it anymore to begin with. It's all ice sculpture, isn't it? Everything we see online?

Tuesday, February 7, 2017

get started with Angular 2 in Windowsland

  1. download node from https://nodejs.org/en/download/ and it's best to get it again cause you could have an old, stale version
  2. make a folder somewhere for your app and put five files in it:
    1. index.html:
      <!DOCTYPE html>
      <html lang="en">
         <head>
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width, initial-scale=1">
            <title>Whatever</title>
            <script src="node_modules/core-js/client/shim.min.js"></script>
            <script src="node_modules/zone.js/dist/zone.js"></script>
            <script src="node_modules/systemjs/dist/system.src.js"></script>
            <script src="systemjs.config.js"></script>
            <script src="node_modules/rxjs/bundles/Rx.js"></script>
            <script>
               System.import('app').catch(function (err) { console.error(err); });
            </script>
         </head>
         <body>
            <entry-point>loading...</entry-point>
         </body>
      </html>
       
    2. tsconfig.json:
      {
         "compilerOptions": {
            "target": "es5",
            "module": "commonjs",
            "moduleResolution": "node",
            "sourceMap": true,
            "emitDecoratorMetadata": true,
            "experimentalDecorators": true,
            "removeComments": false,
            "noImplicitAny": false
         }
      }
       
    3. package.json:
      {
         "name": "Whatever",
         "version": "1.0.0",
         "scripts": {
            "start": "tsc && concurrently \"tsc -w\" \"lite-server\" ",
            "lite": "lite-server",
            "tsc": "tsc",
            "tsc:w": "tsc -w"
         },
         "licenses": [
            {
               "type": "MIT",
               "url": "https://github.com/angular/angular.io/blob/master/LICENSE"
            }
         ],
         "dependencies": {
            "@angular/common": "~2.1.1",
            "@angular/compiler": "~2.1.1",
            "@angular/core": "~2.1.1",
            "@angular/forms": "~2.1.1",
            "@angular/http": "~2.1.1",
            "@angular/platform-browser": "~2.1.1",
            "@angular/platform-browser-dynamic": "~2.1.1",
            "@angular/router": "~3.1.1",
            "@angular/upgrade": "~2.1.1",
            "angular-in-memory-web-api": "~0.1.13",
            "core-js": "^2.4.1",
            "reflect-metadata": "^0.1.8",
            "rxjs": "5.0.0-beta.12",
            "systemjs": "0.19.39",
            "zone.js": "^0.6.25"
         },
         "devDependencies": {
            "@types/core-js": "^0.9.34",
            "@types/node": "^6.0.45",
            "concurrently": "^3.0.0",
            "lite-server": "^2.2.2",
            "typescript": "^2.0.3"
         }
      }
       
    4. systemjs.config.js:
      (function (global) {
         System.config({
            paths: {
               'npm:': 'node_modules/'
            },
            map: {
               app: 'app',
               '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
               '@angular/common':
                     'npm:@angular/common/bundles/common.umd.js',
               '@angular/compiler':
                     'npm:@angular/compiler/bundles/compiler.umd.js',
               '@angular/platform-browser': 'npm:@angular/platform-
                     browser/bundles/platform-browser.umd.js',
               '@angular/platform-browser-dynamic': 'npm:@angular/platform-
                     browser-dynamic/bundles/platform-browser-dynamic.umd.js',
               '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
               '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
               '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
               '@angular/upgrade':
                     'npm:@angular/upgrade/bundles/upgrade.umd.js',
               'rxjs': 'npm:rxjs',
               'angular-in-memory-web-api': 'npm:angular-in-memory-
                     web-api/bundles/in-memory-web-api.umd.js'
            },
            packages: {
               app: {
                  main: './main.js',
                  defaultExtension: 'js'
               },
               rxjs: {
                  defaultExtension: 'js'
               }
            }
         });
      })(this);
       
    5. favicon.ico
  3. run the command prompt as administrator, navigate to your folder, and then run the command: "npm install"
  4. this will make a "node_modules" folder in your folder and you need to make an "app" folder that sits side by side with it and contains a "main.ts" file with the following inside:
    import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
    import { WrapperOfEverything } from './modules/wrapper-of-everything.module';
    const platform = platformBrowserDynamic();
    platform.bootstrapModule(WrapperOfEverything);
     
  5. you next need to make a "modules" folder within the "app" folder that has "wrapper-of-everything.module.ts" inside of it containing as copy:
    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { StartingPoint } from '../components/starting-point.component';
    import { HttpModule } from '@angular/http';
    import { Headers, Http } from '@angular/http';
    @NgModule({
       imports: [BrowserModule, HttpModule],
       declarations: [StartingPoint],
       bootstrap: [StartingPoint]
    })
    export class WrapperOfEverything { }
     
  6. now there needs to be a "components" folder in the "app" folder and it needs to hold "starting-point.component.ts" which will have the following copy:
    import { Component, Input } from '@angular/core';
    import {Http, Headers} from '@angular/http';
    import {Observable} from 'rxjs/observable';
    @Component({
       selector: 'entry-point',
       template: 'If you can see this the app works!',
       providers: []
    })
    export class StartingPoint {}
     
  7. run the command prompt as administrator, navigate to your folder, and then run the command: "npm start"
  8. this should compile TypeScript (and recompile TypeScript when it senses you change a file) while also spawning a browser to show you the application you've made
  9. click Ctrl-C when you are ready to kill the process

the convention of naming a module or a component in kebab case with a trailing .component or .module comes from John Papa and regular objects just have names in kebab case and NOT .object on the end or nuthin'

 
 

Addendum 2/10/2017: whatever.service.ts and whatever.model.ts may be perfectly legitimate names per the angular.io style guide.

random things from a dinner discussion tonight

  • Raspberry Pi was said to be one of the easier-to-program devices to reach programming out to other things in an Internet of Things manner. Thing this might be the "new" Arduino.
  • CGM stands for Continuous Glucose Monitor. Nightscout is one type of this.

PagerDuty and OpsGenie

These are DevOps dashboards and alerts management tools. Think of that NORAD map that shows the nuclear missions going from Russia to America and vice versa. It is that sort of war room thing.

September of 1969

This suggests that the first two nodes of the internet were at UCLA in, well, LA, and Stanford Research Institute in the Bay Area. It was September of 1969. Anyhow, they are BOTH in Cali. I always had it in my head that one of the first two points to crosstalk was at a university in Minnesota, and it looks like I was wrong.

Cannot find module '@angular/core'

Do you see this error at element_schema_registry.d.ts in Visual Studio 2015 when you try to build your app? Delete and rehydrate your node_modules folder to fix this.

I found this image yesterday and thought it was cool.

  1. Surface Web
    • Bing
    • Google
    • Wikipedia
  2. Deep Web
    • Academic Information
    • Medical Records
    • Legal Documents
    • Scientific Reports
    • Subscription Information
    • Social Media
    • Multilingual Databases
    • Financial Records
    • Government Resources
    • Competitor Websites
    • Organization-specific Repositories
  3. Dark Web
    • Illegal Information
    • TOR-Encrypted sites
    • Political Protests
    • Drug Trafficking sites
    • Private Communications

Monday, February 6, 2017

Cascading CSS styles are a little painful to overpower.

Let's say...

  1. You have some HTML in an app like so:
    <div class="dotty">
       <table>
          <tr>
             <td nowrap>I like:</td>
             <td>
                <table>
                   <tr>
                      <td>cats</td>
                      <td>grapes</td>
                   </tr>
                   <tr>
                      <td nowrap>not dying</td>
                      <td>Texas</td>
                   </tr>
                </table>
             </td>
          </tr>
       </table>
    </div>

     
  2. And, your stylesheet looks like this:
    .dotty {
       padding: 13px;
    }
    .dotty table {
       border: 1px #FF0000 dotted;
    }

     
  3. Creating something that looks like this:
    I like:
    cats grapes
    not dying Texas

But you really don't want the cascading effect to put a border on the inner table.

  1. You just want something like so:
    I like:
    cats grapes
    not dying Texas

But the dotty class is used pervasively in your application and you dare not alter it. Also, you don't want to write your own dotty because you don't understand what all dotty does because someone else made dotty. What will you do? There are only a few things you can do and they will quickly make you fall out of love with the cascading part of cascading stylesheets as you'll realize that whenever you're clever and you make things cascade that you are in fact painting yourself into a corner that will require others to hack in order to get around your madness. If you're going to have cascading effects they better be small in scope and not applied to, for example, the body tag down. If you just make a new class called nada to apply to the inner table like so:

.nada {
   border: none;
}

 
 

...you will be disappointed when nothing changes! I'm serious. It makes my nose want to bleed in disbelief but that is how it is. You will find that cascading effects always beat direct effects and thus nothing will change. There are three ways around this and they are all bad. One is like so:

.nada {
   border: none !important;
}

 
 

Yuck, I feel dirty already. An inline style parameter with border: none; as a value at the second table tag is another solution and it's hard to say which of these two fixes is worse. There is a slightly better third way, and, no, it's not using an id as that won't work either. The third way is to change up the HTML like so:

<div class="dotty">
   <table>
      <tr>
         <td nowrap>I like:</td>
         <td>
            <div class="nada">
               <table>
                  <tr>
                     <td>cats</td>
                     <td>grapes</td>
                  </tr>
                  <tr>
                     <td nowrap>not dying</td>
                     <td>Texas</td>
                  </tr>
               </table>
            </div>
         </td>
      </tr>
   </table>
</div>

 
 

...and then have nada like this:

.nada table {
   border: none;
}

 
 

We can overpower an outer cascading effect with an inner cascading effect.

What do you call the different "threads" in JavaScript if they are not threads?

* (excludes the main "thread")

First rule of .NET and C#: Forget everything you know about locks and threads and Mutex and what not if you are not making a Windows app. At the web, the UI has one thread. Do not expect IIS to give a different thread to each session as there could be one hundred different sessions and that would then be silly. So, with that in mind, JavaScript isn't using multiple threads either. There is something running in a loop in the background that periodically checks if x, y, and z has happened to match up event causality consequences to the greater reality. My understanding is that this is how Node.js works under the hood too. Clearly there are a lot of psuedothread concerns to think about.

TED stands for Technology, Entertainment and Design

TED Talks are online videos of these high falutin ideas.

Saturday, February 4, 2017

questions marks inside of an *ngIf in AngularJS 2's markup

Alright, the following is pretty straightforward, right? We are going to see the picture of Robert DeNiro if the bar object hanging off the foo object has a baz property hanging off of it that is truthy.

<div *ngIf="foo.bar.baz">
   <img src="DeNiro.jpg" />
</div>

 
 

If baz is falsey we will not see the picture and if bar just doesn't have a baz property then we will also not see the picture as baz will read as undefined which is, yes, falsey. But what if foo doesn't even have a bar property? What if bar is undefined? Well then the application is gonna crash, right? It will barf red stuff up to the console in Google Chrome Developer Tools. There is a way to prevent a missing bar object from ruining the show like so:

<div *ngIf="foo.bar?.baz">
   <img src="DeNiro.jpg" />
</div>

 
 

This is kinda like this stuff from C# 6.0. In the C# scenario I think we are just falling over to null if we cannot read forward (rightward) from the question mark, and that made me initially assume the same of Angular 2, but coworkers pointed out to me that undefined will be used instead of null. If bar was explicitly set to null would it be evaluated as null? I'm not sure. This all came up in conversation yesterday because I saw something like this and initially assumed it would blow up if bar were missing...

<div *ngIf="foo.bar?.baz > 7">
   <img src="DeNiro.jpg" />
</div>

 
 

It turns out that this is completely legitimate. I think undefined is just used in the comparison and maybe that (er, well, null) would lead to a freak out in C# but this isn't C#. You can compare undefined and null to things in JavaScript with greater than and less than signs. Herein it is important to note the distinction between null and undefined. They are both falsey but can nonetheless compare differently.

  1. undefined !==0 is true
  2. undefined !=0 is true
  3. undefined > 7 is false
  4. 7 > undefined is false
  1. null !==0 is true
  2. null !=0 is true
  3. null > 7 is false
  4. 7 > null is true

Another place where I've struggled to let go my C# head trash is with private versus public at components. If a field or a method is private in a component it is still accessible from the Angular 2 HTML template. You just can't grab ahold of that thing in the Jasmine/Karma/PhantomJS tests or from other TypeScript objects. It differs of course from web forms code behinds where the counterpart would need public accessibility to get used in the ASP.NET markup.

sjaj

AJAX is an acronym for Asynchronous JavaScript and XML, right? AJAJ is sort of offered up as a replacement term in modern times as the X stands for XML and not JSON and, anymore, we just use JSON. I've never once used XML with AJAX, not to my memory. Maybe XML was shepherded around under the hood in that old web forms Update Panel thing, but never have I actually caught XML at JavaScript and made sense of it. Never. Now will this new name ever be embraced? Never. We are all used to and in love with the term AJAX. It just sounds awesome. It's the name of some Trojan War or Greek Myths hero that we can't quite remember and it's the name of that iconic caustic cleaning product.

Manly! What's not to like about the name AJAX? Anyways, I thought of this because I ran into a way in which the beginning of the acronym should be challenged the way the ending really should be. Behold:

var showStopper = function(url) {
   var whatever=new XMLHttpRequest();
   whatever.open("GET", url, false);
   whatever.send(null);
   return whatever.responseText;
};

 
 

We are not waiting for a promise to come back in the above code. The process will just hang until we get something back. The asynchronous part of the process is replaced with a synchronous one and you could describe this as SJAJ it seems. I didn't know this was even possible. It's not recommended. I saw some sort of warning while I did this about how it was deprecated, and it's not the sort of thing I would normally brush across as I normally never use XMLHttpRequest directly but instead find myself using a framework like jQuery or Angular 2 which has its own, better way of doing AJAJ which I suppose wraps XMLHttpRequest under the hood and doesn't allow for stupid stuff like synchronous calls. The code above just scrapes from a URL, returning whatever may be there, conditionallessly.

Friday, February 3, 2017

MOAR applications

I went to lunch with former coworkers today and some other thing-of-the-moment applications came up in conversation. moviepass.com is an app which allows you to pay a $45 per month subscription (and there is at least one cheaper/weaker option too) for a creditcardesque card and a mobile app that you may use to otherwise see movies for free in the theaters provided that you do not see more than one movie a day. That means that if you are seeing one movie a week with the system you are basically breaking even and if you are a real fan then you have a cost savings indeed. Yay! Major chains of theaters are on the system for this thing and so might be Alamo Drafthouse. Audible, which is Amazon-owned and at audible.com, was the other app discussed. I had heard of this one before from a current coworker. It's getting more and more trendy to listen to books as audio instead of reading books and this is a place to go for audio books.

Thursday, February 2, 2017

falsey six

Yikes! There are not five falsey values as I suggest here and here but instead at least six as the Boolean value for false is obviously falsey as it's literally false. This moreover makes a distinction between negative zero and zero and between an empty string defined with single quotes and an empty string defined with double quotes and all four things are falsey. The same thread suggests there is an obscure thing called document.all which is of old IE that is also falsey, so there could be as many as nine falsey shapes.

  1. undefined
  2. null
  3. false
  4. NaN
  5. 0
  6. ""
  7. ''
  8. -0
  9. document.all

Wednesday, February 1, 2017

When do I want to break up the falsey five?

Almost never. The convenience of checking to see if something is falsey is a convenience for a reason, you know? The one exception might be to see if a numeric property is set yet or not. In those cases you would want a distinction between a zero versus null and/or undefined. Do something like so:

if (whatever || whatever === 0) {

 
 

Something to avoid is to write a separate pipe (in an Angular 2 app for example) that tries to return true or false based on if something is undefined or null. The one line comparison against zero is the way to keep it simple. While I'm thinking of pipes, don’t use a pipe directly in TypeScript. If you need a repurposable blob of functionality that can work in both the front face Angular 2 markup and the TypeScript files you should write a service for it and then have a shim of a pipe for wrapping the service that exclusively is used in the markup.

isNaN should perhaps be avoided

You use it like this right?

if (isNaN(whatever)) {

 
 

You'd think this would be truthy or falsey based on whether or not whatever was a number or not, but that's not so. Some strings will cause false to be returned from this thing, specifically strings that will survive the trip through a parseInt or a parseFloat. Also an empty string or a string with a single space looks to me like it will sail through with a false output based upon what I'm seeing on StackOverflow.

funmoppet

The book "Generation X: Tales for an Accelerated Culture" by Douglas Coupland is credited with assigning the moniker "Generation X" to my generation. I just finished reading it this Sunday after having originally discovered a Swedish language version while on vacation in Stockholm last summer. I like what Doug had to say about my generation and, as he puts it, McJobs:

VEAL-FATTENING PEN: Small, cramped office workstations build of fabric-covered disassemblable wall partitions and inhabited by junior staff members. Named after the small preslaughter cubicles used by the cattle industry.

Vine has gone away with Obama.

Stupid apps like Gowalla come and go. Others like Digg die by way of shapeshifting. I kinda get the impression that Digg used to be something like what StumbleUpon is now though I've never used either app. Anyhow, Vine has been watered-down (shapeshifted) into Vine Camera for fifteen days now and while this was just another stupid app like Gowalla, Digg, and StumbleUpon I nonetheless fell in love with this one, embracing it completely. I could not get enough of it. I used to make six second movies all the time and kept one hundred and three of them. Thirteen of the most recent fifteen (the least recent of the most recent) are from a vacation I took in Stockholm, Sweden in the summer of last year which is the best vacation I've ever had.

103.generic beach experience
 Virginia Beach Boardwalk
 
 
Aug 29, 2016
102.stupid octopus!
 Blacklight Mini Golf
 
 
Aug 29, 2016
101.Who's doggie are you?
 Stadsbiblioteket (B)
 
 
Jul 9, 2016
100.Facey McFaceface!
 Ã…hléns City
 
 
Jul 9, 2016
99.the flute!
 Dansmuseet
 
 
Jul 7, 2016
98.Milenkovic Vojin the cab driver scared the hell out of me by getting out of the cab and wandering about the not-yet-open museum grounds.
 Artipelag
 
 
Jul 7, 2016
97.the night rolls in
 Radisson Blu Waterfront Hotel
 
 
Jul 6, 2016
96.Swedish girls have the bright blonde hair that American white girls pretend to have.
 Drottningholms Slott | Drottningholm Palace
 
 
Jul 5, 2016
95.these kids try to figure their shit out on the boat ride to Drottningholm
 Mälarhöjden
 
 
Jul 5, 2016
94."Hey!"
 TrÃ¥ngt & Trevligt
 
 
Jul 4, 2016
93.art at the Tensta subway stop
 Tensta T-bana
 
 
Jul 4, 2016
92.girl panhandling on her celly didn't want her photo taken
 Wayne's Coffee
 
 
Jul 3, 2016
91.what is this machine supposed to do???
 Scandic Grand Central
 
 
Jul 2, 2016
90.howl on through the night, call the stars...
 Zara
 
 
Jul 2, 2016
89.bags
 Stockholm-Arlanda Airport (ARN)
 
 
Jul 2, 2016
88.wasting time in Newark
 Newark Liberty International Airport (EWR)
 
 
Jul 1, 2016
87.Sunny!
 Austin Bergstrom International Airport (AUS)
 
 
Jul 1, 2016
86.I overstep.
 Maiko Sushi Lounge
 
 
May 15, 2016
85.the carousel dies
 Dallas Zoo
 
 
Apr 9, 2016
84.brave! came up on the table
 Rio Rio Cantina
 
 
Apr 2, 2016
83.um... something about a cheeseburger... it's kinda hard to follow
 Gold's Gym
 
 
Mar 19, 2016
82.chill cat
 Starbucks
 
 
Mar 18, 2016
81.Visual Studio and its master artist @jeffreypalermo
 DeVry University Austin Campus
 
 
Jan 21, 2016
80.do something interesting
 Planet Hollywood Resort & Casino
 
 
Aug 5, 2015
79.the selfie stick
 New York-New York Hotel & Casino
 
 
Aug 4, 2015
78.rock!
 Tom's Urban
 
 
Aug 4, 2015
77.it's for a good cause
 Twin Peaks Restaurant & Sports Bar
 
 
Aug 3, 2015
76.super gross cloudy fish tank at Buffet Palace
 Buffet Palace
 
 
Jul 30, 2015
75.I'm trying Salvation Pizza!
 Salvation Pizza
 
 
Jul 26, 2015
74.Does daytime use of the night drop qualify as irony? I feel conflicted.
 Vulcan Video North
 
 
May 31, 2015
73.dictation!
 Star Nails
 
 
May 13, 2015
72.silhouette
 Bon Eco Design
 
 
May 12, 2015
71.Felisha and I aimlessly wander the local hardware store.
 Tamworth Pro Hardware
 
 
May 12, 2015
70.WOW!
 Tamworth
 
 
May 11, 2015
69.This is my second speeding ticket in New York State today! They didn't make me sign anything! Am I really liable? Yes, I probably am.
 Town of Ellisburg
 
 
May 10, 2015
68.trying to keep the Mexican Revolutionaries happy, festive
 Republic Square Park
 
 
Apr 11, 2015
67.Oddity: I hook my hand like I'm left-handed when I write, but I'm not left-handed.
 Mansfield Dam Park
 
 
Mar 29, 2015
66.x+
 Texadelphia
 
 
Mar 27, 2015
65.hula hoop
 Darwin's Pub
 
 
Mar 22, 2015
64.curlers!
 Aaron's Rock & Roll
 
 
Mar 22, 2015
63.scary
 Chupacabra Cantina
 
 
Mar 16, 2015
62.war reel
 Pace Bend Park
 
 
Mar 15, 2015
61.keepers!
 Keepers Clothing
 
 
Mar 13, 2015
60.zero calories!
 Hidden Gardens Apartments
 
 
Mar 5, 2015
59.nasty weather be damned, let's fly kites
 Zilker Park
 
 
Mar 1, 2015
58.What does the pizza at @hobokenpie smell like?
 Hoboken Pie
 
 
Feb 28, 2015
57.dog
 Anderson Mill
 
 
Feb 27, 2015
56."colorless Hawaiian shirt" is almost an oxymoron
 Guitar Resurection
 
 
Feb 21, 2015
55.she digs the lavender slacks (I think)
 Hut's Hamburgers
 
 
Feb 20, 2015
54.I guess the food at Athenian is pretty good!
 Athenian Bar & Grill
 
 
Feb 10, 2015
53.all of my vines are made in the right now (2013 style) the way Hephaestus intended without @goldbergsisters after edits
 Iron Cactus Downtown Austin
 
 
Jan 2, 2015
52.sudden death of the sock puppet!
 ACC Northridge
 
 
Jan 1, 2015
51.guy with the guitar just had the guitar thrown at him
 The Mohawk
 
 
Dec 3, 2014
50.I haven't seen one of these machines in action in many, many years. They're noisy up close!
 Shoal Crossing Event Center
 
 
Nov 16, 2014
49.It's the day of the Austin Heart Walk! (though it looks like rain)
 Long Center for the Performing Arts
 
 
Oct 18, 2014
48.Hollister Noise
 Hollister Co.
 
 
Oct 14, 2014
47.We have jelly!
 Steiner Ranch
 
 
Oct 13, 2014
46.silly
 Walgreens
 
 
Oct 5, 2014
45.some chickens at the Texas School for the Blind and Visually Impaired Gardens
 TSBVI Bistro
 
 
Oct 4, 2014
44.at WalMart in the middle of the night
 Walmart Supercenter
 
 
Oct 4, 2014
43.by campus
 St. Austin's Catholic Church
 
 
Oct 2, 2014
42.classy entertainment
 The Bat Bar
 
 
Sep 27, 2014
41.her Mohawk need assistance
 Wild About Music
 
 
Sep 27, 2014
40.I think I'll have one of the "Chocolate Chunk" cookies!
 Walton's Fancy and Staple
 
 
Sep 8, 2014
39.I'm easily entertained.
 Catfish Parlour
 
 
Sep 7, 2014
38.shooting with Rick Cymbalist and Dip Manandhar!
 Shady Oaks Gun Range
 
 
Sep 6, 2014
37.eating
 Winflo Osteria
 
 
Sep 5, 2014
36.rope line at "The Madison"
 The Madison
 
 
Aug 30, 2014
35.surreptitious is delicious
 Pete's Dueling Piano Bar
 
 
Aug 28, 2014
34.Kafka's Castle!
 Frankenstein Computers
 
 
Aug 24, 2014
33.with new wave hairdos, I want #GIRLS
 Dillard's
 
 
Aug 20, 2014
32.at Lanai
 Lanai
 
 
Aug 10, 2014
31.feel my WRATH!!!!!
 Balcones Woods
 
 
Jul 18, 2014
30.Tejano jams
 Central Market
 
 
Jun 15, 2014
29.I never really noticed the hummingbird before. #ctcc14
 Chesapeake Energy
 
 
Jun 14, 2014
28.It's the first day of work in the new office building and I couldn't resist going into the hallway in the middle of the air.
 Chase Bank
 
 
Jun 3, 2014
27.if everyone jumped off a bridge, would you jump too?
 ZaCH Topfer Theatre
 
 
May 25, 2014
26.the drive home
 Mopac Loop 1
 
 
May 13, 2014
25.Whatever. SXSW.
 Austin Convention Center
 
 
Mar 9, 2014
24.meow!
 Longhorn Rentals
 
 
Dec 28, 2013
23.the last show ever of Bad Rackets!
 The Legendary White Swan
 
 
Dec 15, 2013
22.Shark Attack!
 Balcones Family Dental
 
 
Sep 3, 2013
21.we are working 28 hours straight on a hackathon
 @hand
 
 
Aug 9, 2013
20.approaching the Pennybacker Bridge from the East on #lake #austin
 360 Bridge (Pennybacker Bridge)
 
 
Aug 1, 2013
19.the dark board at @headspring
 Headspring
 
 
Jul 26, 2013
18.I'm breaking down and making a vine again. Sigh. (I'm so weak.)
 Main Event Entertainment
 
 
Jul 16, 2013
17.Creating a whitelist is a good way to prevent "mass assignment" attacks per @amirrajan at the Austin .NET Users group tonight!
 Microsoft Corporation
 
 
Jul 8, 2013
16.an apple (and a vine) for teacher, specifically my high school art teacher, Mary Ann Evans Miller, who died May 1st
 Westwood High School
 
 
Jul 7, 2013
15.I don't want your girl!
 #'s Night Club
 
 
Jul 4, 2013
14.a successful shopping outing at Walgreens!
 Walgreens
 
 
Jun 27, 2013
13.I'm meeting Felisha Storring for the first time in a dozen years.
 Graveyard Point
 
 
Jun 23, 2013
12.Tiger Jaw is playing at Red 7! So says Ayssa.
 Red 7
 
 
Jun 13, 2013
11.Summer is calling.
 Lady Bird Lake Trail
 
 
Jun 2, 2013
10.another Katie Pennington ecigarette movie
 Recess Arcade Bar
 
 
May 20, 2013
9.Katie explains the ecigarette!
 Alamo Drafthouse Cinema – Ritz
 
 
May 19, 2013
8.Fight! Fight!
 Buckshots
 
 
May 16, 2013
7.a "God" story
 Old School Bar & Grill
 
 
May 8, 2013
6.Caffe la Toscana
 Olive Garden
 
 
Mar 19, 2013
5.I bought a hat!
 Sherwood Forest Faire
 
 
Mar 10, 2013
4.I just got the High Score on Q*bert at Pinballz Arcade!
 Pinballz Arcade
 
 
Mar 9, 2013
3.IHOP he hop a we hop, she hop you hop a they hop, be hop, be hop a lu hop, I don't think you'll understand
 IHOP
 
 
Mar 1, 2013
2.ring of fire!
 Dell Round Rock 2
 
 
Feb 7, 2013
1.. @eric_anderson open spaces scribbles at #HTML5tx
 St. Edward's University
 
 
Feb 2, 2013