• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

magician

Desafio de Programação

Gostariam de mais desafios deste género?   35 membros votaram

  1. 1. Gostariam de mais desafios deste género?

    • Sim
      33
    • Não
      2

Please inicie sessão ou registe-se para votar.

27 mensagens neste tópico

Ora bem tenho aqui um pequeno desafio para quem quiser, quem quizer resolver está convidado a fazê-lo podem usar qualquer linguagem de programação basta apenas respeitar a restrições impostas no desafio :(

Tarefas :

    - Aceder à pagina http://feeds.feedburner.com/revistaprogramar_pdfs?format=xml usando apenas sockets e implementando o protocolo necessário.

    - Fazer a leitura do ficheiro e retirar os seguintes dados

        -> title

        -> link

        -> enclosure

    - A os dados devem ser apresentados pela consola com o seguinte formato :

        Titulo : X Edição - XXXX de 200X

        Link : http://www.portugal-a-programar.org/revista-programar/edicoes/....pdf

        URL : http://www.portugal-a-programar.org/revista-programar/edicoes/....pdf

        Tamanho : 2717712 bytes

        Tipo : application/pdf

Restrições :

    Não devem ser utilizadas bibliotecas de conexão HTTP, a ligação deve ser feita pelo método GET aplicado a sockets.

    No caso de linguagens WEB não devem ser usadas libs como CURL e afins.

Todas as linguagens que suportem Sockets por ser usadas.

Libs para leitura de XML como DOM ou SAX podem ser usadas mesmo sendo externas ao core da linguagem.

As resoluções devem ser postadas aqui e apresentadas com a ajuda do GeSHi.

Qualquer questão é só postar aqui ou mandar uma PM :)

Já agora aproveitem e votem na pool :)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Vais ter que o mostrar LOL

Eu já fiz o desafio em Java mas quero ver como se safam :(

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Vais ter que o mostrar LOL

Eu já fiz o desafio em Java mas quero ver como se safam :)

Pois vou, mas não vai ser ainda eheh. :(
0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

hehe porreiro. Até era menino para tentar fazer isto em Haskell. Tenho que ver que bibliotecas existem disponiveis para fazer a ligação.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Tenho que ver que bibliotecas existem disponiveis para fazer a ligação.

Só podes usar sockets.
0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Tenho que ver que bibliotecas existem disponiveis para fazer a ligação.

Só podes usar sockets.

Claro, claro. Mas é a primeira vez que estou a usar ligações externas em Haskell, tive que andar haver como é que era, ler documentação praticamente inexistente, etc. E ao fim de um par de horas já pus a ir buscar o xml. Hurray  :wallbash:

Bem agora vou dormir que já se faz tarde e amanhã vai ser um dia penoso /me olha para as horas.

Fica uma pergunta, qual é a diferença entre link e url a ser mostrado pela aplicação?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Está feito. A minha pergunta é se publico já o código ou espero que haja mais participações?

PS: O encoding de cedilhas e acentos no MSDos está fora do meu controlo, posso adaptar e converter caracteres acentuados, mas de qualquer forma fica já aqui o trabalho feito.

euzzlyygld.PNG

mk0des0hao.PNG

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Uma coisa magician, queres o output:

1º edicção

2º edição

3º edicaçõ

...

ou pode ser:

...

3º edicaçõ

2º edicção

1º edição

?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Também acabei o meu. Em C++. Sem bibliotecas externas, e com sockets do Linux.

progrevistayj1.png

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

526080it_works.png

Custou mas foi (e está tãaaaaaaaaaaaaaaaaaaaaaaaaaaaao dirty este código :x). :(

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Ainda bem que gostarem do desafio :( quando poder posto a minha solução em Java, já vi que temos soluções em C++, Python e até PHP :)

Se quiserem podem postar o código usem o GeSHi :)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
#!/usr/bin/python
# -*- coding: utf-8 -*-
##########################################
# XML Sockets Programar                  #
# by djthyrax                            #
#                                        #
#   blame all the dirty code in magician #
##########################################
# http://portugal-a-programar.org        #
# (O Triton é uma bicha)                 #
##########################################

import socket, sys
from xml.dom import minidom

class UrlParser: ## URL Parser
def __init__(self, parent, url):
	self.url = url
	self.parent = parent

def parse(self):
	try:
		protocol, resto = self.url.split("//", 1)

		if not protocol in self.parent.protocols:
			raise TypeError # Foi a primeira exception que me veio à cabeça...

		stuff = resto.split("/", 1)
		self.host = stuff[0]
		self.uri = "/"+stuff[1] # O URI começa sempre com /

		if not self.host:
			raise TypeError

		try: # encontrar fragmentos
			self.uri, self.fragment = self.uri.split("#", 1)
		except:
			pass
		return True
	except:
		return False

class Connection: ## Ligação
def __init__(self, host, port, connect, part):
	self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	self.host = host
	self.port = port
	self.part = part
	if connect:
		self.connect()

def connect(self):
	try:
		self.socket.connect((self.host, self.port)) # Connect it bitch!
		return True
	except:
		return False

def communicate(self, content):
	self.socket.send(content)
	self.buffer = []
	while True:
		tmp = self.socket.recv(4096)
		if self.part: # Dirty Hack para ter só os 2 headers que preciso :F
			if 'Content-Type' in ''.join(self.buffer) and 'Content-Length' in ''.join(self.buffer):
				break
		if not tmp:
			break
		self.buffer.append(tmp)
	self.socket.close()
	self.reply = ''.join(self.buffer)
	return self.reply


class HttpHeader: # Yay for classes!
def __init__(self, name, value):
	self.name = name
	self.value = value
	self.representation = "%s: %s" % (self.name, self.value) # É tão giro poupar no código ^_^

class HttpRequest: # Request
def __init__(self, parent, method, uri, part):
	self.headers = []
	self.method = method
	self.uri = uri
	self.conn = Connection(parent.url.host, 80, True, part) # abrir uma ligação

def setHeader(self, name, value):
	self.headers.append(HttpHeader(name, value))

def setHeaders(self, headers): # Yay for shortcuts 
	for name in headers:
		value = headers[name]
		self.setHeader(name, value)

def getHeaders(self):
	returns = ''
	for header in self.headers:
		returns += "%s\r\n" % (header.representation)
	return returns

def communicate(self):
	self.textToSend = ''
	self.textToSend += "%s %s HTTP/1.0\r\n" % (self.method, self.uri)
	self.textToSend += self.getHeaders()
	self.textToSend += "\r\n"
	self.reply = self.conn.communicate(self.textToSend) # Ouve-me cabra! 
	return self.reply


class Program:
def __init__(self, url, part):
	self.protocols = ["http:"] # É sempre bom prepararmo-nos para o futuro
	self.url = url
	self.part = part

def start(self):
	self.url = UrlParser(self, self.url) # Parsa o raio do URL
	if not self.url.parse(): # Something happen
		print "Ups. Aconteceu um erro."
		sys.exit(0)
	# Bora lá!
	self.request = HttpRequest(self, 'GET', self.url.uri, self.part) # Ligar
	self.request.setHeader('Host', self.url.host) # Passar pelos vHosts
	self.reply = self.request.communicate() # Comunicar
	if '\r\nLocation: ' in self.reply.split("\r\n\r\n")[0]: # Raios parta os redireccionamentos, só me fazem sujar o código...
		self.reply = self.reply.split("\r\n\r\n")[0]
		for header in self.reply.split("\r\n"):
			header = header.split(": ", 1)
			if header[0] == 'Location':
				if not "http:" in header[1]:
					self.reply = Program('/'.join(self.url.url.split("/")[0:-1])+'/'+header[1], True) # eheh.
					self.reply.start()
					self.reply = self.reply.reply

def parseXml(self):
	self.xml = self.reply.split("\r\n\r\n", 1)[1] # Nós queremos o body da resposta, os headers não interessam
	self.xml = minidom.parseString(self.xml) # Yay for DOM!
	self.edicoes = self.xml.getElementsByTagName("item")

def parseHeaders(self):
	self.headers = self.reply.split("\r\n\r\n", 1)[0] # Not body, headers. 
	self.headers = self.headers.split("\r\n") # Dividir os headers
	returns = { }
	for header in self.headers:
		header = header.split(": ", 1)
		if header[0] == 'Content-Type':
			returns['type'] = header[1]
		elif header[0] == 'Content-Length':
			returns['length'] = header[1]
	return returns

def showEdicoes(self):
	for edicao in self.edicoes:
		print u"Título: %s" % (edicao.childNodes[1].childNodes[0].data) # Nem imaginam as voltas que eu dei à pala do childNodes[0]...
		print "Link: %s" % (edicao.childNodes[5].childNodes[0].data)
		print "URL: %s" % (edicao.childNodes[5].childNodes[0].data)
		self.edicao = Program(edicao.childNodes[5].childNodes[0].data, True)
		self.edicao.start()
		details = self.edicao.parseHeaders()
		print "Tamanho: %s bytes" % (details["length"])
		print "Tipo: %s" % (details["type"])
		print


root = Program("http://feeds.feedburner.com/revistaprogramar_pdfs?format=xml", False) # woot. chain reactiong start. piriripum. *robot sound*
root.start()
root.parseXml()
root.showEdicoes()

# IT WORKS, GIVE ME COOKIES!

Sim, eu sei que está dirty. Mas como diz o rolando2424, "foi feito assim à pressa". :)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Após alteração de algumas coisitas, nomeadamente a criação da classe Enclosure e das funções auxiliares, aqui fica um código igualmente a dar para o feio:

#include <cstdio>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string>

const unsigned int BUFFSIZE = 1024;

class TDsocket {
int socketDescriptor;
struct sockaddr_in serverAddress;
struct hostent *hostInfo;

public:

void open(char *hostname, unsigned short int port) {

	hostInfo = gethostbyname(hostname);
	if (hostInfo == NULL) {
		printf("Problema ao obter host: %s\n", hostname);
		return;
	}

	socketDescriptor = socket(AF_INET, SOCK_STREAM, 0);
	if (socketDescriptor < 0) {
		printf("Impossível criar socket\n");
		return;
	}

	serverAddress.sin_family = hostInfo->h_addrtype;

	memcpy((char *) &serverAddress.sin_addr.s_addr,
			   hostInfo->h_addr_list[0], hostInfo->h_length);

	serverAddress.sin_port = htons(port);
	if (connect(socketDescriptor, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0)
		printf("Impossível ligar\n");

}

void get(char *req, std::string *xb) {

	if (::send(socketDescriptor, req, strlen(req)+1, 0) < 0) {
		printf("Erro ao enviar pedido GET\n");
		close(socketDescriptor);
		return;
	}

	char buff[bUFFSIZE];

	int r=0;

	sleep(2);
	do{
		memset(buff, 0x0, BUFFSIZE);
		r=recv(socketDescriptor, buff, BUFFSIZE-1, 0);
		xb->append(buff);
	} while (r == BUFFSIZE-1);

	close(socketDescriptor);
}
};

class Enclosure {
const std::string *orig;

void encFill(std::string::size_type &s2 /*start*/) {

	std::string::size_type
		s1 = orig->find("url=\"", s2),
		sz = 5;

	s2 = orig->find('"', s1+sz);

	if (s1 != std::string::npos && s2 != std::string::npos)
		url=orig->substr(s1+sz, s2-(s1+sz));

	s1 = orig->find("length=\"", s2),
	sz = 8;

	s2 = orig->find('"', s1+sz);

	if (s1 != std::string::npos && s2 != std::string::npos)
		length=orig->substr(s1+sz, s2-(s1+sz));

		s1 = orig->find("type=\"", s2),
		sz = 6;

	s2 = orig->find('"', s1+sz);

	if (s1 != std::string::npos && s2 != std::string::npos)
		type=orig->substr(s1+sz, s2-(s1+sz));
}

public:
std::string url, length, type;

Enclosure(std::string *_orig, std::string::size_type _pos): orig(_orig) {
	encFill(_pos);
}
};

bool getTagContent(const std::string &fullstring, const std::string &tag, std::string::size_type &start, std::string &content) {

std::string fulltag("<"), fullendtag("</");
fulltag.append(tag + ">");
fullendtag.append(tag + ">");

content.clear();

std::string::size_type
	s1 = fullstring.find(fulltag, start),
	sz = fulltag.length();

start = fullstring.find(fullendtag, s1);

if (s1 == std::string::npos || start == std::string::npos)
	return false;

content=fullstring.substr(s1+sz, start-(s1+sz));

return true;
}

int main(int argc, char **argv) {

std::string xmlbuffer;
xmlbuffer.clear();

TDsocket tds;
tds.open("feeds.feedburner.com", 80);
char *req = "GET /revistaprogramar_pdfs?format=xml HTTP/1.1\n"
			"Host: feeds.feedburner.com\n\n";

tds.get(req, &xmlbuffer);

std::string::size_type s2=0;

printf("----------------------------------\n");

s2 = xmlbuffer.find("<item>", 0);
std::string tagct;
tagct.clear();

while (true) {

	if (getTagContent(xmlbuffer, "title", s2, tagct) == false)
		break;
	printf("Titulo : %s\n", tagct.c_str());

	if (getTagContent(xmlbuffer, "link", s2, tagct) == false)
		break;
	printf("Link : %s\n", tagct.c_str());

	s2 = xmlbuffer.find("<enclosure ", s2);

	Enclosure enclosure(&xmlbuffer, s2);

	printf("URL : %s\nTamanho : %s\nTipo : %s\n",
		enclosure.url.c_str(), enclosure.length.c_str(), enclosure.type.c_str());

	printf("----------------------------------\n");

}

return 0;
}

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Não acabei o script como queria porque tenho alguns trabalhos mais importantes a fazer por isso fica aqui o que fiz...

capturaecra1ng4.th.png

<?php

$feed = new FeedGet();
$feed->display();

class FeedGet {

var $feedurl = 'http://feeds.feedburner.com/revistaprogramar_pdfs?format=xml';
var $parsedXML = null;

function FeedGet( $feedurl = null, $show = array( 'link', 'size', 'title', 'type' ) ) {

	if(!empty( $feedurl )) {
		$this->feedurl = $feedurl;
	}

	$data = $this->getData();

	$this->parseXML( $data, $show );
}

function getData() {

	$data = file_get_contents( $this->feedurl );

	return $data;
}

function parseXML( $data, $show ) {

	$exp1 = explode( '<item>', $data );
	$parsed = array();
	$x = 0;

	foreach( $exp1 as $items ) {
		$exp = explode( '</item>', $items );

		$item = $exp[0];

		foreach( $show as $value ) {

			if($value == 'link' || $value == 'url' || $link = 'title' ) {

				if(preg_match( '/<('. $value .')>(.*)<\/'. $value .'>/i', $item, $match )) {

					$parsed[$x][$match[1]] = $match[2];
				}
			}

			if(preg_match( '/<enclosure(.*)length="(.*)"\s+type="(.*)"\s*\/>/i', $item, $match )) {

				if($value == 'type' && !empty( $match[3] )) {
					$parsed[$x][$value] = $match[3];
				}

				if($value == 'size' && !empty( $match[2] )) {
					$parsed[$x][$value] = $match[2];
				}
			}
		}
		$x++;
	}

	$this->parsedXML = $parsed;
}

function display() {

	if(is_null( $this->parsedXML )) {
		return false;
	}

	foreach( $this->parsedXML as $xml ) {
		$display[] = 'Titulo: '. $xml['title'] ."\r\nLink: ". $xml['link'] ."\r\nSize: ". $xml['size'] ."\r\nType: ". $xml['type']."\r\n";
	}

	echo implode( str_repeat( '-', 30 )."\r\n", $display );
}
}

?>

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

estou de férias quando tiver oportunidade envio o código.

Mas vai provar que com php se consegue fazer coisas mais simples com menos código :(

Cumprimentos

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Welele!!! Demorou mas aqui está  :(

rssgetterer7.th.jpg

Sim o DOS é rabeta...

Aqui fica o código.

import Prelude hiding (catch)
import Network (connectTo, withSocketsDo, PortID(..))
import System.IO
import System.IO.Error (isEOFError)
import Control.Exception (finally, catch, Exception(..))
import Text.XML.HXT.Arrow


main = withSocketsDo $ do
sock <- connectTo "feeds.feedburner.com" $ PortNumber 80
start sock `catch` procErro `finally` hClose sock
	where
	procErro (IOException e) | isEOFError e = return ()
	procErro e = print e

start h = do 
hSetBuffering h LineBuffering
hPutStr h "GET /revistaprogramar_pdfs?format=xml HTTP/1.0\r\n"
hPutStr h "Host: feeds.feedburner.com\r\n\r\n"
xml <- hGetContents h >>= return . dropWhile ('<'/=)
runX (filtraXML xml) >> return ()

filtraXML xml = 
readString [(a_validate, v_no)] xml	>>>
processChildren ( getChildren3 >>> processItems ) >>>
writeDocument [(a_no_xml_pi, v_1)] "-" >>>
getErrStatus

getChildren3 = getChildren >>> getChildren 

processItems = deep $ 
mudaTexto "title" "\n\nTitulo: " <+>
mudaTexto "link" "Link: " <+>
buscaAttributo "enclosure" "url" "URL: " <+>
buscaAttributo "enclosure" "length" "Tamanho: " <+>
buscaAttributo "enclosure" "type" "Tipo: " 

mudaTexto nome header = 
getChildren >>>
isElem >>> hasName nome >>> getChildren >>> 
getText >>> arr (\s -> header ++ s ++ "\n") >>> mkText

buscaAttributo nomeElem nomeAtrib header = 
getChildren >>>
isElem >>> hasName nomeElem >>>
getAttrValue nomeAtrib >>>
arr (\s -> header ++ s ++ "\n") >>>
mkText

Não é a melhor solução, já que estou apenas a transformar o XML. Para ser melhor era usar as Monads do Xml e do IO juntas e fazer os prints à mao. Mas prontos assim também serve...

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Mais importante que um desafio do P@P?? :shocking:

::P

talvez  :(

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Uma solução em Haskell ora ai está uma coisa que não esperava ver LOL

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Bem como não tinha mais nada para fazer (e enquanto não sai mais nenhum desafio), aproveitei para melhorar o aspecto do código original que não curtia nada. Ou seja, o facto de estar a transformar o XML em vez de propriamente obter os dados numa primeira fase e processa-los numa fase seguinte, neste caso imprimir para o ecrã...

{-# LANGUAGE Arrows #-}
import Prelude hiding (catch)
import Network (connectTo, withSocketsDo, PortID(..))
import System.IO
import System.IO.Error (isEOFError)
import Control.Exception (finally, catch, Exception(..))
import Text.XML.HXT.Arrow

data Item = Item { titulo, link, url, tamanho, tipo :: String }

main = withSocketsDo $ do
sock <- connectTo "feeds.feedburner.com" $ PortNumber 80
start sock `catch` procErro `finally` hClose sock
	where
	procErro (IOException e) | isEOFError e = return ()
	procErro e = print e

start h = do 
hSetBuffering h LineBuffering
hPutStr h "GET /revistaprogramar_pdfs?format=xml HTTP/1.0\r\n"
hPutStr h "Host: feeds.feedburner.com\r\n\r\n"
xml <- hGetContents h >>= return . dropWhile ('<'/=)
itens <- runX ( readString [(a_validate, v_no)] xml >>> getElem "item" >>> mkItem)
mapM_ printItem itens

printItem i = 
putStr "Titulo: " >> putStrLn (titulo i) >>
putStr "Link: " >> putStrLn (link i) >>
putStr "URL: " >> putStrLn (url i) >>
putStr "Tamanho: " >> putStrLn (tamanho i) >>
putStr "Tipo: " >> putStrLn (tipo i) >>
putStrLn "" >> putStrLn ""

getElem s = deep (isElem >>> hasName s)

getTexto = getChildren >>> getText

mkItem = proc i -> do
title <- getTexto <<< getElem "title" -< i
link <- getTexto <<< getElem "link" -< i
url <- getAttrValue "url" <<< getElem "enclosure" -< i
len <- getAttrValue "length" <<< getElem "enclosure" -< i
typ <- getAttrValue "type" <<< getElem "enclosure" -< i
returnA -<  Item title link url len typ

Assim fica mais legível para além de permitir muito mais facilmente expandir o código com novas funcionalidades para futuras versões, que não irão haver... B)

Hehe reparei agora que este pequeno pedaço gera um binário de 7 megas B)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Boas...

Obrigado pelo desafio... veio mesmo a calhar, comecei à uns dias a aprender Ruby e precisava de algo pra praticar  ;)

Aqui vai o que saiu:

###
# Desafio de Programacao
# Ruby language
# ic <ivandscastro@gmail.com>
###

require 'socket'
require 'rexml/document'

include Socket::Constants

HOST = 'feeds.feedburner.com'
GET = "GET /revistaprogramar_pdfs?format=xml HTTP/1.0\n\n\n"

class Magazine
def initialize(d)
	@title = d.elements["title"].text
	@link = d.elements["link"].text
	if d.elements['enclosure']
		@url = d.elements["enclosure"].attributes["url"]
		@length = d.elements["enclosure"].attributes["length"]
		@type = d.elements["enclosure"].attributes["type"]
	else
		sock = Socket.new(AF_INET,SOCK_STREAM,0)
		saddr = Socket.pack_sockaddr_in(80,gethost)
		sock.connect(saddr)

		@url = @link

		@type = @length = nil

		sock.write("GET #{@link} HTTP/1.0\n\n\n")
		sock.each_line do |line|
			if line =~ /^Content-Length:.*/
				@length = line.split[1]
				break if @length and @type
			elsif line =~ /^Content-Type:.*/
				@type = line.split[1]
				break if @length and @type
			end
		end
		sock.close
	end
end
def gethost
	if t = @link.index("//")
		tmp = @link[t+2..@link.length]
	else
		tmp = @link
	end	
	return tmp[0..tmp.index("/")-1]
end
def print
	puts "Titulo: #@title\nLink: #@link\nURL: #@url\nTamanho: #@length bytes\nTipo: #@type\n\n"
end
end

class List
def initialize
	@count = 0
	@list = []
end
def add(d)
	@list.push Magazine.new(d)
	++@count
end
def show
	@list.each { |i| i.print }
end
end

s = Socket.new(AF_INET,SOCK_STREAM,0)
sa = Socket.pack_sockaddr_in(80,HOST)
s.connect(sa)

s.write(GET)

doc = REXML::Document.new(s.read)

s.close

r = List.new

doc.root.elements.each("channel/item") { |i| r.add(i) }

r.show

Inte  :cheesygrin:

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!


Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.


Entrar Agora