feat(Scope): add `$watchGroup` method for observing a set of expressions

Given an array of expressions, if any one expression changes then the listener function fires
with an arrays of old and new values.

$scope.watchGroup([expression1, expression2, expression3], function(newVals, oldVals) {
 // newVals and oldVals are arrays of values corresponding to expression1..3
 ...
});

Port of angular/angular.dart@a3c31ce1dddb4423faa316cb144568f3fc28b1a9
refactor($interpolate): split .parts into .expressions and .separators

BREAKING CHANGE: the function returned by $interpolate
no longer has a `.parts` array set on it.
It has been replaced by two arrays:
* `.expressions`, an array of the expressions in the
  interpolated text. The expressions are parsed with
  $parse, with an extra layer converting them to strings
  when computed
* `.separators`, an array of strings representing the
  separations between interpolations in the text.
  This array is **always** 1 item longer than the
  `.expressions` array for easy merging with it
perf($compile): watch interpolated expressions individually
WIP: working before refactoring with some extra changes
WIP: speed up the returned interpolation fn using the same trick as watchGroup
WIP: undo watchgroup use
WIP: remove extra cruft from $watchGroup + update tests
WIP: remove compute, use $parse, remove scope.$eval
WIP: move stringify around
WIP: use log test service in watchGroup tests