Monday 23 December 2013

What is OpenEHR anyway?

I am not an expert in OpenEHR, but I (and the Mexican government by the way) are very interested in knowing the proper way to standardize, store and consult health information. Is almost unnecessary to justify this interest, in one hand the developing of software is too expensive to update and sometimes rebuild entire health systems every eight years to meet the new health requirements and standards. In the other hand, the health information is too important to allow that this information becomes obsolete. Most of the children born after 1995 will reach more than one hundred years of age and we are living in a era where huge amounts of genetic information will be added to the Health Record of every citizen. We must find the way that those Health Records remain always available and ready to be updated for the next century. Piece a cake, right?

Unfortunately, right now the situation is a mess: terabytes of information are --and in many cases always will be-- unreachable and useless because the software companies choose a developing approach which is great to do a LMS, a video game or an insurance tool but is a nightmare in the long run to handle complex and always changing data. Considering that the information contained in a Health Tecord can save the life of someone, somewhere, this is a pretty serious issue.

So, I have been reading the OpenEHR PDFs and until now this is my resumé:

Archetypes have definitions, ontologies and constraints. The process to create a new Archetype is called "modelling" and is do it for medical experts, who in many occasions know nothing about the software and computer world and the don't need to know about it anyway. This is why OpenEHR is called a "two modelling" specification, because the Medical Knowledge Domain remains independent from the Programmer Knowledge Domain. Archetypes are the "lego bricks" that allow us to build a full OpenEHR application and, happily, most of the Archetypes that we could need are already modeled and contained in the CKM:

http://www.openehr.org/ckm/

On the other hand, Templates are a kind of archetypes with "slots", basic archetypes are adapted and embedded in this slots to build the data what we need. For instance the "Annual Medical Check Up" template could be conformed by the "Name", "Age", "Sex", "Blood Pressure", "Is Smoker", "Heart Rate", "Menopause", etc, etc, archetypes. Templates are expressed in screen forms showing the data points of its archetypes. When you insert the basic archetypes in the template's slots you can remove parts of the basic archetypes that you don't need. So templates are nearest to a real application.

Templates are "compiled" to generate the Operational Templates (OT). This OT connect the medical world (i.e. the doctors who defined the archetypes and templates) with the programmers world and contain the info to build the models (the "M" in MVC) using Java, C#, Ruby, whatever. This pass from archetypes (health experts domain) to concrete classes (software experts domain) is make it through the Reference Model and the Archetype Object Model.

Having the Models derived from the OTs, the data can now be stored in MySQL, PosgtreSQL, whateverSQL, like any other MVC software. The Archetype Query Language allows extract data from the system if you want to build a RESTful based API to be consulted for external entities. This video explains the templates process:

Thursday 14 November 2013

Hashing password as devise do

I am stuck in an stupid office waiting for some seal, so in order to not to lose all my day I guess I would write some tip, many of this tips are for my future myself because I hate when I've spent two hours resolving a problem and half year later I need start searching all over again, sometimes is just a parameter in a command sometimes a lib I need to compile emacs. If you are a developer you know what I'm talking about ;-)

The problem: sometimes I just wanna update a password manually using PostgreSQL console or sometimes I wanna create the initial user settled in seeds.rb file, so to do this I need hash the password first. We do this entering in the rails console:

$ bundle exec rails c RAILS_ENV=development

And now the hash:

hashed_password = ::BCrypt::Password.create("s0m3HardAndNewP44ss")

Update the user model:

user = User.find(456)
user.update_attribute('encrypted_password', hashed_password)

Or you can do it in the old SQL way:

UPDATE users SET encrypted_password='$2a$10$4R.gf6j9AmV4GAgszYVLxeCa' WHERE id=456;

And that is all!!

Monday 23 September 2013

Symfony 2.3 para impacientes

Una empresa me pide que le actualice su intranet del 2002. Es una empresa mediana, sin mucho soporte, ponerles Ruby On Rails les elevaría mucho los costos. Aquí PHP es buena opción. Como ya conozco CakePHP al derecho y al revés me parece que es una buena oportunidad de echarle ojo a Symfony. Como soy mexicano, valiente y bragao, uso Emacs y PostgreSQL para evitar de Vim y MySQL. ;-)

Aquí se los resumo pués:

1) Instalar composer:

$curl -sS https://getcomposer.org/installer | php

2) Ejecutar:

$ php ./composer.phar create-project symfony/framework-standard-edition intranet 2.3.1

database_driver (pdo_mysql):pdo_pgsql
database_host (127.0.0.1):
database_port (null):5432
database_name (symfony):DBSYMFONY
database_user (root):postgres
database_password (null):*********
mailer_transport (smtp):
mailer_host (127.0.0.1):
mailer_user (null):
mailer_password (null):
locale (en):
secret (ThisTokenIsNotSoSecretChangeIt):

3) Una checadita:

$ php app/check.php

4) En una nueva consola de tmux corremos el the built-in web server:

$ php app/console server:run

5) Browser:

http://localhost:8000/config.php

6)creamos la DB:

$ php app/console doctrine:database:create

7) Los bundles son las pequeñas "apps" con las que está construido nuestro proyecto web, son como las apps de Django. Esta modularización es un plus de este framework. Symfony usa los NameSpaces de PHP 5.4, de este modo el nombre de los name spaces en los bundles sigue este criterio: NombreDeLaEmpresa/NombreDelProyecto/NombreDelModelo. Asi pues creamos nuestro primer bundle:

$ php app/console generate:bundle --namespace=GCP/Intranet/ImagesBundle --no-interaction --dir=./src --format=yml

OJOOOO!!!: Symfony soporta diferentes tipos de formatos en la configuración de los bundles (php, yaml, xml, annotation) pero no soporta mezclas entre ellos, los bundles deben ser todos con el mismo formato.

8) Ahora creamos una entity de Doctrine, en Ruby On Rails sería algo así como:

$rails g scaffold Image file:string tags:string user_id:integer

En Symfony:

$php app/console generate:doctrine:entity --entity=GCPIntranetImagesBundle:Image --format=yml --fields="file:string(100) tags:string(255) user_id:integer"

La columna "id serial" de PostgreSQL, Doctrine la crea por default y no es necesario ponerla.

9) Ahora queremos el CRUD para este modelo:

$php app/console generate:doctrine:crud --entity=GCPIntranetImagesBundle:Image --format=yml --with-write --no-interaction

10) Ahora hacemos la migración de la entity de Doctrine a PostgreSQL:

$php app/console doctrine:schema:update --force

Entiendo a los que les gusta Symfony, y supongo que entre más se usa, más se le toma gusto. Pero al principio la configuración de tantos archivos puede resultar tediosa pues por alguna razón el exitosísimo princpio "convención sobre configuración" brilla por su ausencia en Symfony.

Saturday 29 June 2013

Rails: changing templates by action

One of the main principles that I like follow when I am developing a Web application is: in your web app, the front end never must looks like your back end. That is, the admin zone and the public area must have their own CSS classes and layouts. The regular user, the admin and even the anonymous visitant to the site must feel clear the difference between one and another areas.

Typically we use Devise gem to set the actions that we wanna keep restricted and in most of the cases that areas share the same action names: new, edit, create, destroy, update, show. So in many cases those are the actions that we wanna present with the "admin" layout.

So in our app/controllers/application_controller.rb file we add the method:

# @@ - Class variable with actions 
@@actions = %w(new edit create destroy update index start show)

 # Layout for action method
 def layout_by_action
     action = params[:action]
     #raise action_name
     if @@actions.include?(action)
         self.class.layout "admin"
     else
         self.class.layout "application"
     end
end

And in the controller where we want to show different layouts we add:

 # load proper layout
  before_filter :layout_by_action

et voilà!, we have our admin restricted area. Of course you must have an admin layout like this in the views layout directory.

Wednesday 26 June 2013

First Crud in Rails+Angular JS



Get the whole code here: https://github.com/aarkerio/rails-angularjs

This a howto about how create your first R+AJS. AngularJS (AJS) is an Ecmascript framework that gives a further and deeper step into the DOM-Javascript merge. AJS is a bidirectional framework, this means that DOM elements and the Javascript code are under an uninterrupted communication and using the $scope object as the application "glue". This "magic link" will saves you many problems and will improve your productivity. This more completes and advanced features are the reason of why AJS is chosen over another options as Backbone.  

 
As you can all starts with the classic:

$ rails new myangular

Now you must download angular.min.js from the angular site currently 1.0.6 and set in the dir APP/assets/javascripts.

Now we create the dirs wee need:

$ mkdir app/assets/javascript/angular
$ mkdir app/assets/javascript/angular/controllers

The Task controller:


// file: app/assets/javasript/angular/controller/tasks_controller.js

'use strict';

Site.controller('crudController', ['$scope', 'Task', 'Tasks', 'EditTask', function($scope, Task, Tasks, EditTask) {

 $scope.orderProp = 'description';
 $scope.tasks = Tasks.get();  // initial fill

 $scope.$watch('tasks', function() {
   console.log('scope.tasks has changed');
  }, true);
 // add task
 $scope.addTask = function(task) {
    Task.save({task:task});
    console.log('addTask: getTasks function'+JSON.stringify($scope.tasks));
    $scope.task.description = '';   // clean form
    $scope.tasks = Tasks.get();  // refill list
  };

  // edit 
  $scope.EditCtrl = function(task) {
        $scope.task = EditTask.get();
        console.log('EditCtrl function'+JSON.stringify(task));
        //console.log('addTask: getTasks function'+JSON.stringify($scope.task));
        //$scope.task = {'task':task};
  };
  
  // remove
  $scope.removeTask = function(task) {
    console.log(task);
    var deleteUser = confirm('Are you absolutely sure you want to delete?'); 
    if (deleteUser) 
    {
        $scope.id = task.id;
        Task.delete({id:task.id});      // services task.js
        // $scope.tasks = Tasks.get();  // refill list
        $scope.tasks = Tasks.get();    // refill list
    }
  };
}]);

Site.controller('TaskDetailCtrl', ['$scope', '$location', '$routeParams', 'Task', 'Tasks', 'EditTask', function($scope, $location, $routeParams, Task, Tasks, EditTask) {
   console.log('TaskDetailCtrl: '+JSON.stringify($routeParams));
   $scope.task = EditTask.get($routeParams);
   // console.log('scope.task:' + JSON.stringify( $scope.task ));
   // update
    $scope.updateTask = function(task) {
      console.log('update function task:' + JSON.stringify(task));
      //console.log($routeParams);
      Task.update({id:task.id}, task);
      $location.path('/tasks');
   };

  // remove
  $scope.removeTask = function(task) {
     console.log(task);
     var deleteUser = confirm('Are you absolutely sure you want to delete?'); 
     if (deleteUser) 
     {
         $scope.id = task.id;
         Task.delete({id:task});  // services task.js
         $location.path('/tasks');
     }
  };

}]);

function TaskShowCtrl($scope, $location, $routeParams, $dialog, Movie) {"use strict";
    $scope.task = Task.show({
        task_id : $routeParams.task_id
    });
} 

The app file:

// file: app/assets/javascripts/angular/app.js
'use strict';

// Declare app level module which depends on filters, and services
var services    = angular.module("crudServices", []); 
var controllers = angular.module("crudController", []);
var Site        = angular.module('Site', ['ngResource', 'crudServices', 'crudController']);

Site.config(function ($routeProvider, $locationProvider) {
  $routeProvider
                .when('', {redirectTo: '/' })
                .when('/tasks', {templateUrl: '/assets/angular/partials/tasks/index.html', controller: 'crudController'})
                .when('/tasks/:id', {templateUrl:'assets/angular/partials/tasks/show.html', controller:TaskShowCtrl})
                .when('/tasks/:id/edit', {templateUrl:'detail.html', controller:'TaskDetailCtrl'})
                .otherwise({redirectTo:"/"});
  // configure html5 to get links working on jsfiddle
  $locationProvider.html5Mode(true);
});

// Rails Token
Site.config(['$httpProvider', function(provider) {
  provider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content');  // this needs jquery
  provider.defaults.headers.post["Content-Type"]   = "application/json; charset=UTF-8";
}]);

The directive file:

// file: app/assets/javascripts/angular/directives/tasks_directives.js
Site.directive('editInPlace', function() {
  return {
    restrict: 'A',
    scope: { value:"=editInPlace" },
    template: '',
    link: function ( $scope, element, attrs ) {
      // Let's get a reference to the input element, as we'll want to reference it.
      var inputElement = angular.element( element.children()[1] );
      
      // This directive should have a set class so we can style it.
      // element.addClass( '.edit-in-place' );
      
      // Initially, we're not editing.
      $scope.editing = false;
      
      // ng-click handler to activate edit-in-place
      $scope.edit = function () {
            $scope.editing = true;
        
            // We control display through a class on the directive itself. See the CSS.
            element.addClass( 'active' );
        
            // And we must focus the element. 
            // `angular.element()` provides a chainable array, like jQuery so to access a native DOM function, 
            // we have to reference the first element in the array.
            inputElement[0].focus();
      };
      
      // When we leave the input, we're done editing.
      inputElement.prop('onblur', function() {
          $scope.editing = false;
          element.removeClass( 'active' );
      });
    }
  };
});

Create macro and create directory inside Emacs 23

These are little notes for my hard head:

1) Create an save a macro:

C-x (   Starts "recording" the macro
C-x )   Ends macro

C-x C-k n  assign a name for the last macro recorded.
M-x  macro-name  execute macro

2) Create a linux directory inside emacs:

M-x make-direct [RET]