How to join multiple mp4 files together using ffmpeg on OS X

Sometimes I need to concatenate several mp4 files together. ffmpeg is a good tool for this job.

On OSX, it’s easy to install using Homebrew:

brew install ffmpeg

If you have MP4 files, these could be losslessly concatenated by first transcoding them to mpeg transport streams.
Source – https://trac.ffmpeg.org/wiki/Concatenate

Say we have 3 mp4 files to concatenate or join together, first we transcode each of these into an intermediate format:

ffmpeg -i input1.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate1.ts
ffmpeg -i input2.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate2.ts
ffmpeg -i input3.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate3.ts

After that we can concatenate these together using the following:

ffmpeg -i "concat:intermediate1.ts|intermediate2.ts|intermediate3.ts" -c copy -bsf:a aac_adtstoasc output.mp4

Push speed test results from OpenWRT to Google Sheets

I recently read Use Raspberry Pi to Measure Broadband Speeds to Hold Your ISP Accountable on Make and realised that this was an excellent candidate for monitoring my somewhat unstable Virgin Media connection.

I use an OpenWRT router (running a VPN to add a little bit of privacy), so I could adapt the article to run on the router rather than an attached Raspberry Pi.

Here are the steps adapted for OpenWRT…
Continue reading…

Adding styles to the Confluence editor

I’ve tried to add styles to the Confluence editor. It wouldn’t take them. Perhaps one of Atlassian’s values is “Don’t f@@k the editor”.

    <web-resource name="editor-scripts" key="editor-scripts">
        <resource name="editor-templates.js" type="download" location="assets/js/editor-templates.js" />
        <!-- // TODO: Check whether I need a context here -->
    </web-resource>

    <web-resource name="editor-styles" key="editor-styles">
        <resource name="css/confluence-editor.css" type="download" location="assets/css/confluence-editor.css"/>

        <dependency>com.atlassian.confluence.plugins:confluence-editor-plugins</dependency>
        <dependency>${project.groupId}.${project.artifactId}:editor-scripts</dependency>
        <dependency>com.atlassian.auiplugin:ajs</dependency>
        <context>editor</context>
        <!-- // TODO: Check whether I need all the dependencies here -->
    </web-resource>

My confluence-editor.css styles just wouldn’t be accepted. Javascript injection worked just fine though. Perhaps I could use JS to inject my styles?

Yup. Adding this to my editor-templates.js file worked a treat:

var editorCss = AJS.params.staticResourceUrlPrefix + '/download/resources/me.davidsimpson.confluence.addon.awesome-addon:editor-styles/css/confluence-editor.css';

if (AJS.params.isDevMode) {
    editorCss = editorCss + '?_=' + Date.now();
}

$('#wysiwygTextarea_ifr').contents().find('head').append('<link type="text/css" rel="stylesheet" href="' + editorCss + '" media="all">');

Note the cache busting timestamp for local development.

Why is my machine contacting all-systems.mcast.net?

I’ve been looking at the network traffic and noticed a lot of calls from one machine to an address I’d never heard of: all-systems.mcast.net

Screen Shot 2015-11-16 at 00.59.42

Information on this seemed somewhat sketchy until I spotted this page on Multicast Addresses

ALL-SYSTEMS.MCAST.NET
224.0.0.1 All systems on the local subnet.

What? All the machines on my local network? Really?

Pinging it confirmed this:

$ ping all-systems.mcast.net
PING all-systems.mcast.net (224.0.0.1): 56 data bytes
64 bytes from 192.168.1.136: icmp_seq=0 ttl=64 time=0.103 ms
64 bytes from 192.168.1.153: icmp_seq=0 ttl=64 time=14.788 ms
64 bytes from 192.168.1.120: icmp_seq=0 ttl=64 time=239.376 ms
64 bytes from 192.168.1.162: icmp_seq=0 ttl=64 time=256.191 ms
...
64 bytes from 192.168.1.119: icmp_seq=1 ttl=64 time=50.762 ms

The machine accessing all-systems.mcast.net is running a DLNA server, so it appears to be broadcasting its presence to all the machines on the local network. Panic over.

Installing OpenWRT on a Linksys WRT1900ACS

WRT1900ACS

Linksys recently released their WRT1900ACS router. Linksys said it collaborated with Marvell andOpenWrt.org to ensure full open source support in the latest version of OpenWrt’s Chaos Calmer release (15.05) at launch. I’ve not seen many OpenWRT compatible routers on the market in the UK, so my interest was piqued. It seems like a decent (though expensive) router, so I thought I’d give it a go and install OpenWRT.

The WRT1900ACS page on the OpenWRT wiki was a little vague about which version of the firmware to install, but stated that the router had Marvell Armada 385 & Shelby hardware, so I used the openwrt-mvebu-armada-385-linksys-shelby-squashfs-factory.img image to flash the firmware. This worked, so I’ve document it here for others.

This merely documents what worked for me. If you brick your router following these instructions, I’m sorry, but you do so at your own risk.

Installing OpenWRT

Download the OpenWRT firmware: openwrt-mvebu-armada-385-linksys-shelby-squashfs-factory.img

Connect to the router with the supplied network cable.

Login to http://192.168.1.1/. The password is admin. Don’t use the setup wizard. Specify manual setup.

Browse to Connectivity and in Router Firmware Update click on Manual > Select File

linksys-1

Select the previously downloaded openwrt-mvebu-armada-385-linksys-shelby-squashfs-factor.img, then click on Start.

linksys-2

Click on Yes in the Unrecognized file name modal:

linksys-3

Click on Yes in the Update firmware modal:

linksys-4

Click on OK in the Reboot Router modal:

linksys-5

Almost immediately, you’ll be able to browse to http://192.168.1.1 and see that OpenWrt has been installed:

linksys-6

It should ask you to set a password at this point. (I forgot to get a screenshot of that).

By default, the wifi is disabled, but it’s really straightforward to enable and secure in the admin UI.

You’ll also be able to ssh into your router. This is where the fun begins…

linksys-7

Secure your internet access with a VPN

The next sensible step is to setup your VPN connection. I use Private Internet Access as my VPN provider, so my VPN setup is tailored to PIA. This is incredibly easy to configure, thanks to previous work by Logan Marchione and Andrew Brereton.

Follow the script and you’ll be done in a couple of minutes.

Reboot nightly

Sometimes it’s best to just restart regularly. Here’s how:

Start & enable cron as it’s not enabled by default.

/etc/init.d/cron start
/etc/init.d/cron enable

Add this line to the crontab to reboot every day at 3am:

0 3 * * * * reboot

Save your eyes, enable the Bootstrap theme

One last thing, go into System | System | Language and Styles and enable the Bootstrap theme. It means that your admin UI is no longer an eyesore.

It turns this:

Screen Shot 2015-11-16 at 00.30.14

Into this:

Screen Shot 2015-11-16 at 00.32.48

Separation of concerns for JIRA gadgets

This blog post started out as an answer to a Stack Overflow question.

For my gadgets, I separate out all the XML, HTML, JavaScript and CSS from the atlassian-plugin.xml.

The setup is initially more complex, but once you’ve got this correct, the separation of concerns is much nicer than mangling everything into the atlassian-plugin.xml file.

The relative paths on the other hand do indeed look crazy.

My file system looks like this:

- resources/
    - gadgets/
        - css/
            - example.css
        - html/
            - example.html
        - js/
            - example.js
        - examaple-gadget.xml
    - atlassian-plugin.xml

In /resources/atlassian-plugin.xml:

<!-- add our web resources -->
<web-resource key="${project.artifactId}-resources" name="${project.artifactId} Web Resources">
    <dependency>com.atlassian.auiplugin:ajs</dependency>
    <resource type="download" name="example-gadgets/" location="/gadgets"/>
    <context>immersive-for-connections</context>
</web-resource>

<gadget name="Example JIRA Gadget" i18n-name-key="example-jira-gadget.name" key="example-jira-gadget" location="gadgets/example-gadget.xml">
    <!-- hosted at: /rest/gadgets/1.0/g/${project.groupId}.${project.artifactId}:example-gadgets/gadgets/example-gadget.xml -->
    <description key="jira-query-gadget.description">The JIRA Query Gadget Plugin</description>
</gadget>

In /resources/gadgets/example-gadget.xml (replace ${project.artifactId} & ${project.groupId} with the correct value):

<?xml version="1.0" encoding="UTF-8" ?>
<Module>
    ...
    <Content type="html" view="example.view" preferred_width="100%" href="../../../../../../download/resources/${project.groupId}.${project.artifactId}:${project.artifactId}-resources/gadgets/html/example.html"/>
</Module>

In /resources/gadgets/html/example.html (replace ${project.artifactId} & ${project.groupId} with the correct value):

<!DOCTYPE html>
<html>
    <head>
        ...
        <!--   added ../../../../../../download/resources/${project.groupId}.${project.artifactId}:${project.artifactId}-resources/gadgets/ to most relative links -->
        <link  href="../../../../../../download/resources/${project.groupId}.${project.artifactId}:${project.artifactId}-resources/gadgets/css/example.css" type="text/css" rel="stylesheet">
        <script src="../../../../../../download/resources/${project.groupId}.${project.artifactId}:${project.artifactId}-resources/gadgets/js/example.js" type="text/javascript" charset="utf-8"></script>
    </head>
    <body>
        ...
    </body>
</html>

From this somewhat excessing starting point, you’ll have content, behaviour and styles completely separated. If that floats your boat, then you’ll be happy.

How to format a disk to FAT32 on a Mac / OS X

From Alex Plumb on superuser:

If you’re comfortable with using the Terminal, try this:

First, look at the partition table by running this command:

diskutil list

You should see something like this:

/dev/disk1
#:                       TYPE NAME                    SIZE       IDENTIFIER
0:      GUID_partition_scheme                        *16.0 GB    disk1
1:                        EFI                         209.7 MB   disk1s1
2:                  Apple_HFS Example                 15.7 GB    disk1s2

The partition we want to change is /dev/disk1.

We want to change the device to an MBR-formatted FAT32 partition.
To do that, run this command:

sudo diskutil eraseDisk FAT32 NAME< MBRFormat /dev/disk1

where NAME is the name you want to give to the disk.

As mentioned in the comments, you cannot put square brackets into the volume’s name lest things mess up. To avoid having everything fail, simply ensure that there are no square brackets in the FAT32 volume’s new name.

Switching Java versions easily on a Mac

duke

I do a lot of development using Java 7 and recently needed to start using Java 8.

The quickest way I know to update to the latest Java uses homebrew:

brew tap caskroom/cask
brew install brew-cask
brew cask install java

I now need an easy way to switch back and forth between Java 7 & 8.

Adding this to your ~/.bash_profile or ~/.profile does the trick:

function setjdk() {
  if [ $# -ne 0 ]; then
   removeFromPath '/System/Library/Frameworks/JavaVM.framework/Home/bin'
   if [ -n "${JAVA_HOME+x}" ]; then
    removeFromPath $JAVA_HOME
   fi
   export JAVA_HOME=`/usr/libexec/java_home -v $@`
   export PATH=$JAVA_HOME/bin:$PATH
  fi
 }
 function removeFromPath() {
  export PATH=$(echo $PATH | sed -E -e "s;:$1;;" -e "s;$1:?;;")
 }

# set your default version
setjdk 1.7

Source.

This script cunningly uses /usr/libexec/java_home -v x.y to do the hard lifting.

I can now easily swap between Java versions as seen below:

david$ setjdk 1.6
david$ java -version
java version "1.6.0_65"
Java(TM) SE Runtime Environment (build 1.6.0_65-b14-462-11M4609)
Java HotSpot(TM) 64-Bit Server VM (build 20.65-b04-462, mixed mode)

david$ setjdk 1.7
david$ java -version
java version "1.7.0_71"
Java(TM) SE Runtime Environment (build 1.7.0_71-b14)
Java HotSpot(TM) 64-Bit Server VM (build 24.71-b01, mixed mode)

david$ setjdk 1.8
david$ java -version
java version "1.8.0_51"
Java(TM) SE Runtime Environment (build 1.8.0_51-b16)
Java HotSpot(TM) 64-Bit Server VM (build 25.51-b03, mixed mode)

This is a nice simple way to swap versions and is at least good enough for now.

Aside: I also tried out jenv which promises much, but wouldn’t accept my versions of Java when I tried it out.

Using wsadmin to quickly restart IBM Connections (or WebSphere) applications

Restarting WebSphere applications using the wsadmin tool feels much faster than through the WebSphere Integrated Solutions Console.

If you’ve already invoked wsadmin to update a configuration then this is especially true. No navigating through menus to find the right item, just a “simple” command line and the application quickly restarts.

Here’s how…

Invoke wsadmin:

cd /opt/IBM/WebSphere/AppServer/profiles/Dmgr01/bin
./wsadmin.sh -lang jython -user icadmin -password PASSWORD_HERE

If you can’t remember the name of your applications, list the applications installed.

AdminApp.list()

This returns a somewhat unattractive string:

'Activities\nBlogs\nCommon\nCommunities\nConnectionsProxy\nDefaultApplication\nDogear\nEditLiveForConnections\nExtensions\nFileNetEngine\nFiles\nForums\nHelp\nHomepage\nMetrics\nMobile\nMobile Administration\nModeration\nNews\nProfiles\nPushNotification\nSearch\nWebSphereOauth20SP\nWidgetContainer\nWikis\nnavigator\noEmbed'

It’s better formatted:

Activities
Blogs
Common
Communities
ConnectionsProxy
DefaultApplication
Dogear
EditLiveForConnections
Extensions
FileNetEngine
Files
Forums
Help
Homepage
Metrics
Mobile
Mobile Administration
Moderation
News
Profiles
PushNotification
Search
WebSphereOauth20SP
WidgetContainer
Wikis
navigator
oEmbed

Aside
If you’ve recently changed any configurations, you may want to update the IBM Connections configuration and synchronise nodes at this point:

execfile("connectionsConfig.py")
LCConfigService.checkOutConfig("/tmp","connectionsCell01")
LCConfigService.updateConfig("versionStamp","")
LCConfigService.checkInConfig("/tmp","connectionsCell01")
synchAllNodes()

Choose one of the applications, for example Communities, then stop and start the application:

appManager=AdminControl.queryNames("cell=connectionsCell01,node=connectionsNode01,type=ApplicationManager,process=IC_server1,*")
AdminControl.invoke(appManager, "stopApplication", "Communities")
AdminControl.invoke(appManager, "startApplication", "Communities")

This is pretty quick. Often no more than 30 seconds.