Paulo Collares

Meu blog pessoal. Tem de tudo um pouco…

  • Exibindo os mapas do Google Earth e Maps com Java

    O Google libera o acesso de sua API do Google Maps para desenvolvedores usarem em suas aplicações, neste tutorial, passarei brevemente como acessar e exibir os mapas em um frame no Java. API do Google Maps Primeiramente você deve criar uma chave para acesso do seu aplicativo no painel do desenvolvedor do Google, clique aqui, [...]

  • Tocador de vinhetas em Java

    Tocador de Vinhetas que permite reproduzir arquivos de áudio de forma simples e rápida. Download Faça download do arquivo aqui Como usar Para adicionar uma nova vinheta, acesse o menu Editar > Adicionar Vinheta… Para adicionar vinhetas de exemplo, acesse o menu Editar > Adicionar Vinhetas de Exemplo Para editar ou excluir uma vinheta, clique com o botão [...]

  • Livro Jogador N°1 – Resenha e Opinião

    Hoje ser Nerd esta na moda, o lado negativo disso é que há pessoas que forçam de tal forma que fica ridículo, mas em compensação, temos os pequenos prazeres de ler um livo como esse, que foi feito na medida para nós. Cinco estranhos e uma coisa em comum: a caça ao tesouro. Achar as [...]

  • Como escrever seu nome na luz (fotografia de longa exposição ou “light painting”)

    Com uma câmera simples, e um ambiente escuro, é possível criar efeitos muitos legais apenas com luz! Vi essa dica no Manual do Mundo, e resolvi experimentar. A ideia é simples, basta fotografar como o minimo de luz possível, com o maior tempo de abertura na câmera, para isso configure sua máquina fotográfica no manual, [...]

  • Sistema simples de Livro Caixa (Gerenciador Financeiro) em PHP

      Fiz esse gerenciador para controlar minhas finanças pessoais, é um sistema simples, mas bem prático e funcional. Versão atual: 1.1 Funcionalidades Navegação por mês Balanço Geral Categorias de movimentos Entradas e saídas do mês Movimentos detalhados por mês Autenticação Requisitos PHP 5 Mysql Instalação Baixe o arquivo e descompacte no diretório do seu servidor [...]


Por Paulo Collares Em 16/maio/2013 Nenhum comentário
Mutação Dirigida Adaptável para Algoritmos Genéticos com Representação Real

Mutação Dirigida Adaptável para Algoritmos Genéticos com Representação Real

Resumo do artigo “Adaptive directed mutation for real-coded genetic algorithms” apresentado na aula de Algorítimos Genéticos na COPPE/UFRJ.

Título: Adaptive directed mutation for real-coded genetic algorithms
Autores: Ping-Hung Tanga, Ming-Hseng Tseng (School of Medical Informatics, Chung-Shan Medical University, Taiwan, ROC e Information Technology Office, Chung Shan Medical University Hospital, Taiwan, ROC)
Link: www.sciencedirect.com/science/article/pii/S1568494612003845

Abstract

Adaptive directed mutation (ADM) operator, a novel, simple, and efficient real-coded genetic algorithm (RCGA) is proposed and then employed to solve complex function optimization problems. The suggested ADM operator enhances the abilities of GAs in searching global optima as well as in speeding convergence by integrating the local directional search strategy and the adaptive random search strategies. Using 41 benchmark global optimization test functions, the performance of the new algorithm is compared with five conventional mutation operators and then with six genetic algorithms (GAs) reported in literature. Results indicate that the proposed ADM-RCGA is fast, accurate, and reliable, and outperforms all the other GAs considered in the present study.

Resumo

Algoritmos genéticos tem sido usado para encontrar soluções reais com técnicas de otimização estudadas ao longo dos anos, tradicionalmente as implementações de AG usam representações binárias, que contém desempenho satisfatórios em soluções pequenas, que requerem pouca precisão, mas conforme esse problema aumenta também aumenta a demanda por um esforço computacional maior. Por isso a representação real tem sido amplamente usada para a elaboração de problemas maiores e mais complexos.

Independente da representação, os AG podem apresentar problemas de convergência prematura, e soluções tem sido relatadas na literatura. Dos operadores clássicos, a mutação é utilizada para prover a diversidade da população, gerando novos indivíduos aleatórios no espaço de busca, na tentativa de achar potenciais soluções, algumas técnicas de mutação clássica para representação com número real são: a mutação uniforme, a mutação gaussiana, a mutação não-uniforme, a mutação aleatória, a mutação polinomial, dentre outras.

Porém, pouco esforço tem sido feito com objetivo de melhorar a eficiência da mutação, o autor afirma que a distância e a direção são as principais características da melhora de performance. Este é o objetivo deste trabalho, apresentar uma nova solução, simples e eficiente para problemas com representação real baseado no Adaptive Directed Mutation (ADM), operador onde a performance é demostrada em funções de otimização de problemas complexos e comparados com outros operadores de mutação encontrados na literatura.

O principal objetivo do ADM é criar um operador que evite a possível concentração da população em um ótimo local, causado pelo crossover, e a busca não sistemática causada pela mutação aleatória.

O novo ponto de busca é dirigido pela solução baseada na aptidão de 3 gerações consecutivas, é gerada também uma probabilidade adaptável de mutação, Pm, que faz com que os piores cromossomos tenham mais chances de sofrerem a mutação.

Neste estudo foi proposto quatro estratégias de mutação baseada em nove tendências evolucionarias de um cromossomo, são elas: Mutação direcional em pequena escala, Mutação aleatória em pequena escala, mutação aleatória em média escala, e mutação aleatória em larga escala.

O algoritmo consegue identificar se a população está convergindo para um ponto de ótimo, neste caso é aplicado uma mutação direcional para aumentar e agilizar as chances de se encontrar boa solução. Caso a população esteja totalmente convergida em um ótimo, é aplicado uma mutação aleatória maior, para explorar o espaço de busca e evitar um convergência prematura, e o risco de estacionar em um ótimo local.

É possível identificar também, se a população passou por um ótimo, sem convergir, neste caso uma pequena mutação direcional, pode auxiliar a convergir neste ótimo.

Há casos em que a população converge por várias gerações em uma planície, neste caso o valor de aptidão não se altera muito, neste caso, o autor recomenda uma mutação aleatória em larga escala, para tentar retirar a solução desse linha.

Foi proposto também neste estudo, o teste deste operador com 41 funções de benchmark conhecidas, tanto de maximização quanto de minimização. Foram utilizados vários operadores de mutação da literatura, nos mesmos contextos e nas mesmas condições de teste.

Em comparação com os operadores de mutação testados (mutação aleatória, mutação polinomial, mutação não-uniforme e mutação não-uniforme múltipla) o ADM obteve melhorias significantes ao encontrar soluções de ótimos globais. Também foram feitos testes com outros algoritmos que propõem uma mutação adaptável, o CMA-ES e o HKY-GA, o ADM-RCGA também obteve resultados superiores a estes.

Slide


Por Paulo Collares Em 10/maio/2013 Nenhum comentário

MPI é a sigla para Message Passing Interface, um padrão de comunicação de dados para computação paralela. Você pode programar e dividir o processamento em vários processadores para otmizar o desempenho. É utilizado em computação de alto desempenho em supercomputadores espalhados pelo mundo.

O Top500 mantém uma lista dos maiores supercomputadores do mundo, atualmente o número 1 é o Titan da Cray com 560.640 cores de processamento.

Super computador Titan - Cray com 560.640 cores de processamento.

Super computador Titan – Cray com 560.640 cores de processamento.

Há implementações para C/C++ e Fortran, e para Java também, mas não tão usada. Neste exemplo usarei o OpenMPI em C.

Felizmente não é necessário um super computador para usar o MPI, você pode usar seu computador de casa para isso, se tiver vários núcleos melhor, mas ele simula caso não tenha, claro que ão terá o desenpenho esperado, mas para fim de teste é suficiente.

Instalação

Para os teste usei uma máquina com Debian 6.

Instale os módulos do OpenMPI, e as bibliotecas de compilação do C.

#apt-get install gcc g++ openmpi-bin openmpi-doc libopenmpi-dev

Para testar você pode enviar um echo para o MPI:

mpirun -np 4 echo oi

A saída será:

oi
oi
oi
oi

O comando mpirun enviou para 4 processos o comando ‘echo oi’ e cada um escreveu ‘oi’ na saida.

Código

Exemplo 1

Escreve na tela para cada processo um ola mundo!

#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>

int size, rank;
int main(int argc, char *argv[]){
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD,&size);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);

printf("Olá eu sou o processo %d de %d\n",rank,size);

MPI_Finalize();
}

Salve este arquivo com o nome de olamundo.c por exemplo, compile com o MPI:

mpicc olamundo.c -o olamundo

e execute:

mpirun -np 5 olamundo

a saída será

Olá eu sou o processo 3 de 5
Olá eu sou o processo 4 de 5
Olá eu sou o processo 0 de 5
Olá eu sou o processo 1 de 5
Olá eu sou o processo 2 de 5

Exemplo 2

O primeiro processo envia uma mensagem ponto a ponto para os restantes

#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>

int size, rank, msg, source, dest, tag;
 
int main(int argc, char *argv[]){
   MPI_Status stat;
 
   MPI_Init(&argc,&argv);
   MPI_Comm_size(MPI_COMM_WORLD,&size);
   MPI_Comm_rank(MPI_COMM_WORLD,&rank);
 
	if(rank==0){
   	msg = 42; dest = 1; tag = 0;
	
	int i;
	for (i=1;i<size;i++){
	   	MPI_Send(&msg, 1, MPI_INT, i, tag, MPI_COMM_WORLD);
	   	printf("Processo %d enviou %d para %d.\n", rank, msg, i);
	}	
	}
 
	if(rank!=0){
		source = 0; tag = 0;
		MPI_Recv(&msg, 1, MPI_INT, source, tag, MPI_COMM_WORLD, &stat);
		printf("Processo %d recebeu %d de %d.\n", rank, msg, source);
	}
 
   MPI_Finalize();
}

Salve, compile e execute como o exemplo acima, a saída com 3 processos será:

Processo 0 enviou 42 para 1.
Processo 0 enviou 42 para 2.
Processo 2 recebeu 42 de 0.
Processo 1 recebeu 42 de 0.

Exemplo 3

Neste exemplo o primeiro processo envia uma mensagem em broadcast para os restantes, o resultado será o mesmo do exemplo 2

#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>

int size, rank, msg, source, dest, tag;
 
int main(int argc, char *argv[]){
   MPI_Status stat;
 
   MPI_Init(&argc,&argv);
   MPI_Comm_size(MPI_COMM_WORLD,&size);
   MPI_Comm_rank(MPI_COMM_WORLD,&rank);
 
	if(rank==0){
   	msg = 42; dest = 1; tag = 0;	
		MPI_Bcast (&msg, 1, MPI_INT, 0, MPI_COMM_WORLD);	
	}else{
		MPI_Bcast (&msg, 1, MPI_INT, 0, MPI_COMM_WORLD);
		printf("%d recebeu a mensagem %d\n",rank,msg);
	}
   MPI_Finalize();
}

Salve, compile e execute como o exemplo 1, a saída com 3 processos será:

1 recebeu a mensagem 42
2 recebeu a mensagem 42

Conclusão

Este é o basico do MPI, espero que sirva como um pontapé inicial para quem estiver interessado em aprender mais, tentarei colocar mais exemplos em breve

[]s

Categorias: C/C++, Linux, Programação
Tags: , ,

Por Paulo Collares Em 10/maio/2013 Nenhum comentário
Imprimir um arquivo de texto em PDF pelo terminal no Linux

Imprimir um arquivo de texto em PDF pelo terminal no Linux

Este tutorial mostra como imprimir em PDF arquivos de texto pelo terminal no Linux, util para imprimir códigos fontes por exemplo, foi o meu caso XD

Primeiramente instalamos o pacote de PDF para o cups:

#apt-get install cups-pdf

Então é só passar este comando, onde file é o arquivo que você deseja imprimir

$lp -d PDF -o scaling=75 -o media=A4 file

O PDF será salvo em /home/usuario/PDF/

Mais opções no próprio cups: http://localhost:631/help/options.html

[]s

Categorias: Linux
Tags:

Por Paulo Collares Em 30/abril/2013 Nenhum comentário

O Google libera o acesso de sua API do Google Maps para desenvolvedores usarem em suas aplicações, neste tutorial, passarei brevemente como acessar e exibir os mapas em um frame no Java.

API do Google Maps

Primeiramente você deve criar uma chave para acesso do seu aplicativo no painel do desenvolvedor do Google, clique aqui, e crie uma para você.

Atenção, a requisição NÃO irá funcionar sem a chave correta.

Nosso aceso será por requisições GET de imagens, abaixo um exemplo de URL:

http://maps.googleapis.com/maps/api/staticmap?center=-22.8634,-43.1792&amp;zoom=12&amp;size=640x640&amp;maptype=satellite&amp;key=sua_chave&amp;sensor=false&amp;format=jpg

Código Java

Crie um BufferedImage e por meio de uma conexão HTTP é possível acessar a imagem no modelo da url acima:

String chave = "sua_chave";

String endereco = "http://maps.googleapis.com/maps/api/staticmap?center=-22.8634,-43.1792&amp;zoom=" + zoom + "&amp;size=640x640&amp;maptype=" + tipo + "&amp;key="+chave+"&amp;sensor=false&amp;format=jpg";

URL url = new URL(endereco);

HttpURLConnection con = (HttpURLConnection) url.openConnection();
BufferedImage img img = ImageIO.read(con.getInputStream());

Com isso é possível exibir em um Label por exemplo

ImageIcon mapa = new ImageIcon(img);
jLabel.setIcon(mapa);

Projeto Completo

Este é um exemplo básico de implementação, clique aqui e baixe o projeto inteiro, que contém zoom e acesso a várias camadas.

Veja mais exemplos na documentação oficial: developers.google.com/maps/documentation/staticmaps/

Espero que tenha sido útil, poste nos comentários dúvidas e sugestões.

Mais imagens

Terreno

Terreno

Híbrido

Híbrido

Ruas

Ruas

Satélite

Satélite

[]s


Por Paulo Collares Em 30/janeiro/2013 Nenhum comentário
Java Native Interfac

Java Native Interfac

Java Native Interface (JNI) é um padrão para escrever métodos nativos em Java. Neste exemplo mostro como chamar um método no Java, escrito em C.

Neste exemplo mostro como chamar um método que escreve “Olá Mundo” implementado no C e chamado na Java.

Utilizei o Linux, com o Debian para este exemplo.

Criando a classe em Java

Primeiramente vamos criar a classe em Java: HelloWorld.java

class HelloWorld {
     private native void print();
     public static void main(String[] args) {
         new HelloWorld().print();
     }
     static {
         System.loadLibrary("HelloWorld");
     }
 }

Compilando a Classe

Use normalmente o javac para compilar a classe HelloWorld

javac HelloWorld.java

Este comando irá gerar o arquivo HelloWorld.class no mesmo diretório

Gerando o Arquivo de Cabeçalho do método nativo

Aqui usamos o javah para gerar o cabeçalho que será usado em nossa classe em C

javah -jni HelloWorld

Ira gerá o arquivo HelloWorld.h no mesmo diretório. A parte mais importante deste arquivo, é o protótipo de função Java_HelloWorld_print, que indica a função que implementa o método HelloWorld().print();

JNIEXPORT void JNICALL
Java_HelloWorld_print (JNIEnv *, jobject);

Escrevendo a implementação nativa

Crie um arquivo HelloWorld.c:

 #include 
 #include 
 #include "HelloWorld.h"

 JNIEXPORT void JNICALL 
 Java_HelloWorld_print(JNIEnv *env, jobject obj)
 {
     printf("Olá Mundo\n");
     return;
 }

A função que você implementa está no padrão do arquivo de cabeçalho gerado Java_HelloWorld_print

Compilando o Código em C e criando uma bibliteca nativa

Em nossa classe em Java é chamada a biblioteca System.loadLibrary(“HelloWorld”); geramos ela a partir da implementação em C.

Considerando que sua JDK está instalada em /opt/jdk1.6.0_31/, rode este comando:

gcc -shared -fpic -o libHelloWorld.so -I/opt/jdk1.6.0_31/include -I/opt/jdk1.6.0_31/include/linux HelloWorld.c

Ele irá gerar um arquivo libHelloWorld.so no mesmo diretório, copie para a pasta de bibliotecas do JDK:

sudo cp libHelloWorld.so /opt/jdk1.6.0_31/jre/lib/amd64/

Agora execute normalmente a classe em Java:

java HelloWorld

Se tudo der certo, aparecerá na tela: “Olá Mundo”.

Parabens, você fez sua primeira aplicação com JNI.

Fiquem na Paz

Fontes

http://192.9.162.55/docs/books/jni/html/start.html
https://blogs.oracle.com/moonocean/entry/a_simple_example_of_jni
http://patriot.net/~tvalesky/jninative.html

Categorias: C/C++, Java, Programação
Tags:

Por Paulo Collares Em 25/janeiro/2013 4 comentários
Tocador de Vinhetas em Java

Tocador de Vinhetas em Java

Tocador de Vinhetas que permite reproduzir arquivos de áudio de forma simples e rápida.

Download

Faça download do arquivo aqui

Como usar

  • Para adicionar uma nova vinheta, acesse o menu Editar > Adicionar Vinheta…
  • Para adicionar vinhetas de exemplo, acesse o menu Editar > Adicionar Vinhetas de Exemplo
  • Para editar ou excluir uma vinheta, clique com o botão direito na vinheta
Tocador de Vinhetas (Editando uma Vinheta)

Tocador de Vinhetas (Editando uma Vinheta)

Código fonte

Disponibilizei também o código fonte para que quiser usar e aprimorar, baixe aqui

Melhorias Futuras

  • Aceitar arquivos em mp3, hoje aceita apenas wav
  • Número de slots de vinhetas flexível, hoje apenas 40
  • Opção de salvar personalizado, hoje salva um .properties automaticamente

 

 

Categorias: Destaque, Java, Programação
Tags:

Por Paulo Collares Em 14/janeiro/2013 2 comentários

Nesta postagem vou mostrar como criar uma simples extensão para o Google Chrome, um botão que quando clicado abra uma pequena janela em HTML.

Primeiro vamos crar uma pasta chamada minha_primeira_extensao, e debtro dela um arquivo com o nome manifest.json, nele ficará as configurações de nossa extensão.

Cole o seguinte código neste arquivo:

{
"name": "Minha Primeira Extensão",
"version": "1.0",
"description": "Descrição da Minha Primeira Extensão",
"manifest_version": 2,
"browser_action":{
"default_icon": "icone.png",
"default_popup": "popup.html"
}
}

Explicando os elementos:

name – Nome de Exibição da sua extensão

version – Versão da sua extensão

description – Descrição

manifest_version – Versão do manifest, não altere

browser_action – Ação que será execudada no navegador

default_icon – Icone que irá aparecer no navegador

default_popup – Arquivo HTML que abrirá al clicarmos no ícone

 

Crie ou baixe uma imagem para ser seu ícone, no tamanho de 16 x 16px e salve nesta mesma pasta com o nome icone.png

Crie um arquivo chamado popup.html e também salve nesta pasta, cole o seguinte conteúdo:

<!--?xml version="1.0" encoding="UTF-8" ?--><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />Minha Primeira Extensão

Olá Mundo!

 

Diretório com os arquivos da extensão

Diretório com os arquivos da extensão

Instalando e compartilhando

Acesse o menu de ferramentas e depois extensões, ative o ‘Modo desenvolvedor’ e clique em ‘Carregar extensão expandida…’ navegue até a pasta criada e clique em ‘Abrir’.

Carregando a Extensão

Carregando a Extensão

Pronto sua extensão já esta carregada e pode ser testada.

Depois de ter feito todas as modificações necessárias, clique em ‘Compactar extensão…’, informe novamente o caminho, e ele criará um arquivo compactado de sua extensão, que poderá ser compartihada com seus amigos através do arquivo minha_primeira_extensao.crx

Espero que tenha sido útil este simples tutorial.

Categorias: HTML, Internet, Programação

Por Paulo Collares Em 14/janeiro/2013 Nenhum comentário

Muitas vezes você precisa abrir mais de uma sessão do NetBeans ao mesmo tempo, seja para verificar ou testar projetos diferentes, seja para utilizar o Grupo de Projetos da IDE.

Porém a instalação do NetBeans não permite isso, vou mostrar aqui como realizar essa ‘façanha’

Duas Sessões do NetBeans Abertas simultâneamente

Duas Sessões do NetBeans Abertas simultâneamente

Linux

Primeiramente, duplique a pasta de configurações do usuários, fica localizada em /home/USUARIO/.netbeans/ 

Cole no mesmo diretório, com o nome de ./netbeans2, por exemplo

Pasta de Configuração Duplicada

Pasta de Configuração Duplicada

Agora, em seu desktop, duplique o atalho do NetBeans, edite as propriedades deste e inclua no fim do campo Comando o atributo: –userdir /home/USUARIO/.netbeans2/7.2.1/ este informará a outra sessão do NetBeans.

Configuração do atalho

Configuração do atalho

 

 Windows

Primeiramente, duplique a pasta de configurações do usuários, fica localizada em C:\Users\USUARIO\AppData\Roaming\NetBeans\

Pasta de Configuração Duplicada

Pasta de Configuração Duplicada

Cole no mesmo diretório, com o nome de NetBeans2, por exemplo

Agora, em seu desktop, duplique o atalho do NetBeans, edite as propriedades deste e inclua no fim do campo Destino o atributo: –userdir C:\Users\USUARIO\AppData\Roaming\NetBeans2\7.2.1\ este informará a outra sessão do NetBeans.

Configuração do atalho

Configuração do atalho

Para conferir o local de configuração do usuário do NetBeans, acesse Ajuda > Sobre

Sobre do NetBeans

Sobre do NetBeans

Repita este processo quantas vezes necessário, fiquem na Paz

Categorias: Programação
Tags:

Por Paulo Collares Em 14/janeiro/2013 1 comentário

Para quem trabalha com vários projetos no Netbeans uma boa dica é utilizar a funcionalidade ‘Grupo de Projetos’ da IDE. Muito útil para quem trabalha com EJB por exemplo.

Como criar um Grupo de Projeto?

Criando um Grupo de Projetos no NetBeans

Criando um Grupo de Projetos no NetBeans

É simples, na aba de projetos, clique com o botão direito, Grupo de Projetos, Novo Grupo. Dê um nome e clique em Criar Grupo.

Repita esses Passos para os vários grupos de projetos que você precisar, e crie ou abra os projetos correspondentes em cada grupo.

É possível criar também um grupo comum projeto mestre e ele abrrá também os projetos que ele requer, ou uma pasta de projetos.

Espero que tenha sido útil esta dica, fiquem na Paz.

Categorias: Programação
Tags: ,

Por Paulo Collares Em 12/dezembro/2012 Nenhum comentário
Aluguel de filmes pelo Google Play

Aluguel de filmes pelo Google Play

Hoje decidi experimentar o aluguel de filmes do Google pelo YouTube, o Google Play já era utilizado para comprar de aplicativos para Android, agora é possível comprar e alugar filmes e livros.

Eles utilizam o player e a tecnologia do Youtube para reproduzir os filmes, e apesar de por algum motivo não ter rodado no Linux, funcionou bem no Windows, ambos com o mesmo navegador, o Chrome.

Player do Aluguel de Filmes pelo YouTube

Player do Aluguel de Filmes pelo YouTube

A primeira barreira para esta plataforma, acredito ser o preço, assisti ao filme MIB 3 e aluguei por R$6.90 o filme em SD, em HD sairia por R$9,90. Acho muito por um serviço que oferece apenas o filme, sem extras nem opção de áudio, apenas o original, com legendas fixas.

Ao alugar, tenho 30 dias para iniciar a reprodução, uma vez feito isso, tenho 48 horas para assistir o filme. Poderia comprar por R$29,90, novamente muito caro apenas pelo filme.

A forma de pagamento é segura e simples, utiliza o Google Wallet, como já tinha cadastro lá, foi apenas confirmar a compra pelo cartão de crédito.

Também testei o aplicativo para Android para reproduzir os filmes alugados, funciona bem, ao abrir o aplicativo, já lista meus filmes disponíveis e reproduz normalmente. Apesar de achar que ficaria melhor em um tablet… rsrs

Pelo aplicativo é possível baixar o vídeo para o seu dispositivo, o que é muito bacana, pois posso baixar no Wifi por exemplo e assistir depois quando estiver off-line.

Google Play no Android

Google Play no Android

Para finalizar, achei um sistema mediano, tem muito que melhorar, principalmente a opção de extras, como áudio e legendas alternativas, mas principalmente o preço.

Fica a dica quem quiser pagar uns ‘trocados’ e assistir um filme, sem peso na consciência, o Google Play é uma boa opção.