<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Luminescente &#187; Code</title>
	<atom:link href="http://luminescente.com/category/code/feed/" rel="self" type="application/rss+xml" />
	<link>http://luminescente.com</link>
	<description>Just another WordPress weblog</description>
	<lastBuildDate>Tue, 07 Feb 2012 22:38:05 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>window.scrollTo for WebOS / Palm Pre</title>
		<link>http://luminescente.com/2010/03/window-scrollto-for-webos-palm-pre/</link>
		<comments>http://luminescente.com/2010/03/window-scrollto-for-webos-palm-pre/#comments</comments>
		<pubDate>Mon, 29 Mar 2010 12:54:48 +0000</pubDate>
		<dc:creator>Pedro Cardoso</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[palm pre]]></category>
		<category><![CDATA[scrollto]]></category>

		<guid isPermaLink="false">http://luminescente.com/?p=531</guid>
		<description><![CDATA[As WebOS wraps the app content inside a scene/stage structure, scrolling does not work like in other widget runtimes, as you can see here. So, how to manipulate the scrolling position using Javascript? Simple, you search for #mojo-scene-main-scene-scroller and set its scrollTop/Left position. var scroller = document.getElementById("mojo-scene-main-scene-scroller"); if (scroller) { scroller.scrollTop = y; }]]></description>
			<content:encoded><![CDATA[<p>As WebOS wraps the app content inside a scene/stage structure, scrolling does not work like in other widget runtimes, as you can see <a href="http://uxebu.com/blog/2009/12/02/mobile-cross-platform-development-palm-pre/">here</a>.</p>
<p>So, how to manipulate the scrolling position using Javascript? </p>
<p>Simple, you search for #mojo-scene-main-scene-scroller and set its scrollTop/Left position.</p>
<p><code>
<pre>var scroller = document.getElementById("mojo-scene-main-scene-scroller");
if (scroller) {
	scroller.scrollTop = y;
}
</pre>
<p></code></p>
]]></content:encoded>
			<wfw:commentRss>http://luminescente.com/2010/03/window-scrollto-for-webos-palm-pre/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Codebits Challenge 4</title>
		<link>http://luminescente.com/2009/11/codebits-challenge-4/</link>
		<comments>http://luminescente.com/2009/11/codebits-challenge-4/#comments</comments>
		<pubDate>Sun, 22 Nov 2009 19:22:03 +0000</pubDate>
		<dc:creator>Pedro Cardoso</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Codebits]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[quiz]]></category>

		<guid isPermaLink="false">http://luminescente.com/?p=507</guid>
		<description><![CDATA[Já acabou o quiz 4 do Codebits, e poucos quizzes me deram tanto gozo fazer como este, pelo que acho que seria interesante fazer um post sobre o assunto. Esta foi a minha participação, mas incorpora várias sugestões de colegas do trabalho que estão perto de mim e que felizmente percebem mais disto que eu. [...]]]></description>
			<content:encoded><![CDATA[<p>Já acabou o quiz 4 do Codebits, e poucos quizzes me deram tanto gozo fazer como este, pelo que acho que seria interesante fazer um post sobre o assunto. Esta foi a minha participação, mas incorpora várias sugestões de colegas do trabalho que estão perto de mim e que felizmente percebem mais disto que eu. Kudos! <img src='http://luminescente.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>A ideia era simples: implementar uma função em Javascript para listar os programas que dão num canal com um nome que contém uma determinada substring, menores que um determinado número de minutos. Isto no menor número de caracteres possível. Não vou documentar o processo todo, que o quiz foi há duas semanas e já não me lembro de tudo, mas deve dar para perceber o que se tem que fazer neste casos.</p>
<p>Vendo a página de serviços do SAPO, vemos que temos que aceder a dois serviços. Um para determinar a lista de canais para saber a sigla dos que tenham no nome a substring desejada, e outro para pedir a programação destes canais para o dia desejado. A filtragem pela duração será feita localmente.</p>
<p>Aqui temos o primeiro problema: aceder aos serviços do SAPO a partir do HTML do Codebits. Como estão em dois domínios diferentes, não podemos usar as técnicas de Ajax normais, já que se viola a regra de que um site apenas pode aceder ao mesmo domínio (e subdomínios). É uma restrição que faz sentido, mas quse pode contornar facimente com o script tag hack, em escrevemos para o header da página uma nova tag de SCRIPT em que o src é o URL do pedido que pretendemos fazer. Em Firefox e Safari, podemos despoletar um evento que ocorre quando termina o carregamento dos dados. Uma função deste tipo pode ser a seguinte:</p>
<p><code> </code></p>
<p><code></p>
<pre>	function loadJSON(url, callback) {
		var tag = document.createElement("script");
		tag.src = url;
		tag.type="text/javascript";
		tag.onload = callback;
		document.getElementsByTagName("head")[0].appendChild(tag);
	}</pre>
<p></code></p>
<p>Duas notas sobre os pedidos ao serviço: vamos pedir os dados em JSON, que é mais fácil de processar que XML, e vamos pedir que os dados sejam atribuídos a uma variável em javascript (com o parâmetro jsontag), de modo a ser mais fácil o acesso.</p>
<p>Nesta função, o parâmetro callback é invocado quando termina o carregamento do JSON, tal como o evento onload normal. Podemos passar uma função anónima neste parâmetro.</p>
<p>Para o primeiro request, e usando a função anterior, podemos fazer algo assim:</p>
<p><code> </code></p>
<p><code></p>
<pre>	loadJSON("http://services.sapo.pt/EPG/GetChannelListjson?jsontag=Canais", function() {
		// init com array vazio
		var	chn = [];
		// caminho para os canais (Canais é o nome da varável que o JSON devolvido no request nos criou)
		var chns = Canais.GetChannelListResponse.GetChannelListResult.Channel;
		// iterar sobre os canais, acrescentando ao array os que tenham "TV" no nome.
		for (i in chns) {
			// usei uma RegExp, mas podiamos usar simplesmente um indexOf
			var r = new RegExp("TV", "i");
			if (r.test(chns[i].Name))
				chn.push(escape(chns[i].Sigla));
		}
		// terminado! aqui já temos na variável "chn" um array com as siglas dos canais que tenham "p1" no nome.
		// parte 2 aqui!!!
	});</pre>
<p></code></p>
<p>Para o segundo request, as coisas são parecidas. Fazer request (passando as siglas dos canais obtidos no passo anterior) e para cada canal ver todos os programas que tenham menos que X minutos. Ordenar pela hora de início, e mostrar or resultado.</p>
<p><code> </code></p>
<p><code></p>
<pre>	// ...
	loadJSON("http://services.sapo.pt/EPG/GetChannelListByDateIntervaljson?channelSiglas="+chn.join(",")+"&amp;startDate="+p2+"+00%3A00%3A00&amp;endDate=01-01-2001+23%3A59%3A59&amp;jsontag=Programacao", function() {
		// inicializar a vazio o array com os programas
		var	progs = [];
		// caminho para os canais
		var chns = Programacao.GetChannelListByDateIntervalResponse.GetChannelListByDateIntervalResult.Channel;
		// para cada canal...
		for (j in chns) {
			// ...e para cada programa deste canal
			var prog = chns[j].Programs.Program;
			for (i in prog) {
				p = prog[i];
				// se duracao menor que 31 minutos (a duração obtida vem em segundos)
				if (p.Duration &lt; 31 * 60) {
					progs.push(p);
				}
			}
		}
		// ordenar os vários programas por hora de início (sort() recebe um parâmetro que é o comparador para determinar a ordenação entre 2 elementos)
		progs.sort(function(a, b) {
			return a.StartTime &lt; b.StartTime ? -1 : 1;
		});
		// mostrar os programas, invocado a função o() fornecida.
		for (i in progs) {
			p = progs[i];
			o(p.ChannelName + " at " + p.StartTime + ": " + p.Title + " (" + (p.Duration/60) + ")");
		}
	});
	// ...</pre>
<p></code></p>
<p>Como podemos ver, não é complicado. É moroso, talvez, especialmente para quem tenha pouca experiência em Javascript, mas é tudo uma questão de tentar.</p>
<p>Este quiz foi para mim como uma montanha russa. Até aqui estivemos a subir, a partir daqui é que vem a parte gira. <img src='http://luminescente.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Este código que aqui meti foi uma versão inicial. Já com algumas optimizações que não consegui evitar fazer, mas ainda há muito a encurtar. Um conselho: nem todas as optimizações originam código menor. É preciso medir bem a alteração que se faz. Coisas como eficiência, validação de código, legibilidade, boas práticas: esqueçam tudo. Um piloto da Red Bull Air Race não se chateia de não ter refeições a bordo do avião.</p>
<p>Há muitas micro-optimizações que podemos fazer, mas posso enumerar o princípio:</p>
<ul>
<li>Esqueçam packers/minifiers de Javascript: aqui funcionam mal, porque a escala é muito menor do habitual, e perceberão melhor o código se fizerem tudo à mão.</li>
<li>Omitir tudo o que não for mesmo necessário. Quebras de linha, pontos e vírgula, &#8220;var&#8221; na declaração de uma variável, espaços a mais nas atribuições, comparações, etc.</li>
<li>Inicialização de variáveis, só mesmo se imprescindível (como no caso dos arrays)</li>
<li>Nomes longos de variáveis e funções, como o &#8220;loadJSON&#8221;? Um luxo impensável: aqui pode ser ficar apenas como a função &#8220;J&#8221;. Têm 26*2 variáveis/funções possíveis, são suficientes <img src='http://luminescente.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
<li>Usar defaults. A tag de script tem por omissão o type &#8220;text/javacsript&#8221;. Apagar a linha em que se faz &#8220;src.type =&#8221;.</li>
<li>Façam a composição de nomes longos com fragmentos.</li>
</ul>
<p>Para este último ponto é melhor explicar em detalhe. Por exemplo, os dois serviços começam por http://services.sapo.pt/.</p>
<p><code> </code></p>
<p><code></p>
<pre>	var u = "http://services.sapo.pt/";
	var a = u + "EPG/GetChannelListjson...";
	var b = u + "EPG/GetChannelListByDateIntervaljson...";</pre>
<p></code></p>
<p>Podemos ir mais além, uma vez que vemos que continam a ter partes em comum.</p>
<p><code> </code></p>
<p><code></p>
<pre>	var u = "http://services.sapo.pt/EPG/GetChannelList";
	var a = u + "json...";
	var b = u + "ByDateIntervaljson...";</pre>
<p></code></p>
<p>Nada mau. Outra coisa que temos ainda em tamanho XXL são os caminhos para as propriedades do resultado do pedido JSON.</p>
<p><code> </code></p>
<p><code></p>
<pre>	var chns = Programacao.GetChannelListByDateIntervalResponse.GetChannelListByDateIntervalResult.Channel;</pre>
<p></code></p>
<p>Isto pode ser muito reduzido. Primeiro, em vez de fazer jsontag=Programacao, fazemos jsontag=B. Depois, em Javascript é igual usar a sintaxe de array ([]) para aceder aos membros de um objecto, pelo que esta linha é equivalente:</p>
<p><code> </code></p>
<p><code></p>
<pre>	var chns = B["GetChannelListByDateIntervalResponse"]["GetChannelListByDateIntervalResult"]["Channel"];</pre>
<p></code></p>
<p>Isto é útil porque agora temos strings nos índices. O que que significa que tal como para o URL dos serviçøs, podemos fazer algo assim:</p>
<p><code> </code></p>
<p><code></p>
<pre>	var g = "GetChannelListByDateInterval";
	var chns = B[g + "Response"][g + "Result"]["Channel"];</pre>
<p></code></p>
<p>Muito melhor. Mas o Response/Result é usado noutro local no código, ainda podemos fazer melhor.</p>
<p><code> </code></p>
<p><code></p>
<pre>	var g = "GetChannelListByDateInterval";
	var u = "Response";
	var v = "Result"
	var chns = B[g + u][g + v]["Channel"];</pre>
<p></code></p>
<p>Mas o &#8220;Channel&#8221; também é usado noutros sítios&#8230;</p>
<p><code> </code></p>
<p><code></p>
<pre>	var c = "Channel";
	var g = "Get" + c + "ListByDateInterval";
	var u = "Response";
	var v = "Result"
	var chns = B[g + u][g + v][c];</pre>
<p></code></p>
<p>Esta última optimização já não é muito útil. Que com a nova variáveil e a concatenação acabamos quase por ter o mesmo número de caracteres, mas aqui é só um exemplo e sabemos que o &#8220;Channel&#8221; é usado noutros sítios, pelo que temos lucro. Estes exemplos também são escritos com vista a serem claros enquanto explico. No meu código, seria algo como isto:</p>
<p><code> </code></p>
<p><code></p>
<pre>	c="Channel",g="Get"+c+"ListByDateInterval",u="Response",v=" Result",chns=B[g+u][g+v][c];</pre>
<p></code></p>
<p>Muito mais denso. Tendo todo o código podemos ver o que podemos reutilizar e sempre se poupam uns caracteres. Chega a uma altura em que é muito difícil espremer mais, mas tal como uma bisnaga de uma pasta de dentes, há sempre um pouquinho mais.</p>
<p>O serviço de EPG devolve os programas que comecem até 20 minutos antes da hora especificada, pelo que isto causava problemas de ter programas do dia anterior. Em vez de meter no código uma condição para lidar com a situação, faço o segundo pedido para programas que comecem às 00:20 do dia. Problema resolvido no mesmo número de caracteres. <img src='http://luminescente.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Algures no tempo tive a participação mais curta, mas depois perdi o comboio e não consegui apanhá-lo mais. Tentei a técnica dos caracteres &#8220;chineses&#8221; que acabou por ganhar, mas uns bugs no meu encode/decoder não me deixaram avançar. A ideia em si é simples: o form do quiz contabilizava caracteres, e não bytes. Se um caracter UTF-8 é multi-byte, podemos empacotar vários (acho que no máximo 4) caracteres ASCII (8 bits) no mesmo caracter UTF-8. Há sempre o overhead de um decoder, mas como se viu é irrisório comparado com o que se poupa no empactamento.</p>
<p>Sem mais delongas, esta foi uma das minhas últimas versões. Esta tem 677 caracteres, mas a final acho que tinha menos, mas já desapareceu da intranet do Codebits. Oops.. É o que dá confiar na cloud. <img src='http://luminescente.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><code> </code></p>
<p><code></p>
<pre>	function epg(a,b,d){T="StartTime",E="Channel",D="Duration",L="Get"+E+"List",G=L+"ByDateInterval",O=document,R="Response",U="Result",Z="json?jsontag="
	function J(u,k){s=O.createElement("script");s.src="/services.sapo.pt/EPG/"+u;s.onload=k;O.body.appendChild(s)}J(L+Z+"A",function(){c="";z=A[L+R][L+U][E]
	for(i in z)with(z[i])if(Name.match(a))c+=Sigla+","
	J(G+Z+"B&amp;channelSiglas="+c+"&amp;startDate="+b+"+00:20:00&amp;endDate="+b+"+23:59:59",function(){m=[];c=B[G+R][G+U][E]
	for(j in c){g=c[j].Programs.Program;for(i in g)if(g[i][D]&lt;d*60)m.push(g[i])}for(i in m.sort(function(a,b){return a[T]&lt;b[T]?-1:1})){p=m[i];o(p[E+"Name"]+" at "+p[T]+": "+p.Title+" ("+(p[D]/60)+" minutes)\n")}})})}</pre>
<p></code></p>
<p>Só garanto que funcione esta última versão. Como as outras foram quase refeitas enquanto escrevia o post, pode-me ter escapado algo, mas não interessa muito, desde que percebam o funcionamento.</p>
<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://luminescente.com/2009/11/codebits-challenge-4/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

