Monthly Archives: March 2015

Console Log – Javascript Preformance in Chrome

Updated and Adjusted to accept optional arguments and track time or memory use as an indicator of performance.

If you are measuring Memory used please launch Chrome from Terminal.

By default, Chrome quantizes/rounds memory use making it inaccurate.

Run the following command from terminal to launch Chrome and prevent quantizing.

/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --enable-precise-memory-info
// performanceType should be a string 'time' or 'memory'
// Optional Arguments (performanceType, divisor, precision, suffix)
var performanceCheck = function () {

  
  // Can't wait for defaults ES2015
  var divisor = 1;
  var precision = false;
  var suffix = (arguments[0] === 'memory') ? ' bytes' : ' ms';

  if (arguments.length > 1) {
    divisor = arguments[1];
  }
  
  if (arguments.length > 2) {
    precision = arguments[2];
  }

  if (arguments.length > 3) {
    suffix = arguments[3] || suffix;
  }

  var start;
  var func = (arguments[0] === 'memory') ? getMemoryUsed : getTime;
  var end;

  start = func();

  function getMemoryUsed() {
    return console.memory.usedJSHeapSize;
  }

  function getTime() {
    return Date.now();
  }

  function convertToUnits(num) {
    if (precision) return (num / divisor).toPrecision(precision);
    return (num / divisor);
  }

  function formatMsg(prefix, usage, suffix) {
    console.log(prefix + usage + suffix);
  }

  return function () {

    var total;
    
    end = func();
    
    total = end - start;

    formatMsg('Initial: ', convertToUnits(start), suffix); 
    formatMsg('Current: ', convertToUnits(end), suffix);
    formatMsg('Use: ', convertToUnits(total), suffix);

  }
}

// USAGE

// Set Initial Use Memory or Time
var check = performanceCheck('time');

// A javascript operation
var doJavascriptThings = [];
for (var i = 1000 - 1; i >= 0; i--) {
  doJavascriptThings[i] = [{'random':'values'}];
};

// Check again after process is complete
check();

Console Log Output – Substitution and CSS in Chrome

Debugging should be more colorful.

Console.log in Chrome accepts a number of parameters including css.

Output can be stylized by using %c prior to the stylized text.

Example:

console.log("I'm%c Colorful.", "color: blue; font-size:14px");

A simple utility wrapper I use to stylize console.log output.

var styled = (function () {

var fontStyle = 'font-family: Helvetica,Arial,sans-serif; font-size: 13px;', boxStyle = ' line-height: 25px; padding: 5px 5px; border-radius: 4px;', styles = { msg : ' color: #eee; background: #222; ' + fontStyle + boxStyle, err : ' color: #0F0; background: #222; ' + fontStyle + boxStyle }, log = function (msg, styleStr) { if (styleStr) { console.log('%c' + msg, styles[styleStr]); } else { console.log('%c' + msg, styles.msg); } } return log; }());

styled('New Log Style. '); 
styled('New Error Style. ', 'err');

Additional Console substitutions.

As String:

console.log('%s', 'String'); // String

As Integer:

console.log('%d', 5.3); // 5
console.log('%i', 5.3); // 5

As Float:

console.log('%f', 5.3); // 5.3

Displaying expandable Objects / Arrays (note: css cannot style this output).

console.log('Expandable object or array %O', {type:'color', color:'blue'}); // Expandable object or array Object

Random Example:

console.log("I'm%c - %c%s%c.", "color: black; font-size:19px", "color: blue; font-size:14px", "Colorful", "color: black; font-size:19px");

Javascript – Observer Pattern Implementation

While working on a project that needs to notify when updates are made, I started playing with the Observer Pattern in Javascript. Changes made to the Observed Object trigger a console.log when updates are made. The actual implementation is using SocketIO to notify users of updates concurrent with updates to the persistence layer.

Note: The code is still in development and needs additional refactoring.

(function () {

  'use strict';
  /*global console */

  function Observable() {

  // Observable class
    var _observingArray = [];
    
    return {

      action: function (action, func) {
        console.log(action, func);
      },

      addWatcher: function (obj) {
        var funcName = arguments[0].name;
        if (!_observingArray[funcName]) {
          this.action('New Watcher:', funcName);
          _observingArray.push(obj);
        }
      },
      
      removeWatcher: function(obj) {
        var i = 0,
          len = _observingArray.length;
        for (i; i < len; i++ ) {
          if (_observingArray[i] === obj ) {
            _observingArray.splice(i, 1);
            var funcName = arguments[0].name;
            this.action('Removing Watcher:', funcName);
            return true;
          }
        }
        return false;
      },
      
      notify: function () {
        // arguments is an array like object / converted to array here
        var args = Array.prototype.slice.call( arguments, 0 );
        var i = 0,
          len = _observingArray.length;
        for (i; i < len; i++) {
          _observingArray[i].update.apply( null, args );
        }
      }

    };
  }

  // basic example of observer object with 
  function MakeObservableObject() {

    // very basic object comparator
    function updateObject(obj, updates) {
        var updated = false;

        Object.keys(updates).forEach(function(k) {
          // if property values are different update
          if (obj.contents[k] !== updates[k]) {
            if (updates[k] > 0 || updates[k].length > 0) {
              // if property has a value - update
              obj.contents[k] = updates[k];
            } else {
              // if property has no value - delete the property
              delete obj[k];
            }
            updated = true;
          }
        });
        if (updated) {
          return obj;
        }
        return false;
    }

    var items = {}; 

    var observer = MakeObserver(this);

    // notifies watchers
    this.getItems = function getItems() {
      observer.notify(items);
    };

    // initial configuration of object properties
    // does not notify watchers
    this.setItems = function setItems(obj) {
      items = obj;
    };

    // updates object properties
    // notifies watchers of new object contents
    this.update = function updateItems(updates) {
      if (updates) {
        var updated = updateObject(items, updates);
        if (updated) {
          items = updated;
          observer.notify(items);
        }
      }    
    };
  }
  

  function MakeObserver(obj) {
      
      // obj passed in is extended with Observable methods and returned
      var observable = Observable();

      // obj passed in is added as an observer
      obj.addObserver = function addObserver(observer) {
        observable.addWatcher(observer);
      };

      // obj passed in is removed from observable as an observer
      obj.removeObserver = function removeObserver(observer) {
        observable.removeWatcher(observer);
      };

      return observable;
  }

  // ============================
  // ========= Examples =========
  // ============================

  // CUSTOM OBSERVER Methods
  var ItemUpdater = {
    name: 'ItemUpdater',
    update : function() {
      var item = arguments[0];
      console.log( 'Update ItemUpdater:', item.name, ' = ', JSON.stringify(item.contents));
    }
  };

  var ItemCharts = {
    name: 'ItemCharts',
    update : function() {
      var item = arguments[0];
      console.log( 'Update ItemCharts:', item.name, ' = ', JSON.stringify(item.contents));
    }
  };

  // OBSERVABLE OBJECT
  var app = new MakeObservableObject();

  // OBSERVABLE OBJECT CONTENTS
  var items = {
    name: 'clothes', 
    'contents': {socks : 7, pants : 3, shirts : 4}
    }; 

  // SET OBSERVABLE OBJECTS - PUBLIC CONTENTS 
  app.setItems.call(app, items);

  // ADD OBSERVER
  app.addObserver(ItemUpdater);

  // ADD OBSERVER
  app.addObserver(ItemCharts);

  // CHECK CURRENT CONTENTS / TRIGGER NOTIFICATION
  app.getItems();

  // REMOVE OBSERVER
  app.removeObserver(ItemUpdater);

  // REMOVE OBSERVER
  app.removeObserver(ItemCharts);

  // ADD OBSERVER
  app.addObserver(ItemCharts);
  app.update({'ties':26.00});
  app.getItems();

  // OBSERVABLE OBJECT
  var music = new MakeObservableObject();
  // OBSERVABLE CONTENTS
  var albums = {
    name: 'music', 
    'contents': {blues : 1, jazz : 3, punk : 2}
    }; 
  music.setItems(albums);
  music.addObserver(ItemCharts);
  music.addObserver(ItemUpdater);

}());

Apple Remote Desktop Client – Status Offline

Apple Remote Desktop Client has been displaying “Current Status = Offline” for machines without cause. When a mac is “Offline”, ARD, AFP, SMB, and SSH are stop working. However, the
mac can still be pinged and its web server is still accessible.

Apple Remote Desktop Client is crashing and causing the issues. I don’t understand why SSH and SMB stop working when this happens, any comments would be appreciated.

I’m posting the AppleScript that I wrote to resolve the issue. A restart is not required, but resolved network issues outside of ARD for me. Please comment if this works, doesn’t work or needs to be updated in any way.


on doShellScript(cmd, pswd)
    if (length of pswd > 0) then
        display dialog pswd
        do shell script cmd password pswd with administrator privileges
    else
        display dialog "This process requires an admin password."
        requestInput()
    end if
end doShellScript

on restartNow()
    tell application "Finder"
        restart
    end tell
end restartNow

on requestInput()
    set admin_password to display dialog ¬
        "Please enter your password:" with title ¬
        "Password" with icon caution ¬
        default answer ¬
        "" buttons {"Cancel", "OK"} default button 2 ¬
        giving up after 295 ¬
        with hidden answer
    set pswd to text of text returned of admin_password
    
    set cmds to {¬
        "ls", ¬
        "sudo /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -agent -stop", ¬
        "sudo rm -R /Library/Application\\ Support/Apple/Remote\\ Desktop/Client", ¬
        "sudo /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -agent -restart"}
    
    doShellScript(item 1 of cmds, pswd)
    doShellScript(item 2 of cmds, pswd)
    doShellScript(item 3 of cmds, pswd)
    requestRestart()
end requestInput

on requestRestart()
    set restartAnswer to display dialog ¬
        "Would you like to restart now?" with title ¬
        "Restart" with icon caution ¬
        buttons {"Cancel", "OK"} default button 2 ¬
        giving up after 295
    
    set answer to text of button returned of restartAnswer
    
    if (answer is equal to "OK") then
        restartNow()
    end if
end requestRestart

requestInput()

Set up Mongodb as a daemon / service on a Mac –

Launch MongoDB on Startup or User Login

A quick post on setting up Mongodb to start automatically on a Mac so I can do my other work. To start, I found a link to Apple’s info about Mac daemons and services.

About Daemons and Services

Which lead me to the section that specifically talks about Launching Custom Daemons Using launchd.

Launching Custom Daemons Using launchd

Which talks about system daemons.

It uses the plist files in the following folders /System/Library/LaunchDaemons/ and /Library/LaunchDaemons/ to register daemons. It attempts to launch the daemons in a somewhat random order, if a daemon has a dependency, its launch is deferred momentarily while other daemons are launched.

MONGODB as a daemon / service for mac

Create a link to the MONGODB plist file

(s = symbolic, f = replace existing, n = link is seen as a normal file)

To start using the current users LaunchAgents

ln -sfv /usr/local/opt/mongodb/*.plist ~/Library/LaunchAgents

use launchctl to direct launchd to load mongodb .

launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mongodb.plist

To start as a system wide daemon use the following

ln -sfv /usr/local/opt/mongodb/*.plist /Library/LaunchDaemons/

use launchctl to direct launchd to load mongodb .

launchctl load /Library/LaunchDaemons/homebrew.mxcl.mongodb.plist

homebrew.mxcl.mongodb.plist

This file tells launchd how to launch the application, where the config files and log files should be and should look something like this.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>homebrew.mxcl.mongodb</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/opt/mongodb/bin/mongod</string>
<string>--config</string>
<string>/usr/local/etc/mongod.conf</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<false/>
<key>WorkingDirectory</key>
<string>/usr/local</string>
<key>StandardErrorPath</key>
<string>/usr/local/var/log/mongodb/output.log</string>
<key>StandardOutPath</key>
<string>/usr/local/var/log/mongodb/output.log</string>
<key>HardResourceLimits</key>
<dict>
<key>NumberOfFiles</key>
<integer>1024</integer>
</dict>
<key>SoftResourceLimits</key>
<dict>
<key>NumberOfFiles</key>
<integer>1024</integer>
</dict>
</dict>
</plist>

The config location is referenced in above plist file (--config). Currently, the default points to /usr/local/etc/mongod.conf. Set the dbPath to the path to the db for your implementation.

mongod.conf
systemLog:
destination: filexvc
path: /usr/local/var/log/mongodb/mongo.log
logAppend: true
storage:
dbPath: /dbData/db
net:
bindIp: 127.0.0.1

AngularJS – UI Bootstrap DatePicker

The AngularUI team made a collection of nice Bootstrap components.

Unfortunately, the DatePicker appears to have a conflict with other scope variables.

The recommended javascript to open the DatePicker is shown below.

$scope.open = function($event) {
$event.preventDefault();
$event.stopPropagation();
$scope.opened = true;
};

This code will work once and only one.

If the DatePicker is closed, it cannot be re-opened.

The problem is caused by a generically named scope property.

Changing three things will fix the issue.

Change the javascript to the following.
$scope.openDatepicker = function($event) {
$event.preventDefault();
$event.stopPropagation();
if (typeof($scope.datepicker) === 'undefined'){
$scope.datepicker = {};
}
$scope.datepicker.opened = true;
};

Change the inputs is-open attribute as shown below.
is-open="datepicker.opened"

Change the buttons ng-click attribute as shown below.

ng-click="openDatepicker($event)"

Angular UI Bootstrap

Angularjs – ngTagsInput v2.2.0 – “Duplicates in a repeater are not allowed.”

ngTagsInput is a great tags input directive for Angularjs. It auto suggests tags from an external source and populates them into an input for form submission. While using it, I discovered that having multiple instances on a form caused an angularjs error.

Error: [ngRepeat:dupes] Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: tag in tagList.items track by track(tag), Duplicate key

If you experience this error, search and find the following.

tag in tagList.items track by track(tag)
item in suggestionList.items track by track(item)
Replace it with the code below.

tag in tagList.items track by $index

This allows Angular to keep track of the items in the repeat.

item in suggestionList.items track by $index

ngTagsInput

ngRepeat