Colocando o Apache para funcionar no Mac OS X 10.10 (Yosemite)

Não vou tecer aqui as minhas reclamações a respeito do novo sistema do Mac. Não estou me entendendo muito bem com ele, espero que seja questão de tempo.

Uma coisa que mudou e me deu trabalho foi o Apache. No Mavericks, o Apache era o 2.2. No Yosemite, eles agora usam o 2.4. Se você usava o Apache no Mavericks, vai ver que ele logo de cara não funciona no Yosemite.

Vamos aos passos que resolveram o meu problema. Talvez resolvam o seu também. Estou supondo que você use o Apache com o PHP na pasta /Library/WebServer/Documents/.

Edite o arquivo /etc/apache2/httpd.conf (você vai reparar que ele salvou uma cópia do seu httpd.conf como httpd.conf.pre-update. Suas configurações antigas estão lá).

sudo vi httpd.conf

Comente a linha “Require all denied” do diretório “/”.

AllowOverride none
# Require all denied

Descomente a linha que carrega o PHP.

LoadModule php5_module libexec/apache2/libphp5.so

Caso você não esteja usando o apache na pasta /Library/WebServer/Documents/, talvez seja útil adicionar o usuário _www aos grupos admin, staff e wheel, usando os comandos abaixo no terminal.

sudo dseditgroup -o edit -a _www -t user admin
sudo dseditgroup -o edit -a _www -t user wheel
sudo dseditgroup -o edit -a _www -t user staff

Pronto. Reinicie o apache que tudo deve funcionar agora.

sudo apachectl restart

Primos na Espiral de Ulam

Uma das razões dos números primos serem tão legais se deve ao fato deles se comportarem de forma estranha. Eles parecem aleatórios.

Algumas vezes você tem longos espaços entre dois números primos e, de repente, como os ônibus, vêm dois de uma vez só. No entanto, no fundo no fundo, eles não são completamente aleatórios.

Um matemático Polonês chamado Stanislaw Ulam, que foi para os EUA pouco antes da Segunda Guerra Mundial, estava, depois da guerra, em 1963, assistindo uma apresentação de um trabalho chatíssimo e longo com um papel e uma caneta na mão e resolveu fazer a seguinte brincadeira para se distrair:

No centro do papel colocou o número 1 e foi fazendo uma espiral quadrada com a sequência, conforme a figura abaixo:
ulam1

Depois disso, começou a circular os números primos nesta espiral, conforme a figura a seguir:
ulam2

Ele ficou surpreso pelo fato dos números primos caírem em diagonais. Como todos os números primos, exceto o 2, são números ímpares e como as diagonais nesta espiral alternam entre pares e ímpares, não é surpresa que os números caiam em diagonais alternadas, mas que algumas diagonais tenham mais primos do que outras.

Pouco tempo depois ele resolveu fazer um programa usando o computador MANIAC II para imprimir pixels nos pontos primos (exatamente como eu fiz em vermelho no excel) e conseguiu fazer uma imagem com os números até 65.025 (255 x 255).

Aqui abro um parêntese para falar do MANIAC II.

Ele era um computador criado em 1957 com 4096 words de 48bits (24kbytes) de memória RAM em Magnetic-core Memory e 12288 words de 48bits (576kbytes) em Williams tubes. Em média, uma multiplicação neste computador demorava 180 microsegundos e uma divisão 300 microsegundos. Uma verdadeira eternidade para os tempos de hoje.

Voltando à espiral do Ulam, o que ele conseguiu com a impressão da matriz de 255 x 255 de pixels foi a confirmação do que ele havia visto com 100 números. Realmente há um padrão no qual os números primos aparecem em diagonais, com intervalos, é claro, e algumas diagonais parecem ter mais primos do que outras.

ulam-255x255

Todas as linhas nesta espiral obedecem à seguinte equação quadrática: 4x^2+bx+c

Por exemplo, a diagonal que começa no número 3 tem a seguinte equação: 4x^2-2x+1
3, 13, 31, 57, 91, … (Confira na imagem acima)

Na prática, há uma hipótese de que estas diagonais podem servir para procurarmos números primos grandes, já que algumas diagonais têm mais primos do que outras diagonais. Melhor dizendo, algumas equações quadráticas têm mais chance de retornar números primos do que outras.

Um exemplo de diagonal com 40 números primos em sequência é a seguinte: x^2-x+41 que gera a seguinte sequência de 40 números primos:

41, 43, 47, 53, 61, 71, 83, 97, 113, 131, 151, 173, 197, 223, 251, 281, 313, 347, 383, 421, 461, 503, 547, 593, 641, 691, 743, 797, 853, 911, 971, 1033, 1097, 1163, 1231, 1301, 1373, 1447, 1523, 1601 (O 41o número é igual a 41^2 e, portanto, não é primo)

As diagonais com as maiores densidades de números primos conhecidas são a belezuras abaixo:

x^2 + x + 3399714628553118047

e (desculpe, não cabe na tela)

x^2 + x + 332518109806968781031500852571295088573128477514981900349983874538507313

O que interessa nisto tudo, é que, parece que, há fórmulas com mais densidade de primos do que outras (isso ainda não foi provado) e isto pode ajudar a resolver outros problemas, como a hipótese de Goldbach (que diz que todos os números pares maiores do que 2 podem ser expressados pela soma de dois números primos) ou a hipótese da existência de infinitos números primos gêmeos.

Como não poderia faltar, eu fiz uma implementação em javascript para mostrar esse grid, só que em vez de 255 x 255, o grid que eu fiz é de 1000×1000. O resultado está neste link. Obviamente você pode aumentar o tamanho do canvas para gerar coisas grandes, como essa de 25.000.000 de números (5000 x 5000) que eu fiz usando o mesmo código (Clica que aumenta).

ulam-5000x5000

 

Edição das 11:50 (Não podia faltar o código Python. O @jbvsmo depois dirá que está lento….)

#!/usr/bin/env python
import sys,math
import Image
 
size = int(sys.argv[1])
 
def sieveGen(siz):
    l = [2,3,5,7,11,13,17,19,23,29]
    if (siz < 31):
        return l
    for i in xrange(31,siz,2):
        isP = True
        rT = math.sqrt(i)
        for j in l:
            if i%j == 0:
                isP = False
                break
            if j>rT:
                break
        if isP:
            l.append(i)
    return l
 
mySieve = sieveGen(size)
 
 
def isPrime(n):
    if (n == 1):
        return False
    if (n < size):
        return (n in mySieve)
    isP = True
    sqrtN = math.sqrt(n)
    for j in mySieve:
        if (n%j)==0:
            return False
        if (j>sqrtN):
            return True
    return True
 
 
 
 
def spiral(N):
    im = Image.new("RGB", (N, N), "white")
    pix = im.load()
    red = (255,0,0)
    if(N%2):
        x = y = ((N-1)/2)
    else:
        x = y = (N/2)
    N2 = N*N
    dx = 1
    dy = 0
 
    val = 1
    amp = 1
    c = 0
 
    while (val <= N2):
        mvd = 0
        while ((mvd < amp) and (val <= N2)):
            if isPrime(val):
                pix[x-1,y-1] = red
            x += dx
            y += dy
            mvd += 1
            val += 1
 
        c += 1
        if (c == 2):
            c = 0
            amp += 1
 
        if (dx == 1):
            dx,dy = 0,1
        else:
            if (dy == 1):
                dx,dy = -1,0
            else: 
                if (dx == -1):
                    dx,dy = 0,-1
                else:
                    if (dy == -1):
                        dy,dx = 0,1
    im.transpose(Image.FLIP_TOP_BOTTOM).save("ulam.png")
 
spiral(size)

CAPTCHAS eficientes e CAPTCHA ruim

Não se preocupe se você não sabe o que significa CAPTCHA. Na prática, são aquelas letrinhas embaralhadas que quase todo formulário de cadastro ou votação online têm.

E para que serve aquele negócio que atrasa a nossa vida?

Serve para impedir que um computador consiga preencher o formulário sozinho, uma vez que ele não vai conseguir entender aquelas letrinhas dentro da imagem. Isso impede que robôs enviem milhares de mensagens ou votem milhões de vezes numa pesquisa online.

Quanto mais embaralhadas forem as letras na imagem, melhor.

Ah, e precisa ser uma imagem, porque se for texto, o computador não faz nem esforço, como é o caso do site de uma das maiores operadoras de telecomunicações do Brasil, que coloca os números do CAPCHA em texto, e ainda coloca os dados na página escondidos num campo “hidden”! Isso não dura 1 segundo na mão de um script feito por um garoto de 10 anos.

Você está fazendo isso errado...

Não vou dizer qual foi a operadora, mas acho que você consegue descobrir. 😉

Outra maneira interessante de fazer um CAPTCHA é exibir uma pergunta simples, mas em linguagem natural, por exemplo:

  • Qual é o triplo de dois?
  • Quais são as vogais da palavra piauiense?
  • Quanto é dois mais sete?
  • A palavra travesseiro começa com qual letra?

Se você tiver uma lista grande de perguntas como essas, e for exibindo de forma aleatória, isso funciona da mesma forma que as imagens do CAPTCHA.

Atualmente o CAPTCHA mais usado por aí se chama reCAPTCHA, inventado por um sujeito chamado Luis von Ahn, que descobriu uma maneira muito simples de pessoas irem convertendo livros digitalizados em texto e ainda fazer isso servir como CAPTCHA.

Como funciona? Há um projeto grande de digitalizar jornais muito antigos e convertê-los em texto através de OCR. O problema é que algumas partes do texto ficam ilegíveis para o OCR e a tradução dessas palavras de imagem em texto sai errada. Veja abaixo:

sample-ocr

Nós conseguimos perfeitamente identificar o texto “This aged portion of society were distinguished from”, mas o computador não. Dessa forma, o que ele faz é partir a imagem do texto em palavras e exibir para as pessoas traduzirem aquilo para texto, no CAPTCHA.

recaptcha

Agora, se ele não sabe o que significam as palavras, como ele faz para saber se você digitou certo as palavras da imagem?

Por esse motivo ele sempre coloca duas imagens juntas. De uma ele sabe o significado, da outra não. Se você acertar uma, provavelmente tentou acertar a outra. Quando um número X de pessoas disse a mesma coisa para aquela palavra, ele guarda aquilo como o texto referente àquela palavra.

E assim vão digitalizando jornais e livros antigos…

Fica aqui uma dica para o sujeito que fez o site da operadora de telefonia: O reCAPTCHA é gratuito e funciona 10 mais 11 vezes melhor do que o seu CAPTCHA feito em texto. 😉

Começa hoje o Google I/O com transmissão ao vivo

Se você desenvolve para Android, ou pretende desenvolver. Se você desenvolve para o Google App Engine, Google Maps, etc, hoje é dia de ver o keynote do Google I/O que começa as 13hs (horário do Rio de Janeiro).

O video pode ser assistido abaixo:

Será um keynote de cerca de 3 horas, mas talvez o começo seja útil mesmo para quem não tem interesse direto em desenvolvimento para a plataforma Google.

Google I-O 2013

Quer ir no WWDC? Vendeu em 2 min …

Imagine o seguinte diálogo.

– Zé, são 13:58, vai começar a vender o WWDC daqui a dois minutos. Cuidado para não perder a vaga.

– Fica tranquilo Simão, eu estou apertado para lavar a mão, vou dar uma passada no banheiro e já volto.

Zé volta assobiando do banheiro e ouve Simão dizer:

– Zé, já era. Acabaram os ingressos.

Foi assim, em dois minutos acabaram os ingressos. Mesmo custando US$ 1599.00

Quer dizer então que os desenvolvedores estão ganhando rios de dinheiro? Imagino que sim, no entanto pode ter certeza que desenvolvedores brasileiros não estão entre os top 1000 que mais ganham, a situação de desenvolvimento mobile no país não anda nada bem.

WWDC vendeu tudo em 2 minutos

Acelerando o emulador de Android no Mac e no Windows

Executar o emulador de Android no Mac em qualquer sistema operacional é terrível.

Você abre o programa, espera, espera, espera, espera, espera, espera, espera, espera, espera, espera, espera, espera, …….(parece que vai abrir)……, espera, espera, espera, espera e ele abre. Aí manda ligar, espera, espera, espera, espera, espera, espera, espera, espera,… Bom você já sabe, né?

Procurando uma solução para isso, encontrei esse post aqui, que fala como resolver o problema para o 4.0.3, mas funcionou para mim também com o 4.2.2.

Os passos a seguir são para o Mac, mas funcionam também para o Windows com algumas mudanças.

Passo 1

Abra o Android SDK Manager e procure por “Intel Atom x86 System Image” dentro de Android 4.X.X.
Obs.: Também tem um dentro de 2.3.3 se você quiser testar no Gingerbread também.

Passo 2

Faça o download do “Intel Atom x86 System Image” e espere terminar de instalar.

Passo 3

Vá para a pasta /extras/intel/Hardware_Acceleration_Execution_Manager/ e abra o arquivo haxm-macosx_r02.dmg (IntelHaxm.exe no Windows). Dentro dele há um IntelHAXM_1.0.1.mpkg. Execute o programa.

No Windows, se o programa reclamar que a virtualização não está ativada. Você vai ter que ativá-la na BIOS do seu computador (Procure no Google como ativar para a sua BIOS).

Passo 4

Siga os passos do instalador e escolha a quantidade de RAM que você deseja reservar para o emulador. Para mudar isso depois, basta executar esse instalador novamente. Não abuse desse valor para não deixar seu Mac lento enquanto estiver usando o emulador.

Passo 5

Feche o Android SDK Manager e abra-o novamente. Isso não tem no tutorial original, mas comigo só funcionou depois de fazer isso.

Passo 6

Abra o AVD Manager e crie um novo Device.
Escolha “Android 4.X.X – API Level XX” (onde XX corresponde à sua versão instalada).
Na parte de CPU/ABI, escolha “Intel Atom (x86)”
Marque o checkbox “Use Host GPU”
Deixe desmarcado os “Snapshots”. (Ou você usa Snapshots ou a GPU).

Passo 6

Use o emulador e seja feliz.

Passo 7

Use o tempo livre que você acaba de ganhar para fazer algo de útil ou ajudar alguém. 🙂

Código de Países: um guia definitivo

Num projeto, para tablets, que vamos mostrar em breve para vocês precisamos importar dados usando country codes (códigos de países). Parece algo simples mas como há multiplos padrões a coisa pode ficar complicada e montar uma planilha mais complicado ainda.

Acontece que a definição de país não é algo simples: pense rapidamente na diferença que há entre Inglaterra, Reino Unido e Grã Bretanha. Ou o caso de Porto Rico. E por aí vai.

Há o FIPS-10-4 que é a forma de abreviatura de duas letras que os EUA usam para se referir aos países. O famoso CIA World Factbook usa este. Há também o ISO-3166-1 que tem três versões: uma com duas letras, uma com três letras e uma com 3 dígitos numéricos. Outro código é o STANAG-1059 que é usado pela OTAN para se referir aos países usando 3 letras maiúsculas.

Por fim há o código de duas letras utilizado para indicar o país nos endereços DNS. São os chamado código TLD de países e são geridos pela IANA.

Se você ficou assustado com toda esta sopa de letras fizemos uma tabela para facilitar a sua vida que pode ser baixada em: http://pastebin.com/pufS81HX

ccTLD_1000b

É preciso saber programar para conferir título de capitalização

Em primeiro lugar eu queria dizer que títulos de capitalização são a maior safadeza já inventada. É a típica parceria Caracu, onde o Banco entra com a cara.

Tendo dito isto, talvez você não saiba como é feito o sorteio dos tais prêmios. Um infeliz amigo que foi obrigado pelo seu gerente a fazer um título de capitalização pediu um help ontem e coloco abaixo a forma como resolvi.

Vamos às regras do título de capitalização do Banco Maldito (você sabe qual é):

  1. Só valem os sorteios da Loteria Federal feitos no último sábado do mês.
  2. Se o mês for Março, Junho, Setembro ou Dezembro vão ser escolhidos dois números. Um tradicional e outro especial.
  3. O número tradicional é formado pela dezena simples e unidade simples do primeiro prêmio da loteria federal e pela unidade simples do 2o, 3o, 4o e 5o prêmios da loteria federal.
  4. No caso do sorteio especial o segundo número é formado pela centena simples do primeiro prêmio da loteria federal e pela dezena simples do 1o, 2o, 3o, 4o e 5o prêmio.

Para resolver você precisa de uma tabela de resultados da loteria federal que pode ser conseguida aqui: http://www1.caixa.gov.br/loterias/loterias/federal/download.asp

Com isto em mãos e o programa em Python que vai abaixo você resolve seu problema. (obviamente os mestres de Python que leem o blog terão soluções melhores).

Mas o melhor conselho é *nunca* fazer título de capitalização.

Título de Capitalização é safadeza

#!/usr/bin/env python
import urllib
import time
import calendar
from bs4 import BeautifulSoup
 
fhtml = open("D_LOTFED.HTM").read()
soup = BeautifulSoup(fhtml)
meus_numeros = [
394465,558487,
572418,640294,
439592,329068,
368570,765895,
023206,847826]
 
l = []
for i in soup.table.tbody.findAll("tr"):
        a = []
        for k in i.findAll("td"):
                a.append(k.text)
        l.append(a)
 
def modalidadeMensal (a1):
        return int(a1[2][3:]+a1[3][4]+a1[4][4]+a1[5][4]+a1[6][4])
 
def modalidadeEspecial(a1):
        return int(a1[2][2:3]+a1[3][3]+a1[4][3]+a1[5][3]+a1[6][3])
 
def isLastSaturday(st):
        tupl = time.strptime(st,"%d/%m/%Y")
        if tupl[6]==5:
                if ((tupl[2])+7) > calendar.monthrange(tupl[0],tupl[1])[1]:
                        return True
        return False
 
def isEspecial(st):
        if (isLastSaturday(st)):
                tupl = time.strptime(st,"%d/%m/%Y")
                if tupl[1] in [3,6,9,12]:
                        return True
        return False
 
for i in l[1:]:
        if isLastSaturday(i[1]):
                print i[0],i[1],modalidadeMensal(i)
                if modalidadeMensal(i) in meus_numeros: print i
        if isEspecial(i[1]):
            print "*",i[0],i[1],%modalidadeEspecial(i)
            if modalidadeEspecial(i) in meus_numeros: print i

Palavra do dia, Geocoding

Imagine que você tem um banco de dados grande de pontos de interesse (padarias, lojas, restaurantes, escolas, monumentos, museus, etc.) com as posições geográficas (latitude e longitude) de cada um e deseja saber qual deles está mais próximo de um certo endereço.

Sabendo a latitude e longitude do endereço, descobrir a distância em “linha reta”, na verdade é um arco, entre cada ponto é uma conta bem simples.

Distância entre duas coordenadas geográficas

Onde  e são respectivamente as latitudes dos dois pontos, é a diferença das longitudes e S é o arco que queremos descobrir. Para saber a distância em km, é preciso multiplicar o valor de S pelo raio da Terra, que, na média é igual a 6367,5km.

Por exemplo, suponhamos que quiséssemos saber a distância entre a Torre Eiffel (48.8582780, 2.2942540) e o museu do Louvre (48.86063610, 2.33760960) em Paris.

= 48.8582780˚ = 0.852737818rad
= 48.86063610˚ = 0.852778975rad
= (2.33760960 – 2.2942540) = 0.0433556˚ = 0.000756697969rad

cos(S) = sin(0.852778975) * sin(0.852737818) + cos(0.852778975) * cos(0.852737818) * cos(0.000756697969) = 0.99999987523

Srad = acos(0.99999987523) = 0.000499539793

Skm = 0.000499539793 * 6367.5 = 3.18km

Antes que me xinguem, esta conta não é muito precisa, visto que o raio da Terra não é constante e a Terra não é uma esfera, mas é uma boa aproximação e serve para podermos comparar distâncias.

Então o problema está resolvido, diria um leitor mais afoito. Infelizmente, não. A pergunta é: “Como eu sei que a posição da Torre Eiffel é (48.8582780, 2.2942540)?”

Para isso, precisamos saber como descobrimos a latitude e longitude de um certo endereço (Ex.: Av. Nações Unidas, 12.901, São Paulo, SP) ou local (Tour Eiffel) para podermos resolver o problema. A ação de converter um endereço em latitude e longitude é chamada de “Geocoding”

Algum esperto poderia dizer de gozação: “Ah, procura no Google!” e eu responderia que ele estava certo. O Google disponibiliza gratuitamente um serviço de Geocoding que resolve esse problema, mas tem algumas limitações. A maior delas é o limite de 2.500 buscas por dia, e também a restrição de ter que exibir o resultado da busca num mapa. O endereço de busca é o seguinte:

http://maps.googleapis.com/maps/api/geocode/json?address=[Endereço]&sensor=false

Existem outras soluções gratuitas, como o Bing Maps, o Mapbox e o OpenStreetMaps, dentre outras.

Este último é o único que realmente é gratuito e sem limites, se você quiser hospedar os dados num servidor próprio. O problema é que os dados e o sistema de Geocoding do OpenStreetMaps, chamado de Nominatim, do planeta inteiro ocupam aproximadamente 600GB de HD e sugerem um servidor com 32GB de RAM para rodar bem. Caso contrário, eles sugerem usar um serviço hospedado em sites de terceiros.

Eu encontrei no site da Mapquest, um serviço gratuito de Geocoding, baseado no Nominatim, que parece não ter as limitações do Google.

O endereço é http://open.mapquestapi.com/nominatim/#search_basic

Ainda não sei qual serviço vou usar no projeto que estou terminando, mas estou tendendo a usar este último.

E você? Já fez algum projeto usando Geocoding? Tem alguma dica para passar? Deixe seu recado nos comentários!

Labirinto Maluco: 1 milhão de downloads e a continuação

O Labirinto Maluco foi uma surpresa para mim, nunca pensei que ele fosse passar a marca de 1 milhão de downloads e ser votado como um dos 25 apps mais baixados de todos os tempos no Brasil. Mas foi assim. É algo muito legal ver pessoas que você não conhece jogando, um jogo no qual você trabalhou, no metrô, no ônibus; o chefe supremo do Zeletron já viu uma pessoa, num vôo internacional, sentado ao seu lado jogando este jogo.

Para celebrar este evento decidimos fazer uma continuação: Labirinto Maluco 2.

Nesta continuação além de o usuário ter todos os níveis grátis, ele tem disponíveis bombas para quebrar as paredes do labirinto e warps para fazer as bolas serem teletransportadas. O jogo passou também por uma mudança visual bastante intensa e ganhou efeitos sonoros, opções de compartilhamento e mais realismo físico.

Gostaria de agradecer todos os que gostaram do Labirinto Maluco e tem jogado ele. Aproveito para sugerir que experimentem o Labirinto Maluco 2.

BlackBerry Jam Sessions & Playbook

Como o Pedro Paulo disse no texto de ontem, fui à edição do Rio de Janeiro do BlackBerry Jam Sessions onde ficamos 10hs projetando e implementando um app para rodar no sistema deles (Tablet OS ou BB 10) e posso afirmar que é algo bem divertido, mas muito desgastante. Ao final, meu grupo ainda saiu vencedor do prêmio Melhor Design, e era de se esperar já que me uni a 3 excelentes alunos de Design da PUC-Rio para essa maratona.

Para o desenvolvimento, deram as seguintes opções: Web, Adobe Air, C++ (Qt & QML) e Android. Os programas deveriam rodar no emulador ou no próprio aparelho Dev Alpha que ainda não estava instalado com a versão do BlackBerry 10, mas com o sistema de tablet que acabou prejudicando um pouco a usabilidade. Espera-se que esse aparelho seja lançado em poucos meses.

Sobre o Playbook que é o tablet da BlackBerry lançado no fim do ano passado e que fui premiado com uma unidade, posso dizer que estou achei bem impressionante como a tela é responsiva (melhor que 95% dos tablets Android que usei) e o multitasking é bem interessante. O sistema usa um conceito bem parecido ao do Meego (que uso no meu Nokia N9) onde você arrasta o dedo de fora da tela para o meio para ir para a área de troca de aplicativos ou para o aplicativo seguinte, dependendo da direção do movimento.

Apesar do Tablet ter um sistema muito interessante, a App World ainda é um pouco pobre, tendo aplicativos muito mais simples que os equivalentes Android ou iOS e é esse o esse motivo de existirem os Jam Sessions.

Algo interessante é que os aplicativos Android podem ser portados para a tecnologia da BlackBerry com um simples empacotamento no formato deles. Quanto a compatibilidade, não sei dizer, mas eles dizem ser alta.

[Objective-C] – Human readable date diff

Sometimes you have to express date differences in a human readable way: “2 hours ago”, “yesterday”, etc. How to do this in Objective-C?

Here’s a nice solution

    - (NSString *) dateToName:(NSDate*)dt withSec:(BOOL)sec {
 
        NSLocale *locale = [NSLocale currentLocale];
        NSTimeInterval tI = [[NSDate date] timeIntervalSinceDate:dt];
        if (tI < 60) {
          if (sec == NO) {
               return NSLocalizedString(@"just now", @"");
           }
           return [NSString stringWithFormat:
                     NSLocalizedString(@"%d seconds ago", @""),(int)tI];
         }
         if (tI < 3600) {
           return [NSString stringWithFormat:
                     NSLocalizedString(@"%d minutes ago", @""),(int)(tI/60)];
         }
         if (tI < 86400) {
          return [NSString stringWithFormat:
                     NSLocalizedString(@"%d hours ago", @""),(int)tI/3600];
         }
 
         NSDateFormatter *relativeDateFormatter = [[NSDateFormatter alloc] init];
         [relativeDateFormatter setTimeStyle:NSDateFormatterNoStyle];
         [relativeDateFormatter setDateStyle:NSDateFormatterMediumStyle];
         [relativeDateFormatter setDoesRelativeDateFormatting:YES];
         [relativeDateFormatter setLocale:locale];
 
         NSString * relativeFormattedString = 
                [relativeDateFormatter stringForObjectValue:dt];
         return relativeFormattedString;
    }

Desenvolver aplicativos para Android requer uma certa dose de loucura

Off topic: Antes de mais nada, gostaria de me desculpar pela falta de atualização do blog no último mês. Este foi o segundo mês com menos posts de toda a história do blog (O primeiro foi o fatídico mês de janeiro de 2010 quando o NokiaBR foi fechado e tive que me organizar para continuar blogando). Andamos todos bastante ocupados com nossos trabalhos que não conseguimos escrever o quanto gostaríamos. Também acho que o Mobile Analyst anda comendo tanto ovo cozido na Cinelândia que se esqueceu de nós…

Mas vamos ao que interessa. Android. Plataforma aberta. Milhares de opções de aparelhos. Isso é bom para o usuário (tenho minhas dúvidas). Mas será que é bom para o desenvolvedor?

Venho desenvolvendo há alguns anos aplicativos para iOS e, no ano passado aqui na empresa começamos a portar alguns dos nossos aplicativos e jogos para Android. Para nossa surpresa, desenvolver um aplicativo no Android que funcione em todos os aparelhos requer muita paciência porque várias coisas que funcionam para uma versão do sistema não funcionam em outras versões. Às vezes, coisas que funcionam no 2.3 não existem no 2.2 e coisas do 2.3 não funcionam da mesma maneira no 3.0, e assim por diante. É preciso testar o programa no máximo de aparelhos que você consiga, o que é inviável.

Para completar a guerra, existe um número absurdo de tipos de tela (dimensões x densidade de pixels x orientação). Telas quadradas, telas verticais, telas horizontais, resolução baixa, resolução média, resolução alta, resolução extra alta, cada uma dessas com suas peculiaridades.

A cereja desse bolo é a chamada “customização” dos fabricantes e operadoras, que pode deixar a guerra ainda mais complicada para o desenvolvedor.

Os defensores do Android dizem que essa fragmentação é uma qualidade e não um problema. Garanto que quem diz isso nunca desenvolveu nada para Android ou nunca teve que responder a um cliente que vem reclamar que o seu aplicativo não roda no aparelho dele que tem tela hexagonal e nem no do amigo dele que tem tela elíptica em landscape. 🙂

Outro dia li num post do TechCrunch que um desenvolvedor chamado Animoca, chega a testar os seus aplicativos em 400 aparelhos diferentes (parte deles na foto abaixo).

E outro, esse eu li no Ars Technica, que diz já ter identificado 4.000, QUATRO MIL, modelos de aparelhos diferentes rodando um aplicativo dele (gráfico abaixo). Outra curiosidade que esse desenvolvedor revelou, é que nesses 4.000 modelos de aparelhos, ele descobriu quase 600 fabricantes diferentes! 599 para ser mais preciso.

Com os nossos aplicativos acontece exatamente a mesma coisa. Temos o exemplo do jogo “Manobrista Maluco“, que é sucesso no iOS e também no Android, que tem mais de 850.000 downloads no iOS e pouco mais 145.000 downloads no Android (a versão Android tem quase dois anos a menos).

O gráfico de aparelhos que usam esse jogo é o seguinte:

Como podemos reparar, somente 46% dos downloads estão concentrados em 9 aparelhos. Os outros 54% estão distribuídos em aparelhos que individualmente participam com menos de 2,6% do total. Se quiséssemos atender à maioria dos usuários, teríamos que testá-lo em centenas de aparelhos diferentes.

Hoje recebemos da Amazon um e-mail informando que o Manobrista Maluco não foi aceito para ser publicado na loja de aplicativos do Kindle Fire. Segundo eles, o jogo não se adapta às dimensões de tela do Kindle Fire. Teremos que adaptar o jogo para o Kindle se quisermos publicá-lo na loja da Amazon.

Cada vez mais vemos aparelhos com Android sendo vendidos nas mais variadas versões do sistema e com as mais diversas disposições de tela. Outro dia alguém me mandou uma foto de um flagra de uma loja de celulares vendendo aparelhos com Android com a versão 1.6 ainda! Isso sem falar dos Xing-Lings dos camelódromos que de MP10 viraram num passe de mágica aparelhos com Android.

Enfim, gostaria de saber se outros desenvolvedores de aplicativos para Android compartilham dessa opinião e o que eles fazem para contornar esse problema, além de testar os seus programas em N+K aparelhos.