<?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>Del&#039;Arco &#187; programação</title>
	<atom:link href="http://blog.delarco.com.br/category/programacao/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.delarco.com.br</link>
	<description>The Pixel Company</description>
	<lastBuildDate>Mon, 07 Jun 2010 18:35:28 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Criando Cheats: Prelúdio</title>
		<link>http://blog.delarco.com.br/criando-cheats-preludio/</link>
		<comments>http://blog.delarco.com.br/criando-cheats-preludio/#comments</comments>
		<pubDate>Mon, 07 Jun 2010 18:35:28 +0000</pubDate>
		<dc:creator>Leandro Del&#39;Arco</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[cheats]]></category>
		<category><![CDATA[games]]></category>
		<category><![CDATA[informática]]></category>
		<category><![CDATA[programação]]></category>
		<category><![CDATA[artmoney]]></category>
		<category><![CDATA[bobafett]]></category>
		<category><![CDATA[c/c++]]></category>
		<category><![CDATA[cheating]]></category>
		<category><![CDATA[diablo]]></category>
		<category><![CDATA[jogos]]></category>
		<category><![CDATA[mario]]></category>
		<category><![CDATA[zsnes]]></category>

		<guid isPermaLink="false">http://blog.delarco.com.br/?p=66</guid>
		<description><![CDATA[Estudo programação à anos e sempre tive maior interesse no que se refere à arte expressa em pixels. Que sou grande fã de jogos eletrônicos (um mid-core gamer, não casual, nem hardcore) não há dúvidas&#8230; e essa paixão estende-se além do ato de jogar e apreciar momentos únicos, que apenas orientais extraterresters (leia Miyamoto) conseguem [...]]]></description>
			<content:encoded><![CDATA[<p>Estudo programação à anos e sempre tive maior interesse no que se refere à arte expressa em pixels. Que sou grande fã de jogos eletrônicos (um mid-core gamer, não casual, nem hardcore) não há dúvidas&#8230; e essa paixão estende-se além do ato de jogar e apreciar momentos únicos, que apenas <em>orientais extraterresters </em>(leia Miyamoto) conseguem proporcionar.</p>
<h2>Senta que lá vem história</h2>
<p>Como todo bom gamer, não me contento em socar o último chefe e sair falando na escola (hoje em dia é twiter, né?) &#8220;ZEREI/TERMINEI/FECHEI MAIS UM JOGO&#8221;. Pq? A mágica está nos detalhes! Os detalhes que muitas vezes não percebemos quando jogamos pela primeira vez. Aquele canto que não serviu pra NADA durante o jogo, mas que estava lá para ser explorado.</p>
<p><img class="size-full wp-image-70 alignright" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/smw_special_zone.PNG" alt="smw_special_zone" width="222" height="165" /></p>
<p>Qual apaixonado por games que terminou Super Mario World e não fez questão de conseguir os 100%? Ou quis passar todas as fases do &#8220;ESPECIAL&#8221; que não tinham relação alguma com o final do jogo?</p>
<p>Quem já jogou The Legend Of Zelda: Ocarina Of Time e não quis pegar as 100 gold skultullas mesmo sabendo que os rupees ilimitados (que vc tem direito ao final da quest) não valem o esforço?</p>
<p>Mesmo sentindo ausência da mágica nos jogos atuais, ainda não consigo &#8220;aposentar&#8221; um jogo logo após terminá-lo.</p>
<p>Atualmente faço questão de TER o video-game para poder jogá-lo (adquiri um Super Nintendo recentemente e já estou cotando um Megadrive), mas é impossível comprar todos os cartuchos, até pq alguns nem são comercializados hj em dia (Atari, Nintendinho etc). Então, como todo gamer que possui um computador e sabe da existência dos emuladores (<a href="http://www.zsnes.com/" target="_blank">ZSNES!</a>), baixei muitos jogos e terminei cada um deles.</p>
<p>Antes de continuar, queria deixar claro que não sou a favor da pirataria, apesar não ser completamente contra (tudo é relativo&#8230;).</p>
<p>Quem conhece um, sabe que a maior virtude do programador é a curiosidade. É claro que não fiquei apenas no &#8220;<em>Load Rom/Save State/Load State</em>&#8221; do ZSNES. Com o tempo fui descobrindo cada funcionalidade e o que me chamou a atenção foram os códigos que podiam ser inseridos para modificar a jogabilidade ou algum estado do jogo. Testei centenas de códigos em dezenas de jogos e chegou uma hora que não tinha como não me perguntar: como um código esquisito daquele (na época eu não sabia o que era base hexadecimal) podia fazer tanto &#8220;estrago&#8221; no jogo? E eu sabia que não podia ser nada projetado/previsto pelos programadores do jogo, pois não eram códigos digitados no controle (como uma sequencia de botões), ou inseridos no menu &#8220;cheat&#8221;.</p>
<p>Nesa fase, fiquei apenas na curiosidade mesmo, pois o material online sobre o asusnto era escasso e meu acesso à internet, mto raro. Tempos depois, qdo comprei o jogo Diablo (o 1 mesmo) e descobri que era possível jogar com outras pessoas na internet, passei várias madrugadas (contava os minutos antes das 00:00h para poder conectar) jogando com os, como diria <a href="http://terramel.org" target="_blank">o bomba</a>, &#8220;<em>amiguinhos virtuais</em>&#8220;. Até que um gringo filho de uma borboleta entrou na minha &#8220;<em>sala</em>&#8220;, zerou todos meus stats e removeu todos os meus itens. Não que eu não tenha chutado o cachorro por isso, mas ao passar o susto (raiva, ódio e outros sentimentos sem nome), fui procurar saber sobre códigos/trapaças para Diablo (o termo <em>cheater </em>era novidade pra mim). Qual não foi minha surpresa ao descobrir que o tal <em>programinha<a href="http://diablo.svatopluk.com/download/bobafett.stm" target="_blank"> </a></em><strong><a href="http://diablo.svatopluk.com/download/bobafett.stm" target="_blank">BoBaFeTT&#8217;s Diablo Trainer</a> </strong>podia editar, não só os stats e itens, como podia acrescentar itens que nem mesmo existiam no jogo. Aquela curiosidade sobre como funcionavam os códigos no emulador ZSENS voltou repentinamente, somada ao incrivel fato de poder adicionar elementos que o jogo não possuia originalmente. Devo ter ficado uns 2 dias sem dormir para poder testar todas as opções e armas.</p>
<p><em>[OFF] Btw, até hj não sei se desligaram os servidores de Diablo I ou se me baniram da Battle.net mesmo u.u [/OFF]</em></p>
<p><img class="size-full wp-image-78 alignright" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/cheating1.JPG" alt="cheating1" width="246" height="117" /></p>
<p>Como nesse tempo eu já havia começado a programar, eu sabia que os stats, pontos de vida e mana estavam armazenados em variáveis e que o cheater, de alguma forma, alterava essas variáveis. Mas também não passou disso, pois muitos conceitos importantes ainda não me eram claros. Como um processo consegue &#8220;<em>modificar</em>&#8221; a memória de outro?</p>
<p>Então comecei a estudar o comportamento de outros cheaters, como o editor de saves de pokemon para gameboy, ou um executável modificado do jogo freecell que permitia mover qualquer carta para qualquer lugar. Cada um deles funcionando de uma forma diferente.</p>
<p>Aí, veio um amigão da escola e me convenceu de que eu só ia conseguir fazer esse tipo de coisa quando eu programasse fluentemente em Assembly e pudesse fazer qlq coisa em C. <strong>O que NÃO é verdade!!!</strong></p>
<p>Depois disso, só voltei a me interessar pelo assunto uns 5 anos depois.<br />
Em 2004 ou 2005 (não lembro) criei <span style="text-decoration: line-through;">copiei e compilei</span> um <em>cheater </em>em Visual Basic 6 para um MMORPG-modinha da época. Como eu apenas modifiquei alguns fontes que peguei na internet, não entendia completamente o que estava acontecendo. Ao ler artigos sobre o assunto e estudar o fonte, entendi que o código simplesmente modificava alguns dados que estavam armazenados na memória utilizada pelo jogo&#8230; <strong>há! é assim que aquele maldito bobafeet funcionava então!</strong></p>
<p>Passou um tempo, o cheater já estava famoso aqui na minha cidade e muitas lan-houses passaram a usá-lo. Esses &#8220;<em>bons jogadores</em>&#8221; sempre pediam para adicionar algum <em>feature</em>, tipo que o cheater possa jogar sozinho enquanto ele vê um video educativo no www.***tube.com. Mas tudo bem, moleques de 12 anos não precisam saber a diferença entre cheater e bot <img src='http://blog.delarco.com.br/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /><br />
O final <span style="text-decoration: line-through;">in</span>feliz dessa história eu deixo pra outro post.</p>
<p>Com as atualizações constantes do jogo, eu tb precisava atualizar os endereços de memória modificados pelo cheater, então as coisas começaram a fazer mais sentido. Utilizava o <a href="http://www.artmoney.ru/" target="_blank">ArtMoney</a> pra escanear a memória do jogo e atualizava a lista de endereços, coisa simples. Nesse processo de escanear e procurar novos endereços, comecei a perceber que vários outros locais armazenavam informações úteis para futuras funções do cheater. E com toda a curiosidade que um programador deve ter, fucei em cada canto do jogo para descobrir mais sobre o funcionamento do mesmo.</p>
<h2>E meu cheater?</h2>
<p>Pra que serviu toda essa lengalenga? Pra deixar claro que não adianta copiar e compilar os códigos postados aqui. Talvez vc consiga fazer um cheater <em>lecalzinho</em> pra algum jogo, mas só isso. Pra aprender, vc PRECISA ter a curiosidade. A curiosidade matou o gato, mas ensinou ele a utilizar mto bem as outras 6 vidas.</p>
<p>Então, no próximo post vou tentar passar o <span style="text-decoration: line-through;"><em>pouco</em></span> que sei sobre o tipo de cheater que eu considero mais fácil: os que editam a memória.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delarco.com.br/criando-cheats-preludio/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>boost::asio &#8211; Introdução</title>
		<link>http://blog.delarco.com.br/boostasio-introducao/</link>
		<comments>http://blog.delarco.com.br/boostasio-introducao/#comments</comments>
		<pubDate>Wed, 18 Nov 2009 19:49:26 +0000</pubDate>
		<dc:creator>Leandro Del&#39;Arco</dc:creator>
				<category><![CDATA[Boost]]></category>
		<category><![CDATA[C/C++]]></category>
		<category><![CDATA[programação]]></category>
		<category><![CDATA[asio]]></category>
		<category><![CDATA[asynchronous]]></category>
		<category><![CDATA[resolver]]></category>
		<category><![CDATA[socket]]></category>
		<category><![CDATA[synchronous]]></category>
		<category><![CDATA[timer]]></category>

		<guid isPermaLink="false">http://blog.delarco.com.br/?p=139</guid>
		<description><![CDATA[Apesar de pouco comentado (pelo menos nos forums que eu participo participava), Boost é um conjunto de bibliotecas que facilitam muito a vida do programador e , sem dúvidas, é o plus-plus do C++. Se vc ainda não conhece: http://www.boost.org/.
Para quem não sabe, Boost.Asio é uma biblioteca multiplataforma (cross-platform) para programação de rede/comunicação (network) e [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-full wp-image-197" src="http://blog.delarco.com.br/wp-content/uploads/2009/11/boost.png" alt="boost" width="277" height="86" />Apesar de pouco comentado (pelo menos nos forums que eu <span style="text-decoration: line-through">participo</span> participava), Boost é um conjunto de bibliotecas que facilitam <strong>muito </strong>a vida do programador e , sem dúvidas, é o <em>plus-plus</em> do C++. Se vc ainda não conhece: <a href="http://www.boost.org/" target="_blank">http://www.boost.org/</a>.</p>
<p>Para quem não sabe, Boost.Asio é uma biblioteca multiplataforma (<em>cross-platform</em>) para programação de rede/comunicação (<em>network</em>) e operações de entrada e saída em baixo nível (<em>low-level I/O</em>) que oferece, aos desenvolvedores, um modelo consistente e assíncrono.</p>
<p><em>(Essa definição foi descaradamente traduzida da encontrada no <a href="http://www.boost.org/doc/libs/1_38_0/doc/html/boost_asio.html" target="_blank">site oficial</a>)</em></p>
<blockquote><p>Então, o que eu posso fazer com isso?</p></blockquote>
<p>Você pode, por exemplo, usar sockets (TCP, UDP e ICMP), Timers e criar/manipular portas seriais.</p>
<blockquote><p>Mas eu sei fazer isso! É só incluir o winsock.h e&#8230; no linux é fácil tb&#8230;</p></blockquote>
<p>Não ter que se preocupar com o startup e cleanup do Winsock e não ter que colocar 8463763 <em>#ifdef</em>&#8217;s no meio do código já é um bom motivo para usar Boost.Asio. Se vc escrever &#8220;<em>socket.read_some(&#8230;);</em>&#8220;, vai funcionar em qualquer plataforma suportada (Win32/64, Linux kernel 2.4+, Solaris, Mac OS X 10.4+).</p>
<blockquote><p>Beleza! Cadê os exemplos?</p></blockquote>
<p>Antes disso, para não ficar perdido, é necessário entender como o Boost.Asio trabalha. Ao inves de oferecer um modelo genérico aproximado ao que há de comum entre as várias plataformas, a biblioteca apresenta uma nova proposta: para efetuar operações de entrada e saída seu programa precisa de, no mínimo, um objeto io_service (boost::asio::io_service). O objeto io_service funciona como um intermediário entre o seu software e o sistema operacional. Overhead? Tenha certeza que o boost faz esse intermédio da forma mais eficiente possível e, até hoje, nunca vi ninguém reclamando sobre o desempenho da biblioteca. A imagem abaixo (que foi retirada do site oficial) mostra o funcionamento do Boost.Asio para operações síncrona:</p>
<p><img class="size-full wp-image-198 alignleft" src="http://blog.delarco.com.br/wp-content/uploads/2009/11/sync_op.png" alt="sync_op" width="232" height="413" />1 &#8211; O programa inicia a conexão chamando o objeto i/o (socket, por exemplo);</p>
<p>2 &#8211; O objeto i/o encaminha a requisição de conexão para o objeto io_service;</p>
<p>3 &#8211; O objeto io_service faz uma chamada ao sistema operacional para realizar a conexão;</p>
<p>4 &#8211; O sistema operacional retorna um resultado para o objeto io_service;</p>
<p>5 &#8211; O objeto io_service &#8220;traduz&#8221; qualquer erro resultante na operação e retorna ao objeto i/o;</p>
<p>6 &#8211; O objeto i/o retorna o resultado para o programa.</p>
<p><span style="color: #ffffff">.</span></p>
<p><span style="color: #ffffff">.</span></p>
<p><span style="color: #ffffff">.</span></p>
<p><span style="color: #ffffff">.</span></p>
<p><span style="color: #ffffff">.</span></p>
<p>O modelo para operações assíncronas é representado pelo diagrama ao lado: <img class="alignright size-full wp-image-199" src="http://blog.delarco.com.br/wp-content/uploads/2009/11/async_op.png" alt="async_op" width="377" height="413" /></p>
<p>Ao invés de esperar cada etapa do modelo síncrono, aqui podemos passar uma função <em>handler</em> que será chamada assim que a operação for concluída, independente da ocorrência de erros.</p>
<p>As três primeiras etapas são praticamente idênticas ao modelo anterior (do ponto de vista do usuário/programador):</p>
<p>1 &#8211; O programa inicia a conexão chamando o objeto i/o (socket, por exemplo);</p>
<p>2 &#8211; O objeto i/o encaminha a requisição de conexão para o objeto io_service;</p>
<p>3 &#8211; O objeto io_service faz uma chamada ao sistema operacional para realizar a conexão;</p>
<p>Após as etapas indicadas, o sistema operacional indica o resultado da operação colocando-o em uma fila que será lida pelo objeto io_service, que por sua vez &#8220;traduz&#8221; qualquer mensagem de erro e chama a função <em>handler</em> passada como parâmetro pelo programa.</p>
<p>É importante comentar que, para que o objeto io_service possa tratar as tarefas/operações assíncronas pendentes, é necessário chamar <strong>io_service::run()</strong>.</p>
<p>A função <strong>io_service::run()</strong> retornará assim que não houver mais tarefa assíncronas pendentes.</p>
<blockquote><p>Okay! Então eu crio um objeto io_service e já era?</p></blockquote>
<p><strong>Aí é que está a grande maravilha do modelo proposto:</strong> usando vários objetos io_service (um em cada thread) e dividindo as operações entre eles, permitimos ao sistema operacional também dividí-las entre os vários núcleo disponíveis!</p>
<blockquote><p>Tá&#8230; e os exemplos?</p></blockquote>
<h2>Timer</h2>
<p>Para um <em>wait </em>síncrono (só retorna depois de completo):</p>
<pre class="brush: cpp;">
#include &lt;iostream&gt;
#include &lt;boost/asio.hpp&gt;

using boost::asio::io_service;
using boost::asio::deadline_timer;

int main(int ac, char ** av)
{
    io_service ios;

    deadline_timer t(ios);
    t.expires_from_now(boost::posix_time::seconds(5));

    std::cout &lt;&lt; &quot;Esperando 5 segundos...&quot; &lt;&lt; std::endl;

    t.wait();

    std::cout &lt;&lt; &quot;Continua...&quot; &lt;&lt; std::endl;
    return 0;
}
</pre>
<p>Para um timer assíncrono, precisamos de um <em>handler</em>:</p>
<pre class="brush: cpp;">

void handler(boost::system::error_code &amp; ec)
{
	if(ec)
		//erro
	else
		//ok
}
</pre>
<p><span>Então, podemos usar o <em>wait </em>assíncrono:</span></p>
<p><span>
<pre class="brush: cpp;">
t.expires_from_now(boost::posix_time::milliseconds(400));
t.async_wait(handler);
ios.run();
</pre>
<p></span></p>
<p>Um exemplo de timer assíncrono:</p>
<pre class="brush: cpp;">
#include &lt;iostream&gt;
#include &lt;boost/asio.hpp&gt;
#include &lt;boost/bind.hpp&gt;

using boost::asio::io_service;
using boost::asio::deadline_timer;

void handler(int segundo, boost::system::error_code &amp; ec)
{
	if(!ec)
		std::cout &lt;&lt; &quot;Esperando... &quot; &lt;&lt; segundo &lt;&lt; std::endl;
}

int main(int ac, char ** av)
{
	io_service ios;

	for(int i = 1; i &lt;= 5; i++)
	{
		deadline_timer * t = new deadline_timer(ios);
		t-&gt;expires_from_now(boost::posix_time::seconds(i));
		t-&gt;async_wait(boost::bind(&amp;handler, i, boost::asio::placeholders::error));
	}

	ios.run();

	std::cout &lt;&lt; &quot;Continua...&quot; &lt;&lt; std::endl;
	return 0;
}
</pre>
<p>Repare que não me preocupei em manter uma referência para os objetos criados dinamicamente (para apagá-los posteriormente), pois o programa é terminado logo após o retorno do último timer assíncrono.</p>
<h2>Socket</h2>
<p>Um exemplo simples de socket (tcp) que se conecta ao site:</p>
<pre class="brush: cpp;">
#include &lt;iostream&gt;
#include &lt;boost/asio.hpp&gt;

using boost::asio::io_service;
using boost::asio::ip::tcp;

int main(int ac, char ** av)
{
    io_service ios;

    tcp::socket sck(ios);
    tcp::endpoint endp(boost::asio::ip::address::from_string(&quot;64.191.3.101&quot;), 80);

    try
    {
        sck.connect(endp);
        std::cout &lt;&lt; &quot;Conectado!&quot; &lt;&lt; std::endl;
    }
    catch(boost::system::system_error &amp; error)
    {
        std::cout &lt;&lt; &quot;Erro ao conectar: &quot; &lt;&lt; error.what() &lt;&lt; std::endl;
    }

    std::cout &lt;&lt; &quot;Continua...&quot; &lt;&lt; std::endl;
    return 0;
}
</pre>
<p>Ou um resolver:</p>
<pre class="brush: cpp;">
#include &lt;iostream&gt;
#include &lt;boost/asio.hpp&gt;

using boost::asio::io_service;
using boost::asio::ip::tcp;

int main(int ac, char ** av)
{
    io_service ios;

    tcp::resolver resolver(ios);
    tcp::resolver::query query(&quot;blog.delarco.com.br&quot;, &quot;http&quot;);
    tcp::resolver::iterator iter = resolver.resolve(query);
    tcp::resolver::iterator end;

    while (iter != end)
    {
        tcp::endpoint endpoint = *iter++;
        std::cout &lt;&lt; endpoint &lt;&lt; std::endl;
    }

    return 0;
}
</pre>
<div style="overflow: hidden;width: 1px;height: 1px">#include &lt;iostream&gt;<br />
#include &lt;boost/asio.hpp&gt;using boost::asio::io_service;<br />
using boost::asio::deadline_timer;int main(int ac, char ** av)<br />
{<br />
io_service ios;</p>
<p>deadline_timer t(ios);<br />
t.expires_from_now(boost::posix_time::seconds(5));</p>
<p>std::cout &lt;&lt; &#8220;Esperando 5 segundos&#8230;&#8221; &lt;&lt; std::endl;</p>
<p>t.wait();</p>
<p>std::cout &lt;&lt; &#8220;Continua&#8230;&#8221; &lt;&lt; std::endl;</p>
<p>return 0;<br />
}</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.delarco.com.br/boostasio-introducao/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>OpenMP: Repetição Distribuída – Parte 2</title>
		<link>http://blog.delarco.com.br/openmp-repeticao-distribuida-%e2%80%93-parte-2/</link>
		<comments>http://blog.delarco.com.br/openmp-repeticao-distribuida-%e2%80%93-parte-2/#comments</comments>
		<pubDate>Tue, 27 Oct 2009 01:23:57 +0000</pubDate>
		<dc:creator>Leandro Del&#39;Arco</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[OpenMP]]></category>
		<category><![CDATA[programação]]></category>
		<category><![CDATA[codeblocks]]></category>
		<category><![CDATA[for]]></category>
		<category><![CDATA[loop]]></category>
		<category><![CDATA[multicore]]></category>
		<category><![CDATA[múltiplos núcleos]]></category>
		<category><![CDATA[openmp]]></category>

		<guid isPermaLink="false">http://blog.delarco.com.br/?p=185</guid>
		<description><![CDATA[Nesse post não vou explicar as várias outras funcionalidades que a API oferece em relação aos loops. Aqui vou fazer uma pausa para testar o que foi explicado até agora. De que adianta a teoria sem um teste prático do que tá rolando?
Para testar um loop distribuído, resolvi criar uma função que calcula a multiplicação [...]]]></description>
			<content:encoded><![CDATA[<p>Nesse post não vou explicar as várias outras funcionalidades que a API oferece em relação aos loops. Aqui vou fazer uma pausa para testar o que foi explicado até agora. De que adianta a teoria sem um teste prático do que tá rolando?</p>
<p>Para testar um loop distribuído, resolvi criar uma função que calcula a multiplicação entre duas matrizes, colocando o resultado em uma terceira matriz (MC = MA * MB):</p>
<pre class="brush: cpp;">
const int MATRIX_SIZE = 1000;

int MA[MATRIX_SIZE][MATRIX_SIZE];
int MB[MATRIX_SIZE][MATRIX_SIZE];
int MC[MATRIX_SIZE][MATRIX_SIZE];

void multi()
{
    int soma;

    //percorre cada linha de MA
    for(int j = 0; j &lt; MATRIX_SIZE; j++)
    {
        //percorre cada coluna de MB
        for(int i = 0; i &lt; MATRIX_SIZE; i++, soma = 0)
        {
            //calcula
            for(int k = 0; k &lt; MATRIX_SIZE; k++)
            {
                soma += MA[j][k] * MB[k][i];
            }

            //coloca resoltado na matriz MC
            MC[j][i] = soma;
        }
    }
}

int main(int ac, char **av)
{
    multi();
    return 0;
}
</pre>
<p>Como o teste consiste em melhorar o desempenho do cálculo, não me dei ao trabalho de iniciar os elementos das matrizes e nem de verificar se o resultado está correto.</p>
<p>Executando o código anterior, o Code::Blocks retornou a mensagem:</p>
<p><strong>Process returned 0 (0&#215;0)   execution time : <span style="color: #ff0000">23.509 s</span><br />
Press any key to continue.</strong></p>
<p>Lembrando que executei a compilação debug sem nenhum tipo de otimização. Com certeza a release seria muito mais rápida.</p>
<p>Quem lembra das aulas de matemática do colegial, sabe que o cálculo de cada elemento resultante (MC) independe do cálculo de elementos anteriores. O laço <strong>for </strong>está de acordo com as restrições impostas pela API, então, pq não dividir a tarefa em várias threads?</p>
<pre class="brush: cpp;">
const int MATRIX_SIZE = 1000;

int MA[MATRIX_SIZE][MATRIX_SIZE];
int MB[MATRIX_SIZE][MATRIX_SIZE];
int MC[MATRIX_SIZE][MATRIX_SIZE];

void multi()
{
    //percorre cada linha de MA
    #pragma omp parallel for
    for(int j = 0; j &lt; MATRIX_SIZE; j++)
    {
        //percorre cada coluna de MB
        for(int i = 0; i &lt; MATRIX_SIZE; i++)
        {
            int soma = 0;

            //calcula
            for(int k = 0; k &lt; MATRIX_SIZE; k++)
            {
                soma += MA[j][k] * MB[k][i];
            }

            //coloca resoltado na matriz MC
            MC[j][i] = soma;
        }
    }
}

int main(int ac, char **av)
{
    multi();
    return 0;
}
</pre>
<p>Repare que, além do <em><strong>#pragma omp parallel for</strong></em> adicionado antes do primeiro loop, outras mudanças foram feitas para adaptar o código:</p>
<ul>
<li>A variável <strong>soma </strong>foi removida do começo da função e declarada dentro do segundo <strong>for, </strong>para evitar que seja compartilhada entre as threads;</li>
<li>Não é mais necessário zerar a variável soma no corpo do segundo <strong>for</strong>;</li>
</ul>
<p>Executando o código modificado, obtive o seguinte resultado:</p>
<p><strong>Process returned 0 (0&#215;0)   execution time : <span style="color: #ff0000">7.129 s</span><br />
Press any key to continue.</strong></p>
<p>Isso corresponde a, praticamente, um terço do tempo necessário para calcular pelo método tradicional. Surpreso? Requisitando 20 threads para executar o loop, obtive um resultado melhor ainda:</p>
<p><strong>Process returned 0 (0&#215;0)   execution time : <span style="color: #ff0000">6.692 s</span><br />
Press any key to continue.</strong></p>
<p>Okay, a diferença não é gritante, mas num sistema onde o desempenho é um faor crítico, esses ms podem fazer toda a diferença.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delarco.com.br/openmp-repeticao-distribuida-%e2%80%93-parte-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OpenMP: Repetição Distribuída &#8211; Parte 1</title>
		<link>http://blog.delarco.com.br/openmp-repeticao-distribuida-parte-1/</link>
		<comments>http://blog.delarco.com.br/openmp-repeticao-distribuida-parte-1/#comments</comments>
		<pubDate>Tue, 27 Oct 2009 00:42:15 +0000</pubDate>
		<dc:creator>Leandro Del&#39;Arco</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[OpenMP]]></category>
		<category><![CDATA[programação]]></category>
		<category><![CDATA[codeblocks]]></category>
		<category><![CDATA[for]]></category>
		<category><![CDATA[loop]]></category>
		<category><![CDATA[multicore]]></category>
		<category><![CDATA[múltiplos núcleos]]></category>
		<category><![CDATA[openmp]]></category>

		<guid isPermaLink="false">http://blog.delarco.com.br/?p=168</guid>
		<description><![CDATA[No post Programação Multicore com OpenMP, mostrei como fazer a API funcionar no Code::Blocks, compilando um exemplo simples que executa um trecho de código em várias threads, ou seja, nada muito útil.
Agora que vc já conseguiu compilar o &#8220;Hello World&#8221; do primeiro post, vamos fazer bom uso do processamento distribuído nos nossos laços da repetição.
Primeiramente, [...]]]></description>
			<content:encoded><![CDATA[<p>No post <a href="http://blog.delarco.com.br/programacao-multicore-com-openmp/" target="_blank">Programação Multicore com OpenMP</a>, mostrei como fazer a API funcionar no Code::Blocks, compilando um exemplo simples que executa um trecho de código em várias threads, ou seja, nada muito útil.</p>
<p>Agora que vc já conseguiu compilar o &#8220;Hello World&#8221; do primeiro post, vamos fazer bom uso do processamento distribuído nos nossos laços da repetição.</p>
<p>Primeiramente, vc deve entender que, na programação com OpenMP, temos variáveis (parte da memória) compartilhadas e privates.</p>
<blockquote><p>Quê?!</p></blockquote>
<p>No exemplo abaixo, a variável <strong>a</strong> é visível para todas as threads que executarão a tarefa do bloco. Já a variável <strong>b</strong> possui uma cópia exclusiva em cada thread, ou seja, cada thread possui sua variável <strong>b</strong>.</p>
<pre class="brush: cpp;">

void some_function()
{
    int a = 0;

    #pragma omp parallel
    {
        int b = 1;
    }
}
</pre>
<blockquote><p>Okay, entendi&#8230; e daí?</p></blockquote>
<p>Por enquanto, leve em conta que saber disso pode evitar várias dores de cabeça.</p>
<h2>Usando OpenMP nos laços de repetição</h2>
<p>Para tal operação, definimos a seguinte linha antes do nosso <strong>for</strong>:</p>
<p><em><strong>#pragma omp parallel for</strong></em></p>
<p>Ficando assim:</p>
<pre class="brush: cpp;">
#pragma omp parallel for
for(int i = 0; i &lt; 10; i++)
{
    printf(&quot;iteration %d on thread %d\n&quot;, i, omp_get_thread_num());
}
</pre>
<p>O resultado é:<br />
<img class="aligncenter size-full wp-image-169" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/omp_parallel_for_01.jpg" alt="omp_parallel_for_01" width="677" height="342" /></p>
<p>Nesse exemplo, as iterações do for serão divididas em várias threads (na minha execução, 3 threads). O número de threads corresponde ao número padrão ou o valor que vc definiu com <strong>omp_set_num_threads(num_threads)</strong>. Para não ter o trabalho de chamar a função em cada parte do código que vc deseja alterar o número de threads, a seguinte sintaxe é permitida:</p>
<p><em><strong>#pragma omp parallel for num_threads(NUM_THREADS)</strong></em></p>
<p>Onde <em><strong>NUM_THREADS</strong></em> corresponde ao número de threads que devem executar a tarefa.</p>
<p>Se o exemplo anterior for modificado para:</p>
<pre class="brush: cpp;">
#pragma omp parallel for num_threads(2)
for(int i = 0; i &lt; 10; i++)
{
    printf(&quot;iteration %d on thread %d\n&quot;, i, omp_get_thread_num());
}
</pre>
<p>Então o loop vai ser dividido em, no máximo, duas threads como mostra o resultado:</p>
<p><img class="aligncenter size-full wp-image-170" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/omp_parallel_for_02.jpg" alt="omp_parallel_for_02" width="677" height="342" /></p>
<p>Como podemos notar, apenas as threads de ID 0 e 1 executam o for.</p>
<p>Repare que as iterações não são executadas em ordem, então leve em conta que se uma iteração depende de outra,  como na soma de médias num vetor de alunos, por exemplo (existe um jeito de fazer isso, vou explicar mais pra frente), vc terá problemas.</p>
<p>A API OpenMP impõe  as seguintes restrições no uso de loops paralelos:</p>
<ol>
<li>A variável que controla o loop (no caso anterior, <strong>i</strong>) deve ser do tipo <em>signed integer</em>;</li>
<li>A operação de comparação no corpo<strong> for</strong> deve ser do tipo <em>loop_variable &lt;,  &lt;=, &gt;, &gt;= integer_invariável</em>;</li>
<li>A terceira expressão do corpo <strong>for </strong>deve ser do tipo que incrementa (x++) ou decrementa (x- -);</li>
<li>Se a operação de comparação usar os operadores &lt; ou &lt;=, então a variável de controle deve ser incrementada a cada iteração. No caso contrário, se forem utilizados os operadores &gt; ou &gt;=, então a variável de controle deve ser decrementada a cada iteração;</li>
<li>O loop deve consistir em um único bloco de código, sem <em>jumps</em> (goto, por exemplo)<em> </em>para fora do loop. Como exceção, podemos usar <strong>exit()</strong> que finaliza a aplicação e não apenas a thread em questão. Caso vc utilize um <strong>break </strong>ou <strong>goto</strong>, esses devem levar a algum lugar DENTRO do loop e não fora. O mesmo vale para exceptions, que devem ser tratadas dentro do loop e não fora dele;</li>
</ol>
<p>Para deixar mais claro aquele conceito de memória compartilhada e private, temos o exemplo abaixo que não é válido, pois a variável <strong>temp </strong>é compartilhada por todas as threads, ou seja, enquanto a thread de ID 0 escreve um valor X e espera ler esse valor algumas instruções adiante, a thread de ID 1 escreve um valor Y no mesmo endereço de memória:</p>
<pre class="brush: cpp;">
int a[4] = {1, 2, 4, 8};
int temp;

#pragma omp parallel for
for(int i = 0; i &lt; 4; i++)
{
    temp = a[i];
}
</pre>
<p>Para um resultado correto, o ideal seria declarar a variável <strong>temp </strong>dentro do laço for:</p>
<pre class="brush: cpp;">
int a[4] = {1, 2, 4, 8};

#pragma omp parallel for
for(int i = 0; i &lt; 4; i++)
{
    int temp;
    temp = a[i];
}
</pre>
<h2>Reductions</h2>
<p>Nos permite compartilhar uma variável sem que sua integridade seja comprometida pela concorrência entre threads. Veja o exemplo:</p>
<pre class="brush: cpp;">
int notas[10] = {7, 4, 8, 3, 6, 9, 10, 1, 2, 5};
int soma = 0;

#pragma omp parallel for
for(int i = 0; i &lt; 10; i++)
{
    soma += notas[i];
}

printf(&quot;soma = %d\n&quot;, soma);
</pre>
<p>Não podemos garantir que a soma seja 55, pois todas as threads estão usando a mesma variável. Criar um lock? Não é necessário, pois a API nos permite fazer da seguinte forma:</p>
<pre class="brush: cpp;">
int notas[10] = {7, 4, 8, 3, 6, 9, 10, 1, 2, 5};
int soma = 0;

#pragma omp parallel for reduction(+:soma)
for(int i = 0; i &lt; 10; i++)
{
    soma += notas[i];
}

printf(&quot;soma = %d\n&quot;, soma);
</pre>
<p>Nos bastidores, o OpenMP cria uma variável private <strong>soma </strong>para cada thread e, ao final, soma todas e coloca o valor na variável compartilhada (global) <strong>soma</strong>. Então vc pode ter certeza que o valor de <strong>soma </strong>é o esperado.</p>
<p>As outras operações disponíveis são:</p>
<ul>
<li><strong>+ (adição)</strong>: a variável private inicia com o valor 0;</li>
<li><strong>- (subtração)</strong>: a variável private inicia com o valor 0;</li>
<li><strong>* (multiplicação)</strong>: a variável private inicia com o valor 1;</li>
<li><strong>&amp; (operador AND)</strong>: a variável private inicia com o valor ~0;</li>
<li><strong>| (operador OR)</strong>: a variável private inicia com o valor 0;</li>
<li><strong>^ (operador OR exclusivo)</strong>: a variável private inicia com o valor 0;</li>
<li><strong>&amp;&amp; (operador condicional AND)</strong>: a variável private inicia com o valor 1;</li>
<li><strong>|| (operador condicional OR)</strong>: a variável private inicia com o valor 0;</li>
</ul>
<p>A segunda parte eu deixo para outro post <img src='http://blog.delarco.com.br/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delarco.com.br/openmp-repeticao-distribuida-parte-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PlayStation 2 &#8211; Hello World!</title>
		<link>http://blog.delarco.com.br/playstation-2-hello-world/</link>
		<comments>http://blog.delarco.com.br/playstation-2-hello-world/#comments</comments>
		<pubDate>Mon, 26 Oct 2009 02:34:48 +0000</pubDate>
		<dc:creator>Leandro Del&#39;Arco</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[games]]></category>
		<category><![CDATA[playsation2]]></category>
		<category><![CDATA[programação]]></category>

		<guid isPermaLink="false">http://blog.delarco.com.br/?p=20</guid>
		<description><![CDATA[
Quem nunca teve vontade de ver um software próprio (nem que seja um &#8220;Hello World&#8221;) rodando num console de verdade ou mesmo num emulador?
Em 2007 me interessei pelo assunto, particularmente em relação ao PS2 e comecei a pesquisar. Em um ou dois dias, já tinha um &#8220;Hello World&#8221; rodando pelo pendrive e&#8230; bom, desisti de [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: left"><img class="aligncenter size-full wp-image-160" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/ps2.png" alt="ps2" width="320" height="320" /></p>
<p style="text-align: left">Quem nunca teve vontade de ver um software próprio (nem que seja um &#8220;Hello World&#8221;) rodando num console de verdade ou mesmo num emulador?</p>
<p style="text-align: left">Em 2007 me interessei pelo assunto, particularmente em relação ao <a href="http://www.us.playstation.com/PS2" target="_blank">PS2</a> e comecei a pesquisar. Em um ou dois dias, já tinha um &#8220;Hello World&#8221; rodando pelo pendrive e&#8230; bom, desisti de fazer algo realmente útil. Não pela dificuldade ou preguiça de ler sobre o hardware-alvo, mas pelo simples fato de que eu não tinha nenhuma proposta inovadora. Se vc levar em conta a enorme quantidade de homebrews disponíveis, vai chegar à mesma conclusão, ou então vai pensar: <em>há! vou fazer um jogo ultra-mega-blaster-fodástico!</em> E duas horas depois vai desistir, pq as ferramentas <em>FREE</em> disponíveis não são tão <em>user friendly</em> quanto vc gostaria (ou comparadas às oficiais, que podem custar seu rim esquerdo).</p>
<p style="text-align: left">Esse é o meu ponto de vista, mas se vc acha que vale à pena programar para um console de quase 10 anos, pode começar fuçando nas minhas principais referências para esse post:</p>
<ul style="text-align: left">
<li><a href="http://ps2dev.org/" target="_blank">http://ps2dev.org/</a></li>
<li><a href="http://ps2dev.ofcode.com/" target="_blank">http://ps2dev.ofcode.com/</a></li>
<li><a href="http://lukasz.dk/" target="_blank">http://lukasz.dk</a>/</li>
</ul>
<p style="text-align: left">Recomendo a última referência, pois você encontrará muito material útil (uma ótima introdução à arquitetura do console, exemplos e até um port de doom para PS2).</p>
<h2 style="text-align: left">Beleza então, meu cadê o Hello World?</h2>
<p style="text-align: left">Para começar a brincar com o seu PS2, primeiro será necessário baixar o PS2SDK no site <a href="http://ps2dev.ofcode.com/modules/wordpress/?page_id=38" target="_blank">http://ps2dev.ofcode.com/</a>. Lá vc encontrará duas opções:</p>
<ul style="text-align: left">
<li><strong>PS2sdk Win32 Full Installation</strong>: contém o compilador (GCC) e as bibliotecas que fornecem as funções básicas para acessar a maioria dos  dispositivos e funções do console;</li>
<li><strong>PS2sdk Win32 Full + ofcode libs</strong>: possui tudo que o item anterior dispõe, com a adição de algumas bibliotecas extras <strong>E</strong> alguns utensílios que serão úteis na hora de testar seu homebrew (pcsx2, que é um emulador de PS2 para PC e o cdgen, que é utilizado para gerar ISO&#8217;s que rodem no seu console).</li>
</ul>
<p style="text-align: left">Levando em conta a diferença entre o tamanho dos instaladores, é claro que você vai baixar o segundo item, clicando <a href="http://ps2dev.ofcode.com/files/Ps2sdk.ofcode.exe" target="_blank">aqui</a>.</p>
<h2 style="text-align: left">Instalando o PS2sdk</h2>
<p style="text-align: left">Okay, você baixou o arquivo, ele possui 44.0 MB e não está corrompido, correto? Creio que qualquer pessoa com uma experiência mínima em computadores (que saiba ligar, por exemplo) consiga instalar. Por via das dúvidas:</p>
<ul style="text-align: left">
<li>Execute o instalador e escolha a língua. Eu prefiro inglês <img src='http://blog.delarco.com.br/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> <img class="aligncenter size-full wp-image-27" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/ps2sdk_install1.JPG" alt="ps2sdk_install1" width="294" height="160" /></li>
<li>Clique em &#8220;Next&#8221; e selecione a opção &#8220;Full&#8221;, então, &#8220;Next&#8221;<img class="aligncenter size-full wp-image-28" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/ps2sdk_install2.JPG" alt="ps2sdk_install2" width="503" height="393" /></li>
<li>Selecione o local de instalação e clique em &#8220;Install&#8221; e, ao finalizar a instalação, em &#8220;Finish&#8221;<img class="aligncenter size-full wp-image-29" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/ps2sdk_install3.JPG" alt="ps2sdk_install3" width="503" height="393" /></li>
<li>Agora, abra o arquivo <strong>ps2setup.bat </strong>(que está no diretório de instalação do PS2sdk) com o bloco de notas e<strong> </strong>adicione um &#8220;cmd&#8221; ao final, ficando assim<img class="aligncenter size-full wp-image-30" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/ps2sdk_install4.JPG" alt="ps2sdk_install4" width="567" height="278" /></li>
</ul>
<h2 style="text-align: left">Compilando os exemplos do PS2SDK</h2>
<p style="text-align: left">Executando o <strong>ps2setup.bat</strong> com um duplo clique fará um prompt de comando surgir. Através desse prompt podemos compilar alguns exemplos que são instalados com o SDK. Entre no sub-diretório <strong>ps2sdk\samples</strong> (creio que vc sabe alguns comandos básicos do DOS) e escolha seu exemplo. Para começar, o exemplo mais simples: hello! Então, entre no sub-diretório <strong>hel</strong><strong>lo</strong> (diretório_de_instalação_\ps2sdk\samples\hello) e digite &#8220;<strong>make</strong>&#8221; (sem aspas).</p>
<p style="text-align: left"><img class="aligncenter size-full wp-image-31" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/ps2sdk_make.JPG" alt="ps2sdk_make" width="972" height="518" /></p>
<p style="text-align: left">Se tudo ocorrer bem, um arquivo <em>hello.elf</em> (um <em>hello.o</em> também) deve ser criado dentro do diretório <strong>hello</strong>. O .elf é o seu executável!</p>
<p style="text-align: left">Uhull! Já tenho meu Hello World no hello.elf!!! Tá&#8230; mas o que eu faço com isso?</p>
<h2 style="text-align: left">Testando seu homebrew</h2>
<p style="text-align: left">Existem várias maneiras de rodar seu .elf. Meu PS2 foi desbloqueado com um DMS4 Pro, que não faz p**** nenhuma, mas com o ToxicOS instalado, permite &#8220;navegar&#8221; em todos dispositivos de armazenamento (DVD, CD, pendrive, memory card etc) e executar qualquer software que você tenha gravado:</p>
<p style="text-align: left">Screen inicial do ToxicOS:</p>
<p style="text-align: left"><img class="aligncenter size-full wp-image-143" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/toxicOS_011.jpg" alt="toxicOS_01" width="320" height="240" /></p>
<p style="text-align: left">Opções:</p>
<p style="text-align: left"><img class="aligncenter size-full wp-image-144" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/toxicOS_021.jpg" alt="toxicOS_02" width="320" height="240" /></p>
<p style="text-align: left">Acessando o dispositivo <strong>mass </strong>(storage):</p>
<p style="text-align: left"><img class="aligncenter size-full wp-image-145" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/toxicOS_031.jpg" alt="toxicOS_03" width="320" height="240" /></p>
<p style="text-align: left">Então, se vc possui um modchip que permita tal operação, grave o hello.elf no seu pendrive e execute no seu PS2. No meu caso, comecei testando o exemplo <strong>math3d.elf</strong>, eis o resultado:</p>
<p style="text-align: left"><img class="aligncenter size-full wp-image-146" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/toxicOS_04.jpg" alt="toxicOS_04" width="320" height="240" /></p>
<p style="text-align: left">Se vc não faz idéia do que é um modchip e só sabe que seu playstation é destravado, vc pode gravar o homebrew em um CD ou DVD (eu gravei num CDRW e deu certo) para testar. É claro que não vai funcionar se vc gravar o arquivo .elf diretamente na mídia e é para isso que serve o cdgenPS2.exe que está no diretório <strong>tools </strong>na pasta de instalação do PS2sdk.</p>
<h2 style="text-align: left">Criando uma imagem com o cdgenPS2</h2>
<p style="text-align: left">Abra o cdgenPS2.exe e arraste o seu .elf para a lista que contém os campos NAME, LBA, SIZE ETC.</p>
<p style="text-align: left"><img class="aligncenter size-full wp-image-35" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/cdgenPS2.JPG" alt="cdgenPS2" width="749" height="318" /></p>
<p style="text-align: left">Agora clique no botão IMG (o do ícone de CD), dê um nome para o sua imagem e grave num CD.</p>
<p style="text-align: left">Okay, vc chegou até aqui mas não possui um PlayStation2 para testar seu homebrew. Então, vc tem a opção de utilizar um emulador.</p>
<h2 style="text-align: left">O emulador PCSX2</h2>
<p style="text-align: left">Além do cdgenPS2, a pasta <strong>tools </strong>possui o <strong>pcsx2-0.8.1</strong>, que é um emulador de PS2 para PC (o melhor, se eu não me engano). O único problema é que ele não vem com uma bios padrão, mas isso é fácil de achar no google <img src='http://blog.delarco.com.br/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  ou vc pode ler meu post sobre <a href="http://blog.delarco.com.br/arquivos-escondidos-em-jpgs/" target="_blank">RAR&#8217;s escondidos em JPG&#8217;s</a> e baixar <a href="http://gelotech.files.wordpress.com/2009/10/ps2_bios.jpg" target="_blank">ESSA</a> imagem (11 MB) ;x</p>
<p style="text-align: left">Ao executar o emulador pela primeira vez, tenha certeza que vc selecionou a bios ocidental mais recente (USA v02.00+). No menu File, selecione a opção &#8220;Open ELF File&#8221; e escolha o seu .elf. Não sei bem o pq, mas o emulador pede para que vc selecione outro arquivo. Selecione a imagem gerada no cdgenPS2 e o seu Hello World será executado.</p>
<p style="text-align: left">Exemplos e homebrews que eu rodei no meu PS2:</p>
<p style="text-align: left"><strong><em>graph.elf</em></strong></p>
<p style="text-align: left"><img class="size-full wp-image-148 alignleft" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/toxicOS_05.jpg" alt="toxicOS_05" width="320" height="240" /></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"><em><strong>snes station<br />
</strong></em></p>
<p style="text-align: left"><img class="size-full wp-image-149   alignleft" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/toxicOS_06.jpg" alt="toxicOS_06" width="320" height="240" /> <img class="size-full wp-image-150 alignnone" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/toxicOS_07.jpg" alt="toxicOS_07" width="320" height="240" /></p>
<p style="text-align: left"><em><strong>doom</strong></em></p>
<p style="text-align: left"><img class="size-full wp-image-151 alignleft" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/toxicOS_08.jpg" alt="toxicOS_08" width="320" height="240" /> <img class="alignnone size-full wp-image-152" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/toxicOS_09.jpg" alt="toxicOS_09" width="320" height="240" /> <img class="alignnone size-full wp-image-153" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/toxicOS_10.jpg" alt="toxicOS_10" width="320" height="240" /></p>
<p style="text-align: left"><em><strong>blade </strong>(carrega e mostra um modelo </em><em>.md2)</em></p>
<p style="text-align: left"><img class="alignnone size-full wp-image-154" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/toxicOS_11.jpg" alt="toxicOS_11" width="320" height="240" /> <img class="alignnone size-full wp-image-155" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/toxicOS_12.jpg" alt="toxicOS_12" width="320" height="240" /></p>
<p style="text-align: left"><em><strong>PS2 Asteroids</strong></em></p>
<p style="text-align: left"><img class="alignnone size-full wp-image-156" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/toxicOS_13.jpg" alt="toxicOS_13" width="320" height="240" /> <img class="alignnone size-full wp-image-157" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/toxicOS_14.jpg" alt="toxicOS_14" width="320" height="240" /> <img class="alignnone size-full wp-image-158" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/toxicOS_15.jpg" alt="toxicOS_15" width="320" height="240" /></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delarco.com.br/playstation-2-hello-world/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Programação Multicore com OpenMP</title>
		<link>http://blog.delarco.com.br/programacao-multicore-com-openmp/</link>
		<comments>http://blog.delarco.com.br/programacao-multicore-com-openmp/#comments</comments>
		<pubDate>Wed, 21 Oct 2009 02:21:37 +0000</pubDate>
		<dc:creator>Leandro Del&#39;Arco</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[OpenMP]]></category>
		<category><![CDATA[programação]]></category>
		<category><![CDATA[codeblocks]]></category>
		<category><![CDATA[instalação]]></category>
		<category><![CDATA[multicore]]></category>
		<category><![CDATA[múltiplos núcleos]]></category>
		<category><![CDATA[openmp]]></category>

		<guid isPermaLink="false">http://blog.delarco.com.br/?p=111</guid>
		<description><![CDATA[
Hoje em dia é normal ouvir do vendedor &#8220;Esse computador é ótimo! Tem 4 GB de RAM e é um Core Duo!&#8220;. Apesar de, na maioria das vezes, a pessoa nem fazer idéia do que diabos é um Core Duo. Mas tudo bem, esse é o papel do vendedor, certo? É claro que qualquer entendido [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: center"><img class="aligncenter size-full wp-image-113" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/mc_processor.jpg" alt="multicore_processor" width="312" height="233" /></p>
<p>Hoje em dia é normal ouvir do vendedor &#8220;<em>Esse computador é ótimo! Tem 4 GB de RAM e é um Core Duo!</em>&#8220;. Apesar de, na maioria das vezes, a pessoa nem fazer idéia do que diabos é um Core Duo. Mas tudo bem, esse é o papel do vendedor, certo? É claro que qualquer entendido sabe que isso não qualifica o produto como &#8220;<em>bom</em>&#8220;, longe disso, temos que levar em conta muitos outros detalhes que pessoas que não são da área não entendem.</p>
<p>Com a chegada dos processadores de múltiplos núcleos, o marketing direcionou-se à  esse fator e esqueceu de que memória cache e barramento contam MUITO no desempenho. A maioria das pessoas não entendem, por exemplo, que um processador de 2 núcleos de 2.0 GHz NÃO significa 4.0 GHz ou que um sistema operacional de 32 bits não aproveita as vantagens do hardware de 64 bits.</p>
<p>O que me deixa triste é ouvir esse tipo de  <span style="text-decoration: line-through;">enganação</span> picaretagem de amigos/conhecidos da faculdade ( <a href="http://www.fatecriopreto.edu.br/php/index.php?option=com_content&amp;view=category&amp;id=34:info&amp;Itemid=34&amp;layout=default" target="_blank">Tecnologia em Informática com Ênfase em Gestão de Negócios &#8211; FATEC Rio Preto</a>). By the way, não quero desmerecer a faculdade, pois devo muito à vários professores que tiveram a paciência de aguentar alunos como eu e o <a href="http://terramel.org" target="_blank">bomba</a>.</p>
<p>Antes de entrar no assunto principal, entenda que não adianta ter um processador com 487564764 núcleos se o software não sabe como utilizá-los, okay?</p>
<p>Como recentemente adquiri um Phenom X3 (é, 3 núcleos) resolvi descobrir como aproveitar todo esse poder. Com uma busca aqui e uma ali (no <a href="http://google.com" target="_blank">oráculo</a>), trago o que aprendi.</p>
<h2>OpenMP?</h2>
<p>O <a href="http://openmp.org/" target="_blank">OpenMP</a> (Open Multi-Processing) é uma API aberta para programação paralela. De acordo com o site oficial:</p>
<blockquote><p>A API OpenMP auxilia na programação multiplataforma, paralela e com memória compartilhada em C/C++ e Fortran em todas as arquiteturas, incluindo plataformas Unix e Windows NT. Constituída por um grupo de grandes empresas de hardware e software, o OpenMP é um modelo portável e escalável que oferece ao programador uma interface flexível para o desenvolvimento de aplicações paralelas visando desktop até supercomputadores.</p></blockquote>
<p>A tradução no olhômetro ficou um lixo, mas dá pra ter uma idéia do que se trata.</p>
<blockquote><p>Beleza, nunca ouvi falar. Vale a pena alocar recursos (tempo) para aprender?</p></blockquote>
<p>Saiba que essa API (pelo menos a especificação) existe desde 1997, sendo os membros permanentes do Architecture Review Board (ARB):</p>
<ul>
<li> AMD (David Leibs)</li>
<li> Cray (James Beyer)</li>
<li> Fujitsu (Matthijs van Waveren)</li>
<li> HP (Uriel Schafer)</li>
<li> IBM (Kelvin Li)</li>
<li> Intel (Sanjiv Shah)</li>
<li> NEC (Kazuhiro Kusano)</li>
<li> The Portland Group, Inc. (Michael Wolfe)</li>
<li> SGI (Lori Gilbert)</li>
<li> Sun Microsystems (Nawal Copty)</li>
<li> Microsoft (-)</li>
</ul>
<p>(<em><a href="http://openmp.org/wp/about-openmp/" target="_blank">Retirado do site oficial</a></em>)</p>
<p><strong>Convencido(a)?</strong></p>
<h2>Instalando o OpenMP</h2>
<p>É simples, você não instala.</p>
<blockquote><p>Como assim?</p></blockquote>
<p>Você DEVE ter um compilador que tenha o OpenMP implementado.</p>
<blockquote><p>E o meu compilador implementa?</p></blockquote>
<p><a href="http://openmp.org/wp/openmp-compilers/" target="_blank">Aqui </a>vc pode ver a lista de compiladores que disponibilizam o recurso. Como, provavelmente, vc usa:</p>
<ul>
<li><strong>V</strong><strong>isual C++ 2008</strong>: apenas a versão Professional (ou sei lá o nome da versão que não seja a Express) possui os headers necessários. ACHO que se vc copiar os headers da versão paga para a Express, irá funcionar;</li>
<li><strong>Code::Blocks (MinGW)</strong>: apenas nas versões (do gcc) 4.3.2 ou superiores.</li>
</ul>
<p>Baixei o <a href="http://www.mingw.org/" target="_blank">MinGW</a> mais recente no site oficial e instalei para usar com o Code::Blocks. Porém, a versão do gcc era a <em>3.4.alguma-coisa</em> e é claro, não funcionou pois não possuia os headers necessários.</p>
<p>Então, resolvi instalar logo o <a href="http://www.tdragon.net/recentgcc/" target="_blank">TDM&#8217;s GCC/MinGW</a> que é uma build não oficial dos binários mais recentes do GCC. Faça o download do <a href="http://sourceforge.net/projects/tdm-gcc/files/TDM-MinGW%20Installer/1.908.0/tdm-mingw-1.908.0-4.4.1-2.exe/download" target="_blank">instalador mais recente</a> e, na hora da instalação, escolha o diretório MinGW que está dentro do diretório de instalação do seu Code::Blocks (no meu caso, E:\CodeBlocks\MinGW):</p>
<p><img class="aligncenter size-full wp-image-121" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/tdm_install1.jpg" alt="tdm_install1" width="513" height="399" /></p>
<p>Clique em &#8220;Next &gt;&#8221; e selecione um mirror:</p>
<p><img class="aligncenter size-full wp-image-122" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/tdm_install2.jpg" alt="tdm_install2" width="513" height="399" /></p>
<p>Clique em &#8220;Next &gt;&#8221; e selecione apenas os componentes que deseja instalar. No meu caso, deixei como está (todos):</p>
<p><img class="aligncenter size-full wp-image-123" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/tdm_install3.jpg" alt="tdm_install3" width="513" height="399" /></p>
<p>Após selecionar os componentes, clique em &#8220;Install&#8221; e espere a extração dos arquivos terminar.</p>
<h2>Hello World!</h2>
<p>Se tudo estiver certo, então será possível compilar o &#8220;Hello World&#8221; abaixo:</p>
<pre class="brush: cpp;">

#include &lt;omp.h&gt;
#include &lt;stdio.h&gt;

int main()
{
#pragma omp parallel
printf(&quot;Hello! (from thread %d, num. threads %d)\n&quot;,
omp_get_thread_num(),
omp_get_num_threads());
}
</pre>
<p>Antes de tentar rodar o exemplo, precisamos definir a compile-time flag <strong>-fopenmp</strong> para que o compilador saiba que o projeto utiliza o OpenMP. Se vc compilar pelo prompt de comando diretamente com o GCC, basta adicionar o parâmetro <strong>-fopenmp</strong>, ficando assim:</p>
<p><span style="color: #000000"><strong><em>gcc.exe hello_world.c -o hello_world.exe -fopenmp</em></strong></span></p>
<p>Já no Code::Blocks, vc também precisa linkar a <strong>libgomp.dll.a </strong>e ter o arquivo <strong>libgomp-1.dll</strong> na pasta BIN do seu compilador ou na pasta do seu projeto. Então, faça assim:</p>
<ul>
<li>Selecione a opção &#8220;Build options&#8230;&#8221; no menu &#8220;Project&#8221; do Code::Blocks;</li>
<li>Na lista da esquerda, selecione o seu projeto (o 1º item, não o Debug, nem o Release);</li>
<li>Procure a aba &#8220;Other options&#8221; dentro da aba &#8220;Compiler settings&#8221;. Adicione a flag <strong>-fopenmp</strong>;<br />
<img class="aligncenter size-full wp-image-125" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/omp_hw1.jpg" alt="omp_hw1" width="680" height="525" /></li>
<li>Agora selecione a aba &#8220;Linker settings&#8221; e adicione o arquivo <strong>libgomp.dll.a</strong>. Na minha instalação, esse arquivo estava no diretório &#8220;<em>E:\CodeBlocks\MinGW\lib\gcc\mingw32\4.4.1\</em>&#8220;;<strong> </strong></li>
<li>É importante que vc linke o arquivo <strong>libgomp.dll.a</strong> e não o <strong>libgomp.a;</strong></li>
<li>O projeto já pode ser compilado, mas para que funcione, será necessário copiar o arquivo <strong>libgomp-1.dll</strong> para o diretório do seu executável. Assim como a lib, o diretório em que esse arquivo pode ser encontrado não é tão trivial. Na minha instalação, encontrei em &#8220;<em>E:\CodeBlocks\MinGW\lib\gcc\mingw32\bin</em>&#8220;;</li>
<li>Creio que não é necessário explicar a parte de copiar o arquivo (<em>CTRL + C, CTRL + V, a mesma coisa que vc usa para fazer os trabalhos da faculdade</em>).</li>
</ul>
<p>Btw, <a href="http://gcc.gnu.org/projects/gomp/" target="_blank">GOMP</a> é o projeto que implementou o OpenMP nos compiladores C, C++ e Fortran do GNU Compiler Collection.</p>
<p>Pronto, o Hello World deve (ou deveria) mostrar algumas mensagens &#8220;Hello!&#8221; com o ID da thread em que está sendo executado, seguido do número de threads. Aqui tive o seguinte resultado:</p>
<p><img class="aligncenter size-full wp-image-126" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/omp_hw2.jpg" alt="omp_hw2" width="677" height="342" /></p>
<p>Mas por que 3 threads? Porque esse é o número padrão para a variável ambiente OMP_NUM_THREADS (na minha implementação, pelo menos). Para definir o número de threads, chame a função <strong>omp_set_num_threads(num_threads).</strong> Então, o &#8220;Hello World&#8221; modificado ficaria assim:</p>
<pre class="brush: cpp;">

#include &lt;omp.h&gt;
 #include &lt;stdio.h&gt;

 int main()
 {
 omp_set_num_threads(10);

 #pragma omp parallel
 printf(&quot;Hello! (from thread %d, num. threads %d)\n&quot;,
 omp_get_thread_num(),
 omp_get_num_threads());
 }
</pre>
<p>Agora vc verá 10 mensagens &#8220;Hello!&#8221;.</p>
<h2>É só isso?</h2>
<p>Não. Apesar de simples, o exemplo anterior usa eficientemente todos os núcleos disponíveis, de forma transparente. Pode parecer que não houve um grande ganho no desempenho, mas com alguns testes vamos ver que a programação multicore pode otimizar de forma significativa o aplicativo.</p>
<p>Para que o post não fique cansativo, deixo o resto para semana que vem.</p>
<p><strong>Fonte:</strong> <a href="http://openmp.org/wp/" target="_blank">OpenMP.org</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delarco.com.br/programacao-multicore-com-openmp/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Arquivos escondidos em JPG&#8217;s</title>
		<link>http://blog.delarco.com.br/arquivos-escondidos-em-jpgs/</link>
		<comments>http://blog.delarco.com.br/arquivos-escondidos-em-jpgs/#comments</comments>
		<pubDate>Tue, 13 Oct 2009 04:21:11 +0000</pubDate>
		<dc:creator>Leandro Del&#39;Arco</dc:creator>
				<category><![CDATA[dicas]]></category>
		<category><![CDATA[informática]]></category>
		<category><![CDATA[programação]]></category>
		<category><![CDATA[camuflar]]></category>
		<category><![CDATA[esconder]]></category>
		<category><![CDATA[imagem]]></category>
		<category><![CDATA[jpg]]></category>
		<category><![CDATA[rar]]></category>

		<guid isPermaLink="false">http://blog.delarco.com.br/?p=38</guid>
		<description><![CDATA[Qual a diferença entre essas duas imagens?

3.17 KB

76.9 KB
Aparentemente só o tamanho, mas ao abrir a segunda imagem com o WinRAR, vc vai encontrar algo além do italiano bigodudo.
Como isso é possível? Coisa mais simples do mundo:

Que jogar um monte de bytes (arquivo) no final de outro monte de bytes (outro arquivo) é possível, tudo [...]]]></description>
			<content:encoded><![CDATA[<p>Qual a diferença entre essas duas imagens?</p>
<p style="text-align: center"><img class="aligncenter wp-image-39" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/mario1.jpg" alt="mario1" width="64" height="64" /></p>
<p style="text-align: center">3.17 KB</p>
<p><img class="aligncenter wp-image-40" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/mario_jpg_rar.jpg" alt="mario_jpg_rar" width="64" height="64" /></p>
<p style="text-align: center">76.9 KB</p>
<p style="text-align: left">Aparentemente só o tamanho, mas ao abrir a segunda imagem com o WinRAR, vc vai encontrar algo além do italiano bigodudo.</p>
<p style="text-align: left">Como isso é possível? Coisa mais simples do mundo:</p>
<p style="text-align: left"><img class="aligncenter size-full wp-image-44" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/jgp_plus_rar.JPG" alt="jgp_plus_rar" width="269" height="95" /></p>
<p style="text-align: left">Que jogar um monte de bytes (arquivo) no final de outro monte de bytes (outro arquivo) é possível, tudo bem, todo mundo já sabia. O que eu não sabia era que o WinRAR conseguia achar o trecho compactado sem saber exatamente onde ele começa. Com certeza deve existir alguma flag que indica onde fica esse trecho. Okay, deixo a parte nerd do post para outra hora.</p>
<h3 style="text-align: left">Tá, legal&#8230; e dái?</h3>
<p style="text-align: left">Veja bem, isso não serve pra p**** nenhuma, certo? Errado!<br />
A internet é uma terra sem lei, mas algumas pessoas insistem em tentar controlar o que vc faz ou deixa de fazer. Então, alguma mente desocupada teve a, diga-se de passagem, ótima idéia de camuflar conteúdo ilegal em imagens inocentes e hospedar em um desses serviços de armazenagem grátis (como o imageshack.us).</p>
<p style="text-align: left">Pode não parecer muita coisa, pois vc baixa seus filmes educativos por torrent, mas com os grandes trackers indo pro saco uma hora a festa acaba (ou fica mais difícil de arrumar convite).</p>
<blockquote>
<p style="text-align: left">Okay, vc tá dizendo que eu posso baixar Doom 4 camuflado num JPG? É impossível ter um JPG de 10+ GB hospedado, qualquer imbecil vai perceber que não se trata de uma imagem.</p>
</blockquote>
<p style="text-align: left">Correto, mas e se esses GB&#8217;s fossem divididos em pequenas partes de, vamos supor, 2 MB cada&#8230; e cada uma dessas partes fosse hospedada como uma imagem diferente? No final, só será necessário &#8220;<em>juntar</em>&#8221; os pedaços para assistir o novo episódio de House.</p>
<p style="text-align: left">É claro que um software gerenciando tudo isso deixaria as coisas mais fáceis, mas não conheço nenhum =/<br />
Por isso comecei um projeto simples (iShare, em C#) que faz o básico:</p>
<ul>
<li>Divide o arquivo-alvo em quantas partes de tamanho Y (especificado pelo usuário) forem necessárias;</li>
<li>Adiciona uma imagem <em>random </em>no começo de cada parte;</li>
<li><span style="color: #ff0000">Armazena as imagens em algum serviço online, ou disco virtual;</span></li>
<li><span style="color: #ff0000">Cria uma lista de links para as imagens que compõem o arquivo-alvo;</span></li>
<li><span style="color: #ff0000">Baixa as imagens;</span></li>
<li><span style="color: #000000">Remove as imagens, deixando só as partes;</span></li>
<li><span style="color: #000000">&#8220;<em>Junta</em>&#8221; as partes.</span></li>
</ul>
<p><span style="color: #000000">Pena que parei com o projeto antes de terminar os itens listados em vermelho. Se houver interesse, posto o source pra quem quiser terminar.</span></p>
<p><span style="color: #000000">Para quem for utilizar essa técnica, uma dica é utilizar o Wordpress, fiz um teste a um ano e a imagem de 7.5 MB está lá até hoje. Quem quiser testar, baixe <a href="http://gelotech.files.wordpress.com/2008/10/bt.jpg">essa imagem</a> (clique com o botão direito e em Salvar link&#8230;), depois tente abrir com o WinRAR.<br />
</span></p>
<h3><span style="color: #000000">Enfim, como faço a gambiarra?</span></h3>
<p><span style="color: #000000">O modo mais simples é:</span></p>
<ul>
<li><span style="color: #000000">Copie a imagem que vc deseja usar para camuflar o seu RAR para seu C:\<br />
</span></li>
<li><span style="color: #000000">Copie seu RAR que será camuflado para seu C:\</span></li>
<li><span style="color: #000000">Escolha um nome para a imagem que será criada contando o RAR (</span><span style="color: #000000"><strong>gambiarra.jpg</strong> ou<strong> gambi</strong></span><span style="color: #000000"><strong>.jpg</strong>, para os íntimos)</span></li>
<li><span style="color: #000000">Abra o menu <strong>Iniciar </strong>e clique em <strong>Executar </strong>e digite &#8220;cmd&#8221;, sem aspas</span></li>
<li><span style="color: #000000">Clique em Ok e um prompt de comando aparecerá<br />
</span></li>
<li><span style="color: #000000">Digite: <strong>copy /b <em>c:\&lt;sua_imagem.jpg&gt;</em> + c:\<em>&lt;seu_rar.rar&gt;</em> c:\gambi.jpg</strong></span></li>
</ul>
<p><span style="color: #000000">No case, se sua imagem original tem o nome A.JPG e seu RAR tem o nome B.JPG, ficaria: <em>copy /b C:\A.JPG + C:\B.RAR C:|GAMBI.JPG</em></span></p>
<p><span style="color: #000000">Para quem programa em C:</span></p>
<pre class="brush: cpp;">
#include &lt;stdio.h&gt;

int main(int ac, char ** av)
{
    FILE *jpg, *rar, *out;
    char c;

    jpg = fopen(&quot;./arquivo.jpg&quot;, &quot;rb&quot;);
    rar = fopen(&quot;./arquivo.rar&quot;, &quot;rb&quot;);
    out = fopen(&quot;./imagem.jpg&quot;,  &quot;wb&quot;);

    while(!feof(jpg))
        fputc(fgetc(jpg), out);

    while(!feof(rar))
        fputc(fgetc(rar), out);

    fclose(jpg);
    fclose(rar);
    fclose(out);
}</pre>
<p><span style="color: #000000">Ou para quem programa em VB (5 ou 6):</span></p>
<pre class="brush: vb;">

sub main()

Dim f1() As Byte
Dim f2() As Byte

Open &quot;.\arquivo.jpg&quot; For Binary As #1
ReDim f1(LOF(1))
Get #1, , f1
Close #1

Open &quot;.\arquivo.rar&quot; For Binary As #1
ReDim f2(LOF(1))
Get #1, , f2
Close #1

Open &quot;.\imagem.jpg&quot; For Binary As #1
Put #1, , f1
Put #1, , f2
Close #1
</pre>
<p><span style="color: #000000">Por enquanto, para músicas e ROM&#8217;s de Super Nintendo, funciona muito bem <img src='http://blog.delarco.com.br/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /><br />
</span></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delarco.com.br/arquivos-escondidos-em-jpgs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

<!-- www.000webhost.com Analytics Code -->
<script type="text/javascript" src="http://analytics.hosting24.com/count.php"></script>
<noscript><a href="http://www.hosting24.com/"><img src="http://analytics.hosting24.com/count.php" alt="web hosting" /></a></noscript>
<!-- End Of Analytics Code -->
