<![CDATA[#refactoring.]]>http://adamrichman.com/Ghost 0.5Sat, 10 Jan 2015 23:10:00 GMT60<![CDATA[ECMAscript 6, my favorite new features]]>I was recently asked about which features of ES6 that most excite me, and in answering, I came to realize that I had not transcended the curiosity that comes from reading about it. That is, I haven't implemented the new experiemental features yet. So before doing so, I figured this would be a good way to review and familiarize my brain and hands with the powers of ES6.

Here's a little dive into some exciting new features.

Inspiration and examples pulled from ES6fiddle and Egghead.io.

let (not var)

var is still a perfectly valid declaration for new variables, but the let keyword introduces some more predictable behavior than that which comes packaged with vanilla javascript.

block scope

The keyword let is not hoisted like var, so a declaration made with let is only created at the time of its declaration.

In respect to block scope, this means that you do not need to be in the scope of a function in order to have different values for the same variable names:

var i = "outside";  
{
    var i = "inside";
}
console.log(i); // "inside"

var i = "outside";  
{
    let i = "inside";
}
console.log(i); // "outside"  
a more useful example

A for loop using var, like we're used to, instantiates a variable declared in the front, and then changes the value on every iteration. This can trip us up pretty easily when we pass our first-class functions by reference, and bind values inside of those functions to the variable. For instance:

var functions = [];

// var keyword declares 'i' once

for (var i = 1; i <= 5; i++){  
  functions.push(function(){
      console.log(i);
  });
}

functions.forEach(function(f){  
    f();
});

yields:

6  
6  
6  
6  
6  

We know to expect this behavior from javascript, but that doesn't mean we have to like it. Because i is declared once, any function that references it should expect its value to equal whatever the value is at the time of the function's invocation. Because we invoke all the functions here after we're done incrementing the same instance of i, each of these functions will reference its final value.

Using the let keyward inside of our for loop can provide us the behavior that we were most likely hoping for:

var functions = [];

// let keyword declares a new 'i' in block scope, each time

for (let i = 1; i <= 5; i++){  
  functions.push(function(){
      console.log(i);
  });
}

functions.forEach(function(f){  
    f();
});

yields:

1  
2  
3  
4  
5  

Nice.

Destructured Assignment

When working with objects with which you are only concerned with particular keys and values, ES6 provides a convenient way of quickly assigning references to those inner keys.

let [one, two] = [1, 2];  
let {three, four} = {three: 3, four:  4};

console.log(one, two, three, four);

yields:

1 2 3 4  

Iterators

I can't be the only guy that, in an itertive loop on more than one unfortunate occasion, referred to the index of an array when my intention was to use the value stored at that index. Well, gone are those days. Behold the of keyword:

var arr = ['A','D','A','M'];  
var result = '';

for (var i of arr){  
    result += i;
};
console.log(result);  

yields:

"ADAM"  

Spread syntax

The spread operator enables us to manipulate values of a collection, as a collection, without having to specifically target them. It works a lot like an each or map method that we would ordinarily pull in via underscore or lodash.

var front = [1,2,3,4,5];  
var back  = [6,7,8,9,10];  
front.push(back)  
console.log(front)

yields:

[1,2,3,4,5,[6,7,8,9,10]]

Of course, but... ick. spread syntax to the rescue!

var front = [1,2,3,4,5];  
var back  = [6,7,8,9,10];  
front.push(...back)  
console.log(front)

yields:

[1,2,3,4,5,6,7,8,9,10]

Default Parameters

Countless times, I have longed for a more semantic way to declare default values for the expected arguments of a function.

var thisThing = thisThing || somethingElse;  

We all know what it means, but that doesn't mean it should be necessary. be able to specify default values in the function declaration is convenient and a familiar feature from myriad other languages. Finally, it's here.

function defaults(x = 3, y = 6){  
    return [x,y];
}

so,

console.log(defaults());  

yields:

[3,6]

and

console.log(defaults(1,1));  

yields:

[1,1]

Lovely.

Generators

A generator is like a function that can be paused and resumed. It can yield a different value each time (like a return, but without finishing), if that's what you'd like. This example from ES6fiddle shows clearly how we can create a range function.

function* range(start, end, step) {  
    while (start < end) {
        yield start;
        start += step;
    }
}

for (let i of range(0, 10, 2)) {  
    console.log(i);
}

yields:

0  
2  
4  
6  
8  

Generators come with a promise-like API, including a .next() method. Calling that method will make your generator step to the next yield declaration. In this example from Egghead.io, you can even go so far as to create an infinite loop in a generator:

function* noStackOverflow(){  
    let x = 0;
    let y = 0;
    while(true){
        yield {x:x, y:y}
        x += 2;
        y += 1;
    }
}
var generator = noStackOverflow();  
console.log(generator.next().value);  
console.log('Do something else');  
console.log(generator.next().value);  

yields:

{x:0,y:0}
Do something else  
{x:2,y:1}

This generator will continue to generate a new object and set of values for us upon every request.

And so much more.

There are many other great features to get excited about that are not covered here. To name a few:

  • built-in support for promises using a Promise constructor
  • ability to instantiate classes via a class declaration
  • function => notation, which carries much of the same functionality with which it comes in Coffeescript.
]]>
http://adamrichman.com/ecmascript-6-my-favorite-new-features/9671436e-45af-4026-b51a-5f420cad899eMon, 22 Sep 2014 21:30:30 GMT
<![CDATA[ADAM D. RICHMAN]]>ar@adamrichman.com
Github: adrichman | LinkedIn: adamrichman | Blog: adamrichman.com

Technical Expertise

Proficient:

Javascript, NodeJS, Express, AngularJS, Ionic, jQuery, HTML5, CSS, Git

Knowledgable:

Ruby, MongoDB, Redis, MySQL, BackboneJS, D3, Mongoose, ActiveRecord, Sinatra, Rails, CoffeeScript, NPM, bower, EJS, Jade, Haml, Cordova, Passport, XSS & CSRF, AWS S3, AWS EC-2, Digital Ocean, Heroku, *NIX

Some Familiarity:

Famo.us, Docker, CouchDB, Python, Django, PHP, Java, C

Experience

Stitch Fix | Freelance Full-Stack Engineer | Online personal styling service for women

San Francisco, CA | 2014

  • Conceived, pitched and developed Stylr, a game-like iOS mobile application from end-to-end, putting focus on increasing brand awareness and introducing new customers to the core product
  • Re-developed customer sign-up flow from legacy code, providing greater functionality to critical on-boarding of new customers. Complete with unit and end-to-end tests, it will be deployed into production and A/B tested
  • Delivered fully-tested production-ready code, working directly with the lead engineer

YY.com | Freelance Back-end Engineer | Chinese Poker Gaming Application

San Francisco, CA | 2014

  • Bridged a legacy C++ TCP game server to a web/mobile client via web socket , facilitating translation of the old protocol to and from binary & JSON streams
  • Secured from Man in The Middle attacks and Cross Site Request Forgeries
  • Utilized socket.io and TCP to relay translated protocol and maintain name-spaced chat rooms and messaging

ZipClips | Back-end Engineer | Mobile Video Sharing App

San Francisco, CA | 2014

  • Enabled user video upload, download, likes, dislikes and favorites via a REST API in Express with MongooseJS
  • Implemented on-demand, signed URLs to provide client fast uploading with an authenticated link to AWS S3

AD-60 | Full-Stack Engineer Internship | Digital Agency

Brooklyn, NY | 2013

  • Contributed to Ruby on Rails apps commissioned by New York Stock Exchange & Nutrisystem
  • Closed security loopholes in NYSE’s ACE Portal, preventing unauthorized access via unclosed sessions
  • Authored tests, preventing bugs from being pushed to the staging environment during rapid development

Sony Music | Recording Artist, Songwriter, Musician & Recording Engineer

NY, NY | 2001 - 2013

  • Toured as a Sony Music Recording Artist, & Musical Director for Jessie James (Island Def Jam / Mercury Records, Eric and Jessie).
  • Performed with Justin Bieber, Jason Derulo, Flo-rida, and for audiences of over 5.5 million viewers on The Today Show , Ellen, MTV & NFL Halftime

Open Source Software Contributions

  • Author – NgLazy | AngularJS library enabling developers to implement lazy load & infinite scroll in 2 LOC.
  • Author – Node-CI | NodeJS Continuous integration server that auto-deploys upon changes to Github repos
  • Contributor – ExpressJS.com, Octokit (Github nodeJS client), node-restful (quick REST routes for expressJS)

Education

Hack Reactor | Software Engineer, Hacker-in-Residence

San Francisco, CA | Jan - Jul 2014

  • Advanced professional software engineering immersive emphasizing Javascript & full-stack engineering
  • Taught toy problems & mentored as a Hacker-in-Residence, HR's selective, paid graduate student program

Startup Engineering | Statement of Accomplishment Distinction

Stanford via Coursera | Aug 2013

  • Developed a mobile-responsive, Bitcoin-powered crowd-funding app in NodeJS, Express, Amazon EC2, Heroku

Personal Statement

I'm a musician for life, an avid builder of intangible things, a proud generalist, and yet, highly detail-oriented.

]]>
http://adamrichman.com/cv/dd05b863-994e-4eb4-ab4b-ddab8b8c8907Mon, 07 Jul 2014 04:02:16 GMT
<![CDATA[NodeJS: Parsing Binary from the TCP Layer]]>For a job recently, I was asked to create a bridge server that translated the protocol of an old legacy server to a new HTML5 client, and vice versa. The old protocol was built upon C# structs, and the server was communicating in binary on the TCP layer. The new client will be communicating in JSON messages via TCP over HTTP (aka web sockets).

NodeJS comes nicely equipped with a module, net, for commuinicating via the TCP layer. Simply require('net') and you are now equipped to open a TCP socket. The module comes with a class Socket, and new socket connections can be instantiated when needed:

var tcpSock = require('net');  
var client  = new tcpSock.Socket;  
var socket  = client.connect(PORT, HOST);  

NodeJS also features a Buffer class, that will assemble raw binary data packets into an array-like object that can contain only integers. One instance of the Buffer class represents a specific, fixed size memory allocation outside of the V8 heap. I use it to collect incoming data packets, as well as to properly assemble my outgoing binary data.

var buffer = new Buffer(0, 'hex');

// listen for incoming data
socket.on("data", function(data){

    // a custom function for logging more readable binary
    logDataStream(data)

    // pack incoming data into the buffer
    buffer = Buffer.concat([buffer, new Buffer(data, 'hex')]);
})

The incoming binary was organized as C structs, and I am able to parse the data fairly easily using a great npm library called node-struct. The node-struct library allows the developer to define the structs in terms of javascript objects with strictly typed, pre-allocated fields. There are types for 8bit words through 32 bit, signed and unsigned, big and little endian. There are also fields for ascii and other encoded characters, as well as fields for other structs within structs. For example:

var Struct = require('struct').Struct;

function makeAndParsePersonFromBinary(buffer){  
  var person = new Struct()
                    .('word8', 'Sex')     // 0 or 1 for instance
                    .('word32Ule', 'Age')
                    .('chars','Name', 64);

  person._setBuff(buffer);
  return person;
};

var incomingPerson = makeAndParsePersonFromBinary(buffer);  

Once the struct has been seeded with the binary buffer, you can now access the values from the binary packets, properly parsed as fields on the struct:

var personName = incomingPerson.get('Name');  

As you can probably see, this node-struct library is a very useful tool when working in NodeJS with binary streams that represent structs.

The data is parsed and I'm ready to start working with it in my app.

Sometimes I just want to see the raw ints come in and out. FWIW, here's how I'm logging my incoming and outgoing binary streams:

function logDataStream(data){  
  // log the binary data stream in rows of 8 bits
  var print = "";
  for (var i = 0; i < data.length; i++) {
    print += " " + data[i].toString(16);

    // apply proper format for bits with value < 16, observed as int tuples
    if (data[i] < 16) { print += "0"; }

    // insert a line break after every 8th bit
    if ((i + 1) % 8 === 0) {
      print += '\n';
    };
  }

  // log the stream
  console.log(print);
}
]]>
http://adamrichman.com/nodejs-parsing-binary-from-the-tcp-layer/9157646c-26a7-488c-9025-59cd4ffe3f52Thu, 26 Jun 2014 07:18:00 GMT
<![CDATA[More AngularJS testing: end-to-end tests with protractor]]>End-to-end tests exist to have a method of programatically testing an actual user's experience in your app. The user never cares how much the pieces of your app are decoupled. The user cares that he or she loaded the page and did all of the things he or she expected to be able to do, without unexpected breaking. We can do this in AngularJS with protractor. Protractor will launch a browser and act just as we expect a user to behave (if we give it the right instructions). There are a few lesser documented tricks in the api that are vital to doing this properly, and I couldn't have truly tested ngLazy without them.

FYI: Most of what I know about testing with protractor, I learned here in the ng-newsletter. You will find very detailed instructions on setting it up, and learn a little about the technology protractor is built upon (Selenium's Webdriver).

Using grunt to build my project, and after installing via npm install grunt-protractor-runner, running my protractor e2e tests is as simple as running my karma unit tests. One command, grunt test, and tests do the rest of the hard work.

Protractor and Webdriver give you access to a browser object, through which you define the user's experience and behavior inside of your test.

Space & Time

I experienced a very confounding problem when writing my e2e tests, and it brought an interesting protractor feature to light. Because my module is dependent on various uses of angular's $timeout, I seemed unable to coordinate protractor's behavior without experiencing it timing out, or blowing through the tests at the improper times. I found the issues documented here and this lead to the eventual solution to my problem:

browser.ignoreSynchronization = true;

When using ignoreSynchonization before running my tests, I'm able to instruct the browser to observe sleep timers at various times, and can verify that the correct items are on screen, or hidden, at the appropriate times.

Because there are several phases during the use of ngLazy in which we can expect different things from our view, I needed a way to allow for Protractor to run different tests during each phase of the cycle. This was fairly easy once I made use of the method:

browser.sleep()

Probably the primary feature of ngLazy is reliant on the user scrolling to the bottom of the list, in order to trigger ngLazy to begin appending more items to the dom. This behavior was also pretty trivial to recreate in protractor! The executeScript method provides an api that takes DOM API arguments and executes them, while returning a promise. When the promise resolves, proceed with more instructions:

browser.executeScript('window.scrollTo(0,' + 800 + ');').then(function(){  
  browser.sleep(2000);

  // range is defined previously
  expect(element.all(by.css('.ng-binding')).count()).toEqual(range * 2);
})

Assert yourself

I'll include the current family of tests below, to demonstrate the kind of integrated tests I'm running. The assertions include:
* it should immediately display a spinner * it should have a spinner-color that matches the configuration * it should have as many ng-repeated items as the scope indicates * it should have an element in the DOM that represents the bottom of the list * it should add elements to the DOM when it scrolls to the bottom of the list

describe("ngLazy-demo", function(){
  browser.driver.manage().window().maximize();
  browser.get('/#');
  browser.ignoreSynchronization = true;

  describe("index", function () {

    it("should display the correct title", function(){
      expect(browser.getTitle()).toBe('ngLazy-Demo');
    });

    it("should have a lazy-load element", function(){
      expect(element(by.css('lazy-load')).isPresent()).toBe(true);
    });

  });

  var range;
  describe("lazy-load directive", function(){
    it ("should immediately display a spinner", function(){
      expect(element(by.css('.ng-hide')).isPresent()).toBe(false);
    });

    it("should have a spinner-color that matches the configuration", function(){
      var color;
      var loadingWidget = browser.findElement(by.css('.loading-widget'));
      loadingWidget.getAttribute('style').then(function(color){
        // ugly way of getting the color string from the directive
        color = (((color
                .split('border-color:')[1])
                .split(';')[0])
                .split('transparent ')[1]).trim()
                .split(' rgb')[0];
        var spinnerElement = browser.findElement(by.model('spinnerColor'));
        spinnerElement.getAttribute('value').then(function(val){
          expect(color).toEqual(val);
        })
      })
    })

    it("should have as many ng-repeated items as the scope indicates", function(){
      var rangeElement = browser.findElement(by.model('range'));
      rangeElement.getAttribute('value').then(function(val){
        browser.sleep(4000);
        range = parseInt(val);
        var repeats = element.all(by.css('.ng-binding')).count();
        expect(repeats).toEqual(range);
      });
    });

    it("should have an element in the DOM that represents the bottom of the list", function(){
      expect(element(by.css('#lazy-bottom')).isPresent()).toBe(true);
    });

    it("should add elements to the DOM when it scrolls to the bottom of the list", function(){
      browser.sleep(2000);
      browser.executeScript('window.scrollTo(0,' + 800 + ');').then(function(){
        browser.sleep(2000);
        expect(element.all(by.css('.ng-binding')).count()).toEqual(range * 2);
      })
    })
  });
})

I am looking to fill out this suite with even more useful tests, so I welcome any suggestions! Please feel free to fork and pull request from the demo app's repo.

]]>
http://adamrichman.com/more-angularjs-testing-end-to-end-tests-with-protractor/afba267b-ccbd-4fb6-8d21-e796c9f813c4Thu, 19 Jun 2014 05:52:00 GMT
<![CDATA[Testing ngLazy: unit tests with karma & jasmine]]>Excited as I am to have implemented my lazy load and infinite scroll modular AngularJS library, ngLazy, I considered it pretty fragile because it was lacking a test suite. And yes, I'm admitting that this was not developed in the style of TDD. I would like to make that a priority for the next project!

My concerns had little to do with the library's ability to handle edge cases, and much more to do with a strong desire to open up my code to the open source community. I didn't feel it was responsible to do this -- to solicit other people for their time and thoughtfulness -- without providing some automated indicator that the library has not been broken by a change that is made. So, I got down to work and wrote some tests.

The recommended engine for unit testing an AngularJS app is karma, and by default, it uses the Jasmine testing framework. npm install karma, followed by karma init got me moving pretty quickly, but there were configuration kinks that took a minute to iron out.

Knowing what questions to ask

A big question was raised before I could begin, though. How was I going to adequately demonstrate and test this library, of which there was but only a few features packed into a module, without a standalone purpose? My solution was to create a demonstration app for the features of the library, and in doing so, integrate my test suite with the demo. The result - http://ng-Lazy.com. My expectations are that this app will be integrated in the development cycle for further iterations on the library, and that the tests will be run against it.

Unit tests should be as decoupled from all pieces of an application as possible, in order to only test the operation of the single feature being tested. So this begged the question, what are the elements of this feature whose functionality needs to be varified in order to ensure nothing has been broken? Understanding which concepts to test was as challenging as figuring out how to test them. This would probably have been easier if the library had been developed in a TDD style!

Regardless, I combed through the pieces of ngLazy that make it tick and came away with some key assertions:

  • the lazyLoader Factory should have the proper methods

  • it should have a div with id 'bottom'

  • when repeated items are rendered, the bottom div should follow the last item

  • it should have a scope with keys for every lazy-load attribute

Now that I had some guidelines to shoot for, I needed to mock up their execution.

Some vital parts of mocking the Angular environment in which the piece you are testing operates:

  • require the module being tested before each test runs
  • mock a new $scope from the rootScope constructor, and
  • inject depedencies via the $injector provider:
  beforeEach(module('ngLazy'));
  beforeEach(inject(['$rootScope','$controller','$injector',function($rootScope, $controller, $injector){
    lazyLoader = $injector.get('lazyLoader');
    $scope = $rootScope.$new();
  }]));
  • with lazyLoader being my module's factory, now I can check that some good-intentioned contributor doesn't break its backwards compatibility:
  it('should have a lazyLoader Factory', function(){
    expect(lazyLoader).not.toBe(undefined);
  });

  it('the lazyLoader Factory should have the proper methods', function(){
    expect(lazyLoader.configure).not.toBe(undefined);
    expect(lazyLoader.getData).not.toBe(undefined);
    expect(lazyLoader.load).not.toBe(undefined);
  });

Testing a directive

In order to test the directive that this module provides, we need to mock an angular element that invokes it, and give it some controller data to validate the features are functioning.

NOTE: if your directive has isolate scope whose properties you will be testing, use the isolateScope() method on your angular element, AFTER you have invoked $compile on it with a scope.

      describe('Directive', function(){
        beforeEach(module('ngLazy'));

        var element, $scope, list, bottom, elementScope;

        beforeEach(inject(['$rootScope','$compile', function($rootScope, $compile){
          $scope = $rootScope.$new();
          $scope.data = {};
          $scope.data.list = [
            "item1",
            "item2",
            "item3",
            "item4",
            "item5"
          ];
          element = angular.element(
          '<lazy-load' +
            ' lazy-data="data"' +
            ' lazy-data-service="dataService"' +
            ' lazy-fetch-method="getList"' +
            ' lazy-range=" {{ range }}"' +
            ' lazy-data-collection-key="list"' +
            ' lazy-data-keys="[\'list\']"' +
            ' lazy-start-delay="{{ startDelay }}"' +
            ' lazy-append-delay="{{ appendDelay }}"' +
            ' lazy-spinner-color="{{ spinnerColor }}">' +
          '<div ng-repeat="item in data.list">' +
            '<h4>{{ item }}</h4>' +
          '</div>' +
          '</lazy-load>');

          $scope.$apply();
          $compile(element)($scope);

          elementScope = element.isolateScope();
        }]));

        it('should not break ng-repeat', function(){
          $scope.$digest();
          list = element.find('h4');
          expect(list.length).toBe(5);
        })

        it('should have a div with id=\'bottom\'', function(){
          bottom = element.find('div')[3];
          expect(bottom.id).toBe('lazy-bottom');
        })

        it('when repeated items are rendered, the bottom div should follow the last item', function(){
          $scope.$digest();
          bottom = element.find('div')[8];
          expect(bottom.id).toBe('lazy-bottom');
        })

        it('should have a scope with keys for every lazy-load attribute', function(){
          expect(elementScope.lazyData).not.toBe(undefined);
          expect(elementScope.lazyDataCollectionKey).not.toBe(undefined);
          expect(elementScope.lazyDataKeys).not.toBe(undefined);
          expect(elementScope.lazyFetchMethod).not.toBe(undefined);
          expect(elementScope.lazyRange).not.toBe(undefined);
          expect(elementScope.lazySpinnerColor).not.toBe(undefined);
          expect(elementScope.lazyAppendDelay).not.toBe(undefined);
          expect(elementScope.lazyStartDelay).not.toBe(undefined);
          expect(elementScope.lazyDataService).toBe('dataService');
        });

      })

    })

I swear, I wrote these tests and now I sleep much better a night. Next up, I'll try my hand at some notes about end-to-end testing ngLazy.

]]>
http://adamrichman.com/testing-nglazy-unit-tests-with-karma-amp-jasmine/09f943f0-5595-461d-ab6c-63744b691a05Sat, 14 Jun 2014 05:51:00 GMT
<![CDATA[Configuring karma for AngularJS testing]]>I've been working on the test suite for ngLazy, and I thought it could be helpful to document some notes that seem relevant after setting up karma in this project.

First thing's first:
npm install karma

followed by:
karma init

The karma tests are configured via a file that is named karma.conf.js by convention. In it, we find a number of config properties on an object passed to the config.set method (config is the parameter that is passed to karma at the time of invocation). A little clarification about these properties would have helped quite a bit, namely:

  {
    files: [...],
  }

This files array must contain paths for all scripts that the app you are testing is dependent on. Not just your spec files. That means angular and all your other vital dependencies, including in this case, the path to ngLazy.

There is also an exclude:[...] property, so that you can include files above using a wildcard * and then exclude specific files within those directories.

Karma launches its own webserver, but this must run CONCURRENT to the locally served app you are testing. By default, it uses port 9876. But this is an important point to understand. You must also serve your app BEFORE you run tests and launch the karma server.

Running your tests will be simplified with a build tool like grunt, and the grunt-karma npm package. This will run the necessary karma commands after defining a karma step in your grunt test script. If you don't use grunt, that is cool too! But don't forget, before you run your tests, you must start the karma server:

karma start path/to/tests/karma.conf.js

Then, to run the tests:

karma run path/to/tests/karma.conf.js
]]>
http://adamrichman.com/configuring-karma-for-angularjs-testing/e868c164-f71f-4257-8584-6207c1564377Wed, 11 Jun 2014 06:34:00 GMT
<![CDATA[ngLazy: Making an AngularJS Library]]>In pursuit of re-usablity

A little while ago, I wrote a blog post about implementing a lazy load / infinite scroll in an app I was hacking on. The logic was spread between a controller and directive, and it needed decoupling. It couldn't be re-used without copying a ton of code into any controller that wanted to use the feature. Further, implementing my spinner required logic throughout the controller that exists just to manipulate the DOM. It was a fine first implementation, but now it's time to refactor. I planned to:

  • extract all DOM logic and spinner related manipulation into a directive
  • extract the entire concept and turn it into an Angular library.

The end goal is for the user to be able to implement a lazy-loading infinite scroll and spinner via a simple directive.

The result is ngLazy.

Now my controller is as agnostic to this feature as any other controller:

.controller('listController', ['$scope', function($scope){
  $scope.data = {
    mongo : [],
    gh    : {},
    keen  : {}
  };
}])

The feature still requires a good amount of configuration per use case, so I have designed it with a factory and directive which takes configuration via the directive's element's attributes:

<lazy-load  
  lazy-data="data"
  lazy-data-service="dataService"
  lazy-fetch-method="getData"
  lazy-range="12"
  lazy-data-collection-key="mongo"
  lazy-data-keys="['mongo','gh','keen']"
  lazy-start-delay="150"
  lazy-append-delay="1000"
  lazy-spinner-color="#4FA7D9"
  >
   <table>
      <thead>
         <tr>
              <td>NAME</td>
              <td>STATS</td>
              <td>COMMENTS</td>
         </tr>
      </thead>
      <tbody>
          <tr ng-repeat="datum in data.mongo">
              <td class="cohort-pic">
                <span class="cohort-name">{{ datum.First }} {{ datum.Last }}</span><br>
              </td>
               <td class="cohort-stats-col cohort-score">
                 <div> some stats</div>
              </td>
              <td ><textarea class="form-control cohort-comments-form" rows="3">{{ datum.comments }}</textarea>
              </td>
          </tr>
      </tbody>
  </table>
</lazy-load>  
(function(angular){
  'use strict';

  angular.module('ngLazy',[
    'ngLazy.factories',
    'ngLazy.directives'
  ]);

  angular.module('ngLazy.directives',[])
  .directive('lazyLoad', ['$injector','$window','$document','$timeout','$rootScope',function($injector, $window, $document, $timeout, $rootScope){

    var appendAnimations = function(){
      var style       = document.createElement('style');
      var keyframes   = '@-webkit-keyframes spin {\n' +
                        '\t0%{-webkit-transform: rotate(0deg);}\n' +
                        '\t100%{-webkit-transform: rotate(360deg);}\n' +
                        '}\n' +
                        '@keyframes spin{\n' +
                        '\t0%{transform: rotate(0deg);}\n' +
                        '\t100%{transform: rotate(360deg);}\n' +
                        '}';

      style.innerHTML = keyframes;
      document.head.appendChild(style);
    };

    var makeSpinner = function(el){
      el.css({
        WebkitBoxSizing: 'border-box',
        boxSizing: 'border-box',
        display: 'block',
        width: '43px',
        height: '43px',
        margin: 'auto',
        borderWidth: '8px',
        borderStyle: 'solid',
        borderColor: 'transparent rgb(85, 148, 250) rgb(85, 148, 250) rgb(85, 148, 250)',
        borderRadius: '22px',
        animation: 'spin 0.8s linear infinite',
        WebkitAnimation: 'spin 0.8s linear infinite'
      });
      return el;
    };

    return {
      restrict: 'E',
      scope: {
        lazyData              : '=',
        lazyDataCollectionKey : '@',
        lazyDataService       : '@',
        lazyFetchMethod       : '@',
        lazyRange             : '@',
        lazyDataKeys          : '=',
        lazyStartDelay        : '@',
        lazyAppendDelay       : '@',
        lazySpinnerColor      : '@'
      },
      transclude: true,
      template: '<div ng-transclude></div>' +
                '<div class=\'col-md-12 loading\' ng-hide=\'spinner.hide\'>' +
                  '<div class=\'loading-widget\'></div>' +
                '</div>'+
                '<div id=\'lazy-bottom\'></div>',
      link: function(scope) {
              var winEl             = angular.element($window),
                  win               = winEl[0],
                  lazyBottom        = angular.element(document.querySelector('#lazy-bottom'))[0],
                  lazyBottomOffset  = lazyBottom.offsetTop - 20,
                  lazyLoader        = $injector.get('lazyLoader'),
                  dataService       = $injector.get(scope.lazyDataService),
                  loadingWidget     = angular.element(document.querySelector('.loading-widget')),
                  hasRun            = false,
                  loading           = false;

              appendAnimations();
              loadingWidget         = makeSpinner(loadingWidget);
              scope.spinner         = { hide : false };

              var lazyLoad = function(){
                lazyLoader.configure({
                  data            : scope.lazyData,
                  collectionKey   : scope.lazyDataCollectionKey,
                  fetchData       : dataService[scope.lazyFetchMethod],
                  range           : scope.lazyRange,
                  dataKeys        : scope.lazyDataKeys,
                  startDelay      : scope.lazyStartDelay,
                  appendDelay     : scope.lazyAppendDelay
                });

                lazyLoader.load().then(function(data){
                  if(!hasRun){
                    angular.forEach(Object.keys(data), function(key){
                      scope.lazyData[key] = data[key];
                    });
                  } else {
                    scope.lazyData[scope.lazyDataCollectionKey] = data[scope.lazyDataCollectionKey];
                  }
                  loading = false;
                });
              };

              $rootScope.$on('hideLoading', function(){ scope.spinner.hide = true; });
              $rootScope.$on('showLoading', function(){ scope.spinner.hide = false; });

              winEl.bind('scroll', function(){
                if (!loading && win.scrollY >= lazyBottomOffset) {
                  loading = true;
                  lazyBottomOffset = lazyBottomOffset * 2;
                  win.requestAnimationFrame(function(){
                    scope.$apply(function(){
                      lazyLoad();
                      lazyBottomOffset = lazyBottom.offsetTop-10;
                    });
                  });
                }
              });
              lazyLoad();
            }
          };
  }]);

  angular.module('ngLazy.factories',[])
  .factory('lazyLoader', ['$timeout','$rootScope', '$q', function($timeout, $rootScope, $q){
    var cache = { data : {} },
        config,
        data,
        collectionKey,
        fetch,
        responseKeys,
        range,
        appendDelay,
        startDelay;

    return ({

      configure:  function(options){
                    config = options;
      },

      getData : function(){
                  data          = config.data;
                  collectionKey = config.collectionKey;
                  fetch         = config.fetchData;
                  responseKeys  = config.dataKeys;
                  range         = config.range;
                  appendDelay   = config.appendDelay;
                  startDelay    = config.startDelay;

                  var deferred  = $q.defer();

                  $rootScope.$broadcast('showLoading');

                  if (!cache.data[collectionKey]) {
                    fetch().then(function(res){
                      angular.forEach(responseKeys, function(key){
                        cache.data[key] = res.data[key];
                        if (key === collectionKey) {
                          data[key]       = [];
                          data[key] = data[key].concat(cache.data[key].splice(0, range));
                        } else {
                          data[key] = cache.data[key];
                        }
                      });
                      deferred.resolve(data);
                      $rootScope.$broadcast('hideLoading');
                    });
                  } else {
                    $timeout(function(){
                      data[collectionKey] = data[collectionKey].concat(cache.data[collectionKey].splice(0, range));
                      deferred.resolve(data);
                      $rootScope.$broadcast('hideLoading');
                    }, appendDelay);
                  }
                  return deferred.promise;
      },

      load :  function(){
                var deferred = $q.defer();
                var _this = this;

                $rootScope.$broadcast('showLoading');

                var loadTimer = $timeout(function(){
                  _this.getData().then(function(col){
                    deferred.resolve(col);
                  });
                }, startDelay);

                loadTimer.then(function(){
                  $timeout.cancel(loadTimer);
                });

                return deferred.promise;
      }
    });
  }]);

})(angular);

In the future, I am looking to make this module more configurable, such as adding a custom spinner or easily changing the spinner styling. I also intend to further refactor this to remove elements from the DOM when they have left the screen, and re-add them upon scrolling up.

The configuration is explained in the repo's README, but the main-takeaway is this: with the <lazy-load> tag, simply wrap the element that will be displaying your list of info. Tell the lazy-load library what service you will use to fetch that data and how you would like it to be divided and presented. ngLazy handles the rest.

NEXT UP: Testing ngLazy

]]>
http://adamrichman.com/nglazy-making-an-angularjs-library/b6efb8c7-e9ad-4345-b50a-f37f6b392ce6Tue, 03 Jun 2014 22:32:00 GMT
<![CDATA[implementing a lazy load and infinite scroll in AngularJS]]>I am planning to refactor this into a more simple, modular directive, but before doing so, I just want to describe how I approached implementing a lazy load and infinite scroll on a project I picked up. It's a dashboard for tracking individual and group progress. (Sidenote: I also would like to modularize it into an easy, near-instant dashboard library. The version I'm currently building interfaces with 2 external APIs (Github and Keen.io), as well as an API that I implemented in a nodeJS server.)

This implemenation is dependent on an API that responds once with the entire data set that will need to be fetched. Originally, I designed the api to respond to multiple calls from the client because I thought that returning too much would negetivley impact browser performance. But, that was naive. The browser can handle this without breaking a sweat.

///////////////////////
// listController.js //
///////////////////////

angular.module('myApp').controller('listController', ['$scope','dataService','$timeout',  function($scope, dataService, $timeout){

  $scope.data = {};
  $scope.spinner = {};
  $scope.data.mongo = [];

  // used to show and hide the table element that will display the data
  $scope.isLoading = true;

  // used to manipulate the element containing the spinner once the data table
  // is displayed
  $scope.spinner.hide = false;

  // this will store the bulk of the data from the initial response.
  // then we will splice items off as needed
  var cache = { data: { mongo: [] } };

  var getData = function(){

    // check that the view-bound data set is empty
    if ($scope.data.mongo.length < 1){

      dataService.getData()
        .then(function(res){

          // display the table element
          $scope.isLoading = false;

          // declare the $timeout with a reference in order to cancel
          // it later. the $timeout invokes the AngularJS digest cycle
          // and will update the view bound to the data
          var appendDataTimer = $timeout(function(){
            cache.data.mongo = res.data.mongo;

            // splice some data to append to the view
            $scope.data.mongo = $scope.data.mongo.concat(cache.data.mongo.splice(0, 12));

            // assign some other data hashes from the response to the $scope
            // so they can be referenced in the view
            $scope.data.gh = res.data.gh;
            $scope.data.keen = res.data.keen;

            // remove the spinner from the view
            $scope.spinner.hide = true;

          },150);

          // invoke the timeout and remove it when the promise resolves
          appendDataTimer.then(function(){
            $timeout.cancel(appendDataTimer);
          })
      });

    } else {
      // the view contained data, so continue to splice from the cache and add // to the view data
      $scope.data.mongo = $scope.data.mongo.concat(cache.data.mongo.splice(0, 12));

      // delays feel more 'magical'
      $timeout(function(){
        $scope.spinner.hide = true;
      },1000);
    }
  };

  // to be invoked on the scroll event in our directive, which will be
  // triggered once we scroll through some data that is already displayed
  $scope.loadMore = function(){
    $scope.spinner.hide = false;
    var loadTimer = $timeout(function(){
      getData();
    }, 2000)
    loadTimer.then(function(){
      $timeout.cancel(loadTimer);
    });
  };

  // invoke the retrieval of data
  getData();
}])
/////////////////////////////////////////
// _list_partial.html (without styles) //
/////////////////////////////////////////

<table class="table table-striped table-hover" ng-if="!isLoading" when-scrolled="loadMore()">  
   <thead>
     <tr>
       <td>NAME</td>
       <td>STATS</td>
       <td>COMMENTS</td>
     </tr>
   </thead>
    <tbody>
      <tr ng-repeat="datum in data.mongo">
        <td>
          <span>{{ datum.First }} {{ datum.Last }}</span><br>
        </td>
        <td class="cohort-stats-col cohort-score"> some stats </td>
        <td ><textarea rows="3">{{ datum.comments }}</textarea></td>
      </tr>
    </tbody>
  </table>
  <div ng-hide="spinner.hide">
    <img src='http://adamrichman.com/img/spinner.gif' >
  </div>
//////////////////////////
// lazyLoadDirective.js //
//////////////////////////

angular.module('myApp')  
.directive('whenScrolled', function($window, $timeout) {
  return {
    restrict: "A",
    link: function(scope, element, attr) {
      var top = angular.element($window)[0].screenTop;
      var origHeight = angular.element($window)[0].screen.height;
      var height = (origHeight * 0.9);

      // bind the digest cycle to be triggered by the scroll event
      // when it exceeds a threshold
      angular.element($window).bind('scroll', function() {
        if (angular.element($window)[0].scrollY >= (height)) {

          // show the spinner when triggered
          scope.spinner.hide = !scope.spinner.hide;

          angular.element($window)[0].requestAnimationFrame(function(){
            // invoke the function passed into the 'whenScrolled' attribute
            scope.$apply(attr.whenScrolled);

            // increment the threshold
            height += (origHeight * 1.5);
          })
        }
      });
    }
  }
})
]]>
http://adamrichman.com/implementing-a-lazy-load-and-infinite-scroll-in-angularjs/e6f8c3b7-0bd5-4c3e-9fd1-f7a86dbf43b9Mon, 12 May 2014 16:03:00 GMT
<![CDATA[Stylr: making a mobile app with AngularJS]]>{% vimeo 99956183 %}

Stylr is a mobile app that, for lack of a better explanation, is probably best referred to as "Tinder for fashion". My friend Brendon Verissimo and I conceived and developed it. The idea behind the app is that users can tell the app about their tastes, and the app will track their preferences, eventually revealing their most prevelent style taste, and then go on to recommend actual fashion items to the user.

The stack for Stylr consists of:

  • mongoDB instance, hosted by mongoLab

  • NodeJS / Express server, hosted on a Digital Ocean droplet

  • AngularJS / Ionic Framework web app

  • Apache Cordova to wrap the app in a mobile native container

The performance of the web app on a phone, in relationship to native apps, is pretty remarkable. The ionic framework is basically bootstrap for your mobile web app. While we didn't use many of its features, it specializes in recreating familar native views, flows and gestures, all in an AngularJS app that's running in a webkit browser.

One of the key components of Ionic's framework is the Angular-UI Router. Once I got to know this module, I basically vowed to never again use Angular's native $routeProvider. The Angular-UI Router allows for nested states, which makes it very easy to implement views as parents and children, allowing for a pattern that much closer suits the way we think about views. It gives the developer a stateProvider, through which states can be accessed through various means.

Perhaps the most difficult challenge during the developemnt of Stylr was implementing the horizontal swipe-cards. I started with an old example of vertically swiped cards that behaved quite differently. A few days of tweaking and I was able to dictate the behaviors I was looking for - namely, the proper interpretation of the user's intent, and the corresponding actions. For instance:

  • if the user is moving at an accelerating velocity at the moment of release, they likely intent to toss this card. So this must trigger an animation that continues the current trajectory of the card view. It must also trigger the logic to pop the last card off the stack of cards to be played.

  • if the user is not accelerating at the moment of releasing their finger, it's likely that they intend to reconsider their own intent. The appropriate action here was to snap the card back to it's starting place, and be sure not to register any preference from the user.

The original card interaction demo has since been iterated on (check the pull requests), and can be found here.

]]>
http://adamrichman.com/stylr-making-a-mobile-app-with-angularjs/96c6f03e-665d-484b-905b-ec47c6aa293bWed, 02 Apr 2014 04:55:00 GMT
<![CDATA[that time when our mocha tests passed consistently... every second time that we ran them]]>We had a thorough suite of tests for our node/express server and mongodb test database, and we were delighted that they were putting our app through the paces. We were even happier that we'd tweaked our app's code until all of them passed. But we were befuddled when the tests consistently failed every second time that we ran them.

A peak inside our code

describe('Video Routes API', function () {

  var server;

  before(function (done) {
    process.env['MONGOHQ_URL']="mongodb://ourApp:ourPWD@subdomain.mongohq.com:10042/ourTestDB";
    server = child.exec('node web.js &', { killSignal: "SIGTERM"}, function(err, stdout, stderr){
      console.log('something', err, stdout,stderr);
      done();
    });
  });
  after(function(done){
    server.kill();
    done();
  });
}

What we were hoping to achieve here was the ability to spin up our server instance from inside of the test suite. This way we could set our environmental variable for the database to direct connections to our remote test database. Also, this would provide for a less granular set of integration tests.

We used the child.exec() method because we expected it to asynchronously start our server from the shell, and return a callback when it was ready.

The results:

First time: All tests pass

Second time:
0 passing (8s) 6 failing

1) User API Video Routes API GET /clips should return 200:
   Error: timeout of 2000ms exceeded
    at null.<anonymous> (/usr/local/lib/node_modules/mocha/lib/runnable.js:175:14)
    at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)
...

6) User API Video Routes API should return 200 upon reciept of favorite of a video:
   Error: connect ECONNREFUSED
    at errnoException (net.js:901:11)
    at Object.afterConnect [as oncomplete] (net.js:892:19)

We were wrong. A few things were fairly obvious:

  1. the callback was never being called!

  2. our tests were unable to connect to our server.

Fine, but why only every other time? We hypothetsized that our server was not hanging up after our tests were done running, but it didn't make a whole lot of sense that it would be unavailable for reconnections.

Resolution

After a long, painful exploration of the native child process functions in nodejs (really, I am still quite grateful for the opportunity to have become familiarized), we understood that our callback wasn't being called because there was never any "finish" to the buffered output of a still-running server. child.exec() was not the method we needed. Sure enough, we verified that our server process was still running after the tests ran, and on the next subsequent attempt, our tests connected and passed. Apparently our server.kill() method wasn't getting the job done for us. As it turns out, child.exec() isn't going to be our friend for that method either.

The answer was two-fold:

  1. substitute child.exec() with the synchronous child.spawn().

  2. implement a timeout before the tests run, just to give the server some time to get up and running before we try to test it.

It's kind of a hacky solution, we know. In a world where we had more time with this project, we would have explored having our server emit a 'ready' message for our tests to listen to. For now, though, this worked just fine:

describe('Video Routes API', function () {  
  var server;

  before(function (done) {
    process.env['MONGOHQ_URL']="mongodb://ourApp:ourPWD@subdomain.mongohq.com:10042/ourTestDB";
    server = child.spawn('/usr/local/bin/node', ['/Users/path/to/ourApp/web.js'],  {detached: true, stdio: [ 0, out, err ]});
    setTimeout(done, 1000);
  });
  after(function(done){
    server.kill();
    done();
  });
}

Now our tests run properly every single time, and they pass to-boot!

TL;DR

Consider child.spawn() when you need to start a different program from inside of your running, node program. And don't presume that your server is ready for connections immediately after instantiating it!

]]>
http://adamrichman.com/that-time-when-our-mocha-tests-passed-consistently-every-second-time-that-we-ran-them/585ea725-3d33-4373-887d-ed18358e46fcTue, 04 Mar 2014 06:56:00 GMT
<![CDATA[Man Vs. S3]]>Solution Gist: https://gist.github.com/adrichman/e550885f6011f37d6bd3

For more hours than I like to admit, I struggled to free ourselves from AWS's S3 SDK.

We were trying to facilitate direct uploads from our client to our S3 bucket, but without exposing any credentials that would need to be present on the client side. The answer to doing this requires that you deliver the client a temporary, signed URL or policy that is generated on your own server and returned to the client in order to accompany the payload to S3. Unfortunately this is where the SDK stopped working for us.

I scoured the web for days in search of solutions and found myriad similar stack overflow questions and blog entries on this very challenge. Still, I came up empty handed when I attempted to integrate many of the code examples, I presume because Amazon has since changed their API, or because of some other finicky detail that I wasn't identifying. I suppose that this kind of request just screams CORS and I understand why. I finally found my way to code that worked for us after finding a few posts that shined some meaningful light on the solving this problem. They are here, here and here.

My takeaways upon succeeding:

  • the order of your headers REALLY matters to amazon. This is not evident in their documentation, which at times is contradictory.

  • getting to know HTML5's FormData object was crucial for appending our policy to the payload.

check out my solution on stack overflow

Ultimately, we reverted to using Amazon's SDK and piping uploads from the client through our server on their way to s3. Solving this problem with our web form was not really going to be sufficient because our client is an Angular / Ionic / Cordova mobile app, and this simple upload form was going to require some refactoring and trial-and-error that would cost us precious time that we didn't have. With a little more time, we can change that and the client will retrieve our dynamically generated, signed-policy that will give it temporary credentials for direct upload to our S3 bucket.

Hopefully someone will find this post some day in the future that is soon enough for it to be helpful - before Amazon changes their API.

]]>
http://adamrichman.com/man-vs-s3/5088c856-8edd-41dd-817b-4934a25b929fFri, 28 Feb 2014 08:05:00 GMT
<![CDATA[super bowl sunday, morning review of toy problems]]>Sundays during my time in San Francisco have revealed a fairly cemented routine of their own. They are the one day I have in a week in which I'm not expected to be at the school on 5th and market. Nonetheless, I usually get a full day's worth of studying on Sundays, but only after doing something Sunday-ish (read: brunch). Today I'm parking at Vinyl Café on Divisadero with plans to do some serious review of this past week's lessons. I may head down to the school to watch the super bowl with the rest of my class of conflicted coders who are as amped to code as they are un-amped to be missing today's TV extravaganza.

Anyway, let's review. I'll be starting with some "toy problems", just like we start every day at Hack Reactor. I will only be writing about code and not showing actual code. I do not have permission to share the class's material and, even though these are common toy problems, I do not feel comfortable publishing the exact answers. Also, writing about the solutions is my preferred mechanism for review to reinforce my comprehension. I understand that it may be virtually useless to anybody else.

Before attending HR, I made it a point to get a grasp on recursive solutions to problems. I had read in many places that the mark of someone who has potential has a programmer is that they must be able to understand and intuit recursive programming.

some background:

A recursive algorithm essentially invokes itself repeatedly until it hits some base case that will make it stop and, sometimes, return it's whole trace of calculated results from the bottom of the stack and propagate them up to the top. Sometimes, while it recurses, it is storing results in some data structure outside of itself that is held in closure scope (in javascript). Programmers call this a side-effect.

The hallmark of a problem that can benefit from a recursive solution is that it is made up of many small instances of the same, larger problem. By calling itself enough times to solve the large problem, it provides a bulletproof set of instructions that can naturally adapt to the size of its input without any additional logic.

Programming: Stay Humble

When I finally felt like I had a grasp on imagining recursive solutions, my confidence as a programmer improved noticeably. Still, there is often many more than one recursive solution to a problem, and at HR, I've come to learn how the feeling that comes with conjuring my first idea for a solution is, sometimes, a liability. In fact, algorithms that depend on using recursion to iterate are often times less efficient than other iterative approaches. When I began to understand that, I started to see how humility was going to play a great role in my ability to program from a practical angle. Sure, the seeming-sophistication of recursion is more obvious, because it wraps its logic inside of what, for me, essentially amounts to a leap of faith. It's cleaner, shorter, and just-plain-cooler to solve things with as few instructions as needed. But it's not always efficient to computation. What matters most, I've learned, is that a solution is judged on its time and space complexity, first and foremost.

This week I began to see some tricks that produce non-trivial improvements in basically the same amount of code. Some examples:

Tree: Breadth-First Filter

A function that applies a truth test to the leaves of a tree that traverses breadth-first by using a for-loop inside of a while loop. The leaves are are pushed into to a queue in the order of their siblings - i.e. their children are not visited until all siblings have been. The while loop iterates through the queue, so as long as there is a leaf in the queue, the function will run. What makes this better than a recursive solution? Often times, a recursive solution can require making a copy of its input at every stage so that it doesn't mutate the original input, which other recursive calls may need to operate on in its original state. Comparatively, that means that this looping solution requires far less space.

This was also a great opportunity to learn a valuable precept of breadth-first tree traversals. In the future, I now know that this kind of problem usually calls for the use of a queue. When traversing an entire tree, the time complexity is limited to O(n) at best. A solution requiring more time than that is less efficient and can be ruled out.

Summing Array

In another problem, we were given an array of size n and asked to calculate the greatest sum of any of its contiguous numbers. The solution must account for the presence of negative numbers. I considered many approaches to this and hoped to land on a recursive solution. What I found is that this would require a lot of space and there was no need to mutate the input or make any copies. By using a for-loop within a for-loop, we can conduct an iteration through the array that starts on index 0, and then repeats itself while i < the length of the array. Each time it repeats, the iteration will begin one index further into the array. We hold the first index as the maximum sum and calculate a new sum that is specific to this round of iteration. When this new sum becomes greater than our max sum, it takes the place of the max sum. Each time the outer for-loop iterates, the new sum is reset to 0 and will begin comparing itself against the last held maximum sum. The time complexity is n squared - an iteration through the array on each step of another iteration of size n.

Numbers into English

In this problem, we are given two hashes of key-value pairs: one with the integers as keys 0-20 (increasing by ones) and 20-90 (increasing by tens) whose values are strings holding their english equivalent.
A second hash features the same pattern for the values ten, hundred, thousand and then increasing up through quintillion with each succeeding value multiplied by 1000.

This problem uses a recursive feature when calling itself on the remainders of modulus calculations. Those remainders are parsed by a step that accounts for numbers 1 - 100. It first checks for a number's presence in the first hash table, and if not, it will divide it by ten and call itself on the remainder.
Excepting the cases between 100 and 1000, the rest is done fairly easily.

  1. calculate a value for the number's current place (1000, 10000, etc...) by multiplying the initial place (1000) by 1000 while the result is less than or equal to the input number.

  2. divide the number by it's current place and round to the nearest integer.

  3. calculate modulus for the remainder when the number and place don't evenly divide.

  4. create a string that is the concatenation of calling itself on the result of the first division and a lookup of the current place in the second hash (words like thousand, million, etc.);

  5. finally, invoke the method on the result of the calculation for the remainder (if the remainder wasn't zero). Concatenate this to the end of the string.

I am unsure of the time complexity of this algorithm because variance in the number of steps is dependent on many qualities of the input, but not its size (always 1).

Function Bind

In this problem we are asked to implement the method on the function prototype called 'bind.' This method operates on the function that call it, binds the current context to future calls of the function and applies arguments as parameters in those subsequent calls. The tricky part is that it must accept a function as future context and be able to call that function on new arguments.
My solution came fairly easily, slicing the the arguments object and treating the first item as a function used as context for future calls. Other slices then deplete the arguments object into the arguments that need to be called on its first call. The function must return a function that applies its initial input on new arguments that will be passed in. While the solution I arrived at didn't seem to have any special need to adjust for time or space complexity, since it didn't require more than a few steps, I was wrong. I planned to separate my arguments with the Array prototype's slice method. Bad idea. While both the slice method and shift/unshift methods require an iteration through the entire length of the array in order to re-index its values, a much more efficient solution is found when considering space complexity. The slice method, by design, creates a copy of the array it is called on, and this is not needed here. The shift and unshift methods mutate the array in its place and require no more space than was initially designated. This isn't all that important when implementing a function like the one we are discussing, but it illustrates well how small decisions can potentially have largely different implications to your application, despite arriving at the same results in the same amount of time.

Coin Sums

Let's discuss a problem that I found challenging to solve, before even considering time or space complexity.

We are given the values of a number of currencies and are asked that given an arbitrary value for our input, we can count all possible combinations of these coins to arrive at that value. The solutions can contain any number of coins.

  1. We instantiate a counter at 0
  2. We create a function that accepts a current index and the input (our total to work towards)
  3. We iterate through the set of denominations from greatest to smallest
  4. We increment our counter on the base case that we are on the final index to be checked, and the modulus of total and our currently held denomination is 0; Then return.
  5. While the total is greater than or equal to 0 (we will be decrementing it), we call this function and pass index-1 and the total.
  6. We decrement the total by the current denomination, and this is used to stop our while-loop as it makes subsequent calls for a diminishing total.
  7. We invoke the function we built from outside and return our count when the function finishes executing.

An important lesson I learned from the solution lecture for this problem: when overwhelmed by a problem that looks to be solved by recursion, consider visualizing the permutations with a much smaller input set. By observing the pattern, your instructions may reveal themselves.

Telephone Words

Lastly, an algorithm to give us all possible permutations of words formed by telephone-number input (of n length, where numbers never change places, but we consider each possible letter that can be represented by each digit). I managed to solve this using a method I frequently try on first approach for solutions that are based on finding permutations. That method usually involves starting with a large structure or number and making it become smaller on each subsequent recursive call. It also involves a usually empty object at the beginning that will accumulate/concatenate results on each subsequent call, eventually being large enough to hit the base case and end the recursive calls. My solution to this worked well but was pretty verbose. The solution presented in class was far more elegant.

  1. an array to store our results is instantiated.

  2. our input number is split into an array of single integers.

  3. we define a recursive function that will take two inputs - the word (which at the beginning is an empty string), and an index (which will increase as we iterate down the array of integers).

  4. the base case will stop the recursive calls when the length of our word is as long as our input's length (n).

  5. we are given a hash of keys 0-9 with their values being the possible letters to match each digit. we hold the string of 3-4 possible letters that corresponds with the digit we are currently operating on (determined by the index, starting at 0).

  6. A for-loop will iterate through each possible letter for the digit at this index.

  7. we call the function inside of the for-loop, passing it the result of the word that we passed in at the beginning concatenating with the letter that is currently identified by the for-loop. the second argument is our index, and we increment it by 1 as we pass it, which will make the next set of calls to all possible letters for the digit that is next in line.

  8. lastly, return the array in which we stored our results.

TL;DR

Forget it, just google 'recursion' and have yourself a good laugh. It may take a second to reveal itself, so read the results carefully.

]]>
http://adamrichman.com/super-bowl-sunday-morning-review-of-toy-problems/cbc556f3-5729-4863-ae1f-ead59300d1b1Sun, 02 Feb 2014 19:16:00 GMT
<![CDATA[traversing the binary data tree... called life]]>This morning I have a quick moment for a short reflection on what we've learned so far at Hack Reactor, but my mind's presence is challenged by big changes back in NYC. While I am prepping myself for our weekly assessment (probably a prompt to recreate the solutions to problems we solved last week), my recording studio, its equipment and most of my instruments are being disassembled and removed for good - on to become another man's treasure. It is very much the point of no return.

So, I suppose that a depth-first log of my life's binary-tree data structure has officially found its longest path to a tree node with no children. It's not THAT crappy of an analogy.

Meanwhile, I am having an unforgettably special experience here in San Francisco at Hack Reactor. Since my arrival just 8 days ago, every moment has consumed me with thoughts about code, and I feel insulated from distraction with my curiosity nurtured. The challenges from day to day are myriad, from the concepts and problem solving, to squeezing out any of the moments for ordinary needs that the day can allow. I can see quite lucidly that my mind is really thriving at this pace, and I feel like I'm among people who have the same interest in learning. To be honest, I am stunned to be in the company of all of the brilliant minds in this cohort of 32 students. Our instructors are superb, the lectures are extremely engaging and thought-provoking, and it all makes for a tremendous environment to gain understanding of concepts that were difficult to grasp without much context. It's really, really great. Every single one of my expectations have been met here, and I'm stupidly fortunate for this opportunity.

tl;dr

most of my things are gone and life at hack reactor is fucking sweet.

]]>
http://adamrichman.com/traversing-the-binary-data-tree-called-life/970b09f8-bdaa-4f7e-a139-66c7bfbb28b5Mon, 13 Jan 2014 16:33:00 GMT
<![CDATA[Javascript Data-Structure Instantiation Patterns]]>earlier this week I learned about the many ways to instantiate a data-structure in javascript. here's what I took away, along with with some examples:

functional: a single function that instantiates an empty instance of an object that we will store data on. we will access the data with functions that we store as properties on the object - aka methods.

var dude = function(name, currentCity, food){  
  var newHacker = {};

  newHacker.name = name;
  newHacker.currentCity = currentCity;
  newHacker.favoriteFood = food;
  newHacker.eatAFood = function(){
    if (newHacker.favoriteFood){
      console.log(newHacker.name + " is totally chomping on some " + newHacker.favoriteFood + " in " + newHacker.currentCity + "!");
    }
  };
  return newHacker;
}
var Adam = dude('Adam','San Francisco','Freedom Fries');  
Adam.eatAFood()  

Adam is totally chomping on some Freedom Fries in San Francisco!

functional-shared: using a few functions that separate concerns, we can make an object that defines properties and methods to be appended to any data store that we extend to it, thereby making the code more DRY, and allowing for fewer instances of those methods upon instantiating new objects. In the previous example, every time we would instantiate a new 'dude', we would create another instance of the 'eatAFood' method. In the following example, we can have one instance in memory of the 'eatAFood' method, even if we create 250 different people.

first, we need a function to assign the properties of one object to another. this helps when we want to share common methods with objects that have other differing properties. this is a naive implementation of the _.extend method from the must-have javascript utility library, UnderscoreJS.

var extend = function(obj1, obj2) {  
  for (var a in arguments){
    for (var prop in arguments[a]){
      obj1[prop] = arguments[a][prop];
    }
  }
  return obj1;
};

now we need a border-line, tastefully sexist example of a few objects that get properties and methods from other objects on instantiation:

var peep = function(name, gender, currentCity, food){  
  var peepHacker = {};

  peepHacker.name = name;
  peepHacker.currentCity = currentCity;
  peepHacker.favoriteFood = food;
  if (gender === "Male"){
    extend(peepHacker, dudeHacker);
  } else if (gender === "Female"){
    extend(peepHacker, chickHacker);
  }
  extend(peepHacker, peopleMethods);
  return peepHacker;
};

var dudeHacker = {};  
dudeHacker.gender = 'dude';  
dudeHacker.hobby = 'wearing a hoodie'

var chickHacker = {};  
chickHacker.gender = 'chick';  
chickHacker.hobby = 'buying shoes'

var peopleMethods = {};  
peopleMethods.eatAFood = function(){  
  if (this.favoriteFood){
    console.log("This " + this.gender + " " + this.name + " is totally chewing on some " + this.favoriteFood + " in " + this.currentCity + " while " + this.hobby + "!");
  }
  return true;
};
var Adam = peep('Adam','Male','San Francisco','freedom fries');  
var KatyPerry = peep('Katy','Female','Los Angeles','carrots');  
Adam.eatAFood();  

This dude Adam is totally chewing on some freedom fries in San Francisco while wearing a hoodie!

KatyPerry.eatAFood();  

This chick Katy is totally chewing on some carrots in Los Angeles while buying shoes!

prototypal: a function that uses the Object.create() method to instantiate the new data structure. we pass it an object for data store that was defined outside of the function. We also previously defined the methods of that data store object as it's properties, and did so outside of the function.

var makePeepHacker = function(name, gender, currentCity, food, hobby){  
    var peep = Object.create(peepHacker(name, gender, currentCity, food, hobby));
    return peep;
};

var peepHacker = function(name, gender, currentCity, food, hobby){  
    var hacker = Object.create(peopleMethods);
    hacker.name = name;
    hacker.currentCity = currentCity;
    hacker.favoriteFood = food;
    hacker.gender = gender
    hacker.hobby = hobby;
    return hacker;
}
var peopleMethods = {};  
peopleMethods.isDoing = function(){  
  if (this.favoriteFood){
    console.log("This " + this.gender + " " + this.name + " is totally chewing on some " + this.favoriteFood + " in " + this.currentCity + " while " + this.hobby + "!");
  }
  return true;
};
var Chris = makePeepHacker('Chris Christie','dude','Trenton','taylor ham, egg and cheese','causing a traffic jam');  
var POTUS = makePeepHacker('Barak Obama','dude','Washington, D.C.','chili dogs','botching an epic site launch');  
Chris.isDoing();  

This dude Chris Christie is totally chewing on some taylor ham, egg and cheese in Trenton while causing a traffic jam!

POTUS.isDoing();  

This dude Barak Obama is totally chewing on some chili dogs in Washington, D.C. while botching an epic site launch!

pseudoclassical: a function that is named for the class that it creates, and assigns its storage object and data access properties to 'this'. We then define more data access methods as properties of this class's prototype. So, calling the original function will effectively instantiate as a new object with these properties.

var Peep = function(name, species, currentCity, activity, hobby){  
    this._name = name;
    this._species = species;
    this._currentCity = currentCity;
    this._activity = activity;
    this._hobby = hobby;
};

Peep.prototype.isDoing = function(){  
  console.log("This " + this._species + " " + this._name + " is totally " + this._activity + " in " + this._currentCity + " while " + this._hobby + "!");
  return true;
};

Peep.prototype.shoutName = function(){  
    console.log(this._name.toUpperCase() + "!!!!!!");
};
var Kanye = new Peep('Yeezy','monster','chi-town','spitting a new verse','improving upon his own self-worship');  
Kanye.isDoing();  

This monster Yeezy is totally spitting a new verse in chi-town while improving upon his own self-worship!

Kanye.shoutName();  

YEEZY!!!!!!

]]>
http://adamrichman.com/javascript-data-structure-instantiation-patterns/92e4b75d-d164-4f5e-a79a-e9efe8e62129Mon, 13 Jan 2014 00:15:00 GMT
<![CDATA[day 3 review]]>Today we began with a timed self-assessment (45-min) in which we had to re-implement some of the familiar functions in the UnderscoreJS library from scratch:

  • a recursive function that accepts a dom node and returns true if it finds 5 or more divs in itself and child nodes (no jQuery allowed).
  • an 'each' function, which accepts a collection to iterate over and an iterator that will be called on each item in the collection.
  • a 'once' function that accepts a function and executes it once, and then does not allow it to be called again
  • a 'defaults' function that accepts an object and optionally any number of objects which contain default key:value pairs to be assigned to the first object if those keys are not already present.
  • a 'contains' function which returns true if a given target value is found in a collection

after this we began learning about stacks and the instantiation styles of data stuctures, while also exploring the red-green-refactor approach to writing code (aka Test Driven Development). In this, we will write tests for what we want our application to do, and we will write them to fail until we write the code that fixes them.

]]>
http://adamrichman.com/day-3-review/c0ea6b69-de9d-45f3-b069-4d33ee2c6852Thu, 09 Jan 2014 08:59:00 GMT