<?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>Technè</title>
	<atom:link href="http://techne.cesar.org.br/feed/" rel="self" type="application/rss+xml" />
	<link>http://techne.cesar.org.br</link>
	<description>Tecnologia &#38; Experiência do Usuário no C.E.S.A.R</description>
	<lastBuildDate>Thu, 18 Aug 2011 20:14:37 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>pt</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Dissector para o Wireshark</title>
		<link>http://techne.cesar.org.br/dissector-para-o-wireshark/</link>
		<comments>http://techne.cesar.org.br/dissector-para-o-wireshark/#comments</comments>
		<pubDate>Thu, 18 Aug 2011 20:14:37 +0000</pubDate>
		<dc:creator>Caio Dias</dc:creator>
				<category><![CDATA[Geral]]></category>
		<category><![CDATA[cores]]></category>
		<category><![CDATA[dissector]]></category>
		<category><![CDATA[filtro colorido]]></category>
		<category><![CDATA[lua]]></category>
		<category><![CDATA[wireshark]]></category>

		<guid isPermaLink="false">http://techne.cesar.org.br/?p=1803</guid>
		<description><![CDATA[Segundo a Wikipédia, Wireshark (anteriormente conhecido como Ethereal) é um programa que analisa o tráfego de rede, e o organiza por protocolos. As funcionalidades do Wireshark são parecidas com o tcpdump mas com uma interface GUI, com mais informação e com a possibilidade da utilização de dissectors.
O Wireshark permite o uso da linguagem de programação [...]]]></description>
			<content:encoded><![CDATA[<p>Segundo a Wikipédia, <a href="https://secure.wikimedia.org/wikipedia/pt/wiki/Wireshark" target="_blank">Wireshark</a> (anteriormente conhecido como Ethereal) é um programa que analisa o tráfego de rede, e o organiza por protocolos. As funcionalidades do Wireshark são parecidas com o tcpdump mas com uma interface GUI, com mais informação e com a possibilidade da utilização de dissectors.</p>
<p>O Wireshark permite o uso da linguagem de programação <a href="https://secure.wikimedia.org/wikipedia/pt/wiki/Lua_%28linguagem_de_programa%C3%A7%C3%A3o%29" target="_blank">Lua</a> para criação de novos dissectors. Esta funcionalidade é interessante quando se tem um protocolo privado e gostaria de facilitar a visualização dos dados trafegados com a utilização do Wireshark.</p>
<p><strong>Como criar um dissector novo?</strong></p>
<p>Vamos criar um dissector atrelado a porta UDP 50000 como exemplo. Para isso, vamos adicionar um novo dissector para trabalhar em cima de um protocolo já existente, no caso UDP, com os pacotes destinados a porta 50000. O Wireshark só repassa ao dissector uma parte do buffer. No nosso caso, somente será repassado ao dissector o conteúdo do buffer destinado a porta 50000.</p>
<p><strong>Código do dissector</strong></p>
<p>Conteúdo do arquivo <strong>novoProtocolo.lua</strong>:</p>
<pre>-- Vamos criar um novo dissector e seus campos
p_novoProtocolo = Proto ("novoProtocolo", "Novo Protocolo")
local f_campo1 = ProtoField.uint16("p_novoProtocolo.campo1", "Campo1", base.HEX)
local f_campo2 = ProtoField.string("p_novoProtocolo.campo2", "Campo2", base.HEX)

p_novoProtocolo.fields = {f_campo1, f_campo2}

-- Função principal do dissector novoProtocolo
function p_novoProtocolo.dissector (buf, pkt, root)
	-- É importante validar o tamanho do pacote recebido.
	if buf:len() &lt;= 0 then
		return
	end

	-- Atribuição do nome que sera exibido na coluna "Protocol"
	pkt.cols.protocol = p_novoProtocolo.name

	-- Criação da subtree para o novoProtocolo
	subtree = root:add(p_novoProtocolo, buf(0))

	-- Adicionar os campos do novo protocolo ao subtree
	subtree:add(f_campo1, buf(0,2)):append_text(" [Detalhes do Campo 1]")
	subtree:add(f_campo1, buf(2,2)):append_text(" [Detalhes do Campo 2]")

	-- Descrição do payload
	subtree:append_text(", Alguns detalhes a mais.")
end

-- Rotina de inicialização.
function p_novoProtocolo.init()
end

-- Registrar um dissector atrelado a porta UDP 50000
local udp_dissector_table = DissectorTable.get("udp.port")
dissector = udp_dissector_table:get_dissector(50000)
udp_dissector_table:add(50000, p_novoProtocolo)</pre>
<p><strong>Rodando seu script Lua no Wireshark</strong></p>
<p>Ainda é preciso algumas etapas antes de conseguir rodar o código acima. Se você tiver a versão 1.4 ou melhor, pule a etapa 3.</p>
<ol>
<li>Salve o script lua acima em qualquer pasta. (ex. C:\NovoProtocolo) e chame o arquivo de novoProtocolo.lua</li>
<li>Abra o arquivo <em>ini.lua</em>, que se encontra no diretorio de instalação do Wireshark, para edição. Você precisará de privilégios de administrador no Windows Vista e 7.</li>
<li>Comente a seguinte linha no arquivo init.lua (Para comentar uma linha basta usar &#8212; no inicio da linha):
<pre>disable_lua = true; do return end;</pre>
</li>
<li>Adicione o seguinte código abaixo no arquivo <em>init.lua</em> (no final dele):</li>
<pre>NOVOPROTOCOLO_SCRIPT_PATH="C:\\NovoProtocolo\\"
dofile(NOVOPROTOCOLO_SCRIPT_PATH.."novoProtocolo.lua")</pre>
</ol>
<p>Vide imagem abaixo da tela do Wireshark utilizando o Novo Protocolo.</p>
<p style="text-align: center;"><a href="http://blog.krix.com.br/krix/wp-content/uploads/2011/07/Novo-Protocolo.png"></a><a href="http://techne.cesar.org.br/wp-content/uploads/2011/08/Novo-Protocolo.png"><img class="alignnone size-medium wp-image-1825" src="http://techne.cesar.org.br/wp-content/uploads/2011/08/Novo-Protocolo-278x300.png" alt="Novo protocolo em utilização no wireshark" width="278" height="300" /></a></p>
<p>Para validar o código demonstrado acima, é só baixar o pcap <a href="http://blog.krix.com.br/wp-content/uploads/2011/07/Test%20NovoProtocolo.pcap" target="_blank">aqui</a>.</p>
<p><strong>Organização dos Dissectors</strong></p>
<p>Entretanto é importante pensar na organização do código. Lua nos deixa bastante livre para decidirmos como organizar o código fonte. Você pode dividir seu código em quantos arquivos forem necessários e também coloca-los para serem carregados na ordem que você desejar. É possível carregar todos os arquivos na inicialização do Wireshark, ao colocar o código abaixo no final do arquivo init.lua no diretório aonde o Wireshark foi instalado.</p>
<pre>PATH="C:\\NovoProtocolo\\"
dofile(PATH.."arquivo1.lua")
dofile(PATH.."arquivo2.lua")
dofile(PATH.."arquivo3.lua")
dofile(PATH.."arquivoN.lua")</pre>
<p>Porem também é possível carregar seu código somente quando necessário, como no código exemplo abaixo:</p>
<pre>if true then
dofile("C:\\NovoProtocolo\\arquivoN.lua")
end</pre>
<p><strong>Trabalhando com bitfields</strong></p>
<p>A API Lua que o Wireshark usa não possui uma forma simples de se trabalhar com bitfield,porque eles só aceitam campos do tipo inteiro com máscara.</p>
<p>O wireshark 1.4.2 e anteriores tem um bug na API Lua. Eles só suportam bitfields (campos int com máscara), quando adicionado a um Proto definindo os campos do protocolo, assim como no exemplo abaixo:</p>
<pre>-- criando novoproto e seus campos
p_novo = Proto ("novoproto","Novo Protocolo")
local f_bitfield = ProtoField.uint8("novoproto.bitfield", "Comando", base.HEX,
{[0]="Pacote Normal", [1]="Último Pacote"}, 0x40)
p_novo.fields = {f_bitfield}</pre>
<p>Isso torna-se complicado caso você tenha um protocolo grande com vários bitfields, você terá que adicionar todos eles no inicio. Então coloco aqui uma função feita por Devendra Tewari que auxilia na exibição de bitfields.</p>
<pre>-- Add a bit field to the dissection tree
-- buf - a tvb
-- subtree - dissection tree to which field will be added
-- offset - offset of the field within the tvb
-- size - number of octets containing the bitfield
-- bitfieldstart - start index of the bitfield, the highest bit is at 0
-- bitfieldlen - length of the bitfield to add
-- name - name of the field
-- valuestring - table containing description of bitfield value, can be nil
-- desc - description of the bit field
-- format - display format of the bitfield value, can be nil
function bitfield_add(buf, subtree, offset, size, bitfieldstart, bitfieldlen,
name, valuestring, desc, format)
    local val = buf(offset, size):bitfield(bitfieldstart, bitfieldlen)
    local binary=""
    local i = bitfieldlen - 1
    local intval = val

    repeat
        local result = intval % 2^i
        if result ~= intval then
            binary = binary.."1"
        else
            binary = binary.."0"
        end
        intval = result
        i = i - 1
    until (i &lt; 0)

    local dotted = string.rep(".", bitfieldstart)..binary
      ..string.rep(".", size*8-bitfieldstart-bitfieldlen)

    local chunked = ""
    for i = 0, size do
        chunked = chunked..string.sub(dotted, 8*i+1, 8*i+4)
          .." "..string.sub(dotted, 8*i+5, 8*i+8).." "
    end

    desc = chunked.." = "..desc
    if format ~= nil then
        desc = desc..": "..string.format(format, val)
    end

    if valuestring ~= nil then
        if valuestring[val] ~= nil then
            desc = desc.." ["..valuestring[val].."]"
        end
    end

    subtree:add(ProtoField.uint8(name), buf(offset, size), desc)
end</pre>
<p>Sua única limitação é que o Wireshark irá destacar todos os octetos que contêm o bitfield, se você ativar Bit View no painel mais abaixo (terceiro), o Wireshark não irá destacar somente os bits referentes ao campo de bits.</p>
<p><strong>Como colorir seu protocolo no Wireshark</strong></p>
<p>O Wireshark tem uma funcionalidade bem interessante e útil quando precisamos analisar grandes logs capturados. Ele nos permite configurar filtros para cada protocolo e assim colorir cada ocasião que aquele protocolo aparecer. Como pode ser visto na imagem abaixo:</p>
<ul>
<li>Para fazer isso basta ir no menu View/Coloring Rules&#8230;</li>
<li>Clique no botão de criar novo, irá abrir uma nova janela.</li>
<li>No primeiro campo dê um nome ao filtro que será criado.</li>
<li>No segundo campo informe o nome do protocolo que será filtrado.</li>
<li>Logo abaixo escolha as cores e dê ok.</li>
<li>Posicione o seu novo filtro acima da camada onde seu protocolo roda. Por exemplo: Se o seu protocolo roda em cima de TCP, então coloque seu filtro logo acima do filtro de TCP.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://techne.cesar.org.br/dissector-para-o-wireshark/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Como utilizar o Google Cloud Print para imprimir via Android</title>
		<link>http://techne.cesar.org.br/como-utilizar-o-google-cloud-print-para-imprimir-via-android/</link>
		<comments>http://techne.cesar.org.br/como-utilizar-o-google-cloud-print-para-imprimir-via-android/#comments</comments>
		<pubDate>Tue, 12 Jul 2011 13:41:59 +0000</pubDate>
		<dc:creator>Felipe</dc:creator>
				<category><![CDATA[Geral]]></category>
		<category><![CDATA[Andorid]]></category>
		<category><![CDATA[Google Cloud Print]]></category>
		<category><![CDATA[Imprimir]]></category>

		<guid isPermaLink="false">http://techne.cesar.org.br/?p=1788</guid>
		<description><![CDATA[Na busca por uma maneira de como enviar um arquivo para impressão de um smartphone Android, surge a dúvida de como faria isso direto da aplicação sem se preocupar como iria ser feito esta conexão com a impressora, ai que surge o Google com suas ferramentas revolucionárias, o Google Cloud Print.

Como a ferramenta já diz, [...]]]></description>
			<content:encoded><![CDATA[<p>Na busca por uma maneira de como enviar um arquivo para impressão de um smartphone Android, surge a dúvida de como faria isso direto da aplicação sem se preocupar como iria ser feito esta conexão com a impressora, ai que surge o Google com suas ferramentas revolucionárias, o Google Cloud Print.</p>
<p><img class="alignnone" src="http://3.bp.blogspot.com/_ZaGO7GjCqAI/S8i57kL6UEI/AAAAAAAASmA/QIXPNqeuQUY/s640/google-cloud-print.png" alt="" width="607" height="231" /></p>
<p>Como a ferramenta já diz, levar a impressão pras nuvens. Ao conectar o seu navegador &#8216;Google Chrome&#8217; à conta do &#8216;Google Cloud Print&#8217;, ele permite que todas as impressoras que o navegador tenha acesso, sejam jogadas nas núvens, para futuras impressões, e o melhor, de qualquer computador / smarthphone, independente de onde você estiver.</p>
<p>A princípio devemos acessar: <a href="http://www.google.com/cloudprint" target="_blank">http://www.google.com/cloudprint</a> e fazer o login para integrar a conta do google com o cloudprint, caso você não esteja no utilizando o &#8216;Google Chrome&#8217; que é um fator fundamental para configurar as impressoras que serão usadas nas nuvens, ele irá sugerir para o download.</p>
<p>Feito isso, vá em Opções (Options) -&gt; Opções Avançadas (Under the hood) -&gt; Na última opção faça o login no cloudprint e configure as impressoas que estarão disponívels para uso. &#8220;Google Cloud Print lets you access this computer&#8217;s printers from anywhere. Sign in to enable.&#8221;</p>
<p>Com tudo configurado, vamos ao código.</p>
<p>A princípio a permissão de acesso a INTERNET no Manifest da sua aplicação, para que a Activity que fará a conexão com o google possa mostrar o conteúdo do site no seu webview.</p>
<pre style="padding-left: 30px;"><span style="color: #008000;">// permissão para uso da internet
&lt;uses-permission android:name="android.permission.INTERNET" /&gt;</span></pre>
<p><span style="color: #339966;"><span style="color: #000000;">Basicamente, o código em si é esta chamada de Activity onde o programador irá passar o documento em forma de URI e seu MimeType (Uma lista de tipos pode ser encontrada <a title="aqui" href="http://www.webmaster-toolkit.com/mime-types.shtml" target="_blank">aqui</a>)</span></span><span style="color: #339966;"><span style="color: #000000;">, e o título no qual o documento terá na lista de arquivos que estão sendo impressos.<em><br />
</em></span></span></p>
<pre style="padding-left: 30px;"><span style="color: #000000;">Intent printIntent = new Intent(this, PrintDialogActivity.class);
printIntent.setDataAndType(docUri, docMimeType);
printIntent.putExtra("title", docTitle);
startActivity(printIntent);</span><strong>
</strong></pre>
<p>Um exemplo seria a impressão de um PDF, para demonstração utilizo a biblioteca <strong>iText</strong> (<a href="http://www.itextpdf.com/">http://www.itextpdf.com/</a>) que é OpenSource e utilizada em Java e C#. Após adicionar o arquivo .jar ao Build Path do seu projeto no eclipse, basta criar um arquivo no SDcard, lembrando que precisamos de criar uma permissão para esse feito:</p>
<pre style="padding-left: 30px;"><span style="color: #008000;">// permissão para escrever no armazenamento externo
&lt;uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /&gt;</span>

// pega o armazenamento externo
File root = Environment.getExternalStorageDirectory();
// instancia um arquivo que será criado no diretório base do SDCARD
File file = new File(root, "teste.pdf");
// se o arquivo já existir, delete-o
if (file.exists())
    file.delete();
// tente criar um arquivo temporário
try {
    file.createNewFile();
} catch (IOException e) {
}

// criamos um documento do tipo PDF
Document document = new Document();
try {
    // avisamos ao PdfWriter que esse documento será salvo
    // na minha instancia de file para que
    // ao fechados o documento ele salve o arquivo
    PdfWriter.getInstance(document, new FileOutputStream(file));
    document.open();
    // adicionamos um paragrafo ao documento
    document.add(new Paragraph("Hello World!"));
} catch (DocumentException e) {
    e.printStackTrace();
}
document.close();

// e finalmente mandamos o arquivo para a Activity que
// fará a comunicação com o Google Cloud Print
Intent printIntent = new Intent(this, PrintDialogActivity.class);
printIntent.setDataAndType(Uri.fromFile(file), "application/pdf");
printIntent.putExtra("title", "PDF para ser impresso");
startActivity(printIntent);</pre>
<p>O código da <strong>PrintDialogActivity </strong>juntamente com seu <strong>layout </strong>está disponível no site do projeto no google, e não precisa de nenhuma modificação, acesse para maiores informações: <a href="http://code.google.com/apis/cloudprint/docs/android.html">http://code.google.com/apis/cloudprint/docs/android.html</a></p>
<p><a title="Outras bibliotecas PDF." href="http://java-source.net/open-source/pdf-libraries" target="_blank">Outras bibliotecas PDF.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://techne.cesar.org.br/como-utilizar-o-google-cloud-print-para-imprimir-via-android/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Como descobrir o nível do sinal de uma rede wireless no Android.</title>
		<link>http://techne.cesar.org.br/como-descobrir-o-nivel-do-sinal-de-uma-rede-wireless-no-android/</link>
		<comments>http://techne.cesar.org.br/como-descobrir-o-nivel-do-sinal-de-uma-rede-wireless-no-android/#comments</comments>
		<pubDate>Mon, 27 Jun 2011 11:51:21 +0000</pubDate>
		<dc:creator>Heitor</dc:creator>
				<category><![CDATA[Sistemas e Aplicações Wireless]]></category>

		<guid isPermaLink="false">http://techne.cesar.org.br/?p=1732</guid>
		<description><![CDATA[Post escrito com ajuda Wallace Thierre e Natália Cabral.
Continuando os post&#8217;s relacionados as informações do android,  iremos descobrir como captar o sinal da rede wireless em que o dispositivo está conectado.
O trecho de código a seguir nos mostra como obter o nível do sinal da rede wireless do
android.


A principal classe responsável por gerenciar as informações da [...]]]></description>
			<content:encoded><![CDATA[<p>Post escrito com ajuda Wallace Thierre e Natália Cabral.</p>
<p>Continuando os post&#8217;s relacionados as informações do android,  iremos descobrir como captar o sinal da rede <em>wireless </em>em que o dispositivo está conectado.</p>
<div>O trecho de código a seguir nos mostra como obter o nível do sinal da rede wireless do</div>
<div>android.</div>
<div>
<p><a href="http://techne.cesar.org.br/wp-content/uploads/2011/06/wifiInfoTech.bmp"><img class="alignnone size-full wp-image-1776" src="http://techne.cesar.org.br/wp-content/uploads/2011/06/wifiInfoTech.bmp" alt="wifiInfo" width="475" height="223" /></a></p>
<div>A principal classe responsável por gerenciar as informações da rede sem fio no android é o</div>
<div><em>WifiManager</em>, mais sobre o <em>WifiManager </em><a title="Wifi Manager" href="http://developer.android.com/reference/android/net/wifi/WifiManager.html" target="_blank">aqui</a>.</div>
</div>
<div>
<div>A instância dessa classe pode ser obtida através da chamada do método <em>getSystemService</em>, que</div>
<div>recebe como parâmetro o contexto.</div>
<div>Mais informações sobre o contexto <a title="context" href="http://developer.android.com/reference/android/content/Context.html" target="_blank">aqui</a>.</div>
</div>
<p></p>
<div>Por fim, temos um método <em>calculateSignalLevel </em>que retorna o nível do sinal da conexão sem fio de acordo com os parâmetros a seguir, o primeiro é RSSI(<em>Received signal strength indication</em>) que é um indicador de energia que representa o sinal recebido pelo aparelho e o segundo é quantidade de niveis a ser calculado menos 1, ou seja, se inicializarmos com 11, o valor do sinal irá variar de 0 a 10.</div>
<div></p>
<div>Obs: Necessário declarar seguinte permissão no AndroidManisfest.xml para o ter acesso as informações da rede sem fio, <em>&lt;uses-permission android:name=&#8221;android.permission.ACCESS_WIFI_STATE&#8221;  /&gt;</em>.</div>
</div>
<div>Em breve mais post sobre o dispositivo Android.</div>
]]></content:encoded>
			<wfw:commentRss>http://techne.cesar.org.br/como-descobrir-o-nivel-do-sinal-de-uma-rede-wireless-no-android/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Descobrindo informações de bateria dos dispositivos Android</title>
		<link>http://techne.cesar.org.br/descobrindo-informacoes-de-bateria-dos-dispositivos-android/</link>
		<comments>http://techne.cesar.org.br/descobrindo-informacoes-de-bateria-dos-dispositivos-android/#comments</comments>
		<pubDate>Fri, 27 May 2011 18:56:31 +0000</pubDate>
		<dc:creator>Wallace</dc:creator>
				<category><![CDATA[Geral]]></category>

		<guid isPermaLink="false">http://techne.cesar.org.br/?p=1714</guid>
		<description><![CDATA[Este post foi redigido com a ajuda de Heitor Nascimento e Natália Cabral
Algumas aplicações em Android necessitam de uma quantidade considerável de processamento, memória e, conseqüentemente, de bateria dos dispositivos móveis. Dada o crescente desenvolvimento dessas tecnologias, bem como seu uso, vivemos em um cenário que a vida útil e a duração de bateria tem [...]]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888">Este post foi redigido com a ajuda de Heitor Nascimento e Natália Cabral</span></p>
<p>Algumas aplicações em Android necessitam de uma quantidade considerável de processamento, memória e, conseqüentemente, de bateria dos dispositivos móveis. Dada o crescente desenvolvimento dessas tecnologias, bem como seu uso, vivemos em um cenário que a vida útil e a duração de bateria tem diminuído gradativamente. Este post tem como objetivo mostrar como descobrir informações referentes à bateria dos <em>Smartphones </em>e Tablets que utilizam a tecnologia Android.</p>
<p>Abaixo veremos um pequeno método responsável por recuperar o percentual de bateria disponível.</p>
<p>Nota: O método abaixo deve fazer parte de uma <em>Activity </em>onde será chamado. Mais informações sobre <a href="http://techne.cesar.org.br/android-activity-e-interacao-entre-activities/"><em>Activities</em> aqui</a>.</p>
<p><a href="http://techne.cesar.org.br/wp-content/uploads/2011/05/Codigo.bmp"><img class="aligncenter size-full wp-image-1716" src="http://techne.cesar.org.br/wp-content/uploads/2011/05/Codigo.bmp" alt="" width="611" height="457" /></a></p>
<p>Para conseguirmos pegar essas informações necessitamos disparar através de um <em>Intent-Filter</em> para ACTION_BATTERY_CHANGED, também programamos um <em>Broadcast</em>( <a href="http://techne.cesar.org.br/android-comunicacao-entre-aplicacoes-e-broadcast-receivers/">Ok, vcs já sabem oq achar aqui <img src='http://techne.cesar.org.br/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  </a>) para ser executado quando essa Intent for disparada, e registramos esse <em>Receiver </em>para que possa escutar sempre que a Intent for disparada.</p>
<p>Na classe ACTION_BATTERY_CHANGED encontramos informações detalhadas da bateria, como status, nível, temperatura, voltagem, tecnologia da bateria e outras informações referentes à bateria, podemos encontrar quais informações estão disponiveis na <em>classe BatteryManager</em> no <a href="http://developer.android.com/reference/android/os/BatteryManager.html">site</a> do android developers.  Para lermos essas informações no <em>broadcast</em>, podemos executar essa tarefa utilizamos os métodos intent.getIntExtra, intent.getBooleanExtra e intent.getStringExtra.</p>
<p>Em breve outros post’s mostrando como descobrimos outras informações nativas dos dispositivos com Android.</p>
]]></content:encoded>
			<wfw:commentRss>http://techne.cesar.org.br/descobrindo-informacoes-de-bateria-dos-dispositivos-android/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Android: Uma visão mais detalhada sobre Widgets</title>
		<link>http://techne.cesar.org.br/android-uma-visao-mais-detalhada-sobre-widgets/</link>
		<comments>http://techne.cesar.org.br/android-uma-visao-mais-detalhada-sobre-widgets/#comments</comments>
		<pubDate>Tue, 17 May 2011 12:05:31 +0000</pubDate>
		<dc:creator>Fernando</dc:creator>
				<category><![CDATA[Geral]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[widget]]></category>

		<guid isPermaLink="false">http://techne.cesar.org.br/?p=1338</guid>
		<description><![CDATA[* Este post foi redigido pela equipe C.E.S.A.R. Sorocaba
Neste post, pretendemos mostrar em mais detalhes a criação de um App Widget, ou Companion Widget (aquelas aplicações que podem ser colocadas na tela inicial do dispositivo). Veremos a criação de uma Activity para configuração do Widget, assim como a sua atualização, e a interação com o [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>* Este post foi redigido pela equipe C.E.S.A.R. Sorocaba</p></blockquote>
<p>Neste post, pretendemos mostrar em mais detalhes a criação de um <a href="http://developer.android.com/guide/topics/appwidgets/index.html">App Widget</a>, ou Companion Widget (aquelas aplicações que podem ser colocadas na tela inicial do dispositivo). Veremos a criação de uma Activity para configuração do Widget, assim como a sua atualização, e a interação com o usuário. Um Widget pode ser adicionado várias vezes à tela, ou seja, pode haver várias instâncias do mesmo Widget sendo exibidas, e iremos tratar os eventos de forma distinta para cada uma delas.</p>
<p>Num <a href="http://techne.cesar.org.br/android-companion-widget-padrao-de-projeto-para-ui/">post anterior</a>, vimos que para construir um App Widget é necessário:</p>
<p>- criar uma subclasse de <a href="http://developer.android.com/reference/android/appwidget/AppWidgetProvider.html">AppWidgetProvider</a>, que será responsável pelo tratamento dos eventos do Widget;<br />
- criar um arquivo XML de metadados do Widget;<br />
- declarar o widget no AndroidManifest.xml;<br />
- criar o layout do Widget, seguindo as limitações de uma <a href="http://developer.android.com/reference/android/widget/RemoteViews.html">RemoteView</a>.</p>
<p>A classe <a href="http://developer.android.com/reference/android/appwidget/AppWidgetProvider.html">AppWidgetProvider</a> é uma sub-classe de <a href="http://developer.android.com/reference/android/content/BroadcastReceiver.html">BroadcastReceiver</a>. Por este motivo, o ciclo de vida de um Widget é similar ao de um Broadcast Receiver, e não ao de uma Activity, além de ser necessário declarar os Widgets existentes do projeto como <strong>&lt;receiver&gt;</strong> no arquivo AndroidManifest.xml.</p>
<p>Como já foi citado naquele post, há cinco métodos de AppWidgetProvider que podem ser sobrescritos no nosso Widget, e cada um é executado em resposta a um broadcast específico (identificados aqui por constantes herdadas daquela classe):<br />
- <a href="http://developer.android.com/reference/android/appwidget/AppWidgetProvider.html#onEnabled(android.content.Context)">onEnabled()</a>: Executado ao adicionar a primeira instância de um Widget na tela, em resposta ao broadcast <strong>ACTION_APPWIDGET_ENABLED</strong>. Pode ser utilizado, por exemplo, para fazer alguma configuração global da aplicação;<br />
- <a href="http://developer.android.com/reference/android/appwidget/AppWidgetProvider.html#onDisabled(android.content.Context)">onDisabled()</a>: Executado ao remover a última instância do Widget da tela, como resposta ao broadcast <strong>ACTION_APPWIDGET_DISABLED</strong>. Pode ser usado para liberar algum recurso global/compartilhado da aplicação;<br />
- <a href="http://developer.android.com/reference/android/appwidget/AppWidgetProvider.html#onDeleted(android.content.Context, int[])">onDeleted()</a>: Executa sempre que uma instância do Widget é removida da tela, em resposta ao broadcast <strong>ACTION_APPWIDGET_DELETED</strong>. Neste método, podem ser liberados recursos utilizados por uma única instância;<br />
- <a href="http://developer.android.com/reference/android/appwidget/AppWidgetProvider.html#onUpdate(android.content.Context, android.appwidget.AppWidgetManager, int[])">onUpdate()</a>: Executa em resposta ao broadcast <strong>ACTION_APPWIDGET_UPDATE</strong>, ou seja, sempre que o Widget é adicionado à tela, quando expira o tempo configurado no atributo <strong>updatePeriodMillis</strong> do AppWidgetProviderInfo, ou quando o sistema é reiniciado. Segundo <a href="http://developer.android.com/guide/topics/appwidgets/index.html">artigo</a> do próprio site do Android, caso uma Activity de configuração tenha sido declarada, este método não é executado ao adicionar o Widget, mas apenas nas próximas atualizações. Desta forma, a Activity de configuração <a href="http://developer.android.com/guide/topics/appwidgets/index.html#AppWidgetProvider">deve ser responsável</a> por executar a primeira atualização do Widget;<br />
- <a href="http://developer.android.com/reference/android/appwidget/AppWidgetProvider.html#onReceive(android.content.Context, android.content.Intent)">onReceive()</a>: É executado em resposta a todos os broadcasts recebidos, e antes de cada um dos métodos acima. Na maioria dos casos, não é necessário sobrescrever este método, uma vez que todos os broadcasts já são filtrados pelo mesmo, na superclasse.</p>
<p>Apenas para demonstrar os conceitos abordados, iremos criar uma aplicação que exibe <a href="http://developer.android.com/reference/android/widget/Toast.html">Toasts</a> na tela do dispositivo, em intervalos configurados, além de alterar um TextView com a quantidade de atualizações ocorridas.</p>
<p>Criamos o projeto, desmarcando a opção para criar uma Activity (o que iremos fazer apenas para a configuração do nosso Widget). Adicionamos então uma nova classe ao nosso pacote, com o nome de <strong>WidgetProvider</strong>, extendendo a classe <a href="http://developer.android.com/reference/android/appwidget/AppWidgetProvider.html">AppWidgetProvider</a>. Por enquanto, sobrescrevemos o método <a href="http://developer.android.com/reference/android/appwidget/AppWidgetProvider.html#onUpdate(android.content.Context, android.appwidget.AppWidgetManager, int[])">onUpdate</a>.</p>
<div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">@Override<br />
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { }</div></td></tr></tbody></table></div>
<p>Os parâmetros deste método são:<br />
- context: o Contexto atual do nosso broadcast receiver;<br />
- appWidgetManager:  objeto que pode ser usado para atualizar ou obter informações sobre widgets;<br />
- appWidgetIds: ids das instâncias deste widget que precisam ser atualizadas.</p>
<p>Como os eventos do widget serão tratados de forma distinta entre as suas instâncias, usaremos o parâmetro appWidgetIds para identificar a instância que os gerou, pois o Android reutiliza os Intents que tenham valores de Action e de Scheme semelhantes.</p>
<p>Em seguida, adicionamos o layout de nosso Widget, num arquivo com nome <strong>layout_widget.xml</strong>. Usaremos um layout simples, exibindo apenas um TextView com a quantidade de vezes Toasts exibidos a partir daquela instância:</p>
<p>&lt;?xml version=&#8221;1.0&#8243; encoding=&#8221;utf-8&#8243;?&gt;<br />
&lt;LinearLayout<br />
xmlns:android=&#8221;http://schemas.android.com/apk/res/android&#8221;<br />
android:orientation=&#8221;vertical&#8221;<br />
android:layout_width=&#8221;fill_parent&#8221;<br />
android:layout_height=&#8221;fill_parent&#8221;<br />
android:gravity=&#8221;center&#8221;&gt;<br />
&lt;TextView<br />
android:layout_width=&#8221;fill_parent&#8221;<br />
android:text=&#8221;@string/txtatualizacao&#8221;<br />
android:layout_height=&#8221;wrap_content&#8221;<br />
android:id=&#8221;@+id/txtatualizacao&#8221;<br />
android:textColor=&#8221;#000000&#8243; /&gt;<br />
&lt;Button<br />
android:layout_width=&#8221;fill_parent&#8221;<br />
android:layout_height=&#8221;wrap_content&#8221;<br />
android:text=&#8221;Atualizar&#8221;<br />
android:id=&#8221;@+id/btatualizar&#8221; /&gt;<br />
&lt;Button<br />
android:layout_width=&#8221;fill_parent&#8221;<br />
android:layout_height=&#8221;wrap_content&#8221;<br />
android:text=&#8221;Resetar&#8221;<br />
android:id=&#8221;@+id/btresetar&#8221; /&gt;<br />
&lt;/LinearLayout&gt;</p>
<p>Adicionamos agora o arquivo de meta-dados do Widget, aqui nomeado <strong>provider_info.xml</strong>. Os atributos da tag appwidget-provider devem ser compatíveis com os da classe <a href="http://developer.android.com/reference/android/appwidget/AppWidgetProviderInfo.html">AppWidgetProviderInfo</a>. Neste exemplo iremos controlar o intervalo de atualização pela Activity de configuração. Portanto, omitimos o atributo <strong>updatePeriodMillis</strong> deste arquivo:</p>
<p>&lt;?xml version=&#8221;1.0&#8243; encoding=&#8221;utf-8&#8243;?&gt;<br />
&lt;appwidget-provider     xmlns:android=&#8221;http://schemas.android.com/apk/res/android&#8221;<br />
android:minWidth=&#8221;146dp&#8221; android:minHeight=&#8221;146dp&#8221;<br />
android:updatePeriodMillis=&#8221;86400000&#8243;<br />
android:initialLayout=&#8221;@layout/layout_widget&#8221;<br />
android:configure=&#8221;cesar.org.br.WidgetConfiguration&#8221;&gt;<br />
&lt;/appwidget-provider&gt;</p>
<p>Caso fôssemos utilizar este o atributo <strong>updatePeriodMillis</strong>, o intervalo  mínimo para atualização seria de 30 minutos, como forma de poupar a bateria do dispositivo. No arquivo acima, foram definidas também as dimensões mínimas do Widget, nos atributos <strong>minWidth</strong> e <strong>minHeight</strong>, e qual o layout a ser utilizado, em <strong>initialLayout</strong>.</p>
<p>Agora, é preciso declarar o Widget como um receiver no AndroidManifest.xml de nosso projeto, dentro da seção <strong>&lt;application&gt;</strong>:</p>
<p>&lt;receiver<br />
android:name=&#8221;.ToastWidgetProvider&#8221;&gt;<br />
&lt;intent-filter&gt;<br />
&lt;action android:name=&#8221;android.appwidget.action.APPWIDGET_UPDATE&#8221; /&gt;<br />
&lt;/intent-filter&gt;<br />
&lt;meta-data<br />
android:name=&#8221;android.appwidget.provider&#8221;<br />
android:resource=&#8221;@xml/imageswidget_info&#8221; /&gt;<br />
&lt;/receiver&gt;</p>
<p>Assim como no post anterior, adicionamos um Intent Filter com a Action <strong>APPWIDGET_UPDATE</strong>, e o nosso arquivo de meta-dados.</p>
<p>O próximo passo é criar a classe de configuração que tem o objetivo de proporcionar um mecanismo de configuração do widget.</p>
<p>As configurações podem ser de diversas espécies, como de mudanças de configuração de views que estão dentro do widget, propriedades do widget ou adição de uma view no widget.</p>
<p>Seguindo nosso exemplo iremos criar uma classe de configuração chamada <strong>WidgetConfiguration</strong>, ela deve ser herdar da classe Activity:</p>
<div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">import android.app.Activity;<br />
public class WidgetConfiguration extends Activity { }</div></td></tr></tbody></table></div>
<p>Como já visto em outros posts, uma activity deve ser declarada no manifesto, entretanto, além dessa configuração iremos fazer mais um passo no caso da nossa classe de configuração.</p>
<p>No manifesto teremos que adicionar o trecho do xml de configuração:</p>
<p>&lt;activity<br />
android:name=&#8221;.WidgetWidgetConfiguration&#8221;<br />
android:label=&#8221;@string/app_name&#8221;&gt;<br />
&lt;intent-filter&gt;<br />
&lt;action<br />
android:name=&#8221;android.appwidget.action.APPWIDGET_CONFIGURE&#8221; /&gt; &lt;/intent-filter&gt;<br />
&lt;/activity&gt;</p>
<p>Observe que diferente de uma Activity declarada de forma convencional no manifesto, ela possui um intent filter contendo uma ação que indica ser uma classe que configura um widget.</p>
<p>O próximo passo é indicar no xml de meta-dados que existe uma classe de configuração, para isso devemos adicionar um atributo:</p>
<p>android:configure=&#8221;cesar.org.br.ToastWidgetConfigure&#8221;</p>
<p>Por fim, para terminarmos a classe de configuração iremos implementar o método onCreate da Activity.</p>
<div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">@Override<br />
protected void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
}</div></td></tr></tbody></table></div>
<p>Existem duas maneiras de atualizar um widget, sendo a primeira delas a mais simples. Para isso basta atribuir um valor em milisegundos para o parâmetro <strong>updatePeriodMillis </strong>no <a href="http://developer.android.com/reference/android/appwidget/AppWidgetProviderInfo.html">AppWidgetProviderInfo</a>, que, como já foi dito anteriormente, só aceita valores maiores que 30 minutos.</p>
<p>Para atualizar um widget com intervalos menores do que 30 minutos, é necessário criar um alarme. Um alarme é um serviço do android que permite que broadcasts sejam enviados para o sistema através do <a href="http://developer.android.com/reference/android/content/Intent.html">Intent</a> registrado para o alarme. Para criar um alarme é necessário criar o Intent com os parâmetros relativos ao widget criado que será chamado cada vez que o tempo do alarme esgotar. A ação do Intent deverá ser <strong>AppWidgetManager.ACTION_APPWIDGET_UPDATE</strong>, que é a ação responsável por atualizar um widget.</p>
<div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);<br />
alarm.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime(), segundos * 1000, pendingIntent);</div></td></tr></tbody></table></div>
<p>Além da ação, é necessário informar ao Intent os IDs dos widgets a serem atualizados por esse Intent. Isso é feito colocando um vetor com os IDs que serão atualizados no extra <strong>AppWidgetManager.EXTRA_APPWIDGET_IDS</strong> do Intent. Também é necessário enviar a URI do seu widget, que faz com que apenas o seu widget receba a notificação. Caso a URI não seja enviada, todos os widgets do sistema serão notificados.</p>
<div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Intent intent = new Intent();<br />
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);<br />
intent.setData(Uri.parse(&quot;widgettoast://widget/id/&quot; + appWidgetId));<br />
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int [] { appWidgetId } );</div></td></tr></tbody></table></div>
<p>Com o Intent criado com todos parâmetros corretos, basta criar um PendingIntent com esse Intent. Para finalmente criar o alarme, basta obter o <a href="http://developer.android.com/reference/android/app/AlarmManager.html">AlarmManager</a> do sistema, e então chamar o método setRepeating desse AlarmManager, passando os parâmetros necessários, entre eles o tipo do alarme, o <a href="http://developer.android.com/reference/android/app/PendingIntent.html">PendingIntent</a> da operação e o intervalo de tempo desejado.</p>
<div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);</div></td></tr></tbody></table></div>
<p>Vale lembrar que os alarmes registrados continuam executando mesmo após a remoção do widget. Portanto devemos cancelar esse alarme no método <strong>onDeleted</strong> do widget, que removerá o alarme relacionado à instância do widget removida.</p>
<div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">@Override<br />
public void onDeleted(Context context, int[] appWidgetIds) {<br />
super.onDeleted(context, appWidgetIds);<br />
for (int appWidgetId : appWidgetIds) {<br />
Intent intent = new Intent();<br />
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);<br />
intent.setData(Uri.parse(&quot;widgettoast://widget/id/&quot; + appWidgetId));<br />
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,<br />
0, intent, 0);<br />
AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);<br />
alarm.cancel(pendingIntent);<br />
}<br />
}</div></td></tr></tbody></table></div>
<p>Confira abaixo o código das principais classes e arquivos do projeto, e o resultado na tela do dispositivo:<br />
<a href="http://pastebin.com/09F1u2Us">Widget Provider</a><br />
<a href="http://pastebin.com/xU5hVsgY">Activity de Configuração</a><br />
<a href="http://pastebin.com/HE7DPRwc">AndroidManifest.xml</a><br />
<a href="http://pastebin.com/U6TYwbE9">XML de meta-dados</a><br />
<a href="http://pastebin.com/QUwkxgaP">Widget Layout</a></p>
<div id="attachment_1358" class="wp-caption aligncenter" style="width: 210px"><a href="http://techne.cesar.org.br/wp-content/uploads/2011/02/widgets.png"><img src="http://techne.cesar.org.br/wp-content/uploads/2011/02/widgets-200x300.png" alt="" width="200" height="300" class="size-medium wp-image-1358" /></a><p class="wp-caption-text">Dois widgets na tela inicial</p></div>
<p>Apesar dos diversos detalhes envolvidos, a criação de um App Widget não é tarefa das mais complicadas. Aplicando conceitos como Intents, Broadcast Receivers, Activities, e boas práticas de desnvolvimento para Android, é possível construir aplicações ricas em conteúdo, com a melhor performance possível.</p>
]]></content:encoded>
			<wfw:commentRss>http://techne.cesar.org.br/android-uma-visao-mais-detalhada-sobre-widgets/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Usando o Cassandra</title>
		<link>http://techne.cesar.org.br/usando-o-cassandra/</link>
		<comments>http://techne.cesar.org.br/usando-o-cassandra/#comments</comments>
		<pubDate>Mon, 09 May 2011 12:04:36 +0000</pubDate>
		<dc:creator>Silvio Cortez</dc:creator>
				<category><![CDATA[Geral]]></category>

		<guid isPermaLink="false">http://techne.cesar.org.br/?p=1659</guid>
		<description><![CDATA[O Cassandra teve origem no facebook, foi desenvolvido por seus engenheiros, e atualmente se tornou um projeto parte do hadoop, após ter tido seu código fonte aberto. O Cassandra faz parte dos bancos de dados distribuídos, não relacionais, com crescimento escalável, tolerante a falhas; possui réplica do seus dados em vários nós, e descentralizado; não [...]]]></description>
			<content:encoded><![CDATA[<p>O Cassandra teve origem no facebook, foi desenvolvido por seus engenheiros, e atualmente se tornou um projeto parte do hadoop, após ter tido seu código fonte aberto. O Cassandra faz parte dos bancos de dados distribuídos, não relacionais, com crescimento escalável, tolerante a falhas; possui réplica do seus dados em vários nós, e descentralizado; não possui um único ponto de acesso.</p>
<p><strong>Conceitos</strong></p>
<p>O Cassandra armazena os dados usando o conceito de chave/valor, assim como o HBase; para aqueles que já usaram, e também usa o conceito de ColumnFamily, que agrupa um conjunto de colunas.</p>
<p><strong>Instalando o Cassandra</strong></p>
<p><strong> </strong></p>
<div>Realmente muito simples, fazendo o download em: <a title="aqui" href="http://cassandra.apache.org/download/">http://cassandra.apache.org/download/</a>, baixe uma das versões estáveis, existem várias delas, estou usando a versão 0.7.4 e descompacte em qualquer pasta.</div>
<p>No meu caso d:/ambiente/apache-cassandra-0.7.4. O Cassandra precisa de 3 diretórios para: dados, cache e logs, então criei como: D:/ambiente/Cassandra-dados, D:/ambiente/Cassandra-cache e D:/ambiente/Cassandra-logs, respectivamente. O importante aqui é modificar as propriedades no arquivo de configuração /cassandra-0.7.4/conf/Cassandra.yaml, indicando a localização dos diretórios, são elas: data_file_directories, saved_caches_directory e commitlog_directory.</p>
<p><a href="http://techne.cesar.org.br/wp-content/uploads/2011/05/cassandra-conf.png"></a><a href="http://techne.cesar.org.br/wp-content/uploads/2011/05/cassandra-conf.png"><img class="alignleft size-full wp-image-1660" src="http://techne.cesar.org.br/wp-content/uploads/2011/05/cassandra-conf.png" alt="" width="620" height="379" /></a></p>
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left"><strong>In</strong><strong>iciando o Cassandra</strong></p>
<p style="text-align: left">Para iniciar o servidor execute o seguinte comando: cassandra –f  do diretório de instalação. Um log será exibido no console como na figura abaixo, e se nenhum erro aparecer, tudo estará funcionado bem.</p>
<p style="text-align: left"><a href="http://techne.cesar.org.br/wp-content/uploads/2011/05/cassandra-start.png"><img class="alignleft size-full wp-image-1664" src="http://techne.cesar.org.br/wp-content/uploads/2011/05/cassandra-start.png" alt="" width="567" height="303" /></a></p>
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p style="text-align: left">
<p><strong>Usando o Cliente</strong></p>
<p>O Cassandra possui um cliente para linha de comando, vamos ver como este funciona. Para iniciar o cliente, execute o seguinte comando no diretório de instalação:<strong> cassandra-cli –host localhost –port 9160.</strong></p>
<p><strong><a href="http://techne.cesar.org.br/wp-content/uploads/2011/05/cassandra-cli.png"><img class="alignleft size-full wp-image-1693" src="http://techne.cesar.org.br/wp-content/uploads/2011/05/cassandra-cli.png" alt="" width="681" height="94" /></a></strong></p>
<p>Crie um keyspace, na própria documentação do Cassandra é feita uma analogia com schema de bancos de dados relacionais, através do comando: <strong> create keyspace Pessoas.</strong></p>
<p><a href="http://techne.cesar.org.br/wp-content/uploads/2011/05/keyspace-cassandra.png"><img class="alignleft size-full wp-image-1694" src="http://techne.cesar.org.br/wp-content/uploads/2011/05/keyspace-cassandra.png" alt="" width="681" height="73" /></a></p>
<p>Podemos notar que o keyspace foi criado no diretório /cassandra-data definido, como mostrado.</p>
<p><a href="http://techne.cesar.org.br/wp-content/uploads/2011/05/dir-keysapce-cassandra.png"><img class="alignleft size-full wp-image-1695" src="http://techne.cesar.org.br/wp-content/uploads/2011/05/dir-keysapce-cassandra.png" alt="" width="681" height="230" /></a></p>
<p>Aqui é necessário definir que você vai usar este keyspace, através do comando: <strong>use Pessoas</strong>. Após este passo, podemos definir nossa columnFamily, como mostrado na figura abaixo:</p>
<p><a href="http://techne.cesar.org.br/wp-content/uploads/2011/05/columnfamily-cassandra.png"><img class="alignleft size-full wp-image-1698" src="http://techne.cesar.org.br/wp-content/uploads/2011/05/columnfamily-cassandra.png" alt="" width="681" height="136" /></a></p>
<div>Basicamente, foi criado uma columnFamily que agrupa duas colunas: name e age, note que age está definido como Keys, isto vai permitir consultas a partir desta coluna.</div>
<div>Vamos agora inserir alguns dados de pessoas, usando o comando <strong>set</strong>, mostrado na figura abaixo:</div>
<div><a href="http://techne.cesar.org.br/wp-content/uploads/2011/05/set-cassandra.png"><img class="alignleft size-full wp-image-1699" src="http://techne.cesar.org.br/wp-content/uploads/2011/05/set-cassandra.png" alt="" width="682" height="94" /></a></div>
<div>
<div>Observe que as chaves usadas no exempo foram: silvio.corte e eric.oliveira, seguindo pelos os valores das colunas: name e age.</div>
<div>Para consultar os dados inseridos, usando o comando <strong>get</strong>, a consulta busca por age:</div>
</div>
<div><a href="http://techne.cesar.org.br/wp-content/uploads/2011/05/get-cassandra.png"><img class="alignleft size-full wp-image-1700" src="http://techne.cesar.org.br/wp-content/uploads/2011/05/get-cassandra.png" alt="" width="681" height="111" /></a></div>
<div>
<div><strong>Próximos Passos</strong></div>
<div><strong><br />
</strong></div>
<div>Nos próximos blogs vou falar do uso do Cassandra através de um cliente Java.</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://techne.cesar.org.br/usando-o-cassandra/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introdução ao MongoDB &#8211; parte 1</title>
		<link>http://techne.cesar.org.br/introducao-ao-mongodb-parte-1/</link>
		<comments>http://techne.cesar.org.br/introducao-ao-mongodb-parte-1/#comments</comments>
		<pubDate>Wed, 27 Apr 2011 13:33:12 +0000</pubDate>
		<dc:creator>Eric Cavalcanti</dc:creator>
				<category><![CDATA[Desempenho e Segurança de Sistemas]]></category>
		<category><![CDATA[Geral]]></category>
		<category><![CDATA[banco de dados]]></category>
		<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[NoSQL]]></category>

		<guid isPermaLink="false">http://techne.cesar.org.br/?p=1604</guid>
		<description><![CDATA[Neste artigo vamos conhecer o MongoDB que é um banco de dados Open Source, de alto desempenho, com esquemas dinâmicos, orientado a documentos e escrito na linguagem C++.  Segundo os criadores, o MongoDB foi criado do zero, utilizando suas experiências na construção de sistemas escaláveis, de alta disponibilidade e robustez. O MongoDB também está na [...]]]></description>
			<content:encoded><![CDATA[<p>Neste artigo vamos conhecer o MongoDB que é um banco de dados Open Source, de alto desempenho, com esquemas dinâmicos, orientado a documentos e escrito na linguagem C++.  Segundo os criadores, o MongoDB foi criado do zero, utilizando suas experiências na construção de sistemas escaláveis, de alta disponibilidade e robustez. O MongoDB também está na lista dos bancos de dados NoSQL por não ser relacional.</p>
<p><strong>Instalação</strong></p>
<p>O processo de instalação do MongoDB é bastante simples, basta realizar o download da versão Production Release de acordo com seu Sistema Operacional <a href="http://www.mongodb.org/downloads" target="_blank">aqui</a>. Neste artigo abordaremos a instalação no Windows, mas o processo é basicamente o mesmo em outros Sistemas Operacionais.<br />
Após o download vamos descompactar o MongoDB é uma pasta qualquer, no meu caso D:\ e opcionalmente podemos renomear de mongo-xxxxxxx para apenas mongodb, ficando então em D:\mongodb.<br />
O MongoDB  precisa da seguinte estrutura de pastas \data\db para armazenamento dos dados, só que a mesma não é criada automaticamente.  Então como nossa instalação está na unidade D:, vamos criar a estrutura de pastas D:\data\db.</p>
<p><strong>Executando o servidor</strong></p>
<p>Com tudo pronto, agora vamos executar o servidor do MongoDB. Para isso vamos executar o arquivo mongod.exe localizado na pasta bin pelo Explorer ou pela linha de comando conforme figura 1.</p>
<p><a href="http://techne.cesar.org.br/wp-content/uploads/2011/04/mongod1.png"><img class="alignnone size-medium wp-image-1607" src="http://techne.cesar.org.br/wp-content/uploads/2011/04/mongod1-300x151.png" alt="" width="300" height="151" /></a><br />
Figura 1. Executando o servidor MongoDB pela linha de comando.</p>
<p><strong>Utilizando o cliente</strong></p>
<p>Agora vamos iniciar um Shell administrativo executando o mongo.exe que também está localizado na pasta bin conforme figura 2.</p>
<p><a href="http://techne.cesar.org.br/wp-content/uploads/2011/04/mongo.png"><img class="alignnone size-medium wp-image-1606" src="http://techne.cesar.org.br/wp-content/uploads/2011/04/mongo-300x151.png" alt="" width="300" height="151" /></a><br />
Figura 2. Executando o cliente mongo.exe</p>
<p>Podemos perceber que por padrão o cliente conecta a base de dados test no servidor localhost. Digitando help o console exibe todos os comandos disponíveis.<br />
Vamos digitar agora o comando:</p>
<pre>&gt; use mydb
switched to db mydb</pre>
<p>Diferentemente de muitos bancos de dados existentes percebam que não é preciso executar um comando para criar um banco de dados. O mais interessante ainda é que o banco só é criado fisicamente quando os primeiros dados forem inseridos. Para confirmar executaremos o comando show dbs para exibir todos os bancos de dados:</p>
<pre>&gt; show dbs
admin   (empty)
local   (empty)
test    0.03125GB</pre>
<p>Está na hora de adicionarmos algumas informações e consultá-las.</p>
<pre>&gt; objeto1 = { nome : "mongo" };
{ "nome" : "mongo" }
&gt; registroNovo = { x : 3 };
{ "x" : 3 }
&gt; db.minhaTabela.save(objeto1);
&gt; db.minhaTabela.save(registroNovo);
&gt; db.minhaTabela.find();
{ "_id" : ObjectId("4db5bda2eac9332a080885e8"), "nome" : "mongo" }
{ "_id" : ObjectId("4db5bdbdeac9332a080885e9"), "x" : 3 }</pre>
<p>Agora vamos analisar o que foi executado. Inicialmente criamos dois objetos (documentos na nomenclatura do MongoDB): objeto1 e registroNovo. Percebam que eles possuem uma estrutura de campos totalmente diferente. Em seguida, adicionamos os dois objetos à tabela (coleção na nomenclatura do MongoDB) minhaTabela através do comando save(), na última linha realizamos uma consulta aos dados da tabela através do comando find().</p>
<p>Com isso passamos a entender o que seria o esquema dinâmico, onde não existe o conceito de estrutura de campos para uma tabela. Sendo o campo (chave na nomeclatura do MongoDB) _id criado automaticamente no momento do insert.</p>
<p>Bem pessoal, por enquanto é só. Aguardem os próximos posts sobre o MongoDB.</p>
]]></content:encoded>
			<wfw:commentRss>http://techne.cesar.org.br/introducao-ao-mongodb-parte-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>bada timer</title>
		<link>http://techne.cesar.org.br/bada-timer/</link>
		<comments>http://techne.cesar.org.br/bada-timer/#comments</comments>
		<pubDate>Tue, 05 Apr 2011 13:01:47 +0000</pubDate>
		<dc:creator>Eduardo</dc:creator>
				<category><![CDATA[Geral]]></category>
		<category><![CDATA[bada]]></category>

		<guid isPermaLink="false">http://techne.cesar.org.br/?p=1578</guid>
		<description><![CDATA[Today we will see how to use Osp::Base::Runtime::Timer
This class can activate the timer and notify the listeners.
This timer class is not a periodic timer, only a one-shot timer. If you want to carry out periodic tasks, you must start it again after it has fired.
It&#8217;s easy to use Timers in your app&#8230; lets see:
You must [...]]]></description>
			<content:encoded><![CDATA[<p>Today we will see how to use <a href="http://dpimg.ospos.net/contents/docs/apis/bada-V1.0.0a3/framework/classOsp_1_1Base_1_1Runtime_1_1Timer.html" target="notarget">Osp::Base::Runtime::Timer</a></p>
<p>This class can activate the timer and notify the listeners.<br />
This timer class is not a periodic timer, only a one-shot timer. If you want to carry out periodic tasks, you must start it again after it has fired.</p>
<p>It&#8217;s easy to use Timers in your app&#8230; lets see:</p>
<p>You must extend and construct your Timer</p>
<p>Extend (.h):</p>
<pre>public Osp::Base::Runtime::ITimerEventListener</pre>
<p>Construct(.cpp):</p>
<pre>    __pTimer = new Timer();
    r = __pTimer-&gt;Construct(*this);
    r = __pTimer-&gt;Start(1000);</pre>
<p>Implement OnTimerExpired (to start again your Timer), as shown below:</p>
<pre>void
MyApp::OnTimerExpired(Timer&amp; timer)
{

    ...

    timer.Start(1000);
}</pre>
<p><strong>Every time your timer ends, OnTimerExpired is called (so you can start your timer again).</strong></p>
<p>Full example:</p>
<pre>class MyApp
    : public ITimerEventListener
{
   ...
public:
    result InitTimer();
public:
    void OnTimerExpired(Timer&amp; timer);
};

void
MyApp::OnTimerExpired(Timer&amp; timer)
{

    ...

    timer.Start(1000);
}

result
MyApp::InitTimer()
{
    result r = E_SUCCESS;

    __pTimer = new Timer;

    r = __pTimer-&gt;Construct(*this);
    if (IsFailed(r))
    {
        goto CATCH;
    }

    __pTimer-&gt;Start(1000);
    if (IsFailed(r))
    {
        goto CATCH;
    }

    return r;
CATCH:
    return r;
}</pre>
<p>A real example &#8211; implementing a bada Chronometer:<br />
Construct:</p>
<pre>    keepRunning = true;
    //get actual time and set as initial time when form is loaded.
    SystemTime::GetTicks(initialTime);
    __pTimer = new Timer();
    r = __pTimer-&gt;Construct(*this);
    r = __pTimer-&gt;Start(1000);

void
MyApp::Cronometer(){
 completeTime = "00:00:00";
 int diff, hour, minutes, seconds;
    String hourTxt, minutesTxt, secondsTxt;
 if(keepRunning){
  SystemTime::GetTicks(currentTime);
                //get actual time to make diff with initial time
  diff = (currentTime - initialTime);

  hour = Math::Floor((diff/1000)/60/60);
  minutes = Math::Floor((diff/1000)/60);
  seconds = Math::Floor((diff/1000)%60);
  if (seconds &lt;= 9){
   secondsTxt = "0" + LongLong::ToString(seconds%60);
  }else if(seconds == 60){
   secondsTxt = "00";
   minutes++;
  }else{
   secondsTxt = LongLong::ToString(seconds%60);
  }

  if (minutes &lt;= 9){
   minutesTxt = "0" + LongLong::ToString(minutes%60);
  }else if(minutes == 60){
   minutesTxt = "00";
   hour++;
  }else{
   minutesTxt = LongLong::ToString(minutes%60);
  }

  if (hour &lt;= 9){
   hourTxt = "0" + LongLong::ToString(hour);
  }else if(hour == 24){
   hourTxt = "00";
  }else{
   hourTxt = LongLong::ToString(hour%24);
  }

  completeTime = hourTxt + ":"+ minutesTxt + ":"+ secondsTxt;

  Label *lblChrono = static_cast<label>(GetControl(L"IDC_CHRONO"));
  if (null != lblChrono){
   lblChrono-&gt;SetText(completeTime);
   lblChrono-&gt;RequestRedraw(true);
  }

 }
    return;
}

void
MyApp::OnTimerExpired (Osp::Base::Runtime::Timer &amp;timer)
{
 result r = E_SUCCESS;
        //call crhonometer to update label with time
 Cronometer();
        //start again - 1second period
 __pTimer-&gt;Start(1000);
 TryCatch(r == E_SUCCESS, , GetErrorMessage(r));
 return;

 CATCH:
  SetLastResult(r);
  return;

}
</label></pre>
<p>Thanks for your visit! <img src='http://techne.cesar.org.br/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Feel free to ask/suggest/comment.<br />
Twitter: <a href="http://www.twitter.com/oliveiraeduardo" target="notarget">@oliveiraeduardo</a></p>
]]></content:encoded>
			<wfw:commentRss>http://techne.cesar.org.br/bada-timer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>bada i18n</title>
		<link>http://techne.cesar.org.br/bada-i18n/</link>
		<comments>http://techne.cesar.org.br/bada-i18n/#comments</comments>
		<pubDate>Mon, 04 Apr 2011 19:23:15 +0000</pubDate>
		<dc:creator>Eduardo</dc:creator>
				<category><![CDATA[Geral]]></category>
		<category><![CDATA[bada]]></category>
		<category><![CDATA[i18n]]></category>

		<guid isPermaLink="false">http://techne.cesar.org.br/?p=1572</guid>
		<description><![CDATA[Today we&#8217;ll learn how to internationalize our bada apps.
i18n = internationalization &#8211; means of adapting computer software to different languages, regional differences and technical requirements of a target market. Internationalization is the process of designing a software application so that it can be adapted to various languages and regions without engineering changes. The terms are [...]]]></description>
			<content:encoded><![CDATA[<p>Today we&#8217;ll learn how to internationalize our bada apps.</p>
<p><a href="http://en.wikipedia.org/wiki/Internationalization_and_localization" target="notarget">i18n = internationalization</a> &#8211; means of adapting computer software to different languages, regional differences and technical requirements of a target market. Internationalization is the process of designing a software application so that it can be adapted to various languages and regions without engineering changes. The terms are frequently abbreviated to the numeronyms i18n (where 18 stands for the number of letters between the first i and last n in internationalization, a usage coined at DEC in the 1970s or 80s).</p>
<p><span style="font-weight: bold;">8 steps to internationalize our bada apps</span>:</p>
<p><a href="http://3.bp.blogspot.com/-zQvYNQA3W_A/TXrOF-rXY9I/AAAAAAAAANo/u4iI5zCXek8/s1600/i18n_1.png"><img style="margin: 0px auto 10px; text-align: center; cursor: pointer; width: 311px; height: 320px;" src="http://3.bp.blogspot.com/-zQvYNQA3W_A/TXrOF-rXY9I/AAAAAAAAANo/u4iI5zCXek8/s320/i18n_1.png" border="0" alt="" /></a></p>
<p>Figure 1. Resource view: Double click in String table (as shown)</p>
<p><a href="http://2.bp.blogspot.com/-jnEOQ0nd6d0/TXrOFhIXJ8I/AAAAAAAAANg/D2smFjsjiRM/s1600/i18n_2.png"><img style="margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 177px;" src="http://2.bp.blogspot.com/-jnEOQ0nd6d0/TXrOFhIXJ8I/AAAAAAAAANg/D2smFjsjiRM/s320/i18n_2.png" border="0" alt="" /></a></p>
<p>Figure 2. String view will be opened</p>
<p><a href="http://3.bp.blogspot.com/-DFYuK4ZlmZY/TXrOFWIpX0I/AAAAAAAAANY/sghYH2LoYTc/s1600/i18n_3.png"><img style="margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 198px;" src="http://3.bp.blogspot.com/-DFYuK4ZlmZY/TXrOFWIpX0I/AAAAAAAAANY/sghYH2LoYTc/s320/i18n_3.png" border="0" alt="" /></a></p>
<p>Figure 3. Right click and choose Language Setting. Here you&#8217;ll select the languages that your app will give support.</p>
<p><a href="http://2.bp.blogspot.com/-CTfBP-tT4jo/TXrN6zBerhI/AAAAAAAAANQ/rU_RK9yp_Bw/s1600/i18n_4.png"><img style="margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 302px;" src="http://2.bp.blogspot.com/-CTfBP-tT4jo/TXrN6zBerhI/AAAAAAAAANQ/rU_RK9yp_Bw/s320/i18n_4.png" border="0" alt="" /></a></p>
<p>Figure 4. Add the languages that your app will give support</p>
<p><a href="http://3.bp.blogspot.com/-3Azi2g5ANyY/TXrN6kKELuI/AAAAAAAAANI/D32I_w0JwSM/s1600/i18n_5.png"><img style="margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 192px;" src="http://3.bp.blogspot.com/-3Azi2g5ANyY/TXrN6kKELuI/AAAAAAAAANI/D32I_w0JwSM/s320/i18n_5.png" border="0" alt="" /></a></p>
<p>Figure 5. String table view will be updated with selected languages</p>
<p><a href="http://1.bp.blogspot.com/-VocWNL2k1ac/TXrN6R0H6xI/AAAAAAAAANA/mFowrk6hVCg/s1600/i18n_6.png"><img style="margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 194px;" src="http://1.bp.blogspot.com/-VocWNL2k1ac/TXrN6R0H6xI/AAAAAAAAANA/mFowrk6hVCg/s320/i18n_6.png" border="0" alt="" /></a></p>
<p>Figure 6. Right click and choose &#8220;insert&#8221; to fill the table with internationalized content. I suggest you to use IDs with some pattern name. Example: IDS_CLASSNAME_VARIABLENAME</p>
<p><a href="http://4.bp.blogspot.com/-iXKHf7nMYZ4/TXrN6O_rqxI/AAAAAAAAAM4/FtIpM7Wi3X8/s1600/i18n_7.png"><img style="margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 205px;" src="http://4.bp.blogspot.com/-iXKHf7nMYZ4/TXrN6O_rqxI/AAAAAAAAAM4/FtIpM7Wi3X8/s320/i18n_7.png" border="0" alt="" /></a></p>
<p>Figure 7. String table with a content example</p>
<p><a href="http://1.bp.blogspot.com/-_jpptG8gLSo/TXrN57pFkwI/AAAAAAAAAMw/IFs6o4jDSWI/s1600/i18n_8.png"><img style="margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 210px;" src="http://1.bp.blogspot.com/-_jpptG8gLSo/TXrN57pFkwI/AAAAAAAAAMw/IFs6o4jDSWI/s320/i18n_8.png" border="0" alt="" /></a></p>
<p>Figure 8. You can just associate the contents, created in String tables, with any control (labels, buttons, &#8230;)</p>
<p>If you need to internationalize any text that will not be constructed directly in any Form or Popup, you must insert the ID and content in String table and you can associate the created content to any control through code, as shown below:</p>
<pre>...
//get controls
Label *lblContent = static_cast<label>(GetControl(L"IDC_LABEL2CONTENT"));
Label *lblTitle = static_cast<label>(GetControl(L"IDC_LABEL2MAINTITLE"));
Application* appStep = Application::GetInstance();
result r;
if(null!=lblContent &amp;&amp; null!=lblTitle){
//get the string associated with an ID (String table) and
//save into titleTxt var
r = appStep-&gt;GetAppResource()-&gt;
    GetString(L"IDS_FORM2SCREENLBL_OBST_TITLE",titleTxt);
TryCatch(r == E_SUCCESS, , "GetAppResource is failed");
//set the internationalized text from String table to Label.
lblTitle-&gt;SetText(titleTxt);
lblTitle-&gt;RequestRedraw(true);
r = appStep-&gt;GetAppResource()-&gt;
    GetString(L"IDS_FORM2SCREENLBL_OBST_CONTENT",contentTxt);
TryCatch(r == E_SUCCESS, , "GetAppResource is failed");
lblContent-&gt;SetText(contentTxt);
lblContent-&gt;RequestRedraw(true);
...
</label></label></pre>
<p>You can change emulator language and test your bada i18n&#8230;</p>
<p>Thanks for your visit! <img src='http://techne.cesar.org.br/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /><br />
Feel free to ask/suggest/comment.<br />
Twitter: <a href="http://www.twitter.com/oliveiraeduardo" target="notarget">@oliveiraeduardo</a></p>
]]></content:encoded>
			<wfw:commentRss>http://techne.cesar.org.br/bada-i18n/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HTML5: Construindo um servidor de WebSockets com .net framework (C#)</title>
		<link>http://techne.cesar.org.br/html5-construindo-um-servidor-de-websockets-com-net-framework-c/</link>
		<comments>http://techne.cesar.org.br/html5-construindo-um-servidor-de-websockets-com-net-framework-c/#comments</comments>
		<pubDate>Thu, 10 Mar 2011 17:39:35 +0000</pubDate>
		<dc:creator>Rafael Amaral</dc:creator>
				<category><![CDATA[Geral]]></category>
		<category><![CDATA[.net framework]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[HTML5]]></category>
		<category><![CDATA[WebSockets]]></category>

		<guid isPermaLink="false">http://techne.cesar.org.br/?p=1490</guid>
		<description><![CDATA[HTML5 é a quinta grande revisão do core da linguagem HTML trazendo novas features e elementos, tentando tratar tópicos que não eram adequadamente cobertos em versões anteriores e trazendo um meio padronizado de se criar aplicações web.
Websockets aparecem como uma interessante nova feature do HTML5. Essa feature define um canal de comunicação full-duplex através do [...]]]></description>
			<content:encoded><![CDATA[<p>HTML5 é a quinta grande revisão do core da linguagem HTML trazendo novas <em>features</em> e elementos, tentando tratar tópicos que não eram adequadamente cobertos em versões anteriores e trazendo um meio padronizado de se criar aplicações web.</p>
<p>Websockets aparecem como uma interessante nova <em>feature</em> do HTML5. Essa <em>feature</em> define um canal de comunicação <em>full</em>-<em>duplex </em>através do qual mensagens podem ser trocadas entre o lado cliente e servidor de uma aplicação web de forma bidirecional. Abaixo temos uma imagem que mostra o atual suporte a websockets nos navegadores retirada da página <a href="http://caniuse.com/">http://caniuse.com/</a>:</p>
<p><a href="http://techne.cesar.org.br/wp-content/uploads/2011/03/WebsockeysSupport.png"><img class="aligncenter size-full wp-image-1492" src="http://techne.cesar.org.br/wp-content/uploads/2011/03/WebsockeysSupport.png" alt="Suporte a Websockets" width="606" height="176" /></a></p>
<p>Assim como o HTML5, websockets ainda estão em versão <em>draft</em>, mas desenvolvedores podem começar a testar esse recurso implementando servidores que suportem uma das versões do protocolo e utilizar clientes que suportem a mesma versão. Atualmente alguns dos mais modernos browsers suportam a versão <em>draft-hixie-thewebsocketprotocol-76</em> (<a href="http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76">http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76</a>) também conhecida <em>como draft-ietf-hybi-thewebsocketprotocol-00</em>.</p>
<p>Neste <em>post</em> veremos como construir um protótipo de um simples servidor que suporta a versão <em>draft-hixie-thewebsocketprotocol-76</em> do protocolo utilizando sockets em c#. O servidor será um console application que aceita uma conexão de websocket, recebe mensagens do cliente e envia os dados recebidos de volta em letras maiúsculas. No lado cliente usaremos uma página com HTML/javascript rodando sobre algum navegador que suporte a versão 76 do protocolo. Em testes durante a escrita deste post foi utilizada a versão mais atual do Chrome (no momento a 10.0.648.127).</p>
<p><strong>Overview do projeto</strong></p>
<p>Para estabelecer uma conexão via websocket cliente e servidor precisam se comunicar e verificar que conseguem falar na mesma língua, para isso é necessário se realizar um <em>handshake</em>. Abaixo um exemplo de <em>handshake</em> extraído do documento <em>draft -hixie-thewebsocketprotocol-76</em>:</p>
<pre><strong>Exemplo de mensagem de <em>handshake</em> vinda do cliente:</strong></pre>
<p>GET /demo HTTP/1.1<br />
Host: example.com<br />
Connection: Upgrade<br />
Sec-WebSocket-Key2: 12998 5 Y3 1  .P00<br />
Sec-WebSocket-Protocol: sample<br />
Upgrade: WebSocket<br />
Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5<br />
Origin: http://example.com</p>
<p>^n:ds[4U</p>
<pre><strong><strong>Exemplo de resposta vinda do servidor:</strong></strong></pre>
<p>HTTP/1.1 101 WebSocket Protocol Handshake<br />
Upgrade: WebSocket<br />
Connection: Upgrade<br />
Sec-WebSocket-Origin: http://example.com<br />
Sec-WebSocket-Location: ws://example.com/demo<br />
Sec-WebSocket-Protocol: sample</p>
<p>8jKS'y:G*Co,Wxa-</p>
<p>Explicando de uma forma simplificada, para completar o <em>handshake</em> o servidor precisa analisar a mensagem que veio do cliente e realizar algumas operações sobre os valores de <em>Sec-WebSocket-Key1, Sec-WebSocket-Key2</em> e os últimos 8 bytes da mensagem (no exemplo acima representada pelo valor  ^n:ds[4U) e construir uma mensagem de resposta garantindo ao cliente que os dois lados sabem falar a mesma língua.</p>
<p>Uma vez tendo estabelecida a conexão, os dois lados podem trocar informações via data frames que são delimitados pelos bytes 0x00 e  0xFF e contém dados com codificação UTF-8 entre os delimitadores.</p>
<p>Todos os métodos para realizar o <em>handshake</em> e as trocas de mensagens estão explicados mais detalhadamente no projeto disponibilizado neste post, bem como a implementação de um cliente HTML/javascript. É necessário que antes de testar o projeto seja modificado o ip no arquivo de configuração do servidor (App.config) e no HTML como  é visto a seguir.</p>
<p><strong>App.config</strong></p>
<pre>&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;configuration&gt;
  &lt;appSettings&gt;
                      &lt;!--Coloque seu ip aqui--&gt;
    &lt;add key="ipaddress" value="SEU_IP_AQUI" /&gt; 

    &lt;add key="port" value="8181" /&gt;
    &lt;add key="location" value="ts" /&gt;

  &lt;/appSettings&gt;
&lt;/configuration&gt;</pre>
<p><strong> WebSocketClient.htm</strong></p>
<pre>&lt;!--Substuir "SEU_IP_AQUI" pelo ip
                              que foi configurado no .config do servidor--&gt;
    &lt;input id="txtConnect" type="text" value="ws://SEU_IP_AQUI:8181/ts" /&gt;

    &lt;input id="btnConnect" type="button" value="Connect" onclick="Connect()" /&gt;
    &lt;br /&gt;
    &lt;input id="txtSend" type="text" /&gt;
    &lt;input id="btnSend" type="button" value="Send" onclick="Send()" /&gt;
    &lt;input id="btnClose" type="button" value="Close" onclick="Close()" /&gt;
    &lt;/form&gt;
&lt;/body&gt;</pre>
<p>Após configurar o App.config do servidor e o HTML do cliente basta rodar o servidor e acessar o arquivo HTML pelo browser. O projeto com o código pode ser acessado aqui: <a href="http://cid-2279647898802a3c.office.live.com/self.aspx/.Public/WebSocket76.zip">http://cid-2279647898802a3c.office.live.com/self.aspx/.Public/WebSocket76.zip</a> e os arquivos do servidor e do cliente são os seguintes:</p>
<p><strong>Program.cs</strong></p>
<pre>using System;
using System.Configuration;
using System.Net;
using System.Net.Sockets;

namespace WebSocket76
{
    class Program
    {
        static void Main(string[] args)
        {
            //Pega dados do arquivo de configuracao WebSocket76.exe.config
            //(App.config), nao esqueca de colocar seu ip la e no html tambem
            string ipAddress = ConfigurationSettings.AppSettings["ipaddress"];
            int port = int.Parse(ConfigurationSettings.AppSettings["port"]);

            string location = &#8220;ws://&#8221; + ipAddress + &#8220;:&#8221; + port
                + &#8220;/&#8221; + ConfigurationSettings.AppSettings["location"];

            TcpListener tcpListener =
              new TcpListener(new IPEndPoint(IPAddress.Parse(ipAddress), port));

            tcpListener.Start();

            Console.WriteLine(&#8220;Esperando conexÃ£o&#8230;&#8221;);
            Socket client = tcpListener.AcceptSocket();

            Console.WriteLine(&#8220;Tentativa de conexÃ£o iniciada&#8230;&#8221;);
            WebSocketServer wss = new WebSocketServer(client, location);

            Console.Read();
        }
    }
}<strong> </strong></pre>
<p><strong>WebSocketServer.cs</strong></p>
<pre>using System;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading;

namespace WebSocket76
{
    public class WebSocketServer
    {
        /// &lt;summary&gt;
        /// Socket usado como servidor
        /// &lt;/summary&gt;
        private Socket _socketClient;

        /// &lt;summary&gt;
        /// Thread para receber dados do cliente
        /// &lt;/summary&gt;
        private Thread _dataReceivedThread;

        /// &lt;summary&gt;
        /// Indica se o servidor esta ativo
        /// &lt;/summary&gt;
        private bool _webSocketServerActive;

        /// &lt;summary&gt;
        /// Tamanho do buffer de recebimento de dados
        /// &lt;/summary&gt;
        private const int BUFFER_SIZE = 1024;

        /// &lt;summary&gt;
        /// Indica se o handshake ja foi feito
        /// &lt;/summary&gt;
        private bool _handShakeDone;

        /// &lt;summary&gt;
        /// Local do servidor
        /// &lt;/summary&gt;
        private string _location;

        /// &lt;summary&gt;
        /// Construtor
        /// &lt;/summary&gt;
        /// &lt;param name="client"&gt;Socket para ser usado como servidor&lt;/param&gt;
        /// &lt;param name="location"&gt;Location&lt;/param&gt;
        internal WebSocketServer(Socket client, string location)
        {
            _socketClient = client;
            _webSocketServerActive = true;
            _dataReceivedThread = new Thread(dataReceived);
            _dataReceivedThread.Start();

            _location = location;

            _handShakeDone = false;

        }

        /// &lt;summary&gt;
        /// Recebe dados do cliente e os trata
        /// &lt;/summary&gt;
        private void dataReceived()
        {
            try
            {
                StringBuilder receivedDataString = new StringBuilder();

                while (_webSocketServerActive)
                {

                    byte[] data = new byte[BUFFER_SIZE];
                    int receivedDataLength = _socketClient.Receive(data);

                    //verifica se a conexao foi fechada
                    if (receivedDataLength &lt; 1)
                    {
                        _webSocketServerActive = false;
                    }
                    else if (_webSocketServerActive)
                    {
                        //realiza handshake se o mesmo ainda nao tiver sido
                        //feito
                        if (!_handShakeDone)
                        {
                            Console.WriteLine("Iniciando handshake...");
                            StartHandShakeProcess(data, receivedDataLength);
                            _handShakeDone = true;
                        }
                        else //pega dados nos outros casos
                        {
                            System.Text.UTF8Encoding decoder =
                                new System.Text.UTF8Encoding();

                            string stringData =
                                decoder.GetString(data, 0, receivedDataLength);
                            receivedDataString.Append(stringData);

                            //Verifica se e o final da mensagem
                            if (receivedDataLength &gt; 0 &amp;&amp;
                                (data[receivedDataLength - 1]
                                == BitConverter.GetBytes(0xFF)[0]))
                            {
                                string strData = receivedDataString.ToString();
                                strData = strData.Substring(1,
                                                           strData.Length - 2);

                                Console.WriteLine("DADOS RECEBIDOS: "
                                    + strData);

                                Console.WriteLine("Enviando dados" +
                                    " de volta para o cliente");

                                //envia a mensagem recebida de volta
                                //ao cliente com tudo em letras maiusculas
                                SendData(strData.ToUpper());

                                receivedDataString = new StringBuilder();
                            }
                        }
                    }
                }
            }
            catch
            {
                _webSocketServerActive = false;
            }
            finally
            {
                Console.WriteLine("Encerrando servidor");

                Shutdown();

                Console.WriteLine("Pressione enter para fechar o servidor");
            }
        }

        /// &lt;summary&gt;
        /// Finaliza servidor
        /// &lt;/summary&gt;
        internal void Shutdown()
        {
            _webSocketServerActive = false;

            if (_socketClient != null &amp;&amp; _socketClient.Connected)
            {
                _socketClient.Shutdown(SocketShutdown.Both);
                _socketClient.Close();
            }
        }

        /// &lt;summary&gt;
        /// Envia dados para o cliente
        /// &lt;/summary&gt;
        /// &lt;param name="data"&gt;Dados a serem enviados&lt;/param&gt;
        internal void SendData(string data)
        {
            byte[] toSend = Encoding.UTF8.GetBytes(data);
            SendDataToClient(toSend);
        }

        /// &lt;summary&gt;
        /// Envia dados para o cliente de acordo com thewebsocketprotocol-76
        /// &lt;/summary&gt;
        /// &lt;param name="toSendBack"&gt;&lt;/param&gt;
        private void SendDataToClient(byte[] toSendBack)
        {
            //Os dataframes sao delimitados pelos bytes 0x00 e 0xFF e
            //contem dados com codificacao UTF-8 entre esses delimitadores
            try
            {
                _socketClient.Send(BitConverter.GetBytes(0x00));
                _socketClient.Send(toSendBack);
                _socketClient.Send(BitConverter.GetBytes(0xFF));
            }
            catch
            {
                Shutdown();
            }
        }

        #region Handshake

        /// &lt;summary&gt;
        /// Iniicia o processo de handshake
        /// &lt;/summary&gt;
        /// &lt;param name="data"&gt;Handshake vindo do cliente&lt;/param&gt;
        /// &lt;param name="receivedDataLength"&gt;Tamanho dos dados recebidos&lt;/param&gt;
        private void StartHandShakeProcess(byte[] data, int receivedDataLength)
        {
            byte[] last8Bytes = new byte[8];
            Array.Copy(data, receivedDataLength - 8, last8Bytes, 0, 8);

            System.Text.UTF8Encoding decoder = new System.Text.UTF8Encoding();
            string stringHandShakeRequest =
                decoder.GetString(data, 0, receivedDataLength - 8);

            DoHandShake(stringHandShakeRequest, last8Bytes);
        }

        /// &lt;summary&gt;
        /// Controi a resposta e a envia para o cliente
        /// &lt;/summary&gt;
        /// &lt;param name="stringHandShakeRequest"&gt;Parte inicial
        ///                                     do handshake&lt;/param&gt;
        /// &lt;param name="last8Bytes"&gt;Ultimos 8 bytes que compoem
        ///                          o handshake&lt;/param&gt;
        private void DoHandShake(string stringHandShakeRequest,
                                 byte[] last8Bytes)
        {
            StringBuilder handShakeSB = new StringBuilder();

            handShakeSB.Append("HTTP/1.1 101 Web Socket Protocol Handshake"
                               + Environment.NewLine);
            handShakeSB.Append("Upgrade: WebSocket" + Environment.NewLine);
            handShakeSB.Append("Connection: Upgrade" + Environment.NewLine);

            string connectionOrigin =
                LoadConnectionOriginFromHandShake(stringHandShakeRequest);
            handShakeSB.Append("Sec-WebSocket-Origin: " +
                               connectionOrigin + Environment.NewLine);

            handShakeSB.Append("Sec-WebSocket-Location: "
                              + _location + Environment.NewLine);
            handShakeSB.Append(Environment.NewLine);

            byte[] handShakeResponsePart1 =
                Encoding.UTF8.GetBytes(handShakeSB.ToString());
            byte[] handShakeChallengeResponse =
                BuildChallengeResponse(stringHandShakeRequest, last8Bytes);

            byte[] handshakeResponse = new byte[handShakeResponsePart1.Length +
                                            handShakeChallengeResponse.Length];
            Array.Copy(handShakeResponsePart1,
                       handshakeResponse, handShakeResponsePart1.Length);
            Array.Copy(handShakeChallengeResponse, 0, handshakeResponse,
                       handShakeResponsePart1.Length,
                       handShakeChallengeResponse.Length);

            Console.WriteLine("Enviando resposta de handshake...");
            //Envia resposta para o cliente
            int a = _socketClient.Send(handshakeResponse, 0,
                    handshakeResponse.Length, 0);

        }

        /// &lt;summary&gt;
        /// Gera a resposta a partir da duas chaves e dos ultimos 8 bytes
        /// do handshake
        /// &lt;/summary&gt;
        /// &lt;param name="stringHandShakeRequest"&gt;Parte inicial
        ///                                      do handshake&lt;/param&gt;
        /// &lt;param name="last8Bytes"&gt;Ultimos 8 bytes que compoem
        ///                          o handshake&lt;/param&gt;
        /// &lt;returns&gt;A resposta&lt;/returns&gt;
        private byte[] BuildChallengeResponse(string stringHandShakeRequest,
                                              byte[] last8Bytes)
        {
            byte[] keyResult1 = null;
            byte[] keyResult2 = null;

            string[] handShakeTextLines = stringHandShakeRequest.Split(
                new string[] { Environment.NewLine },
                System.StringSplitOptions.RemoveEmptyEntries);

            foreach (string line in handShakeTextLines)
            {
                if (line.Contains("Sec-WebSocket-Key1:"))
                {
                    keyResult1 = getKeyResult(line.Substring(line.IndexOf(":")
                          + 2));
                }
                else if (line.Contains("Sec-WebSocket-Key2:"))
                {
                    keyResult2 = getKeyResult(line.Substring(line.IndexOf(":")
                        + 2));
                }
            }

            byte[] challengeResponse = BuildMD5ChallengeResponse(keyResult1,
                keyResult2, last8Bytes);

            return challengeResponse;
        }

        /// &lt;summary&gt;
        /// Gera um pedaco da resposta final baseado na chave passada como
        /// parametro seguindo as especiicacoes de
        /// http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76
        /// &lt;/summary&gt;
        /// &lt;param name="originalKey"&gt;Uma chave&lt;/param&gt;
        /// &lt;returns&gt;Um numero no formato big-endian 32-bit(byte mais
        ///          significativo armazenado primeiro)&lt;/returns&gt;
        private byte[] getKeyResult(string originalKey)
        {
            byte[] resultKey = null;
            StringBuilder keyNumbers = new StringBuilder();
            int whiteSpacesCount = 0;

            foreach (char c in originalKey.ToCharArray())
            {
                //peque os digitos da chave e concatene gerando um numero
                if (char.IsDigit(c))
                {
                    keyNumbers.Append(c);

                }//conte quantos espacos em branco existem
                else if (char.IsWhiteSpace(c))
                {
                    whiteSpacesCount++;
                }
            }

            //Divida o numero gerado pela quantidade de espaÃ§os em branco
            int numericResult = (int)(Convert.ToInt64(keyNumbers.ToString()) /
                                 whiteSpacesCount);

            resultKey = BitConverter.GetBytes(numericResult);

            //garanta que esta como big-endian
            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(resultKey);
            }

            return resultKey;
        }

        /// &lt;summary&gt;
        /// Constroi a resposta em md5 de key1 + key2 + key3
        /// 4 bytes big endian key1 + 4 bytes big endian key2 + 8 bytes key3.
        /// &lt;/summary&gt;
        /// &lt;param name="key1"&gt;4 bytes big endian key1&lt;/param&gt;
        /// &lt;param name="key2"&gt;4 bytes big endian key2&lt;/param&gt;
        /// &lt;param name="last8Bytes"&gt;8 bytes key3&lt;/param&gt;
        /// &lt;returns&gt;16 bytes md5 de key1 + key2 + key3&lt;/returns&gt;
        private byte[] BuildMD5ChallengeResponse(byte[] key1, byte[] key2,
                                                 byte[] last8Bytes)
        {
            byte[] challengeResponse = null;
            byte[] challengeArray = new byte[16];

            Array.Copy(key1, 0, challengeArray, 0, 4);
            Array.Copy(key2, 0, challengeArray, 4, 4);
            Array.Copy(last8Bytes, 0, challengeArray, 8, 8);

            MD5 md5Gen = MD5.Create();
            challengeResponse = md5Gen.ComputeHash(challengeArray);

            return challengeResponse;
        }

        /// &lt;summary&gt;
        /// Pega a origin do handshake
        /// &lt;/summary&gt;
        /// &lt;param name="stringHandShakeRequest"&gt;Handshake&lt;/param&gt;
        /// &lt;returns&gt;Origin&lt;/returns&gt;
        private string LoadConnectionOriginFromHandShake(
                                                 string stringHandShakeRequest)
        {
            string connectionOrigin = null;

            string[] handShakeTextLines = stringHandShakeRequest.Split(
                new string[] { Environment.NewLine },
                System.StringSplitOptions.RemoveEmptyEntries);

            foreach (string line in handShakeTextLines)
            {
                if (line.Contains("Origin:"))
                {
                    connectionOrigin = line.Substring(line.IndexOf(":") + 2);
                }
            }

            return connectionOrigin;
        }
    }
        #endregion
}</pre>
<p><strong> </strong></p>
<p><strong>WebSocketClient.htm</strong></p>
<pre>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;
&lt;head&gt;

    &lt;title&gt;Web socket client test&lt;/title&gt;

    &lt;script type="text/javascript"&gt;

        var wsClient;

        //Verifica se o browser da suporte a websockets,
        //mas nao verifica versao do protocolo
        function WebSocketTest() {
            if (!("WebSocket" in window)) {
                alert("Este browser nÃ£o suporta websockets!");
            }
        };

        //realiza a conexao
        function Connect() {

            try {

                //cria cliente websocket
                wsClient =
                   new WebSocket(document.getElementById("txtConnect").value);

                document.getElementById("txtConnect").disabled = true;
                document.getElementById("btnConnect").disabled = true;

                //cadastra eventos

                //chamado ao realizar a conexao com sucesso
                wsClient.onopen = OnOpen;
                //chamado quando o servidor manda mensagens para o cliente
                wsClient.onmessage = OnMessage;
                //chamado em caso de fechamento de conexao
                wsClient.onclose = OnClose;
                //chamado em caso de erro
                wsClient.onerror = OnError;

            } catch (ex) {
                alert(ex);
            }
        };

        //envia mensagem para o servidor
        function Send() {

            wsClient.send(document.getElementById("txtSend").value);

            document.getElementById("txtSend").value = "";
        };

        //fecha conexao com servidor
        function Close() {

            try {

                wsClient.close();

            } catch (ex) {
                alert(ex);
            }
        };

        function OnOpen() {
            alert("ConexÃ£o realizada com sucesso!");
        };

        function OnMessage(evt) {
            alert("Mensagem recebida: \"" + evt.data + "\"");

        };

        function OnClose() {
            alert("ConexÃ£o fechada!");
        };

        function OnError() {
            alert("Erro!");
        };

    &lt;/script&gt;

&lt;/head&gt;
&lt;body onload="WebSocketTest()"&gt;
    &lt;form&gt;
                                        &lt;!--Substuir "SEU_IP_AQUI" pelo ip
                               que foi configurado no .config do servidor--&gt;
    &lt;input id="txtConnect" type="text" value="ws://SEU_IP_AQUI:8181/ts" /&gt;

    &lt;input id="btnConnect" type="button" value="Connect" onclick="Connect()" /&gt;
    &lt;br /&gt;
    &lt;input id="txtSend" type="text" /&gt;
    &lt;input id="btnSend" type="button" value="Send" onclick="Send()" /&gt;
    &lt;input id="btnClose" type="button" value="Close" onclick="Close()" /&gt;
    &lt;/form&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p><strong> </strong></p>
<p><strong>Considerações finais</strong></p>
<p>Websocket parece ser uma tecnologia promissora. Vale ressaltar que o w3c pretende finalizar a normalização do html5 até 2014 e acontecerão melhorias até lá. O protocolo usado pelo websocket provavelmente ainda passará por algumas mudanças para melhorar, por exemplo, questões relacionadas à segurança.</p>
<p>Seguem alguns links interessantes:</p>
<blockquote>
<ul>
<li>Especificação da API: <a href="http://dev.w3.org/html5/websockets/">http://dev.w3.org/html5/websockets/</a></li>
<li>Versão do protocolo utilizada no exemplo: <a href="http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76">http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76</a></li>
<li>Versão do protocolo mais atual: <a href="http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-06">http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-06</a></li>
<li>Site com tabelas que indicam o suporte a tecnologias como HTML5, CSS3, SVG: <a href="http://caniuse.com/">http://caniuse.com/</a></li>
<li>Texto falando sobre algumas vantagens no uso de websockets: <a href="http://websocket.org/quantum.html">http://websocket.org/quantum.html</a></li>
<li>Tutorial introdutório sobre websockets: <a href="http://www.html5rocks.com/tutorials/websockets/basics/">http://www.html5rocks.com/tutorials/websockets/basics/</a></li>
<li>Demos do HTML5 em geral: <a href="http://html5demos.com/">http://html5demos.com/</a></li>
</ul>
</blockquote>
<p>.</p>
]]></content:encoded>
			<wfw:commentRss>http://techne.cesar.org.br/html5-construindo-um-servidor-de-websockets-com-net-framework-c/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
<!-- <script type="text/javascript">

  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-17547091-1']);
  _gaq.push(['_trackPageview']);

  (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();

</script> -->

