viernes, 3 de octubre de 2014

Bash script to measure http request times


The other day I created a nice bash script for measuring web site load time. Basically you pass an url you
want to test and the number of times you want to hit it and it returns the total time and promedy.

I use curl to make the http request and it returns me the response time in seconds (like "0.123").

The hard part was to be able to do the maths in bash. First I thought I needed to parse the numbers somehow,
but there is no such thing. I found the command bc and based the script on it to do the math.


Well, here is the code:

# Usage example: 
# sh run-times.sh 40 http://wordpress.com/

times=$1

i=0
sum=0
while [  $i -lt $times ]; do

 # make the request output will be the response time in seconds. 
 output=`curl -w "@curl-format-only-total.txt" -o /dev/null -s $2`

 #multiply by 1000
 ms=`echo "$output * 1000" | bc` 

 sum=`echo "$sum + $ms" | bc`

 #round float to integer
 sum=`printf "%.0f\n" "$sum"` 

 let i=i+1 

done

mean=`echo "$sum / $times" | bc` 

echo "count: $times, total_time: $sum, mean: $mean"


domingo, 13 de julio de 2014

How to update a branch with master

I always forget how to update a branch with all my changes in the master branch. For example in github, I want to update my branch gh-pages with my latest changes in master - so the documentation and examples of my projects are updated. This is how to do it:
git checkout gh-pages
git rebase master
git push

git checkout master

miércoles, 28 de mayo de 2014

How to identify in IRC

Sometimes I need to identify myself on irc chats, mostly freenode.org for programming questions and I often not remember how to. Well this is it:
/nick cancerbero_sgx
/msg NickServ identify my_secret

sábado, 24 de mayo de 2014

Calculate average in javascript

Currently I'm doing a lot of performance improvements in one of our pages in often I need to calculate the average of the numbers in an array. For this I simply write something like the following in a javascript terminal:
(function(a){var c = 0; for(var i in a){c+=a[i]}; return c/a.length})([11.368,  10.065, 4.403])

viernes, 23 de mayo de 2014

How to measure web page load visually using window.performance API

Navigation Timing API, http://www.w3.org/TR/navigation-timing/ provides detailed  measurements about of current web page performance in terms of load time. It support server, requests and browser loading and rendering information. This standar is supported at least by chrome, firefox and IE>=9

The project https://github.com/kaaes/timing provides a visual report for seeing this information. For make it work, in your web page just add the following lines:

var profiler_js = 'https://raw.githubusercontent.com/kaaes/timing/gh-pages/profiler.js'; 
var d = document;
var h = d.getElementsByTagName('head')[0];
var s = d.createElement('script');
var t = new Date();  
s.type='text/javascript';
s.src=profiler_js+'?'+t.getTime();  
s.onload = c;
s.onreadystatechange = function(){
 if(this.readyState == 'loaded'){
  c();
 }
};  
h.appendChild(s);
function c() {
 window.__profiler = window.__profiler || function() {
  var p = new __Profiler();
  p.init();
 }  
 window.__profiler();
 __profiler.scriptLoaded = true;
}

IMHO this is the best way of measure some browser internal stuff like DNS fetching, rendering, html markup parsing, etc.

Also another way of running this profile tools but less intrusive, this is not downloading any extra file is the following:
Include the minified inline version of profile.js:
function __Profiler(){this.totalTime=0;this.barHeight=18;this.timeLabelWidth=50;this.nameLabelWidth=160;this.textSpace=this.timeLabelWidth+this.nameLabelWidth;this.spacing=1.2;this.unit=1;this.fontStyle="11.5px Arial";this.containerPadding=20;this.container=null;this.customElement=false;this.timingData=[];this.sections=[]}__Profiler.prototype.eventsOrder=["navigationStart","redirectStart","redirectStart","redirectEnd","fetchStart","domainLookupStart","domainLookupEnd","connectStart","secureConnectionStart","connectEnd","requestStart","responseStart","responseEnd","unloadEventStart","unloadEventEnd","domLoading","domInteractive","msFirstPaint","domContentLoadedEventStart","domContentLoadedEventEnd","domContentLoaded","domComplete","loadEventStart","loadEventEnd"];__Profiler.prototype.cssReset="font-size:12px;line-height:1em;z-index:99999;text-align:left;font-family:Calibri,'Lucida Grande',Arial,sans-serif;text-shadow:none;box-shadow:none;display:inline-block;color:#444;font-weight:normal;border:none;margin:0;padding:0;background:none;";__Profiler.prototype.elementCss="position:fixed;margin:0 auto;top:0;left:0;right:0;border-bottom:solid 1px #EFCEA1;box-shadow:0 2px 5px rgba(0,0,0,.1);";__Profiler.prototype.containerCss="background:#FFFDF2;background:rgba(255,253,242,.99);padding:20px;display:block;";__Profiler.prototype.headerCss="font-size:16px;font-weight:normal;margin:0 0 1em 0;width:auto";__Profiler.prototype.buttonCss="float:right;background:none;border-radius:5px;padding:3px 10px;font-size:12px;line-height:130%;width:auto;margin:-7px -10px 0 0;cursor:pointer";__Profiler.prototype.infoLinkCss="color:#1D85B8;margin:1em 0 0 0;";__Profiler.prototype._getPerfObjKeys=function(obj){var keys=Object.keys(obj);return keys.length?keys:Object.keys(Object.getPrototypeOf(obj))};__Profiler.prototype._setUnit=function(canvas){this.unit=(canvas.width-this.textSpace)/this.totalTime};__Profiler.prototype._getSections=function(){return Array.prototype.indexOf?[{name:"network",color:[224,84,63],firstEventIndex:this.eventsOrder.indexOf("navigationStart"),lastEventIndex:this.eventsOrder.indexOf("connectEnd"),startTime:0,endTime:0},{name:"server",color:[255,188,0],firstEventIndex:this.eventsOrder.indexOf("requestStart"),lastEventIndex:this.eventsOrder.indexOf("responseEnd"),startTime:0,endTime:0},{name:"browser",color:[16,173,171],firstEventIndex:this.eventsOrder.indexOf("unloadEventStart"),lastEventIndex:this.eventsOrder.indexOf("loadEventEnd"),startTime:0,endTime:0}]:[]};__Profiler.prototype._createContainer=function(){var container=document.createElement("div");var header=this._createHeader();var button=this._createCloseButton();button.onclick=function(e){button.onclick=null;container.parentNode.removeChild(container)};container.style.cssText=this.cssReset+this.containerCss;if(!this.customElement){container.style.cssText+=this.elementCss}header.appendChild(button);container.appendChild(header);return container};__Profiler.prototype._createHeader=function(){var c=document.createElement("div");var h=document.createElement("h1");var sectionStr="/ ";for(var i=0,l=this.sections.length;i<l;i++){sectionStr+='<span style="color:rgb('+this.sections[i].color.join(",")+')">'+this.sections[i].name+"</span> / "}h.innerHTML="Page Load Time Breakdown "+sectionStr;h.style.cssText=this.cssReset+this.headerCss;c.appendChild(h);return c};__Profiler.prototype._createCloseButton=function(){var b=document.createElement("button");b.innerHTML="close this box ×";b.style.cssText=this.cssReset+this.buttonCss;return b};__Profiler.prototype._createInfoLink=function(){var a=document.createElement("a");a.href="http://kaaes.github.com/timing/info.html";a.target="_blank";a.innerHTML="What does that mean?";a.style.cssText=this.cssReset+this.infoLinkCss;return a};__Profiler.prototype._createNotSupportedInfo=function(){var p=document.createElement("p");p.innerHTML="Navigation Timing API is not supported by your browser";return p};__Profiler.prototype._createChart=function(){var chartContainer=document.createElement("div");var canvas=document.createElement("canvas");canvas.width=this.container.clientWidth-this.containerPadding*2;var infoLink=this._createInfoLink();this._drawChart(canvas);chartContainer.appendChild(canvas);chartContainer.appendChild(infoLink);return chartContainer};__Profiler.prototype._prepareDraw=function(canvas,mode,eventData){var sectionData=this.sections[eventData.sectionIndex];var barOptions={color:sectionData.color,sectionTimeBounds:[sectionData.startTime,sectionData.endTime],eventTimeBounds:[eventData.time,eventData.timeEnd],label:eventData.label};return this._drawBar(mode,canvas,canvas.width,barOptions)};__Profiler.prototype._drawBar=function(mode,canvas,barWidth,options){var start;var stop;var width;var timeLabel;var metrics;var color=options.color;var sectionStart=options.sectionTimeBounds[0];var sectionStop=options.sectionTimeBounds[1];var nameLabel=options.label;var context=canvas.getContext("2d");if(mode==="block"){start=options.eventTimeBounds[0];stop=options.eventTimeBounds[1];timeLabel=start+"-"+stop}else{start=options.eventTimeBounds[0];timeLabel=start}timeLabel+="ms";metrics=context.measureText(timeLabel);if(metrics.width>this.timeLabelWidth){this.timeLabelWidth=metrics.width+10;this.textSpace=this.timeLabelWidth+this.nameLabelWidth;this._setUnit(canvas)}return function(context){if(mode==="block"){width=Math.round((stop-start)*this.unit);width=width===0?1:width}else{width=1}context.strokeStyle="rgba("+color[0]+","+color[1]+","+color[2]+",.3)";context.lineWidth=1;context.fillStyle="rgba(255,255,255,0)";context.fillRect(0,0,barWidth-this.textSpace,this.barHeight);context.fillStyle="rgba("+color[0]+","+color[1]+","+color[2]+",.05)";context.fillRect(0,0,barWidth-this.textSpace,this.barHeight);context.shadowColor="white";context.fillStyle="rgba("+color[0]+","+color[1]+","+color[2]+",.2)";context.fillRect(Math.round(this.unit*sectionStart),2,Math.round(this.unit*(sectionStop-sectionStart)),this.barHeight-4);context.fillStyle="rgb("+color[0]+","+color[1]+","+color[2]+")";context.fillRect(Math.round(this.unit*start),2,width,this.barHeight-4);context.fillText(timeLabel,barWidth-this.textSpace+10,2*this.barHeight/3);context.fillText(nameLabel,barWidth-this.textSpace+this.timeLabelWidth+15,2*this.barHeight/3)}};__Profiler.prototype._drawChart=function(canvas){var time;var eventName;var options;var skipEvents=[];var drawFns=[];var context=canvas.getContext("2d");context.font=this.fontStyle;this._setUnit(canvas);for(var i=0,l=this.eventsOrder.length;i<l;i++){var evt=this.eventsOrder[i];if(!this.timingData.hasOwnProperty(evt)){continue}var item=this.timingData[evt];var startIndex=evt.indexOf("Start");var isBlockStart=startIndex>-1;var hasBlockEnd=false;if(isBlockStart){eventName=evt.substr(0,startIndex);hasBlockEnd=this.eventsOrder.indexOf(eventName+"End")>-1}if(isBlockStart&&hasBlockEnd){item.label=eventName;item.timeEnd=this.timingData[eventName+"End"].time;drawFns.push(this._prepareDraw(canvas,"block",item));skipEvents.push(eventName+"End")}else{if(skipEvents.indexOf(evt)<0){item.label=evt;drawFns.push(this._prepareDraw(canvas,"point",item))}}}canvas.height=this.spacing*this.barHeight*drawFns.length;context.font=this.fontStyle;var step=Math.round(this.barHeight*this.spacing);drawFns.forEach(function(draw){draw.call(this,context);context.translate(0,step)},this)};__Profiler.prototype._matchEventsWithSections=function(){var data=this.timingData;var sections=this.sections;for(var i=0,len=sections.length;i<len;i++){var firstEventIndex=sections[i].firstEventIndex;var lastEventIndex=sections[i].lastEventIndex;var sectionOrder=this.eventsOrder.slice(firstEventIndex,lastEventIndex+1);var sectionEvents=sectionOrder.filter(function(el){return data.hasOwnProperty(el)});sectionEvents.sort(function(a,b){return data[a].time-data[b].time});firstEventIndex=sectionEvents[0];lastEventIndex=sectionEvents[sectionEvents.length-1];sections[i].startTime=data[firstEventIndex].time;sections[i].endTime=data[lastEventIndex].time;for(var j=0,flen=sectionEvents.length;j<flen;j++){var item=sectionEvents[j];if(data[item]){data[item].sectionIndex=i}}}};__Profiler.prototype._getData=function(){if(!window.performance){return}var data=window.performance;var timingData=data.timing;var eventNames=this._getPerfObjKeys(timingData);var events={};var startTime=timingData.navigationStart||0;var eventTime=0;var totalTime=0;for(var i=0,l=eventNames.length;i<l;i++){var evt=timingData[eventNames[i]];if(evt&&evt>0){eventTime=evt-startTime;events[eventNames[i]]={time:eventTime};if(eventTime>totalTime){totalTime=eventTime}}}this.totalTime=totalTime;return events};__Profiler.prototype._init=function(){this.timingData=this._getData();this.sections=this._getSections();this.container=this._createContainer();if(this.customElement){this.customElement.appendChild(this.container)}else{document.body.appendChild(this.container)}var content;if(this.timingData&&this.sections.length){this._matchEventsWithSections();content=this._createChart()}else{content=this._createNotSupportedInfo()}this.container.appendChild(content)};__Profiler.prototype.init=function(element,timeout){if(element instanceof HTMLElement){this.customElement=element}if(timeout&&parseInt(timeout,10)>0){var self=this;setTimeout(function(){self._init()},timeout)}else{this._init()}};


And now just run it:
 window.__profiler = window.__profiler || function() {
  var p = new __Profiler();
  p.init();
 }  
 window.__profiler();


Enjoy!

sábado, 14 de diciembre de 2013

La justificación del "trencito"

Del por qué copiar en un exámen no es algo tan malo 


Un exámen en un liceo o universidad es un mecanismo que le permite al docente evaluar los conocimientos de un estudiante, más o menos objetivamente. Aquí hablaremos de un mecanismo que poseen los estudiantes de salvar ése examen llamado trensito (o en inglés cheatsheet).


De http://www.merriam-webster.com/dictionary/cheat%20sheet
1: a sheet containing information (as test answers) used secretly for cheating
2:  a written or graphic aid (as a sheet of notes) that can be referred to for help in understanding or remembering something complex

Tradicionalmente, un trensito consiste en una minificación visual de grandes cantidades de datos, visualizados sobre un papel de tamaño mínimo que puede ser consultado "discretamente" sin que el profesor vea para consultar información relevante durante la prueba. En general la información es seleccionada y estructurada muy objetivamente según las dificultades del autor, por ejemplo "los temas que no estudió" o "aquella fórmula complicada".

En este caso particular la causa de tal mecanismo es que esté prohibido consultar información durante la prueba. Sin embargo el concepto de "trensito" o "cheatsheet" en si se extendió a una técnica de visualización de la información hoy utilizada formalmente por los académicos cuando se tiene la necesidad de mostrar mucha información en una sola hoja, y la técnica se llama ni mas ni menos que cheatsheet. Algunos ejemplos formales:




En mi caso como desarrollador de software y siedo portador de una "mala memoria", dado que tengo que utilizar varios lenguages y tecnologías distintas, cada una con un lenguage o interface textual distinta, las cheat sheets son muy comunes en el ámbito profesional y en general una tecnica muy bien aceptada.

Éste es el principal argumento que afirmamos en contra de la supuesta "maldad" del trensito. La "maldad" como todas "las maldades" es objetiva y definida por un profesor, por eso las siguientes sentencias van para ellos:

Diseñar un trensito es una tarea que implica conocimiento sobre los temas a tratar en un exámen y muy probablemente el estudiante lo haya implementado no porque no estudió, sino porque su memoria "no le da" para tanta información o datos puntuales.

Reconozcan que la información se reproduce y nos invade exponencialmente. Ya pasaron aquellos tiempos en que una persona "sabía de todo", ahora debemos especializarnos intelectualmente si de verdad deseamos ser buenos en algo en la vida.

Reconozcan que la memoria de un ser humano si bien importante, puede verse comprometida ante tanta información, y que cualquier tarea intelectual requiere siempre de herramientas como el lapiz y el papel o la informatica para procesar o transmitir grandes cantidades de información.

Reconozcan que siempre y cuando el estudiante poseedor de un "trensito" sea el autor, entonces el sólo hecho de él mismo haber hecho un trensito el día anterior, implica que algo tuvo que haber estudiado.

Firma: Sebastián Gurin, alguien que se siente del lado del conocimiento pero a quien los exámenes de memoria siempre le costaron mucho.


martes, 5 de noviembre de 2013

lint CSS code

What is "linting" ? Programming languages can all be validated against its syntax reference, but nothing can prevent you to write bad code. Fortunately many common errors can be found in compile time, and especially if we are talking about non typed languages like javascript or CSS. So that's a linter, a compile-time program used to indicate possible mistakes or bad practices detected in our sources.

Today I'm happy because I've found a CSS source code linter recess that seems to be very nice, or at least it has philosophical posture about CSS very similar to mine and this is, in general the principles of Object Oriented CSS.

The CSS linter I've found is developed (and used) for bootstrap 3. I liked all the suggestions the linter tells me but the "Incorrect property order" so I disabled it (yes, there is a correct property order inside a CSS rule definition! ):

#install it
sudo npm install recess -g
recess all-my.css --strictPropertyOrder false

And the best part, it seems to work nicely with less sources
recess all-my.less --strictPropertyOrder false

Also, recess can be used for CSS minification and indentation or formatting of CSS.