Extending Array functionality safely in Javascript

So I’m using AngularJS to create some tables of data and want to have a simple way to sum the columns at the bottom. I could write a function and attach to $scope however I’d like to be able to use this with a minimum of typing and have it the same in the templates as in Javascript. A good situation to extend Array.prototype.

Array.prototype.sum_col = function(col) {
        var t = 0; 
        for( var i = 0; i < this.length; i++ )
            t += parseFloat( this[i][col] );
            
        return t;
    };

Nice and easy. However then I noticed that certain pages of my Angular app didn't load with a very random error. After some debugging in the chrome JS browser it came down to the fact that whilst the above 3-statement for loop works fine, if I now do for( var i in array ) it also includes the sum_col function. D'oh. So after some research on stackoverflow I figured out the correct way to add stuff to Array.prototype which should probably be done by default whenever you want to:

Object.defineProperty( Array.prototype, "sum_col", {
    enumerable: false,
    value: function(col) {
        var t = 0; 
        for( var i = 0; i < this.length; i++ )
            t += parseFloat( this[i][col] );
            
        return t;
    }       
});         

Upgrading bootstrap LESS files stored in a git repo

Since starting a project several months ago with bootstrap 3.2.0 I noticed that there’s a newer version. I’ve been editing the LESS files quite a bit and adding various bits of my own in and then recompiling into a single CSS file for the project. As this is all stored in a git repo it’s a bit difficult (and I wouldnt want all of the extra stuff and history) to just pull and update from the bootstrap repo. So, the easy way to upgrade:

cd bootstrap-repo
git pull
git diff v3.2.0..v3.3.1 less/ > ../less.patch
cd .. # (go to main project)
git apply --reject --directory=bootstrap/ less.patch

You’ll probably have a handful of rejects (check for *.rej files) – fix those as with any patch apply, recompile your LESS and you’re done plus you don’t have any of the bootstrap history left around.

Replacing glyphicons with font-awesome in bootstrap

So, I wanted to use the much wider range of icons available with Font Awesome compared to the glyphicons in bootstrap. As most of them are in this icon set and as I’m already compiling bootstrap straight from LESS, it didn’t seem worth it to keep the glyphicons in there. However because I’m using Angular Bootstrap they already had a number of glyphicon sections embedded in the templates that I didn’t want to have to remember to change whenever I updated.

Anyway, to replace them first you download the less for bootstrap and font awesome, then you open up bootstrap/less/bootstrap.less, comment out the

@import "glyphicons.less";
line and add the following import:

@import "../../font-awesome/less/font-awesome.less";

You then need to edit font-awesome/less/variables.less and change the @fa-css-prefix: to be glyphicon rather than fa. Recompile and just include the general output in your html, no need for fa to be included as well any more. Then you have a drop-in replacement with many more icons available. Anything you can do with font-awesome can also be done with bootstrap you just have to remember to use glyphicon* rather than fa* in any CSS. So far I’ve only noticed that glyphicon-log-out and glyphicon-floppy-disk classes need to be changed to their fa equivalents.

Cutting a video into segments on the command-line

So, today I needed to cut a video into several segments and figured that as in the future I may need to reprocess the best thing to do would be to write a small script on the command-line to do this. Fortunately it turned out to be pretty easy… First create a file called cut_points with the points (in seconds):

5
10
20
100

(That last line of 100 is some value greater than the length of the video). Then using the following bash one-liner:

i=1;
prev=0;
for new in `cat cut_points`; do
  avconv -y -i out.mp4 -ss $prev -t $(echo "$new-$prev" | bc) -async 1 -strict experimental $i.mp4; i=$(($i+1));
  prev=$new;
done

Unfortunately this does reencode the video (I guess if you just try doing copy for the a/v streams it will only do it to the nearest B-frame so you’ll only have your cut points accurate to the nearest few seconds which wouldn’t work in my case)

Experimenting with different layout options flexibly using AngularJS

One of the great things about AngularJS is the way you can easily reuse and embed templates and controllers. Recently I was asked to create two versions of a control panel – one where there were several individual pages, and another where we had the pages as tabs. As I was already using the excellent AngularJS Bootstrap plugin I thought about doing something like:

<tabset>
  <tab ...>
    <div ng-include=... />
  </tab ...>
  ...
<tabset>

However the issue with this is that you load all the templates (and controllers) at page-load so if I update data in one tab it will still show the old data (from page-load time) when I change to another tab.

After scratching my head for a while I came up with the following simple method:

<div ng-controller="Tabs">

  <ul class="nav nav-tabs noprint">
    <li role="presentation"><a href="#/">
      <span class="glyphicon glyphicon-circle-arrow-left"></span>
        Dön
    </a></li>
    <li role="presentation" ng-class="{ active: type == 'recipe' }"><a href="#/edit/recipe/{{ rec_id }}">
      <span class="glyphicon glyphicon-edit"></span>
      Tarife
    </a></li>
    ...
  </ul>

  <div ng-include="'templates/' + template + '.html'"></div>

</div>

Then create a simple controller:

t.controller('Tabs', function($scope, $routeParams) {
  $scope.rec_id = $routeParams.rec_id;
  $scope.template = $routeParams.template;
});

And set up the routing (individual pages have their own routes&params already set up):

// For new combined tabs
path: '/edit/:template/:rec_id?'

Job done!

Running processing (and updating the commit) straight after a commit in git

In one project I have a set of templates that I want built into a single file for quicker download. Rather than having to run a command manually after a commit I’d rather this was done at commit-time and then added to the commit bundle. I spent a while figuring out how to do this but basically you need to create a file .git/hooks/post-commit (in every repository – it doesn’t get pushed/pulled) containing the following:

#!/bin/sh

# Build templates as you wish eg "perl bin/build_templates.pl"

git diff --quiet compiled_file_name  # Did we have any change?
if [ $? != "0" ]; then # Yes - redo previous commit
    git commit -C HEAD --amend --no-verify compiled_file_name
fi

Stripping out elements when sending an using AngularJS $http

I’m increasingly using AngularJS for frontend stuff to shift as much as possible into the browser. Basically it just receives some JSON, processes it and then sends it back to be stored in the database. However often to reduce the number of round-trips to the server you want to include additional data with the response. For example if you have a table of foods and you want to form a list of them in Angular, one way would be to get the list of ID’s and then fetch them either one-by-one or in bulk, however this is obviously not good for responsiveness or the backend server. So you’d typically want to send an array of rows from the server but for saving again, effectively you only actually need the ID’s as the rest of the data is already on the server. When you are dealing with big lists this can be rather annoying. Here’s an easy way to strip out keys on AngularJS before sending to the server:

$http.post('/api/save', { data_object }, {
  transformRequest: function(obj) {
    function toJsonReplacer(key, value) { // This taken from angular's function of the same name
      var val = value;
 
      if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
        val = undefined;
      }
 
      // These are the custom lines we add in to strip out certain keys - could use a regex too
      if (typeof key === 'string' && ( key == 'nutrients' || key == 'portions' ) )
        return undefined;
 
      return val;
    }
    return JSON.stringify(obj, toJsonReplacer);
  }
});

This overrides the $http.defaults.transformRequest as it basically does the same thing (using Angular’s toJson function). It would be nice if it were possible to just use toJson but specify a function for the json transformation.

Importing and prepending subversion history to a git repo

So, when I converted some repos from svn to git a few years ago I just threw away the history (I think the git-svn tool wasn’t working or I was in a hurry or something). Anyway, today I was reminded of this and thought I’d backup all my svn repos into git and where possible prepend the history to the repositories. Based on this stackoverflow post and some experimenting I did the following:

git svn clone --preserve-empty-dirs file://path/to/svn-repo/project/trunk/
 
INITIAL_SHA1=$(git rev-list --reverse master | head -1)
# the last commit of old history branch
oldhead=$(git rev-parse --verify old-history)
# the initial commit of current branch
newinit=$(git rev-list master | tail -n 1)
# create a fake commit based on $newinit, but with a parent
# (note: at this point, $oldhead must be a full commit ID)
newfake=$(git cat-file commit "$newinit" \
  | sed "/^tree [0-9a-f]\+\$/aparent $oldhead" \
  | git hash-object -t commit -w --stdin)

# replace the initial commit with the fake one
git replace -f "$newinit" "$newfake"

git push origin 'refs/replace/*'
git filter-branch --tag-name-filter cat -- --all
git replace -d $INITIAL_SHA1

git push

Automatically removing a torrent when it has finished downloading

So as not to saturate my (very limited) uplink when a torrent as finished downloading (using transmission-daemon on my Raspberry Pi) I wanted it to be removed automatically. There were a number of docs on the web about how to do this but here is a simple 2-line file that will do it:

#!/bin/bash
transmission-remote -t $TR_TORRENT_ID -r

Save this as /usr/bin/torrent-complete.sh, chmod +x the script. Stop transmission-deamon (you need to do this rather than a restart as it always dumps the current live config on stop/restart so any changes you make while it is running will be nuked) Then open up /etc/transmission-daemon/settings.json and add (or modify) the following lines:

    "script-torrent-done-enabled": true,
    "script-torrent-done-filename": "/usr/bin/torrent-complete.sh",

Start up transmission-deamon and there you go.