<?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>Petryx :: &#187; C</title>
	<atom:link href="http://petryx.blogrs.com.br/category/c/feed/" rel="self" type="application/rss+xml" />
	<link>http://petryx.blogrs.com.br</link>
	<description>Linux,Java,Postgresql,Banco de dados, Processamento de imagens</description>
	<lastBuildDate>Fri, 30 Jul 2010 11:11:03 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>LibSDL exemplo Fogos de artifício</title>
		<link>http://petryx.blogrs.com.br/2009/02/25/libsdl-exemplo-fogos-de-artificio/</link>
		<comments>http://petryx.blogrs.com.br/2009/02/25/libsdl-exemplo-fogos-de-artificio/#comments</comments>
		<pubDate>Thu, 26 Feb 2009 00:44:54 +0000</pubDate>
		<dc:creator>Marlon Petry</dc:creator>
				<category><![CDATA[C]]></category>
		<category><![CDATA[developer]]></category>

		<guid isPermaLink="false">http://petryx.blogrs.com.br/?p=134</guid>
		<description><![CDATA[Pessoal Quem curte fogos de artifício e programação em C com libsdl, eis aqui um exemplo muito bom para experimentar SDL com OpenGL. Veja o screenshot: Características: - OpenGL - Reprodução de .wav - Threads - Interação do Teclado - Números Randômicos Esse exemplo de SDL pode ser modificado para um gerador de partículas, podendo [...]]]></description>
			<content:encoded><![CDATA[<p>Pessoal</p>
<p>Quem curte fogos de artifício e programação em C com libsdl, eis aqui um exemplo muito bom para experimentar SDL com OpenGL.<br />
Veja o screenshot:</p>
<p><a href="http://petryx.blogrs.com.br/wp-content/uploads/2009/02/fogossdl4.jpg"><img class="aligncenter size-medium wp-image-135" title="fogossdl4" src="http://petryx.blogrs.com.br/wp-content/uploads/2009/02/fogossdl4-300x225.jpg" alt="exemplo SDL fogos de artifício" width="300" height="225" /></a></p>
<p>Características:<br />
- OpenGL<br />
- Reprodução de .wav<br />
- Threads<br />
- Interação do Teclado<br />
- Números Randômicos</p>
<p>Esse exemplo de SDL pode ser modificado para um gerador de partículas, podendo modificar as cores, velocidade, número de partículas e muito mais.</p>
<p>Baseado na lição 19 do site: <a href="http://nehe.gamedev.net/">http://nehe.gamedev.net/</a><br />
<a href='http://petryx.blogrs.com.br/wp-content/uploads/2009/03/fogostar.gz'>fogos.tar.gz</a></p>
]]></content:encoded>
			<wfw:commentRss>http://petryx.blogrs.com.br/2009/02/25/libsdl-exemplo-fogos-de-artificio/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>AVL com Ncurses em C</title>
		<link>http://petryx.blogrs.com.br/2008/07/17/avl-com-ncurses-em-c/</link>
		<comments>http://petryx.blogrs.com.br/2008/07/17/avl-com-ncurses-em-c/#comments</comments>
		<pubDate>Thu, 17 Jul 2008 19:39:21 +0000</pubDate>
		<dc:creator>Marlon Petry</dc:creator>
				<category><![CDATA[C]]></category>
		<category><![CDATA[developer]]></category>

		<guid isPermaLink="false">http://petryx.blogrs.com.br/?p=82</guid>
		<description><![CDATA[Olhando os trabalhos que realizei na faculdade. Encontrei uma AVL desenvolvida para a cadeira de estutura de dados. Implementei utilizando como interface gráfica NCURSES, para mostrar a árvore. Irei compartilhar o código. Com certeza será bastante util para quem está estudando. Este código tem alguns conceitos interessantes como: Não utiliza variáveis globais Os dados são [...]]]></description>
			<content:encoded><![CDATA[<p>Olhando os trabalhos que realizei na faculdade. Encontrei uma AVL desenvolvida para a cadeira de estutura de dados. Implementei utilizando como interface gráfica NCURSES, para mostrar a árvore.</p>
<p>Irei compartilhar o código. Com certeza será bastante util para quem está estudando.<br />
Este código tem alguns conceitos interessantes como:</p>
<ul>
<li>Não utiliza variáveis globais</li>
<li>Os dados são inseridos na árvore quando ficar desbalanceada é informado e solicitado ao usuário se deseja balancear a árvore</li>
<li>Informe como a árvore esta desbalanceada em quatro casos: EE,ED,DD e DE</li>
<li>Calcula a altura da árvore</li>
<li>Menu em Ncurses</li>
<li>Visualização da árvore com Ncurses</li>
</ul>
<pre name='code' class='C'>
/*
 * Nome: Marlon Luis Petry
 * Description: AVL
 compilacao
 gcc       "Avl-Marlon.c"     -o "Avl-Marlon" -g  -lncurses -w
 Data: 20/10/2005

 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ncurses.h>

#define CENTERX COLS/2
#define CENTERY LINES/2
#define DIST 5

typedef char string[50];

typedef struct t {
	 string info;
	 int alt;
	 struct t *pai;
	 struct t *left;
	 struct t *right;
	 }tree;

int tipoBal = -1;
string bal[4] = {"Caso EE","Caso ED","Caso DD","Caso DE"};	 

tree *bal_esq(tree *aux);
tree *bal_dir(tree *aux);
tree *rotacaoRR(tree *aux);
tree *rotacaoLL(tree *aux);
tree *rotacaoLR(tree *aux);
tree *rotacaoRL(tree *aux);

tree *insere(tree **root, string info, int  h) {

    char ch;
    tree *aux;

    if (*root == NULL)
	 {
		 aux = (tree *) malloc(sizeof(tree));
		 strcpy(aux->info,info);
		 aux->left = NULL;
		 aux->right = NULL;
		 aux->pai = NULL;
		 aux->alt = 0;
		 h = 1;
		 *root = aux;
	 }
	 else
	 {
         if (strcmp(info,(*root)->info) < 0)
		 {
                 insere(&#038;(*root)->left, info, h);
                 //Atualiza PAI do nÃ³ inserido
                 if ((*root)->left->pai == NULL)
                     (*root)->left->pai = *root;

             	 if (h)
                     switch((*root)->alt)
					 {
                         //Estava mais alto Ã  direita e inseriur mais um nÃ³ Ã  esquerda
                         case -1:
                             (*root)->alt = 0;
                             h = 0; //NÃ£o propaga os ajustes nos fatores de balanceamento
                              break;
                         case 0:
                             (*root)->alt = 1; //o lado esquerdo fica maior e os fatores de
                                           //balanceamento acima deverao ser ajustados
                              break;
                         case 1:
							mvprintw(8,10,"Arvore Desbalaceou a esquerda A = %s Y = %s",(*root)->info,info);
                            mvprintw(9,10,"Baleancear (S)im (N)nao: ");
                            scanw("%c",&#038;ch);
						 	if(ch == 'S' || ch == 's')
							{
						 	*root =  bal_esq(*root); //FB == 2 -> retorna a sub-Ã¡rvore balanceada
                             h = 0; //nÃ£o propaga a atualizaÃ§Ã£o dos fatores de
							}            //balanceamento
                              break;
                     }
		}
        else
		{
             insere(&#038;(*root)->right, info, h);
                 //Atualiza PAI do nÃ³ inserido
                 if ((*root)->right->pai != NULL)
				    (*root)->right->pai = *root;

                 if (h)
                     switch ((*root)->alt)
				     {
                         //estava mais alto Ã  esquerda e inseriu mais um nÃ³ Ã  direita
                         case 1:
                             (*root)->alt = 0;
                             h = 0; //nÃ£o propaga os ajustes nos fatores de balanceamneto
                              break;
                         case 0:
                             (*root)->alt = -1; // o lado direito fica maior do que o esquerdo e
                                               // o ajuste deve ser propagado
                              break;
                         case -1:
                             //FB == -2 -> retorna a sub-Ã¡rvore balanceada
						 	mvprintw(8,10,"Arvore Desbalaceou a direita A = %s Y = %s",(*root)->info,info);
                            refresh();
						 	mvprintw(9,10,"Baleancear (S)im (N)nao: ");
                            scanw("%c",&#038;ch);
						 	if(ch == 'S' || ch == 's')
							{
						 	*root = bal_dir(*root);
                             h = 0; //nÃ£o propaga a atualizaÃ§Ã£o dos fatores de
                            }             //balanceamento
                             break;
                     }
            }
		}
           return(*root);
     }

tree *bal_esq(tree *aux)
{

    tree *p;
     p = aux->left;

     if (p->alt == 1)
	 {		 //sinais iguais e positivo
         tipoBal = 1;

		 aux = rotacaoLL(aux);
	 }
     else
	 {
		 tipoBal = 2;
         aux = rotacaoLR(aux);    //sinais diferentes
	 }
     aux->alt = 0;
 	 return(aux);
}

/*
 *  O novo nÃ³ foi inserido Ã  direita. Ocorreu desbalanceamento (fb == 2)
 */
tree *bal_dir(tree *aux)
{

    tree *p;

     p = aux->right;
     if (p->alt == -1)                //Sinais iguais e negativo
	 {
		 tipoBal = 3;
         aux = rotacaoRR(aux);
	 }
     else
	 {
		 tipoBal = 4;
         aux = rotacaoRL(aux);     //Sinais diferentes
	 }
     aux->alt = 0;
     refresh();
     return(aux);
}

//rotacoes
tree *rotacaoRR(tree *aux) {

    tree *p;
     p = aux->right;
     aux->right = p->left;
     if (p->left != NULL)
         p->left->pai = aux;
     p->left = aux;
     p->pai = aux->pai;
     aux->pai = p;
     aux->alt = 0;

     return(p);
 }

tree *rotacaoLL(tree *aux) {

    tree *p;

     p = aux->left;
     aux->left = p->right;
     if (p->right != NULL)
         p->right->pai = aux;
     p->right = aux;
     p->pai = aux->pai;
     aux->pai = p;
     aux->alt = 0;

     return(p);
 }

tree *rotacaoLR(tree *aux) {

    tree *pai;     //ponteiro para depois atualizar o pai apÃ³s a rotaÃ§Ã£o
    tree *no_left;  //ponteiro para o filho esquerdo para atualizar o FB apÃ³s a rotaÃ§Ã£o
    tree *novo_no; //ponteiro Ã  ser retornado
     int FB_fright;  //fator de balanceamento do no Ã  direita do filho esquerdo

     pai = aux->pai;
     no_left = aux->left;
     FB_fright = no_left->right->alt;
     aux->left = rotacaoRR(no_left);
     novo_no = rotacaoLL(aux);
     novo_no->pai = pai;
     aux->alt = (FB_fright == 1)?-1:0; //Atualiza FB do nÃ³ rotacionado
     no_left->alt = (FB_fright == -1)?1:0; // Atualiza FB do nÃ³ Ã  esquerda do nÃ³ rotacionado

     return(novo_no);
 }

/*
 *  AtualizaÃ§Ã£o do FB e balanceamento para a raÃ­z esquerda
 */
tree *balanceamento_esquerdo(tree *no, int h) {

    tree *f_dir;
     int fb_dir;

     switch (no->alt) {
         case 1:
             no->alt = 0;
             break;
         case 0:
             no->alt = -1;
             h = 1;
             break;
         case -1:
                 f_dir = no->right;
                 fb_dir = f_dir->alt;
                 if (fb_dir <= 0) {
                     f_dir = rotacaoRR(no);
                  if (fb_dir == 0) {
                     no->alt = -1;
                        f_dir->alt = 1;
                        h = 0;
                     }
                     else {
                         no->alt = 0;
                         f_dir->alt = 0;
                     }
                     no = f_dir;
                 }
                 else {
                     no = rotacaoRL(no);
                     no->alt = 0;
                 }
     }
     return(no);
 }

 /*
 *  AtualizaÃ§Ã£o do FB e balanceamento para a raiz direita
 */
tree *balanceamento_direito(tree *no, int h) {

    tree *f_esq;
     int alt_esq;

    switch (no->alt) {
         case -1:
             no->alt = 0;
             break;
         case 0:
             no->alt = 1;
             h = 0;
             break;
         case 1:
             f_esq = no->left;
             alt_esq = f_esq->alt;
             if (alt_esq >= 0) {
                 f_esq = rotacaoLL(no);
                 if (alt_esq == 0) {
                     no->alt = 1;
                     f_esq->alt = -1;
                     h = 0;
                 }
                 else {
                     no->alt = 0;
                     f_esq->alt = 0;
                 }
                 no = f_esq;
             }
             else {
                 no = rotacaoLR(no);
                 no->alt = 0;
             }
     }
     return(no);
 }

/*
 *  Busca nÃ³ substituto e realizada a remoÃ§Ã£o (busca o mais Ã  direita do nÃ³ esquerdo
 */
tree *busca_remove(tree *no, tree *no_chave, int  h) {

    tree *no_removido;
     if (no->right != NULL) {
         no->right = busca_remove(no->right, no_chave, h);
         if (h)
             no = balanceamento_direito(no, h);
     }
     else {
         strcpy(no_chave->info,no->info);
         no_removido = no;
         no = no->left;
         if (no != NULL)
             no->pai = no_removido->pai;
         h = 1;     //Deve propagar a atualizaÃ§Ã£o dos FB
         free(no_removido);
     }
     return(no);
 }

/*
 *  RemoÃ§Ã£o da Ãrvore AVL
 */
tree *removeTree(tree **raiz, int info, int h) {

    if (*raiz == NULL) {
         printf("Chave nÃ£o localizada !");
         h = 0;
     }
     else {
         if (strcmp((*raiz)->info, info) > 0)
		 {
             removeTree(&#038;(*raiz)->left, info, h);
             if (h)
                 *raiz = balanceamento_esquerdo(*raiz, h);
         }
         else if (strcmp((*raiz)->info , info) < 0)
		  {
			  removeTree(&#038;(*raiz)->right, info, h);
              if (h)
                *raiz = balanceamento_direito(*raiz,h);
          }
          else { //Encontrou o elemento a ser removido
                 if ((*raiz)->right == NULL) {
                     if ((*raiz)->left != NULL) //Escolhe o nÃ³ Ã  esquerda como substituto
                         (*raiz)->left->pai = (*raiz)->pai;
                     *raiz = (*raiz)->left;
                     h = 1;
                 }
                 else
                     if ((*raiz)->left == NULL) {
                         if ((*raiz)->right != NULL) //Escolhe o nÃ³ Ã  direita como substituto
                             (*raiz)->right->pai = (*raiz)->pai;
                         *raiz = (*raiz)->right;
                         h = 1;
                     }
                     else { // Busca o elemento mais Ã  direita do nÃ³ esquerdo
                         (*raiz)->left = busca_remove((*raiz)->left, *raiz, h);
                         //Se necessÃ¡rio efetua balanceamento (Esquerdo pois a funÃ§Ã£o
                         //busca_remove foi para o nÃ³ esquerdo)
                         if (h)
                             *raiz = balanceamento_esquerdo(*raiz, h);
                     }
             }
     }
     return(raiz);
 } 

tree *rotacaoRL(tree *aux) { 

    tree *pai;     //ponteiro para depois atualizar o pai apÃ³s a rotaÃ§Ã£o
    tree *no_right;  //ponteiro para o filho direito para atualizar o FB apÃ³s a rotaÃ§Ã£o
    tree *novo_no; //ponteiro Ã  ser retornado
     int FB_fleft;  //fator de balanceamento do no Ã  esquerda do filho direito

     pai = aux->pai;
     no_right = aux->right;
     FB_fleft = no_right->left->alt;
     aux->right = rotacaoLL(no_right);
     novo_no = rotacaoRR(aux);
     novo_no->pai = pai;
     aux->alt = (FB_fleft == -1)?1:0;      //Atualiza FB do nÃ³ rotacionado
     no_right->alt = (FB_fleft == 1)?-1:0;  // Atualiza FB do nÃ³ Ã  direita do nÃ³ rotacionado
     return(novo_no);
}

int maxDepth(tree *node) {
  if (node==NULL) {
    return(0);
  }
  else {
    int lDepth = maxDepth(node->left);
    int rDepth = maxDepth(node->right);

    if (lDepth > rDepth) return(lDepth+1);
    else return(rDepth+1);
  }
}

//print
int print(tree *r,int x, int y)
{
	int TotalWidth = width(r)*DIST;
	int centerWidth = (x + TotalWidth/2);
	int tamStr;
	int d = 0;
	//int centerWidthLinen= centerWidth +20;
	char t;
	if(r != NULL)
	{
		int leftWidth = width(r->left) * DIST;
		int rigtWidth = width(r->right) * DIST;
		tamStr = strlen(r->info);
	    mvprintw(y + (DIST/20),(centerWidth -1- (tamStr/2)),"%s", r->info);

	 if (r->left != NULL)
	 {
		int leftX = print(r->left, x , y + DIST);
	 }
	 if (r->right != NULL)
	 {
		int rightX = print(r->right, x + leftWidth, y + DIST);
	 }

	}
	return centerWidth;
}

int width(tree *root)
{
	if(root == NULL)
		return 1;
	else if(root->left == NULL &#038;&#038; root->right == NULL)
		return 1;
	else
		return width(root->left) + width(root->right);
}

main()
{

	tree *root = NULL;
	char ch;
	string msg;
	string info;
	int opt;
	int d=0;
	initscr();

	bkgd(COLOR_PAIR(4));

	strcpy(msg,"Pressione Qualquer Tecla");
	while(1)
	{
		clear();
		mvprintw(1,10,"%s","(1) - Inserir novo valor ");
		mvprintw(2,10,"%s","(2) - Mostrar");
		mvprintw(3,10,"%s","(3) - Remove");
		mvprintw(4,10,"%s","(4) - Altura");
	        mvprintw(5,10,"%s","(5) - Sair");
	       	mvprintw(6,10,"[ ]");
		move(6,11);

		scanw("%d",&#038;opt);
		refresh();

		switch(opt)
		{
			mvprintw(10,10,"%d",opt);
			case 1:
				mvprintw(7,10,"%s","Informe Valor: ");
				refresh();
				getstr(info);
				insere(&#038;root,info,1);
				break;
			case 2:
				clear();
				print(root,CENTERX,0);
				mvprintw(LINES -2,CENTERX,"%s",bal[tipoBal]);
				tipoBal = -1;
		        mvprintw(LINES -1,CENTERX,"%s",msg);
				getch();
				break;
			case 3:
				mvprintw(7,10,"%s","Informe Valor: ");
				refresh();
				getstr(info);
				removeTree(&#038;root,info,1);
			    break;
			case 4:
				//mvprintw(LINES - 1,CENTERX,"%s","f para sair ");
			       mvprintw(7,10,"%s","Nivel");
				refresh();
                               d = maxDepth(root);

			       mvprintw(8,10,"%d",d);
                               refresh();
                               break;

			case 5:
				//mvprintw(LINES - 1,CENTERX,"%s","f para sair ");
				ch = 'f';
				break;

		}
		refresh();

		if(ch == 'f')
			break;
	}

	endwin();
}
</pre>
<p>Não se esqueça este código é GPL pode ser usado desde que mantido os direitos autorais.</p>
<p>Assinem os FEEDS é de graça. Só essa semana <img src='http://petryx.blogrs.com.br/wp-includes/images/smilies/icon_lol.gif' alt=':lol:' class='wp-smiley' />  </p>
]]></content:encoded>
			<wfw:commentRss>http://petryx.blogrs.com.br/2008/07/17/avl-com-ncurses-em-c/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>C chat with sockets and thread</title>
		<link>http://petryx.blogrs.com.br/2008/06/28/c-chat-with-sockets-and-thread/</link>
		<comments>http://petryx.blogrs.com.br/2008/06/28/c-chat-with-sockets-and-thread/#comments</comments>
		<pubDate>Sun, 29 Jun 2008 01:13:16 +0000</pubDate>
		<dc:creator>Marlon Petry</dc:creator>
				<category><![CDATA[C]]></category>
		<category><![CDATA[Sem categoria]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[developer]]></category>

		<guid isPermaLink="false">http://petryx.blogrs.com.br/?p=61</guid>
		<description><![CDATA[I developed a chat server in the C language and Python language The chat written in Python is posted here. Now I developed the chat using the C sockets and threads. The code developed in C follows the same principles of the code in Python. In C had to develop a double linked list to [...]]]></description>
			<content:encoded><![CDATA[<p>I developed a chat server in the C language and Python language The chat written in Python is posted  <a href="http://petryx.blogrs.com.br/2008/05/30/tutorial-write-a-multithread-chat-in-python/">here</a>. Now I developed the chat using the C sockets and threads.  The code developed in C follows the same principles of the code in Python. In C had to develop a double linked list to store the file descriptor of the socket, user name and nickname.  This code was developed to the discipline of Distributed Systems.</p>
<pre name="code" class="C">
#include
<pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <sys/wait.h>
#include <stddef.h>
#include <errno.h>
#include <sys/un.h>

#include "listaDDE.h"
#define MYPORT 5800    // the port users will be connecting to

#define BACKLOG 10     // how many pending connections queue will hold
#define MAXLINE 1024
#define NUM_THREADS     50
fd_set rmask;
pthread_mutex_t mutexsum;
pthread_mutex_t mutexLogin;
int fd_max;
int maxfds;

int sockfd;
fd_set read_fds;
fd_set master;
nodo *root = NULL;
static int	read_cnt;
static char	*read_ptr;
static char	read_buf[MAXLINE];

static void *sendMensagem(void *arg);
void sigchld_handler(int s);
static void *sendALL(char msg[],int soks);
static void *sendMensagem(void *arg);
static void *newClientConnect(int arg);

void sigchld_handler(int s)
{
    while(waitpid(-1, NULL, WNOHANG) > 0);
}

void *sendALL(char msg[],int soks)
{
	nodo *aux = getFirst();
	while(aux != NULL)
	{
		int soc =aux->socket;

		if(soc != soks)
			{
	      	       		if(write(soc, msg, strlen(msg)) == -1)
		    			perror("send");
				printf("send %s %s\n",msg,aux->nick);

			}
		aux = aux->prox;
	}
}

void *sendMensagem(void *arg)
{
  char *buff;
  int fd = (*(int *) arg);
  int nbytes;
  char tmp[5000];

  printf("\nthread call %d",fd);
  newClientConnect(fd);
  printf("\n entry LOOP\n");
  nodo *cliente = busca(fd);

while(1)
{

     buff = (char *) calloc( MAXLINE,sizeof(char));
     if(FD_ISSET(fd,&#038;master))
     {
         nbytes = recv(fd,buff, MAXLINE -1 , 0);
	 if(nbytes > 1)
	 {

	   if(!tmp)
	   {
		perror("alocation:");
		exit(-1);
	   }
           strcat(tmp, cliente->nick);
	   strcat(tmp, " >> ");
	   strcat(tmp, buff);
           sendALL(tmp,fd);
	 }
	 else
	 {
	       if (nbytes == 0) {
                       printf ("servidor: socket %d desligado\n",  fd);
               } else {
                       perror ("recv");
               }
              close (fd); // BYE!!
              FD_CLR( fd , &#038;master);
	      removi(getFirst(),fd);
	      pthread_exit(NULL);
	  }

     }
     free(buff);

}

}

static void *newClientConnect(int arg)
{
	int fd = arg;
	pthread_t tid;
	struct sockaddr_in their_addr;
	char welcome[] = "Welcome Chat SistDistribuidos 0.1 \n";
	char msg1[] = "Login: ";
	char msg2[] = "NickName: ";
	char nome[100];
	char nick[100];
	int nbytes;
	socklen_t sin_size;

	pthread_mutex_lock (&#038;mutexLogin);

		printf("\naccept \n");
		if (write(fd, welcome, sizeof welcome - 1) != sizeof welcome - 1) {
	   		perror("write:");
			exit(1);
		}		

		printf("write %s \n",welcome);
		usleep(1000);

		if (write(fd, msg1, strlen(msg1)) != strlen(msg1)) {

	   		perror("write:");
			exit(1);
		}

		printf("write %s \n",msg1);
		usleep(1000);
		if ((nbytes = recv(fd, nome, 100,0)) < 0) {
		perror("read:");
	        exit(1);
	   	return;
		}
		nome[nbytes -1] = '\0';
		printf("Read %d %s\n",strlen(nome),nome);
		usleep(1000);
		if (write(fd, msg2, sizeof msg2 - 1) != sizeof msg2 - 1) {
	        	perror("write:");
	   	exit(1);
		}

		if ((nbytes =recv(fd, nick, 100,0)) < 0) {
	  	perror("read:");
		 exit(1);
		}
		nick[nbytes-1]='\0';
		printf("Read %d %s\n",strlen(nick),nick);		

		inseri(&#038;root,fd,nome,nick, inet_ntoa(their_addr.sin_addr));
		FD_SET(fd, &#038;master);		/* listen to this socket too */

	printf("end welcome \n");

	pthread_mutex_unlock (&#038;mutexLogin);

}

int main(void)
{
      // listen on sock_fd, new connection on new_fd
    int j,new_fd;
    struct timeval waitd;
    int nbytes;
    char buf[256];
    int fd_max; //numero maximo de descritores

    struct sockaddr_in my_addr;    // my address information
    struct sockaddr_in their_addr; // connector's address information
    socklen_t sin_size;
    struct sigaction sa;
    int yes=1;

    FD_ZERO(&#038;master);
    FD_ZERO(&#038;read_fds);

    pthread_mutex_init(&#038;mutexsum, NULL);
    pthread_mutex_init(&#038;mutexLogin,NULL);

    if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }

    if ( setsockopt ( sockfd , SOL_SOCKET , SO_REUSEADDR , &#038;yes , sizeof ( int ) ) == -1 )
    {
		perror ( " setsockopt " );
		exit ( 1 );
    }

    my_addr.sin_family = AF_INET;         // host byte order
    my_addr.sin_port = htons(MYPORT);     // short, network byte order
    my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
    memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero);

    if (bind(sockfd, (struct sockaddr *)&#038;my_addr, sizeof my_addr) == -1) {
        perror("bind");
        exit(1);
    }

    if (listen(sockfd, BACKLOG) == -1) {
        perror("listen");
        exit(1);
    }

    FD_SET(sockfd, &#038;master);

    fd_max = sockfd;	

    int rc =0;	 

    int i = 0;
    int ret;

    int fd;
      waitd.tv_sec = 1;
      waitd.tv_usec = 0;

     while(1)
     {  

        read_fds = master;
        if (select (fd_max+1,  &#038;read_fds, NULL, NULL, NULL)== -1) {
                perror ("select");
                exit(1);
        }

        int addrlen = sizeof (their_addr);
        if (( new_fd = accept(sockfd,(struct sockaddr *)&#038;their_addr,&#038;addrlen)) == -1)  {
            perror ("accept");
        } else {

            FD_SET ( new_fd , &#038;master);

            printf ("server : new connection %s socket %d\n",
                              inet_ntoa (their_addr.sin_addr),new_fd);

	    pthread_t tred;
	    rc = pthread_create( &#038;tred, NULL,sendMensagem, (void *) &#038;new_fd);
       	    if (rc){
        	printf("ERROR; return code from pthread_create() is %d\n", rc);
       		exit(-1);
            }

        }
      } 

pthread_mutex_destroy(&#038;mutexsum);
pthread_mutex_destroy(&#038;mutexLogin);

    return 0;
}
</pre>
<p>Header Double Linked List name ListaDDE.h</p>
<pre  name="code" class="C">
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define MAXBUFFER 2048

typedef struct cel
{
	int socket;
	char nome[50];
	char nick[50];
	char host[50];
	char buff[MAXBUFFER];
	struct cel *ante;
       	struct cel *prox;
}nodo;

nodo *getFirst();
nodo *getLast();
nodo *busca(int key);

void inseri(nodo **root, int socket,char nome[],char nick[],char host[]);

void removi(nodo *root, int socket);
void print (nodo *ini);
</pre>
<p>Implementation Double Linked List without use global variable</p>
<pre name="code" class="C">
#include <string.h>
#include <stdlib.h>
#include "listaDDE.h"

nodo *first = NULL, *last = NULL;

nodo *getFirst()
{
	printf("call getFirst()\n");
	return first;
}

nodo *getLast()
{
	return last;
}
void inseri(nodo **root, int socket, char nome[],char nick[],char host[])
{
	nodo *aux;
	//primeira inserção
	if(*root == NULL)
	{
		*root = (nodo *) malloc(sizeof (nodo));
		if(*root == NULL)
		{
			perror("erro de alocação\n");

		}
		(*root)->socket = socket;
		strcpy((*root)->nome , nome);
		strcpy((*root)->nick , nick);
	        strcpy((*root)->host , host);
		(*root)->prox = NULL;
		(*root)->ante = NULL;
		 first = (*root);
		last = first;

	}
	else
	{
		aux = (nodo *) malloc(sizeof (nodo));
		if(aux == NULL)
		{
			perror("erro de alocação\n");

		}
		aux->socket = socket;
		strcpy(aux->nome , nome);
		strcpy(aux->nick , nick);
	        strcpy(aux->host , host);

		aux->ante =last;
            	aux->prox = NULL;

                last->prox = aux;
            	last = aux;
		*root = last;
	}
}

void removi(nodo *primeiro,int dado)
{
   nodo *aux = primeiro;
   while(aux != NULL)
   {
       if(dado == aux->socket &#038;&#038; aux == first) //Remove first element
      {

	 if(aux->prox != NULL)
	 {
		printf("!= null\n");
		aux->prox->ante = NULL;
	        first = aux->prox;
	 }
	 else
	 {
		printf("null\n");
		free(first);

		break;
	 }

      }
      else if(dado == aux->socket &#038;&#038; aux->prox == NULL) //remove last
      {
      	 aux->ante->prox = NULL;
         last = aux->ante;
         free(aux);
         break;
      }
      else if(dado == aux->socket &#038;&#038;  aux->prox != NULL &#038;&#038; aux->ante !=NULL) //remove middle
      {
      	aux->ante->prox = aux->prox;
         aux->prox->ante = aux->ante;
         free(aux);
         break;
      }

      aux = aux->prox;
   }
}

void print (nodo *ini)
{
   nodo *p = first;
   while(p != NULL)
   {   printf ("socket %d cliente %s\n", p->socket,p->nome);
	p = p->prox;    

   }
}

nodo *busca (int key)
{
   nodo *p = getFirst();
   int flag = 0;
   while(p != NULL)
   {
   	if(p->socket == key)
	{
		return p;
	}
	p = p->prox;    

   }
   return NULL;
}
</pre>
<p>In order to compile this code together use the follow command  <strong>gcc -o chatserver server.c listaDDE.c -lpthread</strong><br />
Using  On the server<br />
 <strong>./chatserver </strong> </p>
<p>On the client <strong>telnet ipServer 5800 </strong> </p>
<p>Digg if you like it:<a href="http://digg.com/programming/Development_of_a_chat_with_the_C_sockets_and_Threads"> Development of a chat with the C sockets and Threads</a></p>
<p>UPDATE: This code is avaible in <a href="http://github.com/petryx/petryx.blogrs.com.br/tree/e5eeb098f5bf0f50e2fb9113a7f09b8ebd2e877e/sockets/C/chatC">http://github.com/petryx/</a> </p>
]]></content:encoded>
			<wfw:commentRss>http://petryx.blogrs.com.br/2008/06/28/c-chat-with-sockets-and-thread/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Ponteiros para Funções</title>
		<link>http://petryx.blogrs.com.br/2008/06/23/funcoes-para-ponteiros/</link>
		<comments>http://petryx.blogrs.com.br/2008/06/23/funcoes-para-ponteiros/#comments</comments>
		<pubDate>Tue, 24 Jun 2008 01:25:19 +0000</pubDate>
		<dc:creator>Marlon Petry</dc:creator>
				<category><![CDATA[C]]></category>
		<category><![CDATA[Sem categoria]]></category>
		<category><![CDATA[developer]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://petryx.blogrs.com.br/?p=54</guid>
		<description><![CDATA[Ponteiros para funções é algo extremamente interessante, eficiente e elegante. Pode ser usado para substituir switch-case, definir em tempo de execução qual função deve ser chamada ou implementar callbacks. Ponteiros para funções são na realidade ponteiros que apontam para o endereço de uma função. Uma função possui um endereço de memória. Quando o programa é [...]]]></description>
			<content:encoded><![CDATA[<p>Ponteiros para funções é algo extremamente interessante, eficiente e elegante. Pode ser usado para substituir switch-case, definir em tempo de execução qual função deve ser chamada ou implementar callbacks.</p>
<p>Ponteiros para funções são na realidade ponteiros que apontam para o endereço de uma função. Uma função possui um endereço de memória. Quando o programa é executado todo seu conteúdo é colocado na memória, então uma função é como um variável do tipo inteira, nada mais que um endereço de memória.</p>
<p>Então para demonstrar esse conceito, desenvolvi um código em C ANSI , que tem a função de uma calculadora de 4 operações, onde o usuário informa o primeiro valor, o operador + &#8211; * ou /, e o segundo valor, e o programa em tempo de execução escolhe a função a ser chamada.</p>
<p>Este pequeno exemplo de código mostra como é possível substituir o switch-case  e chamar funções em tempo de execução.</p>
<pre name="code" class="C">
#include <stdio.h>
#include <stdlib.h>

float adicao(float a, float b) {return a+b;};
float subtracao(float a, float b) {return a-b;};
float multiplicacao(float a, float b) {return a*b;};
float divisao(float a, float b) {return a/b;};

int main()
{
   float(*pt2Func[4])(float, float) = {NULL};
   float(*Func)(float, float) = NULL;

   pt2Func['+'] = &adicao;
   pt2Func['-'] = &subtracao;
   pt2Func['/'] = &divisao;
   pt2Func['*'] = &#038;multiplicacao;

   float a;
   float b;
   char operator;

    while(1)
    {
           printf("Informe a: ");
           scanf("%f",&#038;a);

           printf("\nInforme operador: ");
           scanf(" %c",&#038;operator);

           printf("\nInforme b: ");
           scanf(" %f",&#038;b);

           if(operator != '-' &#038;&#038; operator != '+' &#038;&#038; operator != '*' &#038;&#038; operator != '/' )
           {
                    printf("OperaÃ§Ã£o nÃ£o implementada");
                    exit(-1);
           }

           Func = pt2Func[operator];
           printf("\nResultado: %f\n", Func(a,b));
           printf("\nDeseja Continuar (y/n):");
           scanf(" %c",&#038;operator);

           if(operator == 'n' || operator == 'N')
             break;
           Func = NULL;

    }
    exit(0);
}
</pre>
<p><strong>Como funciona</strong></p>
<p>A partir da linha 3 até a linha 7 definimos as funções que irão realizar a adição, multiplicação, divisão e subtração note que todas as funções possuem o mesmo protótipo.</p>
<p>Na linha 11 declaramos um ponteiro array que também possui o mesmo protótipo das funções. Esse é uma detalhe importante. O nosso array de ponteiros tem 4 posições onde iremos informar o valor de cada posição e o endereço da função que é feito nas linhas 14,15,16 e 17. Definimos como posição os símbolos da operações matemáticas então quando o usuário escolher uma soma informa o símbolo <strong>+</strong> e o programa por sua vez aponta para a função desejada isso acontece na linha 40.</p>
<p>O restante do programa é um loop onde após cada cálculo é solicitado ao usuário se deseja continuar ou não.  </p>
<p>Este programa foi compilado com o gcc no linux.</p>
<p>Caso tenha dúvida sobre o funcionamento deixe um comentário.</p>
<p></p>
<p>Para saber mais: O <a href="http://afiliados.submarino.com.br/books_productdetails.asp?Query=ProductPage&#038;ProdTypeId=1&#038;ProdId=10418&#038;ST=SE&#038;franq=263686"><strong>livro C completo e Total</strong></a> é muito bom vale a pena ter esse livro na estante.</p>
<p>UPDATE: Este código está disponível no repositório git <a href="http://github.com/petryx/">http://github.com/petryx/</a></p>
<p></p>
]]></content:encoded>
			<wfw:commentRss>http://petryx.blogrs.com.br/2008/06/23/funcoes-para-ponteiros/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Segurança Linux Dicas básicas &#8211; Permissão Arquivos &#8211; parte 1</title>
		<link>http://petryx.blogrs.com.br/2008/05/18/seguranca-linux-dicas-basicas-permissao-arquivos-parte-1/</link>
		<comments>http://petryx.blogrs.com.br/2008/05/18/seguranca-linux-dicas-basicas-permissao-arquivos-parte-1/#comments</comments>
		<pubDate>Mon, 19 May 2008 01:48:24 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[C]]></category>
		<category><![CDATA[Dicas Linux]]></category>
		<category><![CDATA[Segurança]]></category>

		<guid isPermaLink="false">http://petryx.blogrs.com.br/?p=14</guid>
		<description><![CDATA[Tenho a intenção de fazer uma série de artigos sobre dicas básicas de segurança em Linux. Muitas coisas passam despercebidas, às vezes nos preocupamos com as regras do firewall, os serviços que estão rodando mas nos esquecemos do básico. Você já deve ter ouvido falar sobre SUID (Set User ID) Bit), SGID (Set Group ID). [...]]]></description>
			<content:encoded><![CDATA[<p>Tenho a intenção de fazer uma série de artigos sobre dicas básicas de segurança em Linux. Muitas coisas passam despercebidas, às vezes nos preocupamos com as regras do firewall, os serviços que estão rodando mas nos esquecemos do básico.</p>
<p>Você já deve ter ouvido falar sobre <strong>SUID (Set User ID) Bit), SGID (Set Group ID)</strong>. Mas  qual a função destes atributos especiais ?</p>
<p><strong>SUID</strong></p>
<p>Quando executamos um programa o sistema operacional aloca recursos baseado no usuário que está executando o processo. Quando o SUID bit, é setado por exemplo para o usuário &#8220;root&#8221;  o sistema irá permitir que um usuário comum execute funções não autorizadas. Muitos buffer overflow exploits são o resultado de programas SUID.</p>
<p>Arquivos com SUID: -rwsr-xr-x</p>
<p><strong>SGID</strong></p>
<p>Este atributo define as permissões para o grupo, funciona do mesmo modo que o SUID, mas a diferença é que as permissões tem efeito em diretórios. Então todos os arquivos e programas que estão dentro do diretório, quando executados ou editados por um usuário comum o sistema irá executar ou editar como se fosse o dono do arquivo.</p>
<p>Exemplo de exploit escrito em C</p>
<pre name="code" class="C">
#include &lt;unistd.h&gt;
#include &lt;stdio.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;stdlib.h&gt;

int main()
{
setgid(0); setuid(0);
execl("/bin/sh","sh",0);
}
</pre>
<p>Com este código acima com SUID habilitado é possível conseguir acesso de root.</p>
<pre name="code" class="bash">

root@localhost ~ # gcc -o exploit exploit.c
root@localhost ~ # chown root exploit
root@localhost ~ # chmod u+s exploit
root@localhost ~ # exit
marlon@localhost ~ $ ./exploit
sh-3.2# id
uid=0(root) gid=0(root) grupos=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
sh-3.2#
</pre>
<p><strong><br />
!!! Não me responsabilizo por uso indevido deste código, a divulgação é somente para conhecimento e  prevenção!!!</strong></p>
<p>Com o comando abaixo todos os programas com SUID e SGID são escritos no arquivo suidfile.txt</p>
<pre name="code" class="bash">
# /usr/bin/find / -type f \( -perm -004000 -o -perm -002000 \)  -exec ls -lg {} \; 2&gt;/dev/null &gt;suidfiles.txt
</pre>
<p>Executando o comando acima no gentoo retorna a seguinte lista.</p>
<pre name="code" class="bash">

#  less suidfiles.txt</code>

/bin/su
/bin/ping
/bin/mount
/bin/umount
/var/qmail/bin/qmail-queue
/usr/bin/chfn
/usr/bin/chsh
/usr/bin/crontab
/usr/bin/chage
/usr/bin/expiry
/usr/bin/sperl5.6.1
/usr/bin/newgrp
/usr/bin/passwd
/usr/bin/gpasswd
/usr/bin/procmail
/usr/bin/suidperl
/usr/lib/misc/pt_chown
/usr/sbin/unix_chkpwd
/usr/sbin/traceroute
/usr/sbin/pwdb_chkpwd
</pre>
<p>Para remover o SUID executa-se o comando chmod -s em cada arquivo.</p>
<p>Eu removi quase todos deixando somente o necessário: su, gpasswd, qmail-queue, unix_chkpwd, pwdb_chkpwd.</p>
<p>Se estiver usando X, a lista com certeza será maior pois necessita de acesso mais elevado.</p>
<p>Referências:</p>
<p>http://tldp.org/HOWTO/Security-HOWTO/file-security.html</p>
<p>http://www.gentoo.org/doc/pt_br/security/security-handbook.xml?part=1&amp;chap=6</p>
<p>http://www.homepage.montana.edu/~unixuser/051602/SUID.html</p>
<p>http://www.hoobie.net/security/exploits/index.html</p>
<p>Comentem, Incentivem !!!!!!!!!</p>
]]></content:encoded>
			<wfw:commentRss>http://petryx.blogrs.com.br/2008/05/18/seguranca-linux-dicas-basicas-permissao-arquivos-parte-1/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Transfêrencia de arquivos pela porta Serial em C</title>
		<link>http://petryx.blogrs.com.br/2008/05/17/transferencia-de-arquivos-pela-porta-serial-em-c/</link>
		<comments>http://petryx.blogrs.com.br/2008/05/17/transferencia-de-arquivos-pela-porta-serial-em-c/#comments</comments>
		<pubDate>Sun, 18 May 2008 01:26:17 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[C]]></category>

		<guid isPermaLink="false">http://petryx.blogrs.com.br/?p=12</guid>
		<description><![CDATA[Desenvolvi um protocolo de transferência de arquivos em C linux, utilizando a porta serial. Este protocolo tem as seguintes características: Cabeçalhos de Controle Controle de Següência; Controle de CRC 16 Bits; Caso o pacote chegue no receptor com erro de CRC é solicitado o reenvio do pacote; Mostra um barra de progresso sobre a transferência [...]]]></description>
			<content:encoded><![CDATA[<p>Desenvolvi um protocolo de transferência de arquivos em C linux, utilizando a porta serial. Este protocolo tem as seguintes características:</p>
<ul>
<li>Cabeçalhos de Controle</li>
<li>Controle de Següência;</li>
<li>Controle de CRC 16 Bits;</li>
<li>Caso o pacote chegue no receptor com erro de CRC é solicitado o reenvio do pacote;</li>
<li>Mostra um barra de progresso sobre a transferência de arquivo.</li>
</ul>
<p>Para compilar:<br />
<code><br />
gcc -o protocol protocol-1.2.5.c</p>
<p></code></p>
<p>Executar transmissor:</p>
<p><code>./protocol -d /dev/ttyS0 -t <arquivo><br />
</code></p>
<p>No receptor<br />
<code><br />
./protocol -d /dev/ttyS0 -r</code></p>
<p><a href='http://petryx.blogrs.com.br/wp-content/uploads/2008/05/protocol-15.c'>protocol-15>>>Código Fonte<< </a> </p>
<p>Desenvolvido por:<br />
Marlon Petry<br />
Gerson Tomas Schmitt</p>
]]></content:encoded>
			<wfw:commentRss>http://petryx.blogrs.com.br/2008/05/17/transferencia-de-arquivos-pela-porta-serial-em-c/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>HeapSort C</title>
		<link>http://petryx.blogrs.com.br/2008/05/17/heapsort-c/</link>
		<comments>http://petryx.blogrs.com.br/2008/05/17/heapsort-c/#comments</comments>
		<pubDate>Sun, 18 May 2008 01:14:58 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[C]]></category>
		<category><![CDATA[coding]]></category>

		<guid isPermaLink="false">http://petryx.blogrs.com.br/?p=10</guid>
		<description><![CDATA[Implementação do algortimo Heapsort, mostrando o pior caso, melhor caso e caso médio e o número de trocas. heapdebug2]]></description>
			<content:encoded><![CDATA[<p>Implementação do algortimo Heapsort, mostrando o pior caso, melhor caso e caso médio e o número de trocas.</p>
<p><a href="http://petryx.blogrs.com.br/wp-content/uploads/2008/05/heapdebug2.c">heapdebug2</a></p>
]]></content:encoded>
			<wfw:commentRss>http://petryx.blogrs.com.br/2008/05/17/heapsort-c/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Compactando arquivos com C</title>
		<link>http://petryx.blogrs.com.br/2008/05/17/compactando-arquivos-com-c/</link>
		<comments>http://petryx.blogrs.com.br/2008/05/17/compactando-arquivos-com-c/#comments</comments>
		<pubDate>Sun, 18 May 2008 01:06:44 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[C]]></category>

		<guid isPermaLink="false">http://petryx.blogrs.com.br/?p=9</guid>
		<description><![CDATA[O Algortimo de Huffman tem a função de comprimir arquivos baseados em caracteres, a compressão é feita através de uma árvore binária onde são adicionados os caracteres encontrados no texto, o caracter que mais aparecer no texto recebe o menor código e o que aparecer menos vezes recebe o código maior. Os códigos atribuídos a [...]]]></description>
			<content:encoded><![CDATA[<p>O Algortimo de Huffman tem a função de comprimir arquivos baseados em caracteres, a compressão é feita através  de uma árvore binária onde são adicionados os caracteres encontrados no texto, o caracter que mais aparecer no texto recebe o menor código e o que aparecer menos vezes recebe o código maior. Os códigos atribuídos a cada caracter numca podem passar de 1 byte.</p>
<p>Em anexo um exemplo do algoritmo de Huffman utilizando uma árvore binária estática.</p>
<p>Desenvolvido em Linux, gcc.  Dentro do arquivo mostra como compilar</p>
<p><a href="http://petryx.blogrs.com.br/wp-content/uploads/2008/05/huff_marlon.zip">huff_marlon</a></p>
]]></content:encoded>
			<wfw:commentRss>http://petryx.blogrs.com.br/2008/05/17/compactando-arquivos-com-c/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
