Este documento descreve como criar uma listview dinâmica usando COBOL, MySQL e recursos de front-end para acessar e exibir dados de um banco de dados. Ele explica como configurar o ambiente de desenvolvimento, conectar ao banco de dados MySQL, gerar copybooks, escrever o programa CGI-COBOL e implementar funcionalidades como paginação usando cursores.
1. Cobol Web com Net Express 5.1 edition Acessando MySQL
Altair Borges
ListView com paginação, JavaScript, Css e MySQL
Neste tutorial, vou mostrar como criar uma listview usando Net Express 5.1 Edition para
acessar um database MySQL via ODBC. Grande parte dos recursos e conceitos aqui utilizados são os
mesmos do tutorial CobolWeb com Net Express 3.1 - parte 2. O NE será usado apenas para gerar os
copybooks de comunicação entre o database MySQL e o programa COBOL através do OpenESQL
Assistent, editar as regras de negócios e debugar. A interface ficará mais uma vez a cargo do
Dreamweaver. Quer usar outra IDE? Fique a vontade. Este projeto terá um formulário de login e
duas páginas dinâmicas criadas pelo CGI COBOL. Uma de mensagem de acesso negado ou erro de
conexão com o MySQL e a própria ListView.
Na interface serão usados recursos de HTML5 (alguns não suportados pelo IE8), Css e
funções JavaScript necessárias para manipulação dos eventos ocorridos na listview. O programa
CGI-COBOL utilizará CURSOR e as cláusulas LIMIT e OFFSET do MySQL para montar as páginas.
Será criado também um link dinâmico para acesso ao programa clientes.exe (a ser implementado
pelo amigo leitor) passando como parâmetro o código do cliente e a ação a ser executada.
A navegação poderá ser realizada clicando nos botões: página inicial, página
anterior próxima página e página final. O usuário também poderá digitar o número da
página desejada ou selecioná-la na listbox. Será mostrado o total de páginas e a quantidade de
registros da tabela. Abaixo, o formulário de login e a listview proposta no projeto.
2. Pre-processadores:
O Net Express possui os pré-processadores ESQL e EHTML que permitem acessar bases de dados
relacionais embutindo instruções SQL e código HTML dentro de seu programa COBOL.
Com o ESQL você pode acessar uma base de dados relacional através de um driver ODBC
embutindo instruções SQL dentro de seu programa COBOL.
O EHTML permite incluir páginas HTML completas como copyfiles dentro do seu programa
bem como, fragmentos de códigos HTML como copyfiles, ou de saída individuais declarações
HTML e construir uma página completa sob controle CGI-COBOL.
Ferramentas utilizadas no projeto:
Net Express 5.1
MySQL
Dreamweaver
Webserver Apache
Database SAKILA
Etapas:
Instalar ferramentas acima
Criar uma conexão ODBC
Criar formulário de login e de mensagem
Criar copybooks (cabec.html, detalhe.html e rodape.html)
Criar projeto vazio com o Net
Conectar ao database via OpenESQL
Testar conexão e gerar copybook customer.cpy a ser inserido do CGI-cobol
Escrever CGI-cobol
Compilar, testar e exportar para o Apache
3. 1ª Etapa - Instalar e testar as ferramentas necessárias
Database SAKILA (Criando e povoando o database)
a) Download: http://mysql-tools.com/downloads/mysql-databases/4-sakila-db.html
b) Descompacta o arquivo em C:TEMP
c) Entre no prompt de comando do MySQL e execute o seguinte comando: mysql -u root –p
d) Informe a senha
e) Execute a linha de commando mysql> SOURCE C:/temp/sakila-db/sakila-schema.sql;
f) Quit
2ª Etapa - Criar uma conexão ODBC
Este processo é bem simples mas para quem ainda não o fez, vamos aos procedimentos:
Painel de controle / Ferramentas administrativas / Fontes de dados ODBC / Fontes de
dados de sistema
4. Caso seu sistema não tenha o drive ODBC será necessário a instalação do mesmo.
5. 3ª Etapa - Criar formulário de login
Primeiramente crie a pasta de trabalho C:Net31Exemplo03. Se você tem um formulário
próprio e prefere usá-lo fique a vontade apenas altere a linha do link para action="/cgi-
bin/viewmysql.exe" e os nomes dos campos de entrada de dados para scrUsuario e scrSenha. Mas
antes de editar os códigos HTML é importante definir as imagens que serão utilizadas na página.
Neste exemplo, a pasta imagens (C:Net31Exemplo03imagens) contém os seguintes
arquivos:
6. Edite o arquivo login.html conforme código HTML abaixo e salve-o na pasta de trabalho
Dica: Use o (ctrl-c + ctrl-v) para copiar e colar os códigos deste tutorial.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<LINK rel=stylesheet href="/cobol/login.css">
<title>Cobol Web - Net Express 5.1 ListView MySQL</title>
<SCRIPT language=javaScript>
function validaForm(){
var frm = document.loginform;
if (frm.scrUsuario.value == "")
{
alert("Informe o Usuário");
frm.scrUsuario.focus();
}
else if (frm.scrSenha.value == "")
{
alert("Informe a senha");
frm.scrSenha.focus();
}
else
frm.submit();
}
</SCRIPT>
</head>
<body>
<div class="container">
<form action="/cgi-bin/viewmysql.exe" method="post" name="loginform" id="loginform"
class="rounded" >
<div class="style2">
<div align="center"><span class="style5"><img src="/cobol/imagens/ne.png" /> <span
class="style6">Cobol Web</span></span> - <span class="style3">Net Express 5.1 -
Listview acessando MySQL </span></div>
9. background: rgba(0, 0, 0, 0.6);
-moz-border-radius: 7px;
-webkit-border-radius: 7px;
border-radius: 7px;
}
.button{
float: right;
margin:10px 55px 10px 0;
font-weight: bold;
line-height: 1;
padding: 6px 10px;
cursor:pointer;
color: #fff;
text-align: center;
text-shadow: 0 -1px 1px #64799e;
/* Background gradient */
background: #a5b8da;
background: -moz-linear-gradient(top, #a5b8da 0%, #7089b3 100%);
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#a5b8da), to(#7089b3));
/* Border style */
border: 1px solid #5c6f91;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
/* Box shadow */
-moz-box-shadow: inset 0 1px 0 0 #aec3e5;
-webkit-box-shadow: inset 0 1px 0 0 #aec3e5;
box-shadow: inset 0 1px 0 0 #aec3e5;
}
.button:hover {
background: #848FB2;
cursor: pointer;
}
.style2 {color: #3333FF}
.style3 {
font-family: Geneva, Arial, Helvetica, sans-serif;
font-size: 16px;
color: #CC9933;
font-weight: bold;
}
.style5 {color: #3333FF; font-size: 24px; }
.style6 {font-size: 18px}
-->
</style>
Alguns recursos não foram suportados pelo IE8. Exemplo o mouseover nos campos de
entrada de dados.
4ª Etapa - Criar copybooks (cabec.html, detalhe.html e rodape.html). Todos deverão ser
salvos na pasta de trabalho C:Net31Exemplo03. A página dinâmica será composta por estes
fragmentos de códigos e será formatada pelo arquivo myCss.css. Existem também 8 funções
escritas em JavaScript que serão utilizadas na navegação da listview. São elas: setaPagina(),
setaPaginaDigitada(), anterior(), primeira(), seguinte(), ultima(), TABEnter() e Tecla() e que foram
iseridas no cabecalho da página.
cabec.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD>
10. <META content="text/html; charset=windows-1252" http-equiv=Content-Type>
<LINK rel=stylesheet href="/cobol/myCss.css">
<title>Cobol Web - Net Express 5.1 ListView MySQL</title>
<SCRIPT language=javaScript>
function TABEnter(oEvent){
var oEvent = (oEvent)? oEvent : event;
var oTarget =(oEvent.target)? oEvent.target : oEvent.srcElement;
if(oEvent.keyCode==13)
oEvent.keyCode = 9;
if(oTarget.type=="text" && oEvent.keyCode==13)
//return false;
oEvent.keyCode = 9;
if (oTarget.type=="radio" && oEvent.keyCode==13)
oEvent.keyCode = 9;
}
function Tecla(e)
{
var tecla = event.keyCode;
if(tecla > 47 && tecla < 58) // numeros de 0 a 9
return true;
else
{
if (tecla != 8) // backspace
return false;
else
return true;
}
}
function setaPagina()
{
document.form1.scrPagina.value =
document.form1.selectBox.options[document.getElementById("selectBox").selectedIndex]
.text;
document.form1.submit();
}
function setaPaginaDigitada()
{
//document.form1.scrPagina.value =
document.form1.selectBox.options[document.getElementById("selectBox").selectedIndex]
.text;
document.form1.submit();
}
function anterior()
{
if (document.form1.scrPagina.value > 1)
{
document.form1.scrPagina.value = document.form1.scrPagina.value - 1;
document.form1.submit();
}
}
function primeira()
{
document.form1.scrPagina.value = 1;
document.form1.submit();
}
function seguinte()
{
p = parseInt(document.form1.scrPagina.value);
u = parseInt(document.form1.scrPaginaFinal.value);
if (p < u)
11. {
p = p + 1;
document.form1.scrPagina.value = p;
document.form1.submit();
}
}
function ultima()
{
document.form1.scrPagina.value = document.form1.scrPaginaFinal.value;
document.form1.submit();
}
</SCRIPT>
<META name=GENERATOR content="MSHTML 8.00.6001.18702">
<style type="text/css">
<!--
.style1 {
color: #0000FF;
font-weight: bold;
}
-->
</style>
</HEAD>
<FORM method=post name=form1 action=/cgi-bin/viewmysql.exe>
<TABLE summary="Aplicação Cobol acessando MySql usando cursor para paginação">
<CAPTION style4>
Aplicação <span class="style1">Cobol Web</span> com Net
Express 5.1/ JavaScript / Css / MySQL <BR>
Listview acessando MySQL e usando cursor para paginação
</CAPTION>
<TBODY>
<TR bgColor=#cccccc>
<TD>
<DIV align=center>Id</DIV></TD>
<TD>
<DIV align=center>First_name</DIV></TD>
<TD>
<DIV align=center>Last_name</DIV></TD>
<TD>
<DIV align=center>E-mail</DIV></TD></TR>
Observe que falta o fechamento das tags </tabela>, </form> e </html>. Isto será realizado
no arquivo rodape.html. O conceito de página dinâmica é o mesmo de um relatório. Você escreve o
cabeçalho, lê o arquivo para imprimir as linhas de detalhes e por último imprime o rodapé.
detalhe.html
O arquivo detalhe.html deverá ficar dentro do loop do programa COBOL que gera a linha de
detalhe.
<Tr bgcolor=:corfundo>
<td align=center>:Id</td>
<td>:First_name</td>
<td align=center>:Last_name</td>
<td>:E-mail</td>
</Tr>
Os textos precedidos de dois pontos (:) são campos definidos na working-storage section e
na FD do programa viewmysql.cbl e que receberão dados dinamicamente.
:corfundo Cor da linha da tabela
:Id Id do cliente
12. :First_name Primeiro nome do cliente
:Last_name Sobrenome do cliente
:E-mail E-mail do cliente
rodape.html
</TABLE>
<style type="text/css">
<!--
.style9 {font-family: "Courier New", Courier, monospace}
.style14 {
color: #CC3300;
font-weight: bold;
}
.style18 {font-family: "Courier New", Courier, monospace; color: #CCCC00; }
-->
</style>
<table>
<tr bgcolor=#DDDDDD>
<td width="50"><img src="/COBOL/imagens/first.png" width="48" height="48"
border="0" title="Primeira página"
onClick="primeira()"
/></td>
<td width="51"><img src="/COBOL/imagens/left.png" width="48" height="48"
border="0" title="Página anterior"
onClick="anterior()"
/></td>
<td width="239">
<div align="center" class="style9">Página:
<input name="scrPagina" type="text" id="scrPagina" value=" 1" size="5"
maxlength="5" onchange="setaPaginaDigitada()"
title="Digite a página e tecle ENTER" onkeypress="return Tecla(event)"
onkeydown="TABEnter()"/>
de
<input name="scrPaginaFinal" type="text" disabled class="centraliza"
id="scrPaginaFinal" value=" 40" size="5" maxlength="5"
/>
</div></td>
<td width="51"><img src="/COBOL/imagens/right.png" width="48" height="48"
border="0" title="Página seguinte" onClick="seguinte()"
/></td>
<td width="52"><img src="/COBOL/imagens/last.png" width="48" height="48"
border="0" title="Última página" onClick="ultima()"
/></td>
<td width="72"><label>
<select id="selectBox" name="selectBox" onchange="setaPagina()">
end-exec
*> Código cobol dentro da páginha html
perform varying idx from 1 by 1 until idx > wTotalPaginas
if idx = f-scrPagina *> posiciona select <listbox) na página atual
String "<option value="'"' idx
'"' "selected>" f-scrPagina
"</option>"
Delimited by size into strSelect
else
String "<option value="'"' idx
'"' ">" idx
"</option>"
Delimited by size into strSelect
end-if
exec html
:strSelect
end-exec
end-perform
move wRegistros to maskPagina
13. String " Nº de Linhas: " maskPagina
Delimited by size into strTexto
exec html
</select>
</label></td>
<td width="186"><div align="left"><span class="style9">Lançamentos:</span><span
class="style14"> 599</span></div></td>
</tr>
<tr align="right">
<td colspan="7"> <span class="style18">By Altair Borges</span> </td>
</tr>
</table>
</body>
</html>
No rodapé foi inserido o fechamento das tags </tabela>, </form> e </html> além de um
perform para montagem da selectbox variando de acordo com a quantidade de páginas encontradas
em wTotalPaginas
Edite o arquivo myCss.css conforme código CSS abaixo e salve-o na pasta de trabalho
C:Net31Exemplo03
table{width:80%;
border-collapse:collapse;
margin:1em 0px;}
caption {
font-family: "Calibri";
background: #FFCC33;
font-size: 18px;
}
th, td {
font-family:"Courier New";
font-size:14px;
font-size-adjust:inherit
padding:.2em;
border:1px solid #fff;}
.centraliza {
text-align: center;
}
A estrutura da página dinâmica está pronta e será montada pela CGI COBOL.
5ª Etapa - Crie o projeto viewmysql vazio com o Net e conecte ao database via OpenESQL
O objetivo do projeto é usar a IDE do NE para editar e debugar.
14. Acessando o database SAKILA através do OpenESQL Assistent. Este aplicativo irá lhe auxiliar
na geração dos copybooks de código COBOL para acessar o database. Estes fragmentos podem ser
incluídos diretamento no programa cobol pelo Assistent.
15. O OpenESQL Assistent cria a estrutura de comunicação entre o programa COBOL e o
banco de dados. Se já existir um programa.cbl no projeto e você clicar ícone será
inserido o código fonte da query no fonte COBOL.
16. Clique em SQLCA e depois em Host Variable Declarations para gerar as áreas de
comunicação entre MySQL e Fonte COBOL.
6ª Etapa - Escrever o CGI-COBOL viewmysql
Crie um novo programa File / New / Program e salve-o como viewmysql.cbl.
Ele deverá ter o seguinte código:
$set preprocess(htmlpp)stephtml endp
$set sql(dbman=odbc, detectdate)
*----------------------------------------------------------------*
* Sistema: Projeto Exemplo do Livro COBOL WEB
* Função.: ListView - Net Express 5.l acessando MySQL via ODBC
*----------------------------------------------------------------*
program-id. viewmysql.
Author. Altair Borges /2012
configuration section.
special-names. decimal-point is comma.
working-storage section.
01 campos-auxiliares.
03 w-Msg pic x(90) value spaces.
03 wPagina pic 9(04) value 1.
03 wTotalPaginas pic 9(04) value zeros.
03 wRegistros pic 9(06) value zeros.
03 wPosicao pic 9(06) value zeros.
03 wQuantidade pic 9(02) value 15.
03 wResto pic 9(02) value zeros.
03 res pic x(01) value spaces.
03 idx pic 9(05) value zeros.
03 strSelect pic x(50).
03 strTexto pic x(20).
03 wLnk pic x(90).
03 wStatus pic zzzzz.
03 wcodigo pic zz.zzz.
03 maskPagina pic zzzzz.
03 maskPaginaFinal pic zzzzz.
03 ws-cnOdbc pic x(09) value "viewmysql".
*>----------------------------------------------------------------
*> The following field receives ESQL error messages wider than the
*> 70 bytes provided by the SQLCA field SQLERRMC
03 MFSQLMessageText pic x(256).
*> The name of the file used to store server state
03 state-filename pic x(255) value "MF-STATE-SAVE.DAT".
*> Status returned by state maintenance routines
17. 03 server-status pic x comp-x.
03 cores.
05 corFundo pic x(07) value spaces.
05 cor1 pic x(07) value "#e5f1f4".
05 cor2 pic x(07) value "#F0FFF0".
01 HTMLFormLogin is external-form.
03 f-scrUsuario pic x(15) identified by "scrUsuario".
03 f-scrSenha pic x(15) identified by "scrSenha".
01 HTMLFormView is external-form.
03 f-scrPagina pic 9(5) identified by "scrPagina".
03 f-scrPaginaFinal pic 9(5) identified by "scrPaginaFinal".
03 f-scrLinhas pic 9(5) identified by "scrLinhas".
EXEC SQL INCLUDE customer END-EXEC
EXEC SQL INCLUDE SQLCA END-EXEC
exec sql begin declare section end-exec
01 h-customer-id pic 9(04).
01 h-store-id pic 9(04).
01 h-first-name pic x(45).
01 h-last-name pic x(45).
01 h-email pic x(50).
01 h-address-id pic 9(04).
01 h-active pic 9(04).
01 h-create-date pic x(19).
01 h-last-update pic x(19).
exec sql end declare section end-exec.
Procedure division.
perform 1000-inicializa
perform 2000-validaAcesso
perform 3000-processa
perform 4000-finaliza
stop run.
*----------------
1000-inicializa.
call "sstate"
call "MF_CLIENT_STATE_FILE"
using state-filename server-status
accept htmlFormView
accept htmlFormLogin
if f-scrPagina = zeros
move 1 to f-scrPagina
end-if
move f-scrPagina to wPagina
maskPagina
move f-scrPaginaFinal to wTotalPaginas
move f-scrLinhas to wRegistros
Exit.
*------------------
2000-ValidaAcesso.
call "cbl_tolower" using f-scrUsuario by value 15
call "cbl_tolower" using f-scrSenha by value 15
String f-scrusuario "." f-scrsenha delimited by spaces
18. into w-msg
End-String
exec sql
connect to :ws-cnOdbc user :w-msg
* connect to 'viewMySql' user 'root.12345'
end-exec
if sqlcode not = 0
perform 2100-acessoNegado
perform 4000-finaliza
end-if.
* if sqlcode not = 0
* exec html
* <br><br><em>
* There was an error connecting to the
* database.>br><br>
* SQLSTATE = :sqlstate<br><br>
* SQL Error Message = :MFSQLMessageText<br><br>
* </em>
* </body>
* </html>
* end-exec
* exit program
* stop run
* end-if
Exit.
*------------------
2100-AcessoNegado.
exec html
copy "msgAcesso.html".
end-exec
Exit.
*--------------
3000-processa.
perform 3100-Cabecalho
perform 3200-leitura
Exit.
*---------------
3100-cabecalho.
exec html
copy "cabec.html".
end-exec
Exit.
*-------------
3200-leitura.
if f-scrPaginaFinal not equal zeros
perform 3210-posiciona-ponteiro
perform 3220-mostra-dados
Exit Paragraph
end-if
*> Pega a quantidade de linhas da tabela
if wRegistros = 0
exec sql
select count(*) into :wRegistros from `customer`
end-exec
19. move wRegistros to f-scrlinhas
*> Calcula o número de páginas
divide wRegistros by wQuantidade giving
wTotalPaginas remainder wResto
end-divide
if wResto > 0
add 1 to wTotalPaginas
end-if
move wTotalPaginas to f-scrPaginaFinal maskPaginaFinal
end-if
perform 3210-posiciona-ponteiro
perform 3220-mostra-dados
Exit.
*------------------------
3210-Posiciona-ponteiro.
compute wPosicao = (wQuantidade * wPagina) - wQuantidade
Exit.
*------------------
3220-Mostra-dados.
Exec sql
Declare csr1 cursor for select
`A`.`customer_id`
,`A`.`first_name`
,`A`.`last_name`
,`A`.`email`
from `customer` A order by `A`.`customer_id`
limit :wQuantidade offset :wPosicao;
End-exec
if sqlcode not = 0
perform 9000-msg-error
end-if
Exec sql
open csr1
End-exec
if sqlcode not = 0
perform 9000-msg-error
end-if
Perform until sqlcode not = zero
Exec sql
fetch csr1 into
:h-customer-id
,:h-first-name
,:h-last-name
,:h-email
End-exec
if sqlcode = 0
perform 3230-Detalhe
end-if
End-Perform
20. Exec sql
close csr1
End-exec
perform 3240-Rodape
Exit.
*-------------
3230-detalhe.
if corFundo = spaces or corFundo = cor1
move cor2 to corFundo
else
move cor1 to corFundo
end-if
initialize wlnk
String *> link p/ o programa clientes.exe a ser implementado
'<A href="/cgi-bin/clientes.exe?scrCodigo='
h-customer-id
'&scrAcao='"Pesquisa"'">'h-customer-id'</A>'
into wlnk
end-string
move h-customer-id to wcodigo
exec html
<Tr bgcolor=:corFundo>
<td width="15%" align=center> :wlnk </td>
<td width="40%"> :h-first-name </TD>
<td width="15%"align=center> :h-last-name </td>
<td width="30%"> :h-email </td>
</Tr>
end-exec
Exit.
*------------
3240-rodape.
exec html
copy "rodape.html".
end-exec
Exit.
*--------------
4000-finaliza.
perform 4100-disconecta
exit program
stop run
Exit.
*----------------
4100-disconecta.
exec sql
disconnect current
end-exec
Exit.
*---------------
9000-msg-Error.
move sqlcode to wStatus
exec html
<html>
Código do Erro: :wStatus :SQLERRMC
21. </html>
end-exec
perform 4000-finaliza
Exit.
*----------------------------Fim---------------------------------*
7ª Etapa Compilar
Nesta etapa será gerado o EXE e isto pode ser feito de duas formas: Usando a IDE do NE ou
através do Prompt de comando.
OPÇÃO (A): Usando a IDE do Net Express
22. EXE gerado é hora de configurar o Animate, mas antes, é preciso alterar a porta do
WebServer SOLO, pois ele por padrão usa a porta 80 a mesma que, neste caso, está sendo usada
pelo Apache. Altere para 8686, por exemplo. Menu / Options / Project
23. Carregue o SOLO Menu / Tools / Solo
O ícone aparecerá na bandeja do Windows
Dê um duplo Clique e verifique se a configuração está igual à figura abaixo:
Configurando o Animate Menu / Animate / Settings
24. Na caixa de texto Start Animating at informe: http://127.0.0.1/COBOL/login.html
Marque também a opção Wait for animatable attachment e clique em ok
Pressione F11 para animar ou F5 para executar
Executando no WebServer SOLO
Abra o browser e digite na URL o seguinte endereço:
http://127.0.0.1:8686/COBOL/login.html Onde 8686 é o número da porta.
Executando no WebServer Apache
Copie para a pasta C:Arquivos de programas Apache Software Foundation Apache2.2cgi-bin os
seguintes arquivos:
Viewmysql.exe c:Net31exemplo03debug
Cblrtss.dll C:Arquivos de programasMicro FocusNet Express 5.1BaseBin
Crie uma pasta chamada COBOL dentro da pasta htdocs C:Arquivos de programas Apache
Software Foundation Apache2.2htdocsCOBOL e copie para dentro dela:
O arquivo login.html origem: cNet31exemplo03
O arquivo login.css e myCss.css origem: c:Net31exemplo03
A pasta imagens origem: c:Net31exemplo03
25. Abra o browser e digite na URL o seguinte endereço:
http://localhost/COBOL/login.html
O resultado deverá ser este:
26. Até a próxima.
Livro
http://www.agbook.com.br/book/34170--Cobol_Web
Comentários e sugestões borgesaltair@hotmail.com 2011