Random Developments And Random Toys

RC2014 retro computer kit

I finally found a DIY retro computer kit that I always wanted: RC2014 (available as a kit on Tindie marketplace). According to the author himself:

RC2014 is a simple 8 bit Z80 based modular computer. It is inspired by the home built computers of the late 70s and computer revolution of the early 80s. It is not a clone of anything specific, but there are ideas of the ZX81, UK101, S100 and Apple I in here.

It’s pretty much everything I always wanted to build myself (but never had enough patience & smarts to design it):

  • Uses Z80 cpu
  • Uses simple a simple bus with pluggable modules
  • Serial I/O for terminal

The kit itself

RC2014 kit

Probably my favourite thing here - the backplane (big square PCB). Very simple, can be easily done from veroboard + uses 0.1″ header sockets.

Assembled modules

5-6 hours and 500 - 600 solder joints later:

RC2014 assembled modules

Aside the back plane this kit includes:

Fully assembled

RC2014 fully assembled

Operation

ROM chip in the kit comes pre-flashed with (drumroll) Microsoft Basic dating back to 1978! And that can be accessed via serial console. So this means you can connect RC2014 to a terminal. But since I’m not that crazy yet and I do not have enough space for that I opted in for simple FTDI USB to serial cable + minicom.

Eventually, after some debugging and circuit troubleshooting I got this:

RC2014 running Microsoft Basic

I think it’s actually running some code written by Bill Gates himself. Other than that I cannot do much else without some kind of permanent storage device or at least a ROM programmer. And it’s also somewhat unstable but I do not have the gear to diagnose it. Good excuse to finally get an oscilloscope I always wanted, eh?

DRY up your API integration specs

Once we established that our API code is correctly wired to a component like Doorkeeper then there’s no point in repeating the fact that every request needs to include one or another kind of token header, for example:

  it '...' do
      get '/me', nil, { 'Authorization' => "Bearer #{token.token}" }
      # ... rest of the testcase
  end

For request/integration specs this could be easily replaced by:

  before(:each) { use_token_of(user) }

  it '...' do
      get '/me'
      # ... rest of the testcase
  end

In most of my projects I have the following helper:

module OAuthHelper
  def oauth_token_of(user)
    Doorkeeper::AccessToken
      .where(resource_owner_id: user.id).last.token
  end

  def use_token_of(user)
    @token = oauth_token_of(user)
  end

  def get(*args)
    args = with_auth_header(args)
    super(*args)
  end

  def post(*args)
    args = with_auth_header(args)
    super(*args)
  end

  def put(*args)
    args = with_auth_header(args)
    super(*args)
  end

  private

  def with_auth_header(args)
    if @token
      header = { 'Authorization' => 'Bearer ' + @token }
      header = args[2].merge(header) if args[2].is_a?(Hash)
      args[2] = header
    end

    args
  end
end

Make sure this gets loaded only for request specs by adding the following to spec/rails_helper.rb config block:

config.include OAuthHelper, type: :request

And finally get FactoryGirl create you authorised user instances:

FactoryGirl.define do
  factory :user do
    # ... skipped

    trait :authorized do
      after(:create) do |user|
        create(:access_token, resource_owner_id: user.id)
      end
    end
  end
end

ngResource class and instance methods

One not really obvious ngResource trick is adding custom instance methods.

Say we have a user resource:

module.factory('User', function ($resource) {
  return $resource('/me');
}

ngResource generates some static (get for example) and instance ($get, $save, $delete) methods for us which is great. But what if we need something more?

First of all, start with declaring resource in wee bit different way:

module.factory('User', function ($resource) {
  var User = $resource('/me');
  return User;
}

Solution for adding a static method is obvious now, isn’t it?

module.factory('User', function ($resource, $cookies) {
  var User = $resource('/me');

  User.token = function() {
    return $cookies.get('token');
  };

  return User;
}

Instance method on the other hand is not:

module.factory('User', function ($resource, $cookies) {
  var User = $resource('/me');

  User.token = function() {
    return $cookies.get('token');
  };

  User.prototype.rememberMe = function() {
    $cookies.set('token', this.token);
  }

  return User;
}

In short - $resource method returns constructor function which is used to initialize the resource instances.

And one last thing: ngResource source code is a good read. Definitely check it out. It is surprisingly flexible for such small component.

Taking screenshots of failed Protractor test cases on Travis CI

So. You got a Protractor test suite doing amazing tricks via browser running under xvfb. And then it ocassionally fails, on remote environment like Travis CI only. Now what? Take a screenshot!

Protractor uses Jasmine and it has a quick and easy reporter API. Which you can define and add within protractor.conf.js:

{
  // ... rest of Protractor conf ...

  onPrepare: function() {
    var FailureScreenshotReporter = function() {
      // ... skipped ...
    };

    jasmine.getEnv().addReporter(new FailureScreenshotReporter());
  }
}

The screenshot reporter itself:

var FailureScreenshotReporter = function() {
  this.specDone = function(spec) {
    if(spec.status === 'failed') {
      var fileName = [];

      try { fs.mkdirSync('.tmp/shots'); } catch(e) {}

      fileName.push('.tmp/shots/');

      if(process.env.TRAVIS_BUILD_ID) {
        fileName.push('BUILD-');
        fileName.push(process.env.TRAVIS_BUILD_ID);
        fileName.push('_');
      }

      if(process.env.TRAVIS_PULL_REQUEST) {
        fileName.push('PR-');
        fileName.push(process.env.TRAVIS_PULL_REQUEST);
        fileName.push('_');
      }

      fileName.push(spec.fullName.toLowerCase().replace(/[^a-z0-9\s]/g, '').replace(/\s+/g, '_'));
      fileName.push('.png');

      console.info('Left a screenshot of failed spec at ' + fileName.join(''));

      browser.takeScreenshot().then(function(png) {
        var stream = fs.createWriteStream(fileName.join(''));
        stream.write(new Buffer(png, 'base64'));
        stream.end();
      });
    }
  };
};

This will create a screenshot with Travis build/PR identifier and spec, for example PR-123_this_and_that_button_opens_a_popup.png.

Next step would be collecting those screenshots since Travis environments are discarded immediately after the build. Probably easiest solution is to upload those to S3. That can be by adding the following to project’s .travis.yml:

before_install:
- pip install --user awscli
- export PATH=$PATH:$HOME/.local/bin

after_script:
- aws s3 cp .tmp/shots s3://my-automated-tests/my-project/ --recursive --exclude="*" --include="*.png"

That of course requires your S3 credentials in environment variables.

Learning something new: Rust programming language

New programming languages lately have been popping up almost monthly but one has really caught my eye: Rust. While everyone else is mostly doing new interpreted, garbage collected languages, Rust is quite a bit different. Key points of interest for me are:

  • Rust is compiled systems language allowing to go as low as C
  • Unique memory model – guaranteed memory safety
  • Non garbage collected but it kind of feels like one
  • Threading without data races
  • Supporting pure-functional, concurrent-actor, imperative-procedural, and object-oriented styles

It’s a modern language systems language which can potentially become a very strong competitor C and C++.

While I have no plans to write actual real world WEB applications in Rust, for me personally it looks like a very promising Internet of Things language. Speed and power of C for microcontrollers without headaches of memory management. Sure, microcontrollers nowadays are cheap and powerful but running Python on your light bulb simply does not make sense. And there’s already at least one project with aim to bring Rust into embedded environment: zinc.rs.