Arquivo da categoria: JavaScript

SWX Direto das trincheiras 03 – Campus Party, Podcasts e Forum de Inovação tecnológica

Neste SWX Direto das trincheiras trazemos as novidades que rolaram na SWX, se perdeu alguma coisa confira:

  • SWX Labs 03 – Editais de Inovação: http://bit.ly/SWXLabs03
    • Bate papo com Marcelo Dósea, sobre Editais de Inovação, sua importância e como se preparar para participar.
  •  SWX Labs 04 – Planejamento: http://bit.ly/SWXLabs04
    • Neste podcast Benhun, gerente de projetos de SWX, fala sobre planejamento. São debatidos conceitos e dicas de como preparar um bom planejamento.
  • 5 formas de utilizar o google alerts para alavancar seu negócio ou carreira: http://bit.ly/GoogleAlerts5Dicas
    • No blog do CIO Market tem dicas interessantes de como aproveitar uma grande ferramenta do google, o Alerts.
  • Model em Ruby on Rails – Parte 02: http://bit.ly/NGczin
    • Segunda parte do artigo explicando um aspecto da aplicação da arquitetura MVC com Ruby on Rails.
  • Uma introdução ao gulp: http://bit.ly/1cCsR4S
    • Saiba mais sobre esse automatizador de tarefas baseado no node.js
  • Desvendando os “Custom Post Types”: http://bit.ly/1iMneoz
    • Para iniciantes e intermediários em wordpress entenderem melhor como personalizar o back end de posts no wordpress.
  • SWX na Startup and Makers da Campus Party 2014: http://bit.ly/1bPGgmy
    • Confira como foi a participação da SWX na Campus Party 2014.
  •  1º Fórum de Inovação, Propriedade Intelectual e Transferência de Tecnologia do IFS (FIPITT) – http://bit.ly/1nwdZqf
    • A SWX participa deste fórum como case de sucesso. Se vc estiver em Aracaju no dia 18/02 apareça no IFS e veja a palestra de Vinicius.

Uma introdução ao gulp

a84cbe09a6fc383b43833c60b3f2aa29

* Por João Paulo

Introdução:

Muitas tarefas são feitas manualmente de forma repetitiva, por exemplo, ao alterar certos arquivos de um site, é necessário fazer o upload para que possam ser acessados pela web; porém, para isso, é necessário abrir o cliente ftp, preencher os dados e conectar, depois selecionar os arquivos e enviar. Além de perder tempo, essas são tarefas chatas a serem feitas, então para isso existem “automátizadores” como o grunt e o gulp.

O gulp é um automatizador de tarefas desenvolvido em cima do nodejs, seu funcionamento será estudado nesse artigo.

Instalando:

Para instalar o gulp é necessário instalar o nodejs (no ubuntu, é só executar o comando #apt-get install nodejs).

Também, obviamente, é necessário instalar o gulp. O gulp é dividido em duas partes, o “gulp CLI” que é o aplicativo para ser executado na linha de comando e o gulp, a biblioteca pro nodejs.

  • Para instalar o CLI, execute: “npm -g install gulp” (npm é o gerenciador de pacotes do nodejs).

  • Para instalar a biblioteca:  “npm install –save-dev gulp”.

Estrutura básica:

O gulp foi desenvolvido sobre o nodejs, logo é necessário ter conhecimento de javascript para poder utilizá-lo.

A primeira coisa a ser feita é criar o arquivo “package.json”, é nesse arquivo que ficam as informações sobre o projeto, como nome, versão e quais bibliotecas estão sendo utilizadas. Outro arquivo importante é o “gulpfile.js”, é esse arquivo que será lido ao executar o gulp no console para executar as automatizações, logo é nele que ficarão nossos scripts.

O “package.json” pode ser criado na mão, porém o npm pode criá-lo pra você, para isso execute “npm init” e seguir as instruções (é possível deixar tudo em branco).

O “gulpfile.js” deverá ser criado a partir de algum editor de textos.

Para instalar um plugin usa-se: “npm install –save-dev <nome-do-plugin>”, por exemplo, o uglify “npm install –save-dev gulp-ufligy”.

Como o gulp foi escrito por cima do nodejs, um plugin do gulp é uma dependência do nodejs, logo o campo com a relação dos plugins instalados no “package.json” é o “dependencies”, assim outra forma de instalar as dependências (caso o “package.json” tenha sido criado manualmente) é colocá-las no campo “dependencies” e executar no console “npm install”. Para a relação dos plugins oficiais do gulp acesse: “http://gratimax.github.io/search-gulp-plugins/”

Ao instalar um plugin, é necessário definir ele no script também, para isso usa-se “require(‘plugin’)”, por exemplo, “var gulp = require(‘gulp’);” e nesse caso, para acessar os métodos do gulp “gulp.nome_do_método();”

O gulp possui poucos métodos, abaixo segue uma DESCRIÇÃO PRÁTICA do uso deles (as informações completas sobre o uso deles são encontradas na documentação):

  • gulp.src(globs): Define o arquivo ou a pasta que terá seus arquivos lidos. O parâmetro “globs” pode ser uma string ou um array, por exemplo, “./arquivos/*.js” ou “[./arquivos/arquivo1.js, ./arquivos/arquivo2.js, …]”
  • gulp.dest(path): Define a pasta de saída do processamento.  ex.: gulp.dest(“./pasta_de_saída”)
  • gulp.task(‘Nome_da_tarefa’, function(){ /* aqui fica seu código */ }): As tarefas são blocos de códigos que serão executados. ex.: gulp.task(‘enviar_por_ftp’, function{ /* aqui ficam as instruções de como enviar */ });
  • gulp.run(‘task1’, ‘task2′, … ,’taskN’): Esse método serve pra chamar outras tarefas do mesmo projeto.
  • gulp.watch(glob, tasks): Equivalente ao “run”, ele executa outras tarefas definidas no task, porém ele executa quando há alterações nos arquivos definidos no glob, ex.: gulp.watch(‘./teste/*’, [‘enviar_por_ftp’, ‘outra_tarefa’]); nesse exemplo se qualquer arquivo na pasta “teste” for alterado, ele executará as tarefas ‘enviar_por_ftp’ e ‘outra_tarefa’.

Para executar uma tarefa basta executar: “gulp <tarefa>”, por exemplo, “gulp enviar_por_ftp”. Caso exista a tarefa “default”, ela será executada simplemente com “gulp”, mas “gulp default” também funciona.

Exemplo:

No exemplo abaixo serão juntados todos os arquivos da pasta “entrada” e será criado um arquivo chamado “concatenados.txt” na pasta “saida”. Para isso será usado o plugin “gulp-concat”.

Primeiramente, é necessário instalar o nodejs (#apt-get install nodejs) e o gulp CLI (#npm -g install gulp).

Depois é necessário criar o projeto ($npm init), observe que o “package.json” foi criado; agora vamos instalar as bibliotecas do gulp e os plugins (npm install –save-dev gulp gulp-concat), observe que o “package.json” agora possui nas dependências “gulp” e “gulp-concat”.

O próximo passo é criar o script, para isso crie o arquivo “gulpfile.js” na pasta raiz do projeto com o script abaixo.

//Criada a variável 'gulp' que é a "instância" da biblioteca 'gulp'

var gulp = require('gulp');

//Criada a variável 'concat' que é a "instância" da biblioteca 'gulp-concat'

var concat = require('gulp-concat');

//Criada a tarefa 'default'

gulp.task('default', function(){

//São lidos todos os arquivos da pasta 'entrada'

gulp.src('./entrada/*')

//Os arquivos lidos são concatenados num arquivo chamado 'concatenados.txt'

.pipe(concat('concatenados.txt'))

//A saída gerada pelo concat é salva na pasta chamada 'saída'

.pipe(gulp.dest('./saida'));

});

 Para executar o script acima basta executar “gulp” (ou “gulp default”) no terminal.

Para informações sobre o gulp acesse: https://github.com/gulpjs/gulp/blob/master/docs/README.md

* João Paulo é estudante de Computação e estagiário da SWX

Criando uma aplicação com o qooxdoo

O qooxdoo é um framework javascript universal usado para criar aplicações interativas, aplicativos para dispositivos móveis, aplicações web single-page, entre outros.

Irei repassar aqui um tutorial da própria qooxdoo para criar uma pequena aplicação web single-page contendo um cliente do twitter onde o usuário possa ler tweets públicos e poder postar tweets também.

No tutorial estarei utilizando o windows 7.

Primeiro passo é baixar o python para poder usar a poderosa ferramenta de gerar aplicações.

Link: http://www.activestate.com/activepython/downloads

Agora é só baixar a SDK do qooxdoo.

Link: http://downloads.sourceforge.net/qooxdoo/qooxdoo-2.0.1-sdk.zip

Instale o python, após a instalação extraia a sdk e coloque em uma pasta de sua preferência, aqui coloquei em C:\qooxdoo-2.0.1-sdk. Antes de começarmos a criar nossa aplicação vamos colocar o python na lista de variáveis de ambiente do windows.

Abra o cmd e digite o comando set PATH=C:\Python27; %PATH% sem aspas, onde C:\Python27 é o diretório de instalação do python.

Para criar uma aplicação é muito simples basta rodar o script create-application.py localizado em tool/bin na pasta da SDK, ainda no cmd digite: C:\qooxdoo-2.0.1-sdk\tool\bin\create-application.py –name=twitter

Isto irá criar uma aplicação chamada twitter contendo toda a estrutura de diretórios e configurações necessárias para o funcionamento da mesma, agora basta executar o comando cd twitter e entrar na pasta da aplicação agora digitando o comando generate.py para gerar os scripts de sua aplicação.

Depois de gerar os scripts, crie na pasta source/class/twitter um arquivo chamado MainWindow.js e dentro deste arquivo escreva o seguinte código.

qx.Class.define("twitter.MainWindow",
{
  extend : qx.ui.window.Window,

    construct : function()
    {
      this.base(arguments, "twitter");
    }
});

O que acabamos de fazer com esse código foi definir uma classe chamada “twitter.MainWindow” que extende da classe Window do qooxdo, o construtor da classe sobrescreve o construtor da super-classe  passando como parâmetro o título da janela, no caso “twitter”. Salve este arquivo  e abra o Application.js e abaixo do bloco de comentário coloque o seguinte código.

var main = new twitter.MainWindow();
main.open();

Nós apenas instânciamos nossa classe MainWindow e executamos o método open. Antes de testarmos nossa aplicação no navegador devemos gerar mais uma vez os scripts, já que estamos utilizando a classe Window do qooxdoo como dependência, então execute mais uma vez o comando generate.py no cmd e abra o arquivo index.html para visulaizar a aplicação no navegador. Você deve ver algo parecido com isto:

Vamos agora fazer algumas alterações na interface gráfica da nossa janela, ainda no Application.js acrescente este código:

main.moveTo(50, 30);

movemos nossa janela para uma nova localização. Voltando agora para o arquivo MainWindow.js coloque o seguinte código no construtor da janela:

//Esconder os botões da janela
this.setShowClose(false);
this.setShowMaximize(false);
this.setShowMinimize(false);

// ajustar o tamanho da janela
this.setWidth(250);
this.setHeight(300);

Atualize a página e veja as mudanças. Abaixo coloque o seguinte código:

// add o layout
var layout = new qx.ui.layout.Grid(0, 0);
this.setLayout(layout);

// toolbar
var toolbar = new qx.ui.toolbar.ToolBar();
this.add(toolbar, {row: 0, column: 0, colSpan: 2});

// lista
var list = new qx.ui.form.List();
this.add(list, {row: 1, column: 0, colSpan: 2});

this.setContentPadding(0);
layout.setRowFlex(1, 1);
layout.setColumnFlex(0, 1);

// Botão recarregar
var reloadButton = new qx.ui.toolbar.Button("Recarregar");
toolbar.add(reloadButton);

// textarea
var textarea = new qx.ui.form.TextArea();
this.add(textarea, {row: 2, column: 0});

// Botão postar
var postButton = new qx.ui.form.Button("Postar");
this.add(postButton, {row: 2, column: 1});

reloadButton.setToolTipText("Recarregar os tweets.");
textarea.setPlaceholder("Digite sua mensagem aqui...");
postButton.setToolTipText("´");

Na linha 2 criamos um layout do tipo grid e setamos ele em nossa janela, na linha 6 criamos uma toolbar e adicionamos ela a nossa janela já preparada para receber os componentes e ajusta-los em forma de grade, mesma coisa com a lista da linha 10. Na linha 13 setamos o padding da janela no valor 0, já as linhas 14 e 15 servem para deixar a lista flexível. Na linha 18 é adicionado um botão na toolbar para recarregar os tweets e nas linhas seguintes são adicionados um textarea e outro botão à janela, nas linhas finais são dados alguns toques para finalizar a nossa janela como mostrar pra que serve o botão quando o mouse fica sobre ele.

No final do construtor acrescente este código:

event : 
 {
	"reload" : "qx.event.type.Event",
	"post"   : "qx.event.type.Data"
 }

E abaixo de postButton.setToolTipText(“Poste esta mensagem no twitter.”); coloque:

reloadButton.addListener("execute", function() {
	this.fireEvent("reload");
}, this);
postButton.addListener("execute", function() {
	this.fireDataEvent("post", textarea.getValue());
}, this);

Até agora nosso arquivo MainWindow.js está assim:

qx.Class.define("twitter.MainWindow",
{
  extend : qx.ui.window.Window,

  construct : function()
  {
    this.base(arguments, "twitter", "twitter/t_small-c.png");

    // hide the window buttons
    this.setShowClose(false);
    this.setShowMaximize(false);
    this.setShowMinimize(false);

    // adjust size
    this.setWidth(250);
    this.setHeight(300);

    // add the layout
    var layout = new qx.ui.layout.Grid(0, 0);
    layout.setRowFlex(1, 1);
    layout.setColumnFlex(0, 1);
    this.setLayout(layout);
    this.setContentPadding(0);

    // toolbar
    var toolbar = new qx.ui.toolbar.ToolBar();
    this.add(toolbar, {row: 0, column: 0, colSpan: 2});

    // reload button
    var reloadButton = new qx.ui.toolbar.Button("Reload");
    toolbar.add(reloadButton);
    reloadButton.setToolTipText("Reload the tweets.");
    reloadButton.addListener("execute", function() {
      this.fireEvent("reload");
    }, this);

    // list
    var list = new qx.ui.form.List();
    this.add(list, {row: 1, column: 0, colSpan: 2});

    // textarea
    var textarea = new qx.ui.form.TextArea();
    this.add(textarea, {row: 2, column: 0});
    textarea.setPlaceholder("Enter your message here...");
    textarea.addListener("input", function(e) {
      var value = e.getData();
      postButton.setEnabled(value.length < 140 && value.length > 0);
    }, this);

    // post button
    var postButton = new qx.ui.form.Button("Post");
    this.add(postButton, {row: 2, column: 1});
    postButton.setToolTipText("Post this message on twitter.");
    postButton.addListener("execute", function() {
      this.fireDataEvent("post", textarea.getValue());
    }, this);
    postButton.setWidth(60);
    postButton.setEnabled(false);
  },

  events :
  {
    "reload" : "qx.event.type.Event",
    "post" : "qx.event.type.Data"
  }
});

Vamos agora para nosso arquivo Application.js e escrever este código:

main.addListener("reload", function() {
	this.debug("reload");
}, this);

main.addListener("post", function(e) {
	this.debug("post: " + e.getData());
}, this);

Até agora nosso arquivo Application.js está desta forma:

/* ************************************************************************

Copyright:

License:

Authors:

************************************************************************ */

/* ************************************************************************

#asset(twitter/*)

************************************************************************ */

/**
* This is the main application class of your custom application "twitter"
*/
qx.Class.define("twitter.Application",
{
  extend : qx.application.Standalone,

  /*
*****************************************************************************
MEMBERS
*****************************************************************************
*/

  members :
  {
    /**
* This method contains the initial application code and gets called
* during startup of the application
*
* @lint ignoreDeprecated(alert)
*/
    main : function()
    {
      // Call super class
      this.base(arguments);

      // Enable logging in debug variant
      if (qx.core.Environment.get("qx.debug"))
      {
        // support native logging capabilities, e.g. Firebug for Firefox
        qx.log.appender.Native;
        // support additional cross-browser console. Press F7 to toggle visibility
        qx.log.appender.Console;
      }

      /*
-------------------------------------------------------------------------
Below is your actual application code...
-------------------------------------------------------------------------
*/

      var main = new twitter.MainWindow();
      main.moveTo(50, 30);
      main.open();

      main.addListener("reload", function() {
        this.debug("reload");
      }, this);

      main.addListener("post", function(e) {
        this.debug("post: " + e.getData());
      }, this);
    }
  }
});

Gere mais uma vez os scripts e veja como está a aplicação, ela deve está parecida com esta imagem:

Agora vamos dar início a interação com o twitter, crie outro arquivo na mesma pasta que Application.js e MainWindow.js chamado de TwitterService e inicialmente escreva o seguinte código:

qx.Class.define("twitter.TwitterService",
{
  extend : qx.core.Object,
  members :
  {
  }
});

Diferente da classe MainWindow, esta não precisa extender de uma classe complexa como a Window, ela extende da classe Object que é uma classe simples. Acrescente este código antes de members:

properties : {
    tweets : {
      nullable: true,
      event: "changeTweets"
    }
  },

  events : {
    "postOk" : "qx.event.type.Event"
  },

E dentro de members o seguinte código:

__store : null,

    fetchTweets : function() {
      if (this.__store == null) {
        var url = "http://api.twitter.com/1/statuses/public_timeline.json";
        this.__store = new qx.data.store.Jsonp(url, null, "callback");
        this.__store.bind("model", this, "tweets");
      } else {
        this.__store.reload();
      }
    },

    post : function(message)
      window.open("http://twitter.com/?status=" + encodeURIComponent(message));
    }
  }

Aqui em cima criamos uma propriedade chamada tweets, que pode ser nulo e possui um evento chamado “changeTweets“. Criamos também um evento chamdo “postOk” do tipo “qx.event.type.Event” além dos membros, um atributo privado chamado “__store” (dois “__” fazem com que o atributo torne-se privado) e dois métodos o fetchTweets e o post, fetchTweets responsável pela captura de tweets públicos do twitter e post por postar o conteúdo no twitter.

Vamos voltar agora ao nosso arquivo Application.js e criar uma instância da nossa classe TwitterService e digite o seguinte código:

var service = new twitter.TwitterService();

E troque este trecho de código:

main.addListener("reload", function() {
	this.debug("reload");
}, this);

Por esse:

main.addListener("reload", function() {
  service.fetchTweets();
}, this);

E este:

main.addListener("post", function(e) {
	this.debug("post: " + e.getData());
}, this);

Por este:

main.addListener("post", function(e) {
        service.post(e.getData());
}, this);

Vamos agora para o arquivo MainWindow.js e criar um acessor para a lista, então troque onde tem var list = new qx.ui.form.List();por:

this.__list = new qx.ui.form.List();

E onde estiver list trocar por this.__list, faça o mesmo para textarea. Ainda no mesmo arquivo abaixo de events crie dois membros o __list e o __textarea ficando assim:

events :
  {
    "reload" : "qx.event.type.Event",
    "post" : "qx.event.type.Data"
  },

  members : {
    __list : null,
    __textarea : null,

Ainda dentro de members crie duas funções a getList e a clearPostMessage com o seguinte conteúdo:

getList : function() {
      return this.__list;
    },

    clearPostMessage : function() {
      this.__textarea.setValue(null);
    }

O nosso arquivo MainWindow agora está assim:

qx.Class.define("twitter.MainWindow",
{
  extend : qx.ui.window.Window,

  construct : function()
  {
    this.base(arguments, "twitter", "twitter/t_small-c.png");

    // hide the window buttons
    this.setShowClose(false);
    this.setShowMaximize(false);
    this.setShowMinimize(false);

    // adjust size
    this.setWidth(250);
    this.setHeight(300);

    // add the layout
    var layout = new qx.ui.layout.Grid(0, 0);
    layout.setRowFlex(1, 1);
    layout.setColumnFlex(0, 1);
    this.setLayout(layout);
    this.setContentPadding(0);

    // toolbar
    var toolbar = new qx.ui.toolbar.ToolBar();
    this.add(toolbar, {row: 0, column: 0, colSpan: 2});

    // reload button
    var reloadButton = new qx.ui.toolbar.Button("Reload");
    toolbar.add(reloadButton);
    reloadButton.setToolTipText("Reload the tweets.");
    reloadButton.addListener("execute", function() {
      this.fireEvent("reload");
    }, this);

    // list
    this.__list = new qx.ui.form.List();
    this.add(this.__list, {row: 1, column: 0, colSpan: 2});

    // textarea
    this.__textarea = new qx.ui.form.TextArea();
    this.add(this.__textarea, {row: 2, column: 0});
    this.__textarea.setPlaceholder("Enter your message here...");
    this.__textarea.addListener("input", function(e) {
      var value = e.getData();
      postButton.setEnabled(value.length < 140 && value.length > 0);
    }, this);

    // post button
    var postButton = new qx.ui.form.Button("Post");
    this.add(postButton, {row: 2, column: 1});
    postButton.setToolTipText("Post this message on twitter.");
    postButton.addListener("execute", function() {
      this.fireDataEvent("post", this.__textarea.getValue());
    }, this);
    postButton.setWidth(60);
    postButton.setEnabled(false);
  },

  events :
  {
    "reload" : "qx.event.type.Event",
    "post" : "qx.event.type.Data"
  },

  members : {
    __list : null,
    __textarea : null,

    getList : function() {
      return this.__list;
    },

    clearPostMessage : function() {
      this.__textarea.setValue(null);
    }
  }
});

Vamos voltar agora para o Application.js e criar um controle para nossa lista com o seguinte código:

var controller = new qx.data.controller.List(null, main.getList());
      controller.setLabelPath("text");
      controller.setIconPath("user.profile_image_url");
      controller.setDelegate({
        configureItem : function(item) {
          item.getChildControl("icon").setWidth(48);
          item.getChildControl("icon").setHeight(48);
          item.getChildControl("icon").setScale(true);
          item.setRich(true);
        }
      });

Agora vamos chamar o método bind para vincular o controle com o modelo vindo do twitter e chamar os tweets quando iniciar a aplicação:

service.bind("tweets", controller, "model");
service.fetchTweets();

Gere novamente os scripts e recarregue a página e teste nosso aplicativo funcionando.

Na hora de postar você será redirecionado para o site do twitter para autenticação, pois é muito complicado fazer a autenticação pelo aplicativo, pois o twitter só usa o OAuth para autenticar os usuários. Para baixar o projeto clique aqui.

Fonte: qooxdoo Docs

 

Como obter e tratar um retorno em JSON com o Wrapper .Net

Fonte: Buscapé Developer/IMasters

Veremos, neste artigo, uma das formas que temos de tratar os dados de um retorno em JSON utilizando o wrapper .Net.

Para começar, faça o download do Wrapper .Net direto do nosso perfil no GitHub e inclua seus arquivos em seu projeto para utilizar a classe Apiki_Buscape_API.

Com os arquivos do Wrapper .Net devidamente inseridos no projeto, vamos instanciar um objeto da classe, que servirá como nosso objeto de negócio principal. Como já estamos acostumados, devemos informar ao construtor da classe o nosso ApplicationId, para identificar a aplicação na requisição ao Buscapé. Pórem, neste exemplo também devemos sobreescrever o formato padrão de retorno dos dados para o JSON. Portanto, temos que informar valores default para os outros parâmetros do construtor da classe e informar o formato como JSON.

Apiki_Buscape_API.Apiki_Buscape_API apiBuscape = new Apiki_Buscape_API.Apiki_Buscape_API("564771466d477a4458664d3d", string.Empty, "BR", "json");

Para este artigo, vamos utilizar o método FindCategoryList, porque ele tem uma estrutura de retorno menos complexa. Consulte a documentação desse serviço na API do Buscapé, se desejar mais informações sobre os campos de resposta.

Vamos, então, invocar o método FindCategoryList com a palavra-chave LG e salvar o seu retorno em uma string.

string categoryList = apiBuscape.FindCategoryList(null, "LG", string.Empty);
Response.Write(categoryList);

Exibindo a resposta na tela, podemos ver o objeto JSON que foi retornado pelo método:

{"details":{"message":"success","elapsedtime":31,"status":"success","code":0,"applicationversion":"1.0.0.0","date":{"minute":2,"valid":true,"timezone":-120,"second":30,"millisecond":770,"month":2,"year":2012,"hour":10,"day":13,"xmlschematype":{"namespaceuri":"http://www.w3.org/2001/XMLSchema","prefix":"","localpart":"dateTime"},"eonandyear":{"lowestsetbit":2}},"applicationpath":"http://bws-apps.buscape.com/mobile/update","applicationid":"564771466d477a4458664d3d"},"schk":true,"subcategory":[{"subcategory":{"id":2852,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/2852.jpg"},"hasoffer":false,"name":"TV","parentcategoryid":1,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/tv.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=2852&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":77,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/77.jpg"},"hasoffer":false,"name":"Celular e Smartphone","parentcategoryid":6420,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/celular-e-smartphone.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=77&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":3661,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/3661.jpg"},"hasoffer":false,"name":"Ar Condicionado","parentcategoryid":116,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/ar-condicionado.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=3661&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":6424,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/6424.jpg"},"hasoffer":false,"name":"Notebook","parentcategoryid":2,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/notebook.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=6424&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":36,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/36.jpg"},"hasoffer":false,"name":"Monitor","parentcategoryid":2,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/monitor.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=36&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":3673,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/3673.jpg"},"hasoffer":false,"name":"Geladeira / Refrigerador","parentcategoryid":116,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/geladeira-refrigerador.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=3673&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":3643,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/3643.jpg"},"hasoffer":false,"name":"Home Theater","parentcategoryid":1,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/home-theater.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=3643&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":3601,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/3601.jpg"},"hasoffer":false,"name":"Micro System / Mini System","parentcategoryid":1,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/micro-system-mini-system.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=3601&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":5,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/5.jpg"},"hasoffer":false,"name":"DVD Player","parentcategoryid":1,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/dvd-player.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=5&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":3671,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/3671.jpg"},"hasoffer":false,"name":"Máquina de Lavar Roupas","parentcategoryid":116,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/maquina-de-lavar-roupas.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=3671&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":6168,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/6168.jpg"},"hasoffer":false,"name":"Gravador","parentcategoryid":2,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/gravador.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=6168&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":9754,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/9754.jpg"},"hasoffer":false,"name":"Blu-Ray Player / HD-DVD Player","parentcategoryid":1,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/blu-ray-player-hd-dvd-player.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=9754&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":126,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/126.jpg"},"hasoffer":false,"name":"Microondas","parentcategoryid":116,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/microondas.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=126&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":37,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/37.jpg"},"hasoffer":false,"name":"Projetor Multimídia","parentcategoryid":2,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/projetor-multimidia.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=37&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":5839,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/5839.jpg"},"hasoffer":false,"name":"Auto-Rádio CD Player","parentcategoryid":1,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/auto-radio-cd-player.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=5839&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":119,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/119.jpg"},"hasoffer":false,"name":"Aspirador de Pó / Água","parentcategoryid":116,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/aspirador-de-po-agua.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=119&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":145,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/145.jpg"},"hasoffer":false,"name":"Forno Elétrico","parentcategoryid":116,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/forno-eletrico.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=145&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":6507,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/6507.jpg"},"hasoffer":false,"name":"Adega Climatizada","parentcategoryid":116,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/adega-climatizada.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=6507&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":3737,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/3737.jpg"},"hasoffer":false,"name":"HD","parentcategoryid":2,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/hd.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=3737&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":8727,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/8727.jpg"},"hasoffer":false,"name":"Pen Drive","parentcategoryid":2,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/pen-drive.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=8727&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":3429,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/3429.jpg"},"hasoffer":false,"name":"Mouse","parentcategoryid":2,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/mouse.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=3429&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":22,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/22.jpg"},"hasoffer":false,"name":"PC","parentcategoryid":2,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/pc.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=22&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":3482,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/3482.jpg"},"hasoffer":false,"name":"Livros","parentcategoryid":3482,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/livros.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=3482&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":80,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/80.jpg"},"hasoffer":true,"name":"Outros Acessórios para Celular e Smartphone","parentcategoryid":6420,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/outros-acessorios-para-celular-e-smartphone.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=80&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":4699,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/4699.jpg"},"hasoffer":true,"name":"Carregador para Celular e Smartphone","parentcategoryid":6420,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/carregador-para-celular-e-smartphone.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=4699&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":9937,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/9937.jpg"},"hasoffer":true,"name":"Fonte para Notebook","parentcategoryid":2,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/fonte-para-notebook.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=9937&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":6359,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/6359.jpg"},"hasoffer":true,"name":"Jaqueta Feminina","parentcategoryid":2468,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/jaqueta-feminina.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=6359&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":4666,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/4666.jpg"},"hasoffer":true,"name":"Bateria para Celular e Smartphone","parentcategoryid":6420,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/bateria-para-celular-e-smartphone.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=4666&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":2921,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/2921.jpg"},"hasoffer":true,"name":"CDs","parentcategoryid":2921,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/cds.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=2921&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":9938,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/9938.jpg"},"hasoffer":true,"name":"Bateria para Notebook","parentcategoryid":2,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/bateria-para-notebook.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=9938&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":9941,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/9941.jpg"},"hasoffer":true,"name":"Outros Acessórios para Notebook","parentcategoryid":2,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/outros-acessorios-para-notebook.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=9941&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":4671,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/4671.jpg"},"hasoffer":true,"name":"Fone de Ouvido para Celular e Smartphone","parentcategoryid":6420,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/fone-de-ouvido-para-celular-e-smartphone.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=4671&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":4667,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/4667.jpg"},"hasoffer":true,"name":"Capa para Celular e Smartphone","parentcategoryid":6420,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/capa-para-celular-e-smartphone.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=4667&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":9469,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/9469.jpg"},"hasoffer":true,"name":"Cabo de Dados para Celular e Smartphone","parentcategoryid":6420,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/cabo-de-dados-para-celular-e-smartphone.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=9469&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":7918,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/7918.jpg"},"hasoffer":true,"name":"Câmera de Segurança","parentcategoryid":2701,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/camera-de-seguranca.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=7918&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":10800,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/10800.jpg"},"hasoffer":true,"name":"Óculos 3D","parentcategoryid":1,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/oculos-3d.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=10800&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":18,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/18.jpg"},"hasoffer":false,"name":"MP3 Player / MP4 Player","parentcategoryid":1,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/mp3-player-mp4-player.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=18&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":8241,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/8241.jpg"},"hasoffer":true,"name":"Outros Serviços em Construção Civil","parentcategoryid":5845,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/outros-servicos-em-construcao-civil.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=8241&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":16,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/16.jpg"},"hasoffer":false,"name":"Fone de Ouvido / Headset","parentcategoryid":1,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/fone-de-ouvido-headset.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=16&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":103,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/103.jpg"},"hasoffer":false,"name":"WebCam","parentcategoryid":2,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/webcam.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=103&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":4669,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/4669.jpg"},"hasoffer":true,"name":"Kit Viva Voz para Celular e Smartphone","parentcategoryid":6420,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/kit-viva-voz-para-celular-e-smartphone.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=4669&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":2947,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/2947.jpg"},"hasoffer":false,"name":"Mochila","parentcategoryid":1328,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/mochila.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=2947&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":4632,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/4632.jpg"},"hasoffer":true,"name":"Outros Acessórios para Áudio / Vídeo","parentcategoryid":1,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/outros-acessorios-para-audio-video.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=4632&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":75,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/75.jpg"},"hasoffer":false,"name":"Roteador","parentcategoryid":2,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/roteador.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=75&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":7356,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/7356.jpg"},"hasoffer":true,"name":"Assistência Técnica de Equipamentos de Informática","parentcategoryid":5845,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/assistencia-tecnica-de-equipamentos-de-informatica.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=7356&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":6399,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/6399.jpg"},"hasoffer":false,"name":"Auto-DVD Player","parentcategoryid":1,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/auto-dvd-player.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=6399&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":3772,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/3772.jpg"},"hasoffer":false,"name":"Aparelho Telefônico","parentcategoryid":6420,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/aparelho-telefonico.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=3772&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":172,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/172.jpg"},"hasoffer":true,"name":"Leitor de Cartão de Memória","parentcategoryid":2,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/leitor-de-cartao-de-memoria.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=172&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":9532,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/9532.jpg"},"hasoffer":true,"name":"Imóveis Residenciais","parentcategoryid":9549,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/imoveis-residenciais.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=9532&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":7985,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/7985.jpg"},"hasoffer":true,"name":"Serviços em Pisos","parentcategoryid":5845,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/servicos-em-pisos.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=7985&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":7349,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/7349.jpg"},"hasoffer":true,"name":"Assessoria Contábil","parentcategoryid":5845,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/assessoria-contabil.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=7349&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":7334,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/7334.jpg"},"hasoffer":true,"name":"Aluguel de Automóvel","parentcategoryid":5845,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/aluguel-de-automovel.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=7334&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":52,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/52.jpg"},"hasoffer":false,"name":"Cartão de Memória","parentcategoryid":2,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/cartao-de-memoria.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=52&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":62,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/62.jpg"},"hasoffer":false,"name":"Caixa de Som para PC","parentcategoryid":2,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/caixa-de-som-para-pc.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=62&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":111,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/111.jpg"},"hasoffer":false,"name":"Vídeo Cassete","parentcategoryid":1,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/video-cassete.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=111&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":2782,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/2782.jpg"},"hasoffer":true,"name":"Controle Remoto","parentcategoryid":1,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/controle-remoto.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=2782&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":4029,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/4029.jpg"},"hasoffer":true,"name":"Suplementos Nutricionais Esportivos","parentcategoryid":1328,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/suplementos-nutricionais-esportivos.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=4029&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":2794,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/2794.jpg"},"hasoffer":true,"name":"Massageador Elétrico","parentcategoryid":249,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/massageador-eletrico.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=2794&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":7606,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/7606.jpg"},"hasoffer":true,"name":"Música Digital","parentcategoryid":7606,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/musica-digital.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=7606&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":7157,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/7157.jpg"},"hasoffer":true,"name":"Apostila para Concursos / Cursos","parentcategoryid":6108,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/apostila-para-concursos-cursos.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=7157&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":6976,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/6976.jpg"},"hasoffer":false,"name":"Mala","parentcategoryid":2468,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/mala.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=6976&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":10369,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/10369.jpg"},"hasoffer":true,"name":"Lâmpada para Projetor","parentcategoryid":2,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/lampada-para-projetor.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=10369&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":9825,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/9825.jpg"},"hasoffer":false,"name":"Carros","parentcategoryid":3841,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/carros.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findProductList/564771466d477a4458664d3d/br/?categoryId=9825&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":10586,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/10586.jpg"},"hasoffer":true,"name":"Outros Acessórios para Aparelhos Telefônicos","parentcategoryid":6420,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/outros-acessorios-para-aparelhos-telefonicos.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=10586&keyword=lg&format=json"}}],"isfinal":true}},{"subcategory":{"id":7444,"thumbnail":{"url":"http://imagem.buscape.com.br/bp5/categorias/7444.jpg"},"hasoffer":true,"name":"Tela de Projeção","parentcategoryid":1,"links":[{"link":{"type":"category","url":"http://compare.buscape.com.br/tela-de-projecao.html?mdapp=100&mddtn=69672797"}},{"link":{"type":"xml","url":"http://sandbox.buscape.com/service/findOfferList/564771466d477a4458664d3d/br/?categoryId=7444&keyword=lg&format=json"}}],"isfinal":true}}],"totalresultsavailable":65,"totalresultsreturned":65}

Para converter os dados do retorno, vamos utilizar a classe JavaScriptSerializer presente no namespace System.Web.Script.Serialization do .NET, portanto não esqueçam de utilizar a diretiva using com esse namespace antes de iniciar.

Após instanciar um objeto da classe JavaScriptSerializer, vamos utilizar o método Deserialize<T>() para transformar o objeto JSON principal em um objeto do tipo Dictionary<string, object>. Depois vamos pegar o nó subcategory do JSON, indexando o objeto Dictionary criado.

JavaScriptSerializer deserializer = new JavaScriptSerializer();
Dictionary<string, object> data = deserializer.Deserialize<Dictionary<string, object>>(categoryList);
ArrayList subcategories = (ArrayList)data["subcategory"];

Como temos vários objetos JSON dentro de subcategory, ele nos retorna um tipo ArrayList com todas as categorias retornadas. Devemos, então, percorrer esse objeto para tratar cada atributo das categorias.

foreach (Dictionary<string, object> sub in subcategories)
{
// Aqui pegamos cada um dos atributos
}

A primeira coisa que vamos fazer é instanciar um objeto do tipo Dictionary<string, object> para receber os dados da categoria.

Dictionary<string, object> subData = (Dictionary<string, object>)sub["subcategory"];

A forma que acessamos os atributos do objeto convertido é indexanda ao objeto com o nome do atributo que desejamos – por exemplo para recuperar o nome da categoria usamos subData[“name”]. Simples, não?

Para não dizer que é tão simples assim, temos dois atributos que vamos ter um pouco mais de trabalho para recuperar seu valor: o thumbnail e a url. Para o thumbnail, com apenas mais um índice conseguimos seu valor. Já para a URL teremos algumas linhas a mais para conseguir:

// Recuperando o link para imagem da categoria
Dictionary<string, object> thumbnail = (Dictionary<string, object>)subData["thumbnail"];

// Recuperando a URL para os produtos da categoria
ArrayList links = (ArrayList)subData["links"];
Dictionary<string, object> productLink = (Dictionary<string, object>)links[1];
Dictionary<string, object> link = (Dictionary<string, object>)productLink["link"];

Pronto, com esses dois últimos atributos setados, podemos exibir os dados de retorno:

Response.Write(string.Format("<img src=\"{0}\" alt=\"{1}\" /> <br />", thumbnail["url"], subData["name"]));
Response.Write(string.Format("Categoria: {0} - {1} <br />", subData["id"], subData["name"]));
Response.Write(string.Format("Link para os produtos: <a href=\"{0}\">{0}</a> <br />", link["url"]));
Response.Write(string.Format("Tem Oferta: {0} - ID categoria pai: {1} - é final? {2} <br />", subData["hasoffer"], subData["parentcategoryid"], subData["isfinal"]));
Response.Write("<hr />");

É isso aí pessoal! Dessa forma, conseguimos trabalhar com o retorno em JSON da API do Buscapé utilizando somente as classes padrões do framework .NET, sem a necessidade de um componente extra. Abaixo, deixo o código completo utilizado neste artigo para não ficar nenhuma dúvida.

// Recuperando os dados em JSON
Apiki_Buscape_API.Apiki_Buscape_API apiBuscape = new Apiki_Buscape_API.Apiki_Buscape_API("564771466d477a4458664d3d", string.Empty, "BR", "json");
string categoryList = apiBuscape.FindCategoryList(null, "LG", string.Empty);

// Convert o JSON em uma coleção do tipo Dictionary e separa somente o nó subcategory em um array list
JavaScriptSerializer deserializer = new JavaScriptSerializer();
Dictionary<string, object> data = deserializer.Deserialize<Dictionary<string, object>>(categoryList);
ArrayList subcategories = (ArrayList)data["subcategory"];

foreach (Dictionary<string, object> sub in subcategories)
{
Dictionary<string, object> subData = (Dictionary<string, object>)sub["subcategory"];

// Recuperando o link para imagem da categoria
Dictionary<string, object> thumbnail = (Dictionary<string, object>)subData["thumbnail"];

// Recuperando a URL para os produtos da categoria
ArrayList links = (ArrayList)subData["links"];
Dictionary<string, object> productLink = (Dictionary<string, object>)links[1];
Dictionary<string, object> link = (Dictionary<string, object>)productLink["link"];

Response.Write(string.Format("<img src=\"{0}\" alt=\"{1}\" /> <br />", thumbnail["url"], subData["name"]));
Response.Write(string.Format("Categoria: {0} - {1} <br />", subData["id"], subData["name"]));
Response.Write(string.Format("Link para os produtos: <a href=\"{0}\">{0}</a> <br />", link["url"]));
Response.Write(string.Format("Tem Oferta: {0} - ID categoria pai: {1} - é final? {2}

Anunciado o lançamento da jQuery Foundation

Fonte: IMasters

Com informações de Linux-Under.org

O Conselho jQuery e o Software Freedom Conservancy anunciaram ontem, dia 07/03, o lançamento da jQuery Foundation. A nova organização independente irá gerenciar todos os assuntos relacionados a jQuery, incluindo os seus projetos.

O Presidente da Fundação será Dave Methvin, que já se pronunciou a respeito e disse que o sistema é a mais popular biblioteca JavaScript. “A criação de uma organização autônoma, será o próximo passo para garantir seu desenvolvimento futuro e beneficiar a todos que utilizam o jQuery”, afirmou.

Methvin também afirmou, que a Fundação anunciará várias iniciativas e conferências, que estão planejadas para serem realizadas em breve. A Fundação jQuery é uma associação comercial sem fins lucrativos, que se dedica a apoiar os diversos projetos da plataforma de mesmo nome (Core, UI e Mobile), fornecendo uma importante documentação e suporte, e ajudando a construir a comunidade jQuery, de forma sólida e com credibilidade.

JavaScript e linguagens de pré-compilação

Texto em resposta ao artigo Criar aplicativos web não precisa ser uma tarefa cansativa e irritante

Fonte: Leo Balter/IMasters

Eu sei que JavaScript não é uma linguagem que vai agradar a todo mundo, mas é a linguagem que roda nativamente em qualquer navegador com uma performance que não deixa nada a desejar. O que poderiam reclamar do JavaScript seria no máximo a sintaxe. Particularmente é questão de gosto.

Problemas? Todas as linguagens têm. Porém, como todas que têm uma boa comunidade ativa, ganham melhorias e novas características bem interessantes, assim como as APIs do HTML5 que já estão por aí e o ECMAScript 6 que vai trazer ótimas novidades.

Mesmo considerando toda a questão de gostos pessoais – e respeito muito isso – ainda acho que não podemos fugir da busca pela qualidade para atender uma vontade individual.

Ou seja, assim como para fazermos o melhor não deixamos de escrever em Java para apps de Android, em Objective-C para apps de iPhone, em Ruby para apps em Rails, utilizar qualquer outra pré-linguagem que compile para JavaScript para execução em navegador é algo que não parece ser a melhor opção.

A melhor linguagem que pode ser compilada para JavaScript é o próprio JavaScript. Tenho certeza das minhas interações pelo código e da qualidade do mesmo, assim como posso encontrar outro profissional bom na linguagem para entender o que está acontecendo. Estaríamos falando da mesma linguagem e a qualidade no código seria um facilitador para essa colaboração.

Outro ponto que acredito ser crucial: não somos únicos. Quando um programador sai da empresa, morre ou esteja em qualquer situação em que não escreva mais o código de determinada aplicação ele simplesmente não leva o código junto com ele, a menos que aquilo seja intencional.

O legado de um código é ensinar para uma pessoa nova aquilo o que está acontecendo. Se eu preciso de um novo profissional quando tenho um aplicativo em CoffeScript, qual linguagem eu devo exigir dele? CoffeScript, Javascript ou as duas?

O dia que encontrar um profissional que saiba apenas CoffeScript, vou acreditar que ele é totalmente incompleto e que teria o mesmo nível de quem somente aprendeu pseudo-código, sem me importar com o tempo que ele possui de experiência.

Como ele vai entender a real situação do meu aplicativo e todos os pontos que poderíamos melhorar? Como ele vai saber se tem ali um JavaScript bem escrito e funcional?

Em outras palavras, usar linguagens de pré-compilação me parece um verdadeiro “eXtreme Go Horse”, do tipo que se funcionar, tudo bem, não se importando com o que estiver no meio do caminho.

Como otimizar códigos jQuery e aumentar a performance do front-end

Este é um artigo traduzido do original Your JQuery: Now With 67% Less Suck, do blog 24 ways – e sofreu pequenas adaptações.

Fonte: DesenvolvimentoparaWeb

Otimizar códigos jQuery em um site significa aumentar sua performance. E, como qualquer desenvolvedor web deveria saber, os componentes e recursos do front-end são responsáveis por, pelo menos, 80% da performance de páginas web!

O jQuery, em relação a JavaScript “puro”, já é bem simples de se aprender e possui uma gama de recursos incrível! Entretanto, principalmente quem está começando e/ou ainda não entendeu bem a dinâmica da biblioteca, desconhece alguma dicas simples que, se aplicadas, garantem que o desempenho seja aumentado escrevendo menos código! É isso que vamos ver neste artigo e aprender como melhorar códigos jQuery para conseguir um desempenho melhor.

1. Otimização de seletores

Para começar, vejamos como é possível otimizar os seletores no jQuery, otimizando as consultas realizadas e aumentando a performance do código.

1.1. Velocidade de seletores

Muito do poder do jQuery vem de sua capacidade de selecionar elementos DOM e agir/interagir com eles através de seus selectors e, através deles, o jQuery provê uma tonelada de maneiras de escolher qual(is) elemento(s) em uma página se quer trabalhar. No entanto, um número surpreendente de desenvolvedores web não sabe que os seletores não são todos iguais e que é incrível a diferença de desempenho entre 2 seletores que, à primeira vista, parecem quase idênticos.

Como exemplo, vejamos 2 maneiras de selecionar todas as tags de parágrafo dentro de uma div com id específico:

$('#id p');

$('#id').find('p');

É surpreendente o fato de que a segunda maneira pode ser 2 vezes mais rápida!

Há muitas maneiras diferentes de selecionar elementos usando jQuery; estas podem ser (virtualmente) divididas em 5 diferentes métodos. Em ordem, do mais rápido para o mais lento, são:

  • $(‘#id’). Sem dúvidas, este é o selector mais rápido, já que mapeia diretamente o document.getElementbyId() nativo do JavaScript. Sempre que possível, os seletores descendentes devem ser feitos com um seletor de ID conjuntamente ao método .find(), que limita o escopo do que está sendo pesquisado (tal como no exemplo $(‘#id’).find(‘p’) anterior).
  • $(‘p’), $(‘input’), $(‘form’), […]. Selecionar elementos pelo nome da tag também é rápido, já que mapeia diretamente para o método nativo document.getElementsByTagname().
  • $(“.class”). Selecionar por nome de classes é um pouco mais custoso. Enquanto isso é executado muito bem por navegadores modernos, pode ser que uma lentidão seja causada em versões do IE baixo da 9. Por quê? Porque o IE9 foi a primeira versão do Internet Explorer a dar suporte para a função document.getElementsByClassName(), nativa do JavaScript. Para interpretar isso, browsers mais antigos têm de recorrer ao usos de artifícios bem mais custosos, que realmente afetam o desempenho do seletor.
  • $(‘[attribute=”value”]’). Não há nenhum método JavaScript nativo para este tipo seletor, então, a única maneira que pode realizar essa busca, é procurar por todo o DOM em busca de combinações que satisfaçam à condição do seletor. Navegadores modernos que suportam o método querySelectorAll() terão um desempenho melhor em certos casos, mas, em geral, este tipo de seletor é bastante lento.
  • $(‘:hidden’). Assim como o caso anterior, não existe um método JavaScript nativo para usar este tipo de seletor. Pseudo-seletores podem ser extremamente lentos, já que a consulta tem que ser executada em cada elemento da página. Novamente, navegadores modernos que suportam o método querySelectorAll() se saem ligeiramente melhores, mas tente evitar este tipo de seleção. Se realmente for necessário, é possível amenizar um pouco usando o .find(), como visto anteriormente. Por exemplo: $(‘#list’).find(‘:hidden’).

1.2. Encadeamento

Quase todos os métodos jQuery retornam um objeto jQuery. Isto significa que, quando um método é executado, seus resultados são retornados e é possível continuar a implementação de mais métodos em sequência, o que é conhecido como encadeamento ou chaining. Ao invés de escrever o mesmo seletor várias vezes, esta característica da biblioteca permite que várias ações possam ser executadas de uma vez.

Sem encadeamento:

$('#object').addClass('active');
$('#object').css('color','#F0F');
$('#object').height(300);

Com encadeamento:

$('#object').addClass('active').css('color','#F0F').height(300);

Isto tem um duplo efeito ao tornar seu código mais curto e mais rápido. Métodos encadeados são executados mais rapidamente do que vários métodos de um seletor em cache e, de ambos os jeitos, são muito mais rápidos que vários métodos através de seletores sem cache. Mas, esperem… “Seletor em cache”? O que é isso?

1.3. Seletores em cache

Outra maneira fácil de melhorar a performance do código jQuery – e que parece ser um mistério para a maioria dos desenvolvedores – é a ideia de fazer cache de seletores. Pense em quantas vezes você acaba escrevendo o mesmo seletor em seus códigos. Cada $(‘.element’) tem que varrer todo o DOM procurando por combinações o tempo todo, independentemente se este seletor tenha sido executado antes. Executando a seleção uma vez e depois guardando o(s) resultado(s) em uma variável, significa que a busca no DOM tem que ser feita apenas uma única vez. Uma vez que os resultados de um seletor tem sido armazenada em cache, é possível fazer qualquer coisa com eles.

Primeiro, executa-se o seletor desejado (como exemplo, pegar todos os li dentro de uma ul de id “blocks”):

var blocks = $('#blocks').find('li');

Agora, é possível usar a variável blocks em qualquer lugar que se queira, sem ter que percorrer todo o DOM novamente em cada vez:

$('#hideBlocks').click(function(){
    blocks.fadeOut();
});
$('#showBlocks').click(function(){
    blocks.fadeIn();
});

Portanto, fica essa preciosa dica: qualquer seletor que é executado mais de uma vez deve ser armazenado em cache! Veja este teste no jsperf que mostra o quão mais rápido e eficiente é um seletor cacheado em detrimento a um não cacheado.

2. Delegação de Evento ou Event Delegation

Event listeners consomem memória. Em sites e aplicações complexos não é incomum ter um monte de event listeners implementados e, felizmente, jQuery fornece métodos realmente fáceis para umaa gestão eficiente event listeners através da delegação.

Num exemplo extremo, imagine uma situação em que uma tabela 10×10 precisa ter um event listener em cada uma de suas células para que, quando ocorrer um clique em alguma delas, seja adiciona ou removida uma classe que define a cor de fundo da respectiva célula. Uma maneira comum de implementar isso (e algo bastante comum de ser visto em códigos jQuery) é:

$('table').find('td').click(function() {
    $(this).toggleClass('active');
});

O jQuery, a partir de sua versão 1.7, passou a oferecer um novo método de escuta de eventos: .on(). Ele age como um utilitário que envolve todos os event listeners anteriores do jQuery em um único e conveniente método e a forma que ele é implementado determina como ele se comporta. Ao reescrever o exemplo acima usando .on(), tem-se o seguinte:

$('table').find('td').on('click',function() {
    $(this).toggleClass('active');
});

Bastante simples, certo? Mas o problema aqui é que, mesmo com a mudança, o código ainda conta com um event listener para cada célula da tabela… Uma maneira muito melhor de fazer isso funcionar é criar um único event listener para monitorar os eventos na própria tabela! Uma vez que a maioria dos eventos faz bubbling (vai percorrendo seus ancestrais em sequência) na árvore do DOM, é possível vincular um único listener para um elemento (neste caso, table) e esperar eventos serem disparados a partir de seus descendentes. A melhor maneira de fazer isso usando o .on() é:

$('table').on('click', 'td', function() {
    $(this).toggleClass('active');
});

Com essa mudança simples, o número de event listeners passou de 100 (10×10 células da tabela) para 1! Acredite: a diferença de performance entre os 2 exemplos acima é impressionante!

Se você está usando alguma versão do jQuery abaixo da 1.7, é possível fazer a mesma coisa usando .delegate(). A sintaxe é diferente, mas uma consulta à documentação vai esclarecer as coisas.

3. Manipulação de DOM

Com jQuery é fácil de manipular o DOM. É trivial criar novos nós, inserir, retirar outros, mudar as coisas ao redor e assim por diante. o código para fazer isso é simples de escrever, mas, toda vez que o DOM é manipulado, o navegador tem que revisar o DOM, o que pode ser muito custoso e impactar a performance do front-end. Um exemplo evidente em que isso acontece é em um loop longo, seja através de um loop for(), while() ou $.each().

Como exemplo, vamos supor que existe um array cheio de URLs de imagens de um banco de dados ou alguma chamada em AJAX e, o que se pretende, é colocar todas essas imagens numa lista não ordenada. Comumente, o código que se encontra para isso é:

var arr = [reallyLongArrayOfImageURLs];
 
$.each(arr, function(count, item) {
    var newImg = '<li><img src="' + item + '"></li>';
    $('#imgList').append(newImg);
});

Existem alguns problemas com isso. Para começar, há a seleção de $(‘#ImgList’) em cada iteração do loop – e, como vimos anteriormente, isso não é nada bom para a performance. O outro problema é que, a cada vez que o loop repete, é adicionado um novo li ao DOM. Cada uma dessas inserções consome recursos e, se o array é muito grande, isso poderia levar a uma grande perda de performance ou, até mesmo, ao temido alerta “Um script desta página está tornando a página lenta”…

Uma outra maneira de implementar a solução é:

var arr = [reallyLongArrayOfImageURLs],
    tmp = '';
 
$.each(arr, function(count, item) {
    tmp += '<li><img src="' + item + '"></li>';
});
 
$('#imgList').append(tmp);

O que foi feito, aqui, foi a criação de uma variável tmp para receber cada li criado. Quando o loop termina, a variável contém todos os itens de lista na memória e estes podem ser anexados ao ul todos de uma vez! Como navegadores trabalham melhor com operações de objetos na memória ao invés de diretamente atualizando o DOM a cada vez, este código é bem mais rápido e eficiente!

4. Conclusão

Logicamente, estas dicas de como otimizar códigos jQuery para aumentar a performance do front-end não são as únicas existentes, mas, certamente, estão dentre as mais simples de implementar. Embora algumas das mudanças, individualmente, façam apenas alguns milésimos de segundo de diferença, ao somar isso, dependendo de sua aplicação, é possível ter um aumento de performance de quase 70%!

Estudos mostram que o olho humano é capaz de discernir delays de 100ms (!), portanto, fazer algumas mudanças no código pode, facilmente, ter um efeito notável sobre o modo (e a percepção) de quão bem um seu site ou aplicativo é executado.

Introdução: JSON

Afinal, o que é JSON?

JSON é basicamente um formato leve de troca de informações/dados entre sistemas. Mas JSON significa JavaScript Object Notation, ou seja, só posso usar com JavaScript correto? Na verdade não e alguns ainda caem nesta armadilha.

O JSON além de ser um formato leve para troca de dados é também muito simples de ler. Mas quando dizemos que algo é simples, é interessante compará-lo com algo mais complexo para entendermos tal simplicidade não é? Neste caso podemos comparar o JSON com o formato XML.

Vamos visualizar esta diferença?


XML

<?xml version="1.0" encoding="UTF-8"?>
  <id>1</id>
  <nome>Alexandre Gama</nome>
  <endereco>R. Qualquer</endereco>
</xml>

JSON

{"id":1,"nome":"Alexandre Gama", "endereco":"R. Qualquer"}

Bom, é notável a diferença. Visualmente o segundo trecho (em JSON) é mais fácil de ler. Mas só existe essa diferença entre os dois? Na verdade não. Podemos listar algumas outras vantagens:

Vantagens do JSON:

– Leitura mais simples

– Analisador(parsing) mais fácil

– JSON suporta objetos! Sim, ele é tipado!

– Velocidade maior na execução e transporte de dados

– Arquivo com tamanho reduzido

– Quem utiliza? Google, Facebook, Yahoo!, Twitter…

Estas são algumas das vantagens apresentadas pelo JSON. Agora vamos ao que interessa: Código!

Vamos fazer um exemplo extremamente simples nesta primeira parte e avançaremos no próximo artigo, inclusive falando sobre JSON em páginas Web.

Qual biblioteca usar?

Existem diversas bibliotecas para trabalharmos com JSON e Java. Usaremos no nosso estudo o json.jar que você pode baixar tranquilamente neste link

O nosso caso de estudo será simples: Teremos uma classe Carro que será a nossa classe POJO e a classe EstudoJSON que terá o nosso famoso método main.

Classe Carro

package br.com.json;

public class Carro {
    private Long id;
    private String modelo;
    private String placa;

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getModelo() {
        return modelo;
    }
    public void setModelo(String modelo) {
        this.modelo = modelo;
    }
    public String getPlaca() {
        return placa;
    }
    public void setPlaca(String placa) {
        this.placa = placa;
    }

        //Aqui fizemos o Override do método toString() para visualizar a impressão com o System.out.println()
    @Override
    public String toString() {
        return "[id=" + id + ", modelo=" + modelo + ", placa=" + placa
                + "]";
    }

}

Esta é uma classe simples, onde temos os atributos Id, Modelo e Placa.

Agora teremos a classe EstudoJSON

package br.com.json;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class EstudoJSON {
    public static void main(String[] args) throws JSONException {
        adicaoSimplesDeDados();
    }
}

Repare que criamos o método adicaoSimplesDeDados() que conterá o código de exemplo:

private static void adicaoSimplesDeDados() throws JSONException {
    //Criação do objeto carro e atribuição dos valores
    Carro carro = new Carro();
    carro.setId(1);
    carro.setModelo("Celta");
    carro.setPlaca("AAA1234");

    //Criação do objeto carroJson
    JSONObject carroJson = new JSONObject();
    //Inserção dos valores do carro no objeto JSON
    carroJson.put("id", carro.getId());
    carroJson.put("Modelo", carro.getModelo());
    carroJson.put("Placa", carro.getPlaca());

    //Impressão do objeto JSON
    System.out.println(carroJson);
}

Se executarmos este código, veremos que foi impresso no console o seguinte:

{"id":1,"Modelo":"Celta","Placa":"AAA1234"}

Você desenvolvedor mais atento vai reparar que existe um objeto impresso: Um Long! Isso mesmo! Como vimos, o JSON consegue armazenar objetos! Podemos inclusive armazenar um objeto do tipo Carro mesmo:

Modificamos o nosso método main:

public class EstudoJSON {
    public static void main(String[] args) throws JSONException {
        adicaoSimplesDeDados();

        adicaoDeUmObjeto();
    }
}

E adicionamos o método adicaoDeUmObjeto():

private static void adicaoDeUmObjeto() throws JSONException {
    Carro carro = new Carro();
    carro.setId(1l);
    carro.setModelo("Celta");
    carro.setPlaca("AAA1234");

    JSONObject carroJson = new JSONObject();
    //Adição do objeto carro
    carroJson.put("Carro", carro);

    System.out.println(carroJson);
}

Neste caso foi impresso no console o seguinte:

{"Carro":"[id=1, modelo=Celta, placa=AAA1234]"}

Simples não?

Como o JSON trabalha com coleção de pares nome/valor, podemos imprimir um valor específico simplesmente chamando o nome que desejamos.

System.out.println(carroJson.get("Modelo"));

Conclusão

É isso pessoal! Vimos as vantagens do JSON e vimos como é simples começar a trabalhar com ele.

Fonte: Alexandre Gama/devmedia

CoffeeScript 1.2.0 é disponibilizado

A versão 1.2.0 do CofeeScript, linguagem que converte arquivos CoffeeScript em JavaScript, foi disponibilizada. Ela traz uma sintaxe melhorada do JavaScript, inspirada em outras linguagens dinâmicas, mas o código do CoffeeScript é então compilado “one-to-one” para JavaScript para portabilidade. O resultado é um fragmento legível do JavaScript.

A atualização melhora os switches –watch ( que monitora arquivos para mudanças quando executa um comando como recompilação) e o –join (que pega o resultado do javaScript a partir da compilação e o transforma em um único arquivo) no comando coffee no coração do CoffeeScript.

Usuários agora podem adicionar e remover diretórios de uma pasta watched e usar os dois switches juntos. Outras mudanças incluem a habilidade de jogar uma exceção como parte de uma expressão, melhorias ao lidar com comentários, e correções para várias regressões encontradas na versão anterior, a 1.1.3.

O CoffeeScript está disponível para download a partir do site do CoffeeScript no GitHub, na qual os usuários podem encontrar uma introdução e documentação de referência para a linguagem, instruções de instalação, um guia para recursos e o change log. O CoffeeScript requer o Node.js para rodar o compilador e é publicado sob a licença MIT.

Com informações de The H

Fonte: IMasters

Javascript para fazer degrade/gradiente

Cada vez que eu vejo um layout com algum tipo de degrade chega a me dar coceira, me vejo recordando um png em milhares de pequenos pedacinhos para poder fazer os gradientes pq os navegadores ainda não implementaram o código de gradiente do css3, como a minha vida seria mais fácil.

Se funcionasse via css seria somente fazer algo assim:

.div_qualquer {
background: -webkit-gradient(linear, left top, left bottom, from(#dfdfdf), to(#f3f3f3));
background: -moz-linear-gradient(top,  #dfdfdf,  #f3f3f3);
}

Mas isto exclui o IE, e é bem difícil explicar aos clientes.

Outra forma é recortar uma imagem em 1px de largura ou altura, deixar ela bem comprida ou larga e usar ela como bg e replicar ela um montão de vezes, assim:

.div_qualquer {
background: url(images/background.png) top repeat-x;
}

Então pesquisando um pouco me surgiu uma opção usando jQuery muito simples que faz isto extremamente bem. Escrito pelo grande Brandon Aaron (contribuidor do jQuery) e fez o jquery-gradient, que de uma forma bem simples pode criar os gradientes para vc, mas ou menos desta forma:

<script type="text/javascript">
// <![CDATA[
    $(document).ready(function(){
         $('.div_qualquer').gradient({ from: 'dfdfdf', to: 'f3f3f3' });
    });
// ]]>
</script>

O que o script faz é criar um bando de divs de 1px diminuindo as cores aos pouquinhos para fazer o degrade linear. Realmente funciona bem para pequenos objetos, mas para objetos muito grandes pode ficar muito pesado e até travar o browser.

Fonte: Rafael Cirolini/NerdHead

Qual o local correto para adicionar scripts em seu site?

Outro dia, após publicar o artigo “Como Adicionar o Código do Google Analytics ao Blogger e WordPress” tivemos uma pequena discussão relacionada a qual parte do código da página, devemos adicionar o código de monitoramento do Google Analytics.

O correto seria adicionar perto da tag </body> que se encontra já no final do código da páginas, porém um dos visitantes perguntou: _ Porque no final?

Temos vários motivos para que o código do Google Analytics seja adicionado no final do código da página. Confira alguns deles.

Ps. Se você não tem idéia de como uma página é construída, recomendo que aperte o botão direito do mouse e clique em “Exibir código fonte” para que você não fique perdido durante o resto deste artigo.

Agilidade no carregamento

Os sites são carregados no computador dos visitantes de acordo com a sequência dos elementos presentes na página. Se você sobrecarregar o início do código da página, com elementos que deveriam estar no final, você poderá deixar o carregamento do que é realmente importante para o visitante mais lento. Conteúdo!

Melhor para SEO

Especialistas em SEO dizem que o Google indexa apenas uma determinada quantidade de KB da página e que todo o resto é ignorado. Por isso, se você deixar elementos desnecessários no começo, o indexador pode deixar de indexar o conteúdo ou outra coisa que seria mais vital para o posicionamento do site.

Monitoramento correto dos visitantes

Ao adicionar o código de monitoramento do Google Analytics no começo do código da página, você poderia coletar dados incorretos sobre os visitantes que acessam seu site, já que existem casos em que o carregamento da página é interrompido/travado por algum motivo ou o visitante desiste de acessar o site antes de carregar a página completamente.

Neste caso, como o código de monitoramento está mais perto do começo do código da página, ele poderia ser contabilizado, mesmo sem o visitante ter permanecido na página.

“É claro que isso não seria um problema se você deseja apenas ter números para aumentar seu EGO”.

Outros exemplos

Existem scripts que exigem que seus códigos sejam adicionados no local exato em que você deseja que ele apareça dentro da página, como é o caso de chats, contadores de visitas, players de músicas e etc.

Mas também existem alguns scripts, que independente do local da página em que você o adicione, ele sempre será exibido (seja lá o que for) em locais determinados pelo código fornecido pelo desenvolvedor. Um exemplo disso é a barra de ferramentas do Wibiya, que não importa se você o adicione no começo, meio ou fim da página. A barra sempre aparecerá no rodapé, exatamente como pode ser visto aqui no CriarSites.com.

Portanto, neste caso não faria sentido adicionar o código no começo do código da página, já que isso estaria atrapalhando o desempenho do site de diversas formas.

Conclusões

Cada script deve ser adicionado ao site de acordo com as especificações do fornecedor de forma que ele funcione corretamente e da melhor maneira. Portanto, recomendo que procure informações no site que fornece o script e que faça como ele descreve.

Fonte: Celso Lemes/CriarSities