Good approach to organize your teams at GitHub

One of the most complicated things nowadays is how to maintain our workspace well organized. It’s not about plannings and projects at all, but in a single point¬† that we can improve everything continuously. And a great point is: everything that you don’t pay attention, maybe will be a problem in future and the things get bigger sometimes.

We have many developers and outsourcing partners working joined to our GitHub account. The company already started and is starting many projects at same time, so the developers manegement accounts must be made in a effective way. I thought in some strategies to handle that and I think that the better way to solve this little puzzle was to group developers by skills. Except to keep business security, maybe it’s interesting to keep just outsourced guys in a different group and give them the desired permission.

Why Skills?

At first you can have a skill mapping of your team. It’s a great overview to understand how your IT environment is established.

If you have a developers group organized by skills, you can have a clear map of what kind of developers that you need to maintain your applications running.

Let’s imagine a scenario that you have many teams working in different projects, and much of them are writing code using the same computer language. Just for an example, let’s say that this guys are using NodeJs for that, and to facilitate our example we are talking about group A and group B. So, if you organize your team putting all NodeJS skilled guys in a common group, you’ll have a good knowledge transfer and will be improving team’s relationship. As a matter of fact that they are working in distinct projects, they will be able to consulting each other codes and be opened to change and share knowledge every time. Your whole team will have better communication and they will be always at the same point.

When you keep the group A and B separated by the project, you just broken the chain that it would be continuous. If a guy from group A elaborates a good solution to his project, maybe it can serve as example and base skill to some guy in group B. It doesn’t matter the order that solutions come from, you’ll extend your knowledge base to all guys. You also can think that if a guy from group A made not a such good solution to some problem that he was handling, this can be identified, improved and suggested by a guy from group B. Coding review?

Another interesting point that you can keep in mind is that, if you needed to add more resources to group B, and group A is in a stable state of work, you could easily identify the right guy and move him to help.

When you already is using git, you probably have a good communication performance, and I think that if you organize your team as above, you can achieve more benefits that you already have.

Advertisements

Piwiki: most viewed pages

I needed to develop a job that was to listen the most clicked questions in a FAQ. The initial solution was to develop some service that would do that, but nowadays some minutes on google is just enough, and so on, my answer was Piwiki.

Piwiki is very powerful analytics solution, and a big deal is that you can use an API provided by this. Better than this, it’s free and very documented. ūüôā That was the dart in the target. If you need something like that, it’s a cake recipe, take a look above.

1. Install Piwiki
2. Create a new website to have the measures
3. Create a new user with grant to view the API methods
4. Put the piwiki code inside your page
5. Create trackpage events on every link that you want
6. And for finish, get the JSON with the most accessed URLs

1. Installing Piwiki

It’s a piece of cake to install Piwiki, just take a look here: http://piwik.org/docs/installation/. Next.

2. Create a new website to have the measures

You can see here: http://piwik.org/docs/manage-websites/#toc-add-a-website

The only consideration here is that if you’re planning to measure URLs that uses hashes in its structure. If you wanna use that, just say yes to the question “Keep Page URLs fragments when track Page URLs”. Don’t you know what I’m saying? This is an example: yousite.com/faq/#first-question.

Keep the website id to be used in the javascript track code.

3. Create a new user with grant to view the API methods

You can see here: http://piwik.org/docs/manage-users/#toc-create-users

Just keep the user’s token_auth to be used in your API request. Next.

4. Put the piwiki code inside your page

It’s very simple. Take a look:

<!-- Piwik -->
<script type="text/javascript">
var _paq = _paq || [];
_paq.push(["trackPageView"]);
_paq.push(["enableLinkTracking"]);

(function() {
var u=(("https:" == document.location.protocol) ? "https" : "http") + "://YOUR_PIWIKI_URL_HERE/";
_paq.push(["setTrackerUrl", u+"piwik.php"]);
_paq.push(["setSiteId", "YOUR_WEBSITE_ID_HERE"]);
var d=document, g=d.createElement("script"), s=d.getElementsByTagName("script")[0]; g.type="text/javascript";
g.defer=true; g.async=true; g.src=u+"piwik.js"; s.parentNode.insertBefore(g,s);
})();
</script>
<!-- End Piwik Code -->

5. Create trackpage events on every link that you want

An example:

<a href="#first-question" onclick="javascript:_paq.push(['trackPageView', '/#first-question'])">First question: I wanna track this!</a>

6. And for finish, get the JSON with the most accessed URLs

Just keep in mind that you need to realize some clicks in your links to get this report with some information. ūüôā

Call this in your Piwiki URL service, don’t forget to replace the TOKEN_AUTH and WEBSITE_ID to get the JSON correctly. The URL was broken in some pieces to be more understandable, just put everything together to get working.

/?module=API
&method=Actions.getPageUrls
&idSite=WEBSITE_ID
&period=month
&date=today
&format=JSON
&token_auth=TOKEN_AUTH
&expanded=1

In this example I set the period to a month, starting with the date “today”.

Utilizando o puLP para modelar problemas de programa√ß√£o linear em python

O puLP é um modelador de programação linear escrito em python. Ele pode gerar MPS ou arquivos LP e chamá-los via GLPK. Ele faz chamada externa dos resolvedores de PL (GLPK, CPLEX, XPRESS, etc) para resolver estes modelos e exibir a solução.

Instalação

Instalar o puLP é realmente simples utilizando o pypi ou easy_install. Veja:

$ sudo apt-get install glpk
$ sudo easy_install pulp

Testando a instalação

$ python
>>> from pulp import *
>>> pulpTestAll()

Modelando um problema real com puLP

Utilizei o problema da dieta descrito no livro “Marins, Fernando Augusto Silva: Introdu√ß√£o √† Pesquisa Operacional – S√£o Paulo: Cultura Acad√™mica: Universidade Estadual Paulista, Pr√≥-Reitoria de Gradua√ß√£o, 2011”. A descri√ß√£o do problema encontra-se no pr√≥prio script.

#!/usr/bin/python
# coding: utf-8
#
# file: dieta.py 
#
# Obter uma dieta de mínimo custo que satisfaça as
# necessidades básicas do indivíduo médio, com
# respeito a Calorias (min. 3,0), C√°lcio (min. 0,8)
# e Vitamina B12 (min. 2,7).
#
# +--------------------+----------+-----------+--------+--------+--------+--------+
# | Alimento/Nutriente | Farinha  | Leite po  | Queijo | Figado | Batata | Feij√£o |
# +--------------------+----------+-----------+--------+--------+--------+--------+
# | Calorias           | 44,7     | 8,4       | 7,4    | 2,2    | 9,6    | 26,9   |
# +--------------------+----------+-----------+--------+--------+--------+--------+
# | C√°lcio             | 2,0      | 19,1      | 16,4   | 0,2    | 2,7    | 11,4   |
# +--------------------+----------+-----------+--------+--------+--------+--------+
# | Vitamina B12       | 33,2     | 23,5      | 10,3   | 50,8   | 5,4    | 24,7   |
# +--------------------+----------+-----------+--------+--------+--------+--------+
# | Custos             | 10,8     | 20,5      | 22,5   | 21,2   | 16,1   | 15     |
# +--------------------+----------+-----------+--------+--------+--------+--------+
#
import sys
from pulp import *

# Cria o problema
prob = LpProblem("Problema da Dieta", LpMinimize)

# Cria as variaveis
x1 = LpVariable("Farinha", 0)
x2 = LpVariable("Leite", 0)
x3 = LpVariable("Queijo", 0)
x4 = LpVariable("Figado", 0)
x5 = LpVariable("Batata", 0)
x6 = LpVariable("Feijao", 0)

# Cria a funcao objetivo
prob += 10.8 * x1 + 20.5 * x2 + 22.5 * x3 + 21.2 * x4 + 16.1 * x5 + 15 * x6, "Total custos"

# Restricoes
prob += 44.7 * x1 + 8.4 * x2 + 7.4 * x3 + 2.2 * x4 + 9.6 * x5 + 26.9 * x6 >= 3, "Calorias requeridas"
prob += 2 * x1 + 19.1 * x2 + 16.4 * x3 + 0.2 * x4 + 2.7 * x5 + 11.4 * x6 >= 0.8, "Calcio requerido"
prob += 33.2 * x1 + 23.5 * x2 + 10.3 * x3 + 50.8 * x4 + 5.4 * x5 + 24.7 * x6 >= 2.7, "Vitaminas B12 requeridas"

# Escreve o modelo no arquivo
prob.writeLP("DietaModelo.lp")

# Resolve o problema
prob.solve()

# Imprime o status da resolucao
print "Status:", LpStatus[prob.status]

# Solucoes otimas das variaveis
for variable in prob.variables():
   print "%s = %f" % (variable.name, variable.varValue)

# Objetivo otimizado
print "Custo total dos ingredientes da dieta: R$ %0.2f" % value(prob.objective)

Saída do programa

Esta é saída padrão do modelo que encontra-se no arquivo DietaModelo.lp:

\* Problema da Dieta *\
Minimize
Total_custos: 16.1 Batata + 10.8 Farinha + 15 Feijao + 21.2 Figado
 + 20.5 Leite + 22.5 Queijo
Subject To
Calcio_requerido: 2.7 Batata + 2 Farinha + 11.4 Feijao + 0.2 Figado
 + 19.1 Leite + 16.4 Queijo >= 0.8
Calorias_requeridas: 9.6 Batata + 44.7 Farinha + 26.9 Feijao + 2.2 Figado
 + 8.4 Leite + 7.4 Queijo >= 3
Vitaminas_B12_requeridas: 5.4 Batata + 33.2 Farinha + 24.7 Feijao
 + 50.8 Figado + 23.5 Leite + 10.3 Queijo >= 2.7
End

Como resultado o script em python me retornou os seguintes valores:

GLPSOL: GLPK LP/MIP Solver, v4.45
Parameter(s) specified in the command line:
 --cpxlp /tmp/2620-pulp.lp -o /tmp/2620-pulp.sol
Reading problem data from `/tmp/2620-pulp.lp'...
3 rows, 6 columns, 18 non-zeros
12 lines were read
GLPK Simplex Optimizer, v4.45
3 rows, 6 columns, 18 non-zeros
Preprocessing...
3 rows, 6 columns, 18 non-zeros
Scaling...
 A: min|aij| =  2.000e-01  max|aij| =  5.080e+01  ratio =  2.540e+02
GM: min|aij| =  2.230e-01  max|aij| =  4.484e+00  ratio =  2.011e+01
EQ: min|aij| =  4.973e-02  max|aij| =  1.000e+00  ratio =  2.011e+01
Constructing initial basis...
Size of triangular part = 3
      0: obj =   0.000000000e+00  infeas =  3.417e-01 (0)
*     4: obj =   1.672862454e+00  infeas =  0.000e+00 (0)
*     7: obj =   1.326169928e+00  infeas =  0.000e+00 (0)
OPTIMAL SOLUTION FOUND
Time used:   0.0 secs
Memory used: 0.0 Mb (45875 bytes)
Writing basic solution to `/tmp/2620-pulp.sol'...
Status: Optimal
Batata = 0.000000
Farinha = 0.033487
Feijao = 0.064300
Figado = 0.000000
Leite = 0.000000
Queijo = 0.000000
Custo total dos ingredientes da dieta: R$ 1.33

Em negrito as solu√ß√Ķes encontradas para o problema, e por fim a solu√ß√£o √≥tima encontrada para o custo final foi de R$ 1.33.

OTRS: adding a new button to move all messages that you want to Spam

It’s a good ideia to use OTRS to manage tickets and have a good Service Desk in your business, but sometimes you a have a lot of bad messages and you need to move them to Spam. It turns into a nightmare on OTRS, ’cause you can only select a single message and move that. I didn’t know about that before a see a guy using it, so I decided to make his life better and I made this little code and think that it can helps you too.
Edit your OTRS file {YOUR_INSTALL_PATH}/Kernel/Output/HTML/Standard/AgentTicketOverviewPreview.dtl and insert the code below after 27th line:

<ul style="float:left;margin:6px 0 0 5px;">
<li>
<a href="javascript:void(0);" id="spam-all" style="display:inline;">Spam All</a>
<script type="text/javascript">
$(document).ready(function(){
  $('#spam-all').click(function() {
     var t = $("input[name='TicketID']:checked").length;

     if( t > 1 ) {
       var d=0,f=0;

       for(i=0;i<t;i++) {
          var msg = $("input[name='TicketID']:checked").eq(i).val();

          $.ajax({
             url: '/index.pl?Action=AgentTicketMove;TicketID='+msg+';DestQueue=Spam',
             type: 'GET',
             error: function() { f++; }
          });
       }

       if(f == 0) {
          alert('All messages moved!');
       } else {
          alert(f+' messages failed');
       }

       location.reload();
     }
  });
});
</script>
</li>
</ul>

Simple pie chart with HTML5

I needed to use some charts in my system, so I’ve decided to code something in HTML5 and to pass all¬†dirty processing job to the user navigator.

After reading a little about canvas object, I got this code below:

$(document).ready( function() {
	var getColors = function( total ) {
		var r,g,b = 0;
		var colors = new Array();

		for( var i = 0; i < total; i++ ) {
			r = Math.abs(Math.floor(Math.random()*254));
			g = Math.abs(Math.floor(Math.random()*254));
			b = Math.abs(Math.floor(Math.random()*254)); 

			colors[i] = 'rgb('+r+','+g+','+b+')';
		}

		return colors;
	};

	var graph = function(obj, width, height, values, colors) {
		if( values.length == 0 && $('#'+obj).attr('id') == '' ) {
			return false;
		} else {
			var canvas = $('#'+obj)[0];

			if( !canvas.getContext ) {
				alert('Problem to load canvas, try moving your javascript code before ');
				return false;
			}
		}

		var total = 0;
		var percent = [];

		for(var i in values) {
			total += values[i];
		}

		if( typeof(colors) != 'object' && !(colors instanceof Array) ) {
			var colors = [];
			colors = getColors(values.length);
		}

		canvas.width = width;
		canvas.height = height;
		var context = canvas.getContext('2d');
		var angle_start = 0;
                var angle_end = 0;
		var point = [width/4, height/2];
		var pointradius = [width/2, height/2];
		var legend_x = pointradius[0]+((5*100)/width);
		var legend_y = pointradius[1] - height/7;
		var rect_size = (30*100)/width;
		var radius = Math.min( pointradius[0], pointradius[1] ) / 1.2;

		for(var i in values) {
			percent[i] = values[i] * 2 / total;
			angle_end += percent[i];
        	        context.beginPath();
			context.arc(point[0],point[1],radius,Math.PI*angle_start,Math.PI*angle_end,false);
			context.lineTo(point[0],point[1]);
			context.fillStyle = colors[i];
			context.fill();
			context.beginPath();
			context.rect(legend_x,legend_y,rect_size,rect_size);
			context.fillStyle = colors[i];
			context.fill();
			context.beginPath();
			context.font = '12px sans-serif';
			context.fillText(values[i].toFixed(2)+'%',(legend_x + rect_size + (15*100/width) ),(legend_y + rect_size ));
			context.fillStyle = '#000000';
			context.fill();
			angle_start += percent[i];
			legend_y += rect_size + (40*100/width);
		}
	};
)}

It has a very simple usage, just save the code above in a file named graph.js and take a look:

<!DOCTYPE>
<html>
<head>
	<script type="text/javascript" src="graph.js">&lt;/script>
	<meta http-equiv="content-type" content="charset=utf-8" />
        <meta http-equiv="X-UA-Compatible" content="chrome=1" />
</head>
<body>
	<canvas id="pieChartId">If you are reading this please download http://code.google.com/intl/pt-BR/chrome/chromeframe/</canvas>
	<script type="text/javascript">graph('pieChartId',400,200,[100,200])</script>
</body>
</html>

The example above will generate charts with random colors, but if you prefer to use your color scheme, just pass an array with the same amount of itens passed in the values array, so we have something like:

graph('pieChartId',400,200,[100,200],['#ff0000','#000000']);

Converting your MySQL tables to mongodb collections

I needed to convert my mySQL database to mongodb collections. So I’ve written a PHP script to make this dirty work. It’s very simple to convert and if you need something like that, just copy the script below and run it. Pay attention if you have memory to get all entries in MySQL, if you don’t have just implement a new code to paginate the query to get these entries. Im my case I just used 500.000 entries and stopped here.

<?php
function getMyTables( $dbname ) {
 $tables = array();
 $sql = mysql_query("SHOW TABLES FROM $dbname ") or die("Error getting tables from $dbname");

 if( mysql_num_rows( $sql ) > 0 ) {
   while( $table = mysql_fetch_array( $sql ) ) {
     $explain = explainMyTable( $table[0] ); 
     $tables[$table[0]] = $explain;
    }
 }
 return $tables;
}

function explainMyTable( $tbname ) {
  $explain = array();
  $sql = mysql_query("EXPLAIN $tbname") or die("Error getting table structure");
  $i = 0;

  while( $get = mysql_fetch_array( $sql ) ) {
     array_push( $explain, $get[0] ); 
     $i++;
  }
  return $explain;
}

function checkEncode($string) {
  if( !mb_check_encoding($string,'UTF-8')) {
    return mb_convert_encoding($string,'UTF-8','ISO-8859-1');
  } else {
    return $string;
  }
}

$mydb   = "YOUR_MYSQL_DB_NAME";
$myconn = mysql_connect('MYSQL_HOST','MYSQL_USER','MYSQL_PASS');
$setmydb   = mysql_select_db( $mydb );
$mytables = getMyTables( $mydb );

$modb   = "YOUR_MONGO_DB_NAME";

try {
  $moconn = new Mongo();
  $modb = $moconn->selectDB( $modb );
} catch(MongoConnectionException $e) {
  die("Problem during mongodb initialization. Please start mongodb server.");
}

foreach( $mytables as $table => $struct ) {
  $sql = mysql_query("SELECT * FROM $table LIMIT 0 , 500000") or die( mysql_error() );
  $count = mysql_num_rows( $sql );

  // Starts new collection on mongodb
  $collection = $modb->$table;

  // If it has content insert all content
  if( $count > 0 ) {
    while( $info = mysql_fetch_array( $sql, MYSQL_NUM )) {
      $infosize = count( $info );
      $mosql = array();

      for( $i=0; $i < $infosize; $i++ ) {
        $mosql[$struct[$i]] = checkEncode($info[$i]);
  }

  $collection->insert($mosql);
  }
// Only create a new entry empty
} else {
  for( $i=0; $i < $infosize; $i++ ) {
    $mosql[$struct[$i]] = '';
  }

  $collection->insert($mosql);
  }
}

echo "Done! Please, check your mongodb collection and have fun!";
?>

Fixing Latin1 problem with accentuation on typeface

I’ve been using typeface to render my websites fonts. It’s a good tool, but some characters were broken during typeface render on latin1 encoding. ¬†At the typeface website doesn’t have some recommendations to insert the correct charset inside <script> tag. So it’s easy to fix the problem, look that:

<script charset="utf-8" src="your_typeface_font.js"></script>