Tomorrow could be an exciting moment in the history of maths. Sir Michael Atiyah is presenting a proof of the Riemann Hypothesis at the Heidelberg Laureate Forum which will be available on their youtube channel. There is a good angle by Ken Regan on the Gödel’s Lost Letter blog.
The Riemann Hypothesis is one of the most important unsolved problems in mathematics and the subject of one of my favourite books about maths: Prime Obsession.
A few years ago in Paris, I had the pleasure of seeing Sir Michael speak. He spoke so cheerfully about life and mathematics. There is a great interview with him on the Web of Stories YouTube channel.
This is part three of a series of posts about the software and tools I find invaluable. See Part 1: essential applications and Part 2: Visual Studio tools. In this post I’m covering the online applications and iPhone apps I find indispensible.
I need simple task manager with support for multiple lists, hierarchies and available everywhere. Google Tasks is often overlooked in this regard. Check out the Google Tasks canvas. There is also a fantastic free iPhone app for it GoTasks.
Feedly is the best RSS news feed reader, in my opinion. I keep up with a few development blogs, a few science blogs and the blogs of my friends. The mobile app is great too.
I like real books but don’t always lug them about with me, so often I buy both the hard copy and the kindle version (there shoudl be some sort of clever discount for this…). The Kindle app is where I spend my time when I have no connectivity (the London tube, airplanes, etc.)
Chess is a mascohistic, character-building pastime. Progress is elusive. You play a couple of good games and you think you’re improving and then you get thrashed repeatedly by a 10 year old.
NCrunch provides continuous testing for Visual Studio. When I make any change to my code which breaks a unit test, the NCrunch risk status goes red a few seconds later, even without recompiling. I get immediate feedback for any breaking change, so long as I have a test for it. Not only does it encourages me and my team to write good tests, but it allows us to make new changes and
refactor with confidence.
Also, while there are several good .NET decompilers, many of them free, I got used to .NET Reflector which comes part of this bundle.
T4
I use code generation to automatically generate templates for unit tests for validation rules and T4 and the T4 Toolbox fit the bill nicely.
For a more advanced use case, see my post about automatically converting DevExpress v1 report scripts to check for compilation errors and allow for unit testing of report scripts.
AWS Toolkit
I always install the Amazon Web Services Toolkit to make it easy to spin up test servers in the Amazon cloud.
This is the first in a series of posts where I list the applications that I use and enjoy the most. See part 2) and part 3.
A bit of preamble, my most powerful machine is a Windows-only desktop with lots of RAM and an SSD drive. I use it almost exclusively for development.
I also have a Macbook Pro which is configured to dual-boot Windows and MacOS. The Windows machine is more or less a mirror of my main development machine. The Mac is where I do all my document editing, Word, blogging, etc. I also use it for my occasional forays in to iPhone development or other non-Windows experiments.
When I upgrade my development machine, I reconfigure the previous system for Linux, currently Ubuntu.
Chocolatey
In Windows, Chocolatey is a very convenient way to install programs. Just go:
C:> choco install nodejs
Boxstarter
Even better, create a powershell script with all the applications you want to install and run it with boxstarter. Repeatable and reboot-resilient environment installations using chocolatey under the hood. For several years now, I have maintained a script for installing my entire development environment (and the build server) from scratch. Works whether it’s a physical or a virtual machine.
BeyondCompare
BeyondCompare is the best file-comparison tool I’ve found. Cross-platform too, I have it installed on my Mac as well.
Synergy
Synergy allows me to share one mouse and keyboard across all my machines. It works just like dual monitors, except when the mouse moves onto the next screen, you’ve actually changed computer. I don’t have multiple monitors any more, I just switch the input on my giant curved 34” Dell monitor via a keyboard shortcut.
7Zip
Nothing to say.
VS Code
First class support for .NET and C#, Typescript in particular, but VS Code is also extremely good with Javascript, Powershell, Python, Markdown, etc. Multiple cursor support. Cross-platform. Extensions. I’m writing this blog post in VS Code.
Visual Studio
My daily workhorse. I’ve spent more screen time here than anywhere.
Zotero
Keep track of academic papers. Download them for offline reading. Handle citations and bibliographies effortlessly from within Word. Zotero.
Next up
More on Visual Studio in the next post where I go through my essential extensions and tools.
It only seemed to happen when I was working while sitting up on the bed with the computer on my lap. It seemed to be related to the position of the computer or possibly the lid. The computer would sleep. I’d wake it and login again. Continue. Sometimes it would happen once. Sometimes three times in ten minutes. Annoying. I assumed some hardware defect.
Pajamas
Then over several days I cracked it. I realised it never happened when I was wearing pajamas. Very strange.
Reflections
I started thinking about what normally triggers sleep mode. Closing the lid. How does a Macbook know the lid is closed. There’s not really a clasp or anything so it must be a magnet. Perhaps it’s getting confused by my belt buckle or something. My phone?
No, my phone case! The flip-case of my phone has a magnet to keep the flap closed. In my jeans pocket it’s near enough to make the laptop think the lid has been closed. Duh.
I was inspired by two events to jump back into serverless framework.
Firstly, I attended the second London serverless meetup yesterday evening which was excellent and showed just how much enthusiasm there is for serverless architectures. Check out their new logo on the left. It was significant that each of the three speakers announced that they are actively hiring serverless developers.
Secondly, Stolz has contributed improvements to my sample project for integrating PHP into the serverless framework. It’s the purpose of this blog post to cover the changes.
The trick to getting AWS lambda to support PHP is to bundle in a PHP binary so that nodejs can call it with child_process.spawn(). In my first implementation, I used an Ubuntu docker base image to compile and produce the php binary. Unfortunately, this is not identical to the container that AWS Lambda uses and so sometimes the logs would contain errors such as:
12345
START RequestId: 728dcddf-feaa-11e6-8346-2125e1c055d7 Version: $LATEST2017-03-01 18:11:10.455 (+00:00) 728dcddf-feaa-11e6-8346-2125e1c055d7 stderr: ./php: /usr/lib64/libcurl.so.4: no version information available (required by ./php)END RequestId: 728dcddf-feaa-11e6-8346-2125e1c055d7
REPORT RequestId: 728dcddf-feaa-11e6-8346-2125e1c055d7 Duration: 6000.08 ms Billed Duration: 6000 ms Memory Size: 1024 MB Max Memory Used: 23 MB
In my experience, these errors were often not fatal, but the correct approach is to build the php binary from a base image which is closer to the one lambda uses. So instead of my docker file starting with FROM ubuntu, it now starts with FROM amazonlinux. Also, with this image, I can use yum to install other dependencies like libpng-devel. So the new docker build script for producing the php binary looks like this:
# Compile PHP with static linked dependencies# to create a single running binaryFROM amazonlinux
ARG PHP_VERSION
RUN yum install \ autoconf \ automake \ libtool \ bison \ re2c \ libxml2-devel \ openssl-devel \ libpng-devel \ libjpeg-devel \ curl-devel -y
RUN curl -sL https://github.com/php/php-src/archive/$PHP_VERSION.tar.gz | tar -zxv
WORKDIR /php-src-$PHP_VERSIONRUN ./buildconf --force
RUN ./configure \ --enable-static=yes \ --enable-shared=no \ --disable-all \ --enable-json \ --enable-libxml \ --enable-mbstring \ --enable-phar \ --enable-soap \ --enable-xml \ --with-curl \ --with-gd \ --with-zlib \ --with-openssl \ --without-pear
RUN make -j 5
If you run this with
$ sh dockerfile.buildphp
It will use docker to overwrite the php binary which will get shipped when you deploy with sls deploy. And this time, there are no more libcurl errors. All the code is on Github.
The service I’m building connects runs a PHP function for pretty-printing chess games from the lichess online chess server. James Clarke has written a PHP function to do this using fpdf17.
The lichess exporter takes the game id of any game that has been played on the lichess server and produced a PDF output. Take for example, Game 8 of the current World Championship which is here. When I open the resulting file, I see this:
In this blog post I’ll describe how I turned this into a serverless service. The goal is to create:
Add an endpoint which takes the game id as a parameter
Next copy in the source from https://github.com/clarkerubber/lichessPDFExporter.
You can check it works by running the following.
$ php main.php COQChpzH > COQChpzH.pdf
What’s going on here? The php binary (from the serverless-php project) is running main.php (from the lichess-pdf-exporter project) with argument COQChpzH (which corresponds to a chess game on the lichess server. The main.php function downloads the game from the lichess API and passes it through the fpdf17 library to create a pdf stream which is written out to the COQChpzH.pdf file.
Lessons learned
I learned a few things while trying to get this project working. The basic plan is to modify handler.js so that it return the output of the call described above. Turns out there are quite a few gotchas along the way.
Lesson 3 - You can redirect the response to an S3 bucket
So instead of returning the binary output, I can write the output to an S3 bucket and return a 302 redirection to the S3 resource. Like this:
handler.js
12345678910111213141516171819202122232425
// body contains the output from the PHP callconstparams={Bucket:bucket,Key:key,ACL:'public-read-write',Body:body,ContentType:'application/pdf'};// Save the pdf file to S3 s3.putObject(params,function(err,data){if(err){returncallback(newError(`Failedtoputs3object:${err}`));}// respond with a 302 redirect to the PDF fileconstresponse={statusCode:302,headers:{location:`https://s3-eu-west-1.amazonaws.com/${bucket}/${key}`}};returncallback(null,response);
Lesson 4 - You can automatically delete S3 objects after a number of days
Each S3 bucket has optional lifecycle rules where you can specify that files are automatically removed after a time period. I wanted to set this up within the serverless.yml resources section, but the syntax for the lifecycle rules were not very obvious and I could not find any examples online. The following seems to work:
Now look at the php function index.php that we’d like our lambda to call.
index.php
123456
<?php# $argv will contain the event object. You can output its contents like this if you like#var_export($argv, true);printf('Go Serverless v1.0! Your PHP function executed successfully!');
And the handler.js for the hello function looks as follows. It defines a simple lambda which calls the PHP binary, logs any errors and returns the result.
'use strict';varchild_process=require('child_process');module.exports.hello=(event,context,callback)=>{varstrToReturn='';varphp='./php';// workaround to get 'sls invoke local' to workif(typeofprocess.env.PWD!=="undefined"){php='php';}varproc=child_process.spawn(php,["index.php",JSON.stringify(event),{stdio:'inherit'}]);proc.stdout.on('data',function(data){vardataStr=data.toString()// console.log('stdout: ' + dataStr);strToReturn+=dataStr});// this ensures any error messages raised by the PHP function end up in the logsproc.stderr.on('data',function(data){console.log(`stderr:${data}`);});proc.on('close',function(code){if(code!==0){returncallback(newError(`Processexitedwithnon-zerostatuscode${code}`));}constresponse={statusCode:200,body:JSON.stringify({message:strToReturn,//input: event,}),};callback(null,response);});};
Included is the PHP binary to bundle with our serverless function.
(You may need to compile it yourself with different options. See below for help on how to do this.)
Check it works from your shell.
$ php index.php
1
Go Serverless v1.0! Your PHP function executed successfully!
Run it locally through the Serverless Framework.
$ sls invoke local --function hello
123456
Serverless: Your function ran successfully.
{"statusCode": 200,
"body": "{\"message\":\"Go Serverless v1.0! Your PHP function executed successfully!\"}"}
Looks good. Let’s deploy.
$ sls deploy
123456789101112131415161718
Serverless: Packaging service…
Serverless: Uploading CloudFormation file to S3…
Serverless: Uploading service .zip file to S3…
Serverless: Updating Stack…
Serverless: Checking Stack update progress…
..........
Serverless: Stack update finished…
Service Information
service: serverless-php
stage: dev
region: eu-west-1
api keys:
None
endpoints:
GET - https://c1w0hct166.execute-api.eu-west-1.amazonaws.com/dev/hello
functions:
serverless-php-dev-hello: arn:aws:lambda:eu-west-1:962613113552:function:serverless-php-dev-hello
Run the remote function via Serverless.
$ sls invoke --function hello
1234
{"statusCode": 200,
"body": "{\"message\":\"Go Serverless v1.0! Your PHP function executed successfully!\",\"input\":{}}"}
Visit the endpoint in your browser.
123
{"message":"Go Serverless v1.0! Your PHP function executed successfully!"}
Nice. It’s all working.
Rebuilding the PHP binary
Depending on the PHP function you need to run, it may be necessary to rebuild the php binary with different flags and dependencies. You can do this best with docker.
$ docker --version
Docker version 1.12.3, build 6b644ec
Modify dockerfile.buildphp as necessary.
Then run:
$ sh buildphp.sh
This will build a new PHP binary and copy it to the project root. You can immediately deploy for testing with:
$ sls deploy
Thanks
Shout out to Danny Linden whose code got me started on this.
When an XAF list view has no selection-based actions available, the selection box still appears in the grid. Users get confused. In this post, we’ll look at a workaround.
The problem
In the XAF MainDemo, lets make Departments read-only for the User role.
Then start the web application, login as John and navigate to the Departments list view. There is a column selection box, but it serves no purpose. There are no actions that depend on a grid selection.
Without the SelectionColumnVisibilityController
The fix
Here is a controller which calculates whether there are any available actions which require one or more rows to be selected. If there are none, the selection box will not appear.
Add the following controller to the MainDemo.Module.Web project. It hides the selection box if there are no actions which depend on a grid selection.
usingSystem;usingDevExpress.ExpressApp;usingDevExpress.ExpressApp.Actions;usingDevExpress.ExpressApp.Editors;usingDevExpress.ExpressApp.SystemModule;usingDevExpress.Web;usingSystem.Linq;namespaceMainDemo.Module.Web.Controllers{publicclassSelectionColumnVisibilityController:ViewController{publicSelectionColumnVisibilityController(){TargetViewType=ViewType.ListView;}privateboolIsSelectionColumnVisible(){boolisSelectionColumnRequired=false;// remove checkbox if there are no available actionsforeach(ControllercontrollerinFrame.Controllers){if(!controller.Active)continue;if(controller.Actions.Count==0)continue;boolallowEdit=true;if((FrameisNestedFrame)&&(((NestedFrame)Frame).ViewItemisPropertyEditor))allowEdit=(bool)((PropertyEditor)((NestedFrame)Frame).ViewItem).AllowEdit;foreach(ActionBaseactionincontroller.Actions){if(action.SelectionDependencyType==SelectionDependencyType.RequireMultipleObjects){if(action.Active||IsActionInactiveBySelectionContext(action)){if(action.Enabled||IsActionDisabledBySelectionContext(action)){isSelectionColumnRequired=true;break;}}}}if(isSelectionColumnRequired)break;}returnisSelectionColumnRequired;}privateboolIsActionInactiveBySelectionContext(ActionBaseaction){if(action.Active)returntrue;else{foreach(stringiteminaction.Active.GetKeys()){if(item==ActionBase.RequireMultipleObjectsContext||item==ActionBase.RequireSingleObjectContext)continue;if(!action.Active[item])returnfalse;}returntrue;}}privateboolIsActionDisabledBySelectionContext(ActionBaseaction){if(action.Enabled)returntrue;else{foreach(stringiteminaction.Enabled.GetKeys()){if(item==ActionBase.RequireMultipleObjectsContext||item==ActionBase.RequireSingleObjectContext||item==ActionsCriteriaViewController.EnabledByCriteriaKey)continue;if(!action.Enabled[item])returnfalse;}returntrue;}}protectedoverridevoidOnViewControlsCreated(){base.OnViewControlsCreated();ASPxGridViewgrid=((ListView)this.View).Editor.ControlasASPxGridView;if(grid!=null){grid.Load+=grid_Load;grid.DataBound+=grid_DataBound;}}protectedoverridevoidOnDeactivated(){base.OnDeactivated();ASPxGridViewgrid=((ListView)this.View).Editor.ControlasASPxGridView;if(grid!=null){grid.DataBound-=grid_DataBound;grid.Load-=grid_Load;}}voidgrid_Load(objectsender,EventArgse){SetSelectionColumnVisibility(sender,e);}voidgrid_DataBound(objectsender,EventArgse){SetSelectionColumnVisibility(sender,e);}privatevoidSetSelectionColumnVisibility(objectsender,EventArgse){boolisSelectionColumnVisible=IsSelectionColumnVisible();if(!isSelectionColumnVisible){vargrid=(ASPxGridView)sender;varselectionBoxColumn=grid.Columns.OfType<GridViewCommandColumn>().Where(x=>x.ShowSelectCheckbox).FirstOrDefault();if(selectionBoxColumn!=null){selectionBoxColumn.Visible=false;}}}}}
Run the application again and see the difference. Now the grid looks like this. Notice, there is no longer a selection box on the row.
By the way, this is how it looks with old-style XAF web apps.
Sometimes the deadline has arrived and you still have some failing tests. After a discussion with the dev team, you decide to deploy anyway and fix the bugs for the next release. You need to get the build server to ignore the tests.
One way is just to mark the test with the [Ignore] attribute.
123456
[Test][Ignore]// TODO: Fix this test before the next release!publicvoidTest(){// Some failing test code...}
After the weekend, everyone forgets about the ignored tests and they never get fixed.
Instead, I like to do this.
1234567
[Test]publicvoidTest(){if(DateTime.Now<newDateTime(2016,10,17))Assert.Ignore("Temporarily ignored until October 17.");// Some failing test code...}