Wednesday, December 17, 2008

Chamando Web Services sobre HTTPS

Utilizar web service sobre HTTPS é da mesma forma que um web service HTTP.

Adicionar a referência web ao projeto, com a url HTTPS.

O uso do web service a nível de código é a mesma coisa.

Só que ao tentar chamar o web service poderá acontecer de obter esta mensagem erro:

The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.

Colocando este código antes da chamada ao web sersvice provavelmente irá resolver o problema:


System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate
{
return true;
};


Basicamente é por que o .Net esta rejeitando o certificado por não ser um certificado válido, com o código acima, mesmo não sendo um certificado válido ele irá aceitar o certificado, e conseguirá comunicar com o web service.

Thursday, November 27, 2008

Script Python para consumir Web Services em .Net

Tive um desafio a poucos dias. Que foi consumir Web Services feitos em .Net a partir de um servidor Solaris 10 via processo.

De todas as soluções possíveis que estive a ver, a melhor foi usar Python.

Encontrei este exemplo:

http://users.skynet.be/pascalbotte/rcx-ws-doc/postxmlpython.htm

Assim fiz o WebServiceGenericClientNet.py:

#!/usr/bin/python

# by eduveks

import sys, httplib, array

try:
    host = ""
    url = ""
    namespace = ""
    header = ""
    method = ""
    params = {}

    for arg in sys.argv[1:]:
        if host == "" and arg.find("host=") == 0:
            host = arg[len("host="):]
        elif url  == "" and arg.find("url=") == 0:
            url  = arg[len("url="):]
        elif namespace == "" and arg.find("namespace=") == 0:
            namespace = arg[len("namespace="):]
        elif header == "" and arg.find("header=") == 0:
            header = arg[len("header="):]
        elif method == "" and arg.find("method=") == 0:
            method = arg[len("method="):]
        elif arg.find("param_") == 0:
            params[arg[len("param_"):arg.find("=")]] = arg[arg.find("=") + 1:]

    SOAP_Request = ""
    SOAP_Request += "<soap:Envelope"
    SOAP_Request += " soap:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\""
    SOAP_Request += " xmlns:xsi=\"http://www.w3.org/1999/XMLSchema-instance\""
    SOAP_Request += " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""
    SOAP_Request += " xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\">"
    if header != "":
        SOAP_Request += "<soap:Header>"
        SOAP_Request += header
        SOAP_Request += "</soap:Header>"
    SOAP_Request += "<soap:Body>"
    SOAP_Request += "<"+ method +" xmlns=\""+ namespace +"\">"
    for param in params.keys():
        SOAP_Request += "<"+ param +">"+ params[param] +"</"+ param +">"
    SOAP_Request += "</"+ method +">"
    SOAP_Request += "</soap:Body>"
    SOAP_Request += "</soap:Envelope>"

    http = httplib.HTTP(host)
    http.putrequest("POST", url)
    http.putheader("Host", host)
    http.putheader("User-Agent", "Python")
    http.putheader("Content-type", "text/xml; charset=\"UTF-8\"")
    http.putheader("Content-length", "%d" % len(SOAP_Request))
    http.putheader("SOAPAction", "\""+ namespace + method +"\"")
    http.endheaders()
    http.send(SOAP_Request)

    http_response_statuscode, http_response_statusmessage, http_response_header = http.getreply()
    SOAP_Response = http.getfile().read()
    if http_response_statuscode == 200 and http_response_statusmessage == "OK":
        print SOAP_Response[SOAP_Response.find("<"+ method +"Result>") + len("<"+ method +"Result>"):SOAP_Response.find("</"+ method +"Result>")]
    else:
        print "### ERROR ###############"
        if SOAP_Response.find("<faultstring>") > -1:
            print SOAP_Response[SOAP_Response.find("<faultstring>")  + len("<faultstring>"):SOAP_Response.find("</faultstring>")]
        print "Response: ", http_response_statuscode, http_response_statusmessage
        print http_response_header
        print SOAP_Response

except:
    print "### ERROR ###############"
    for err in sys.exc_info():
        print err


Para executar o script basta dar permissões de execução e executar:

chmod +x WebServiceGenericClientNet.py
./WebServiceGenericClientNet.py host=localhost url=/HelloWorld.asmx namespace=http://tempuri.org/ method=HelloWorld param_strSay=HelloWorld


O output é:

HelloWorld


Os parâmetros do WebServiceGenericClientNet.py são:

host: Endereço do servidor
url: Endereço do web service
namespace: Namespace do web service, que pode ser encontrado vendo o WSDL, http://localhost/HelloWorld.asmx?WSDL
method: Método do web service a ser chamado
param_*NOME_DO_PARAMETRO*: Caso o método precise de parâmetros, podem ser definidos assim, atenção a ordem.

Além de usar este script no Solaris, também acabei por usar este script para chamar web services apartir do .Net/C#, pois são web services que serão atualizados constantemente, com novos métodos e talz, e em vez de ficar atualizando o WSDL, basta chamar diretamente com o script a queima-roupa, e a configuração da chamada dos web services pode ser feita a partir de configurações em base de dados. Para fazer isto no .Net/C# foi só lançar um processo assim:

System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.FileName = "C:\Python26\python.exe";
process.StartInfo.Arguments = "WebServiceGenericClientNet.py host=localhost url=/HelloWorld.asmx namespace=http://tempuri.org/ method=HelloWorld param_strSay=HelloWorld";
process.StartInfo.WorkingDirectory = "C:\Python26\";
process.Start();
string output = process.StandardOutput.ReadToEnd();

O script suporta a configuração do header, passando o argumento header=... para o script.

Para explorar e ver fácilmente os SOAPs enviados e recebidos na chamada de um web service, existe o WebServiceStudio:

Monday, September 15, 2008

Nvidia vs Ubuntu

O driver da Nvidia que vem por padrão no Ubuntu tem alguns bugs, como este:

http://www.nvnews.net/vbulletin/showthread.php?t=106790

Aqui estão os screenshots do bug:

http://home.arcor.de/cziepke/ut2004/



Para instalar o driver que resolve o problema, o NVIDIA-Linux-x86-177.13-pkg1.run, não é tão simples assim, eu pensava que era...

Baixei aqui o driver:

http://www.nvnews.net/vbulletin/showthread.php?t=118602

Consegui instalar, mas o Xorg ficou todo estragado, fiquei com a resoluão de 800x600 e o driver vesa, então procurei e encontrei a solução num forum francês:

http://forum.ubuntu-fr.org/viewtopic.php?id=249234

O que fiz então foi o seguinte:

Fiz logout, e mudei para o terminal 1 (ctrl + alt + F1), fiz o login, e matei o GDM:

# sudo killall gdm

Feito isto o Xorg deverá esta morto, verifique no terminal 7 (ctrl + alt + F7), se esta tudo preto.

Agora remova tudo que esta instalado da nvidia:

$ sudo apt-get remove --purge nvidia*

Instalar os headers do kernel e o xorg-dev:

$ sudo apt-get install build-essential linux-headers-`uname -r` xserver-xorg-dev

Faça um backup da configuração do Xorg:

$ sudo cp /etc/X11/xorg.conf /etc/X11/xorg.conf.good.backup

Agora é só instalar o driver, diga Yes para tudo:

$ sudo sh NVIDIA-Linux-x86-177.13-pkg1.run


Se durante a instalação der erro, dizendo que não consegue criar alguns arquivos, veja o caminho, provavelmente como aconteceu comigo será preciso criar a pasta:

$ sudo mkdir /usr/lib/nvidia

Depois é só voltar a executar a instalação e diga Yes para tudo mais uma vez:

$ sudo sh NVIDIA-Linux-x86-177.13-pkg1.run

Reiniciar o computador, e pronto, os gráficos deverão estar muito melhores, e o UT2004 sem bugs.

Guarde o arquivo de instalação, pois sempre que for instalado um novo kernel será preciso reinstalar o driver.

Friday, September 5, 2008

Unreal Tournament 2004 - Linux Dedicated Server

Nossa como é bom voltar a jogar UT2004 :P

Downloads

Servidor:
$ wget http://downloads.unrealadmin.org/UT2004/Server/DedicatedServer3323.zip
BonusPack:
$ wget http://downloads.unrealadmin.org/UT2004/Server/dedicatedserver3339-bonuspack.zip
Anticheater:
$ wget http://downloads.unrealadmin.org/UT2004/AntiCheat/UTSecure2K4-111.zip

Quem for jogar, convêm ter o MegaPack instalado, para evitar que fique fazendo download:

MegaPack - 12/13/05 - 205 MB

Instalação

$ unzip DedicatedServer3323.zip
$ mv UT2004-Dedicated-3323 UT2004srv
$ unzip -o dedicatedserver3339-bonuspack.zip -d UT2004srv
$ unzip -o UTSecure2K4-111.zip -d UT2004srv
$ chmod +x UT2004srv/System/ucc*

Configuração

Não apague nenhuma linha do arquivo, apenas altere as linhas indicadas abaixo.

Editar o UT2004.ini:

$ vim UT2004srv/System/UT2004.ini

Habilitar a administração web:

[UWeb.WebServer]
bEnabled=True
ListenPort=7775

Alterar o nome do servidor:

[Engine.GameReplicationInfo]
ServerName=Nome Do Teu Servidor
ShortName=Nome Servidor

Liberar para quem não tem o jogo original poder jogar, e desabilitar a verificação de keys:

[IpDrv.MasterServerUplink]
DoUplink=False
UplinkToGamespy=False
SendStats=False
ServerBehindNAT=False
DoLANBroadcast=False
bIgnoreUTANBans=True


Executar

$ cd UT2004srv/System
$ sudo ./ucc-bin server DM-Gael?game=XGame.xDeathMatch?mutator=XGame.MutQuadJump?AdminName=admin?AdminPassword=XXXXX?GamePassword=XXXXX ini=UT2004.ini log=UT2004.log -nohomedir


Os XXXXX são as senhas, a senha para entrar no servidor é a ?GamePassword=XXXXX, substitua os XXXXX por uma senha mais intuitiva do seu entender. Os parametros ?Admin* são os dados para entrar na administração web pelo endereço http://servidor:7775.

Se obtiver este erro:
./ucc-bin: error while loading shared libraries: libstdc++.so.5: cannot open shared object file: No such file or directory

Para resolver este erro é preciso fazer um link simbólico para a versão 5.* da libstdc++, que fica na pasta /usr/lib/libstdc++*, no meu caso fiz assim:

$ sudo ln -s /usr/lib/libstdc++.so.5.0.7 /usr/lib/libstdc++.so.5

Agora é só executar de novo!

Jogar

Para jogar no servidor, é só ir na lista de servidores online dentro do jogo e clicar com o botão direito e no menu que aparece ir em "Open Ip", e colocar o endereço do servidor!

Quem não tem o jogo original pode jogar no teu servidor usando este crack:

Unreal Tournament 2004 v3369 PRIVATE WINDOWS SERVER PATCH

Detalhes da Configuração

Na linha de execução tem os parâmetros:

DM-Gael?game=XGame.xDeathMatch?mutator=XGame.MutQuadJump

DM-Geal se refere ao Mapa, você pode colocar o nome de outro mapa, basta ver os mapas disponíveis em UT2004srv/Maps/*.

O game= XGame.xDeathMatch é o tipo de jogo, todos os tipos de jogos:

Assault: AS-MotherShip?game=UT2k4Assault.ASGameInfo
CTF: CTF-FaceClassic?game=XGame.xCTFGame
Bombing Run: BR-Serenity?game=XGame.xBombingRun
DoubleDomination: DOM-SunTemple?game=xGame.xDoubleDom
DeahtMatch: DM-Rankin?game=XGame.xDeathMatch
Invasion: DM-Antalus?game=SkaarjPack.Invasion
LastManStanding: DM-Morpheus3?game=BonusPack.xLastManStandingGame
Mutant: DM-Deck17?game=BonusPack.xMutantGame
Onslaught: ONS-Torlan?game=Onslaught.ONSOnslaughtGame
TeamDeathMatch: DM-Rankin?game=XGame.xTeamGame

O mutator=XGame.MutQuadJump é o mutator, pode remover isto se não quiser nenhum mutator, todos os tipos de mutators:

Arena: XWeapons.MutArena
Beserk: UnrealGame.MutBerserk
Big Head: UnrealGame.MutBigHead
Delayed Spawn: UnrealGame.MutDelayedSpawn
Float-Away Corpses: XGame.MutHeliumCorpses
InstaGib: XGame.MutInstaGib
Zoom InstaGib: XGame.MutZoomInstaGib
LowGravity: UnrealGame.MutLowGrav
No Adrenaline: XGame.MutNoAdrenaline
No Super Weapons: XWeapons.MutNoSuperWeapon
Quad Jump: XGame.MutQuadJump
AutoHealing: XGame.MutRegen
Slow Motion Deaths: XGame.MutSlomoDeath
Species Specific Stats: XGame.MutSpeciesStats
UDamage Reward: XGame.MutUDamageReward
Vampire :XGame.MutVampire
UTV2004S (UTV2004 in SeeAll mode): UTV2004s.utvMutator
UT2k3 Style Weapon Throwing/Boosting: XGame.MutFastWeapSwitch
UTClassic: UTClassic.MutUTClassic
Lightning Gun 2 Sniper Rifle: UTClassic.MutUseSniper
Sniper Rifle 2 Lightning Gun: UTClassic.MutUseLightning
Camouflage Combo (RRRR): Bonuspack.MutCrateCombo
Pint-sized combo (LLLL): Bonuspack.MutPintSizeCombo
BigWheels: Onslaught.MutBigWheels
Light Weight Vehicles: Onslaught.MutLightweightVehicles
Onslaught Weapons: Onslaught.MutOnslaughtWeapons
Jumping Vehicles: Onslaught.MutWheeledVehicleStunts
Vehicle Arena: OnslaughtFull.MutVehicleArena

Referência

DragonBe - Unreal Tournament 2004 Dedicated Server

Gentoo - UT2004 Dedicated Server Installation

LINUX; UT2004-bin: error while loading shared libraries: libstdc++.so.5

Compre o jogo orignal!

Este jogo esta barato e vale a pena ter o original.

É um excelente jogo, e é dos jogos que mais se preocupa em ter suporte nativo ao Linux, por isso também, não deixe de colaborar.

Monday, September 1, 2008

Nginx

Conheci o Nginx no forum do GUJ.com.br, depois com os resultados que o Fabio Kung postou no blog da Caelum, fiquei convencido que o Nginx seria a melhor solução para os meus problemas.

E depois que conheci o Nginx já não quero mais nada, estou extremamente satisfeito, excelente robustez.

Para instalar o Nginx fiz um artigo no VivaOLinux.com.br que ensina como fazer a instalação e os links do site e da documentação.

Consegui fazer uma configuração simples para configurar multiplos domínios virtuais, segue a configuração:


worker_processes 5;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
gzip on;
gzip_min_length 1100;
gzip_buffers 16 8k;
gzip_types text/plain text/html text/xml text/xhtml text/css text/js application/x-javascript application/json;
error_page 500 502 503 504 /50x.html;
server {
listen 80;
server_name _;
root /home/websites/$host;
location / {
index index.html index.htm index.jsp;
}
location ~ \.jsp$ {
proxy_pass http://localhost:8080;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
}
}
}


Repare nesta linha:


root /home/websites/$host;


Ai em /home/websites/* eu tenho os atalhos para as pastas reais dos domínios.

Então por exemplo para acrescentar um novo domínio dominio.com:

ln -s /home/dominio.com /home/websites/dominio.com
ln -s /home/dominio.com /home/websites/www.dominio.com


Assim para configurar um novo domínio no Nginx é só adicionar um novo atalho no /home/websites neste caso.

Ativar compressão gzip:


gzip on;
gzip_min_length 1100;
gzip_buffers 16 8k;
gzip_types text/plain text/html text/xml text/xhtml text/css text/js application/x-javascript application/json;


Para o Nginx encaminhar os JSPs para o Jetty:


location ~ \.jsp$
proxy_pass http://localhost:8080;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
}

Thursday, August 21, 2008

Movie Clip Fit

Um problema básico hoje em dia para fazer resize em flash é posicionar os movieclips corretamente, existe este projeto que facilita a vida para fazer resize do flash dentro do browser:

http://swffit.millermedeiros.com/

Baseado neste projeto fiz este objeto que ajuda a ajusta as posições dos movieclips dentro do flash de acordo com o resize:


var fit = {
baseStageWidth: Stage.width,
baseStageHeight: Stage.height,
oldStageWidth: Stage.width,
oldStageHeight: Stage.height,
xLeft: 0,
xRight: 1,
yTop: 0,
yBottom: 1,
xMovies: new Array(),
xs: new Array(),
xAligns: new Array(),
x: function (mv:MovieClip, align:Number, x:Number) {
if (align == null) {
align = this.xLeft;
}
this.xMovies.push(mv);
if (x == null) {
if (align == this.xLeft) {
x = mv._x;
} else if (align == this.xRight) {
x = mv._x + mv._width;
}
}
this.xs.push(x);
this.xAligns.push(align);
},
yMovies: new Array(),
ys: new Array(),
yAligns: new Array(),
y: function (mv:MovieClip, align:Number, y:Number) {
if (align == null) {
align = this.yTop;
}
this.yMovies.push(mv);
if (y == null) {
if (align == this.yTop) {
y = mv._y;
} else if (align == this.yBottom) {
y = mv._y + mv._height;
}
}
this.ys.push(y);
this.yAligns.push(align);
},
widthMovies: new Array(),
widths: new Array(),
width: function (mv:MovieClip) {
this.widthMovies.push(mv);
this.widths.push(mv._width);
},
heightMovies: new Array(),
heights: new Array(),
height: function (mv:MovieClip) {
this.heightMovies.push(mv);
this.heights.push(mv._height);
},
proportionalMovies: new Array(),
proportionalWidths: new Array(),
proportionalHeights: new Array(),
proportional: function (mv:MovieClip) {
this.proportionalMovies.push(mv);
this.proportionalWidths.push(mv._width);
this.proportionalHeights.push(mv._height);
},
fix: function () {
for (var k:Number = 0; k < this.widthMovies.length; k++) {
this.widths[k] = (Stage.width * this.widths[k]) / this.oldStageWidth;
this.xMovies[k]._width = this.widths[k];
}
for (var k:Number = 0; k < this.heightMovies.length; k++) {
this.heights[k] = (Stage.height * this.heights[k]) / this.oldStageHeight;
this.heightMovies[k]._height = this.heights[k];
}
for (var k:Number = 0; k < this.proportionalMovies.length; k++) {
var ratioW = Stage.width / this.proportionalWidths[k];
var ratioH = Stage.height / this.proportionalHeights[k];
if (ratioW < ratioH ) {
this.proportionalWidths[k] = this.proportionalWidths[k] * ratioW;
this.proportionalHeights[k] = this.proportionalHeights[k] * ratioW;
} else {
this.proportionalWidths[k] = this.proportionalWidths[k] * ratioH;
this.proportionalHeights[k] = this.proportionalHeights[k] * ratioH;
}
this.proportionalMovies[k]._width = this.proportionalWidths[k];
this.proportionalMovies[k]._height = this.proportionalHeights[k];
}
for (var k:Number = 0; k < this.xMovies.length; k++) {
this.xs[k] = (Stage.width * this.xs[k]) / this.oldStageWidth;
if (Stage.align.indexOf("L") > -1) {
this.xMovies[k]._x = this.xs[k];
} else {
this.xMovies[k]._x = ((this.baseStageWidth - Stage.width) / 2) + this.xs[k];
}
if (this.xAligns[k] == this.xRight) {
this.xMovies[k]._x -= this.xMovies[k]._width;
}
}
for (var k:Number = 0; k < this.yMovies.length; k++) {
this.ys[k] = (Stage.height * this.ys[k]) / this.oldStageHeight;
if (Stage.align.indexOf("T") > -1) {
this.yMovies[k]._y = this.ys[k];
} else {
this.yMovies[k]._y = ((this.baseStageHeight - Stage.height) / 2) + this.ys[k];
}
if (this.yAligns[k] == this.yBottom) {
this.yMovies[k]._y -= this.yMovies[k]._height;
}
}
this.oldStageWidth = Stage.width;
this.oldStageHeight = Stage.height;
}
};


Se quiser que um movieclip fique sempre na posição x e y de acordo com o resize, basta passar a referência do movieclip para as funções x e y:


fit.x(MovieClip);
fit.y(MovieClip);


Ou então se precisar que um movieclip tenha o tamanho dinâmico de acordo com o resize, basta passar a referência do movieclip para as funções width e height:


fit.width(MovieClip);
fit.height(MovieClip);


Para fazer resize em porporção, ideal para imagens, use:


fit.proportional(MovieClip);


E para fazer alinhamentos, por exemplo alinhar um movieclip colado ao lado direito:


fit.x(MovieClip, fit.xRight);


E para alinhar colado a base:


fit.y(MovieClip, fit.yBottom);


Os alinhamentos suportados para o x são fit.xLeft(padrão) e fit.xRight, e para y são fit.yTop(padrão) e fit.yBottom.

O alinhamento esta preparado apenas para a configuração padrão de alinhamento do Flash e para o "TL" (alinhamento Top/Left):


Stage.scaleMode = "noScale";
Stage.align = "TL";


Outros parâmetros de alinhamento não foram testados.

No exemplo do swffit tem a função calcSize que é chamada quando cada resize é feito, é preciso adicionar a função fix, para cada vez que for feito o resize ajustar as posições:


function calcSize() {
fit.fix();
...
}


Veja o video que demonstra como utilizar:

Monday, June 9, 2008

GlassFish vs Apache

Gastei um tempinho para desvendar certos mistérios por trás desta configuração e contornar alguns problemas.

Para configurar segui o post do Jean-Francois Arcand's e da Amy Roh's.

Então vamos lá!

Primeiro no Apache, instalar o mod_jk:

apt-get install libapache2-mod-jk

Configurar o conteúdo do arquivo /etc/apache2/mods-available/jk.load:

# Modulo do mod_jk
LoadModule jk_module /usr/lib/apache2/modules/mod_jk.so
# Arquivo de configuração
JkWorkersFile /etc/apache2/mod_jk_worker.properties
# Arquivo de log
JkLogFile /var/log/apache2/mod_jk.log
# Nível de detalhe dos logs [debug/error/info]
JkLogLevel debug
# Formato das mensagens de log
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
# JkOptions indica para enviar SSL KEY SIZE
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories
# JkRequestLogFormat define o formato dos requests no Log
JkRequestLogFormat "%w %V %T"
# Envia todos jsp para o GlassFish
JkMount /*.jsp worker1
# Envia todos os acessos ao meu projeto web para o GlassFish
JkMount /WebApplication/* worker1

Na última linha, o WebApplication se refere ao nome do nosso projeto no GlassFish, coloque aqui o nome do teu projeto no GlassFish.

Agora falta configurar o /etc/apache2/mod_jk_worker.properties, com este conteúdo:

# Define 1 worker usando ajp13
worker.list=worker1
# Define as propriedades do worker1 (ajp13)
worker.worker1.type=ajp13
worker.worker1.host=localhost
worker.worker1.port=8009
worker.worker1.lbfactor=50
worker.worker1.cachesize=10
worker.worker1.cache_timeout=600
worker.worker1.socket_keepalive=1
worker.worker1.socket_timeout=300

Agora vamos ao GlassFish...

No Glassfish configurar as seguintes opções da JVM:

$GLASSFISH_HOME/bin/asadmin create-jvm-options -Dcom.sun.enterprise.web.connector.enableJK=8009

E também:

$GLASSFISH_HOME/bin/asadmin create-jvm-options -Dcom.sun.enterprise.web.connector.enableJK.propertyFile=/etc/apache2/mod_jk_worker.properties

Para confirmar se ficou bem configurado, verifique o arquivo:

$GLASSFISH_HOME/domains/domain1/config/domain.xml

Procurar neste arquivo por:

<jvm-options>-Dcom.sun.enterprise.web.connector.enableJK=8009</jvm-options>
<jvm-options>-Dcom.sun.enterprise.web.connector.enableJK.propertyFile=/etc/apache2/mod_jk_worker.properties</jvm-options>

Fazer o download do apache-tomcat-5.5.16.zip, e pegar o tomcat-ajp.jar, só serve o jar desta versão, os das versões superiores não funcionam, provocam o seguinte erro no GlassFish:

Caused by: java.lang.NoSuchMethodError: org.apache.coyote.Response.getContentLengthLong()J

Depois do download, procurar o tomcat-ajp.jar dentro do zip:

apache-tomcat-5.5.16/server/lib/tomcat-ajp.jar

E copiar este jar para dentro do GlassFish:

$GLASSFISH_HOME/lib/

Também são precisos os jars commons-modeler e commons-logging, que podem ser adquiridos aqui:

http://commons.apache.org/downloads/index.html

Modeler:
http://commons.apache.org/downloads/download_modeler.cgi

Logging:
http://commons.apache.org/downloads/download_logging.cgi

Copiar estes dois jars também para dentro do:

$GLASSFISH_HOME/lib/

Feito isto, é preciso reiniciar o Apache e o GlassFish, e agora deverá estar funcionando através do Apache:

http://localhost/WebApplication

Assim através do Apache da para acessar os projetos publicados no GlassFish!

O porto 8009 que configuramos para o JK não tem nada haver com o porto web do GlassFish, o mod JK usa um protocolo próprio para comunicar com o Tomcat/AJP, e o GlassFish o que faz é inicia um novo porto usando o JK do Tomcat para poder comunicar com o mod_jk no Apache, e para testar se este porto esta funcionando pode-se usar o telnet e ver se conecta:

telnet localhost 8009

Futuramente pretendo investigar sobre Load Balancing usando o Apache e Glassfish e espero falar sobre isto.

Friday, May 9, 2008

Backup

A alguns anos fiz um sistema de backups em ShellScript e hoje configurei ele num servidor novo, e reparei como ele tem sido útil e tem resultado muito bem, resolvi partilhar.

Criar as pastas:

# mkdir /backup
# mkdir /backup/log


Criar os seguintes arquivos:

# touch /backup/backup
# touch /backup/backup.start
# touch /backup/backup.end
# touch /backup/directory
# touch /backup/run


Dar permissões de execução:

# chmod +x /backup/backup
# chmod +x /backup/backup.start
# chmod +x /backup/backup.end
# chmod +x /backup/run


Os backups diários serão guardados dentro da pasta /backup/daily. E os mensais sempre no dia 1 serão guardados dentro da pasta /backup/monthly. Não é preciso criar estas pastas, elas são criadas automaticamente.

Colar este conteúdo no arquivo /backup/backup:

#!/bin/bash
echo ""
echo -e "\e[40;32;1m Backup \e[0m"
echo ""
echo -e "\e[44;33;1m Start \e[0m"
echo ""
dir1="/backup"
dir2=$1
echo -ne "\e[34;1mcomand.begin\e[0m \e[32mstart\e[0m \e[30;5m...\e[0m"
$dir1/backup.start
echo -e "\e[31;1m end \e[0m"
echo ""
dateDay=`date "+%d"`
dateMonth=`date "+%m"`
dateYear=`date "+%Y"`
folder1=$dir1/daily/$dateDay
folder2=$dir2/daily/$dateDay
echo -ne "\e[34;1mWork Folder\e[0m $folder1 \e[32mstart\e[0m \e[30;5m...\e[0m"
rm -dfr $folder1
mkdir -p $folder1
echo -e "\e[31;1m end \e[0m"
echo ""
if [[ $dir2 != "" ]]; then
echo -ne "\e[34;1mWork Folder\e[0m $folder2 \e[32mstart\e[0m \e[30;5m...\e[0m"
rm -dfr $folder2
mkdir -p $folder2
echo -e "\e[31;1m end \e[0m"
echo ""
fi
echo -e "\e[40;31;1m BACKUP: directory \e[0m"
echo " |"
_x=0
_to=""
for i in `cat /backup/directory`; do
if [ $_x = 0 ]; then
_to=$folder1/$i.tar.gz
echo -ne " | $i \e[32mstart\e[0m \e[30;5m...\e[0m"
_x=1
else
tar -czPf $_to $i
if [[ $dir2 != "" ]]; then
cp -rf $_to $folder2
fi
echo -e "\e[31;1m end \e[0m"
_x=0
fi
done
echo " |____________________________________________________"
echo ""
echo -ne "\e[34;1mcomand.end\e[0m \e[32mstart\e[0m \e[30;5m...\e[0m"
$dir1/backup.end $folder1
echo -e "\e[31;1m end \e[0m"
if [ $dateDay = 01 ]; then
folderMonthly1=$dir1/monthly/$dateYear.$dateMonth.$dateDay
echo -ne "\e[34;1mMonthly Backup]\e[0m $folderMonthly1 \e[32mstart\e[0m \e[30;5m...\e[0m"
mkdir -p $folderMonthly1
cp -rf $folder1 $folderMonthly1
echo -e "\e[31;1m end \e[0m"
if [[ $dir2 != "" ]]; then
folderMonthly2=$dir2/monthly/$dateYear.$dateMonth.$dateDay
echo -ne "\e[34;1mMonthly Backup]\e[0m $folderMonthly2 \e[32mstart\e[0m \e[30;5m...\e[0m"
mkdir -p $folderMonthly2
cp -rf $folder2 $folderMonthly2
fi
echo ""
fi
echo ""
echo -e "\e[44;33;1m End \e[0m"
echo ""
echo -e "\e[40;32;1m by eduveks \e[0m"
echo ""


O arquivo /backup/run é o que inicia o backup e grava o output no arquivo de log, colocar o seguinte conteúdo:


#!/bin/bash
logFileName=`date "+%Y-%m-%d_%H-%M-%S"`
/backup/backup "/mnt/backupmirror" > /backup/log/$logFileName


Atenção ao "/mnt/backupmirror/backup", esta opção é para fazer uma cópia do backup para outra pasta, no meu caso sempre uso um servidor secundário para ter um espelho do backup original, e esta pasta é uma pasta montada remotamente ao outro servidor.

Os arquivos /backup/backup.start e /backup/backup.end, servem para poder colocar comandos para serem executados antes e depois do backup respectivamente, por exemplo para fazer o mount e o umount de uma partilha remota, preparando o cenário da cópia secundária. Ou ainda para parar serviços e reinicia-los no fim, por exemplo para o MySql antes de começar o backup e no fim voltar a inicializa-lo. Gravar nestes arquivos o conteúdo:


#!/bin/bash


Finalmente o arquivo /backup/directory serve para dizer as pastas que deverá ser feito backup, adicionar aqui o nome que vai ter o arquivo.tar.gz e qual a pasta que vai ser armazenada neste arquivo, no seguinte formato:


DB_NAME     /var/lib/mysql/DB_NAME
USER1       /home/USER1


Depois de tudo afinado vamos executar o backup, assim podemos ver o output:

# /backup/backup


Se tudo correu bem, o backup deverá estar em:

# /backup/daily/01/DB_NAME.tar.gz
# /backup/daily/01/USER1.tar.gz


Onde o "01" é o número do dia do mês atual.

Assim a cada dia haverá uma pasta com os backups deste dia, e no dia 1 de cada mês, o backup deste dia estará em:

# /backup/monthly/2008.05.01/01/DB_NAME.tar.gz
# /backup/monthly/2008.05.01/01/USER1.tar.gz


E executar o backup passando uma pasta para ser o espelho do backup:

# /backup/backup /tmp


Poderá reparar que também dentro do /tmp passará a ter o conteúdo do backup.

Feito o teste, voltar a ver como esta o /backup/run, verificar se esta tudo certo, e testa-lo:

# /backup/run


Dentro da pasta /backup/log deverá ter o log do backup:

# cd /backup/log
# ls
# cat 2008-05-01_11-51-53


Agora só falta configurar no crond para executar o backup, criar um arquivo no /etc/cron.daily/backup, com o seguinte conteúdo:


#!/bin/sh
/backup/run


Pronto, agora o backup irá ser executado todos os dias, e assim temos uma solução bem simples e prática para fazer backups...

Wednesday, May 7, 2008

Ubuntu 8.04 vs RaLink RT2561/RT61

Após uma longa batalha, finalmente posso desfrutar do prazer do wireless :P

Tentei durante alguns dias configurar a rede wireless, por duas vezes consegui, mas não ficou bom, e depois parou de funcionar.

O problema era que conseguia conectar, e até o ping funcionava mas muitooo lento, com 200ms, e as vezes não funcionava, e depois por mais que insistisse o DNS não funcionava e não consegui que algum site abrisse, mesmo o site do router, então começei a fazer buscas frenéticas atrás da solução, medidas de desespero.

Para começar verifique o modelo da tua placa:

$ lspci | grep RaLink
02:09.0 Network controller: RaLink RT2561/RT61 rev B 802.11g

Primeiro tentei desta forma, utilizando os drivers do Windows:

http://i-eat-noobs.blogspot.com/2007/08/get-wireless-working-in-ubuntu-704.html

http://www.ralinktech.com/ralink/Home/Support/Windows.html

Usei o PCI/mPCI/CB(RT256x/RT266x), mas como diz a descrição ao lado, vem o drive da RT61 para o Windows Vista, mesmo assim tentei, o cabextract, e o unshield e ainda com o wine, não consegui pegar o arquivo .inf que o ndiswrapper pede, por motivos de força maior deste jeito a coisa não vai e tive que ir atrás de outra solução.

Mais pesquisas, e descobri que muitos já tiveram este problema e indicavam que tinha a ver com o Driver mesmo:

http://ubuntuforums.org/showthread.php?t=550351

Além de muitos outros...

Então encontrei esta dica para instalar o driver para Linux oficial da RaLink:

http://ubuntuforums.org/showthread.php?p=4867439

http://www.ralinktech.com/ralink/Home/Support/Linux.html

Usei o RT2501PCI/mPCI/CB(RT61:RT2561/RT2561S/RT2661), a instalação não foi bem como diz na dica, foi quase, cosegui instalar e configurar, mas não consegui de nenhuma forma que funcionasse, ficou bem mais rápido as mensagens do ping mas sempre sem sucesso, e também o nm-applet não reconheceu mais o wireless, reparei que por mais que tentasse alterar a configuração da conexão, no iwconfig ficava sempre igual, nenhuma configuração era alterada. Comecei a ver que estava sem saída de novo...

Resolvi rever os passos, e se olhar melhorar para este link:

http://www.ralinktech.com/ralink/Home/Support/Linux.html

Tem lá em baixo... "The rt2x00 Open Source Project"... rt2x00 que porcaria é esta, resolvi clicar, tudo que precisava para ter esperança:

This project is a development effort to provide free, stable and feature rich Linux drivers for
wireless 802.11b/g/i cards based on the following Ralink chipsets: rt2400, rt2500, rt2570,
rt61 and rt73.


Em downloads fiz o download do "Last beta release: v1.1.0-b2", mas como tenho muita sorte, ao tentar compilar deu erro na compilação...

Agora só falta a última chama de esperança, o "CVS hourly tarball: rt61-CVS", o que correu muito bem, e mais simples impossível.

Fazer o download:

http://rt2x00.serialmonkey.com/rt61-cvs-daily.tar.gz

Extrair:
$ tar -xzf rt61-cvs-daily.tar.gz

No meu caso foi:
$ cd rt61-cvs-2008050721/Module

Dá para ver que o projeto não esta abandonado.

Compilar e instalar, com a conta do root:
# make && make install

Caso de erro na compilação deve ser que falta instalar o source da versão do kernel que esta sendo usado, ter atenção a isto, é preciso ter a source do kernel instalada.

Feito isto falta registrar o novo module:
# echo "rt61" >> /etc/modules

Também pode tentar um "modprobe rt61", mas convém fazer um: Reboot!

O nm-applet reconheceu o wireless, consegui conectar facilmente, logo de primeira a internet funcionou, e vim fazer este post com tudo fresquinho na cabeça, são agora 4:50 da manhã e seja o que Deus quiser amanhã no trabalho, ou melhor hoje :P

Usei a configuração manual, que na automática pediu a senha 2 vezes e ai cancelei e fui tentar no manual e funcionou muito bem com WEP (ASCII).

Também fui testar alguns sites mais pesado, e reparei que ficou muito mais rápido que no outro notebook com windows... muito rápido mesmo, demorou, custou, mas valeu a pena.

Próximo é passo configurar com WPA em vez de WEP...

Sunday, April 20, 2008

DragonFlyBSD - Instalação de pacotes

Hoje começei a brincar com o DragonflyBSD, e até agora estou gostando, vários detalhes facilitados comparado a outros BSDs.

Mas depois de instalar e ao tentar usar o pkg_search, tive o seguinte erro:


No pkgsrc(7) tree found. Fetching pkg_summary(5) file.
fetch: http://pkgbox.dragonflybsd.org/packages/DragonFly-1.12/i386//All/pkg_summary.bz2: Not Found
fetch: http://pkgbox.dragonflybsd.org/packages/DragonFly-1.10.1/i386//All/pkg_summary.bz2: Not Found
Unable to fetch pkg_summary(5) file.


Tentei abrir estas URLs no browser mas também sem sucesso, então comecei a fuçar e descobri este site:

http://www.pkgsrc-box.org/

Que tem os packages do DragonflyBSD, então fuçando neste site descobri que aqui tem a lista dos packages:

http://www.pkgsrc-box.org/packages/stable/DragonFly-1.10/All/

E também o precioso pkg_summary.bz2:

http://www.pkgsrc-box.org/packages/stable/DragonFly-1.10/All/pkg_summary.bz2

E da versão 1.12 estão aqui:

http://pkgbox.dragonflybsd.org/packages/DragonFly-1.12/stable/All/

Boa, mas agora como configurar para usar estas URLs em vez das que vem por default?! Procurei e procurei no /etc e nada, então resolvi arriscar e fiz:


vi /usr/bin/pkg_search


Boas notícias é um script mesmo e logo nas primeiras linhas estava a string com as preciosas URLs, é preciso dar permissões de escrita no arquivo:


chmod u+w /usr/bin/pkg_search


Mudei as linhas do PKGSRCBOX1 e do PKGSRCBOX2 para:


PKGSRCBOX1=http://pkgbox.dragonflybsd.org/packages/DragonFly-1.12/stable/
PKGSRCBOX2=http://www.pkgsrc-box.org/packages/stable/DragonFly-1.10/


Depois foi só usar o pkg_search, o qual funcionou perfeitamente.


pkg_search nano


Para usar o pkg_add precisei passar a url completa do arquivo, as dependências são instaladas automaticamente se estiverem na mesma URL base:


pkg_add http://pkgbox.dragonflybsd.org/packages/DragonFly-1.12/stable/All/nano-2.0.7.tgz

Tuesday, April 8, 2008

LVM vs Mount

Se por acaso ao tentar montar uma partição no Linux e der com o seguinte erro:

mount: unknown filesystem type 'LVM2_member'

O problema é que as partições do disco foram registradas na LVM.

Minha distribuição é o OpenSuse 10.3, mas em princípio esta solução servirá para qualquer Linux.

Podemos ver a estrutura LVM com o comando:

# /sbin/pvs

PV VG Fmt Attr PSize PFree
/dev/sdb1 system lvm2 a- 5,86G 5,86G


Para mais detalhes:

# /sbin/pvscan

PV /dev/sdb1 VG system lvm2 [5,86 GB / 5,86 GB free]
Total: 1 [5,86 GB] / in use: 1 [5,86 GB] / in no VG: 0 [0 ]


Precisamos do VG Name, mais detalhes ainda:

# /sbin/pvdisplay /dev/sdb1

--- Physical volume ---
PV Name /dev/sdb1
VG Name system
PV Size 5,86 GB / not usable 3,73 MB
Allocatable yes
PE Size (KByte) 4096
Total PE 1499
Free PE 1499
Allocated PE 0
PV UUID lPwtfx-5ocj-eXah-gqcX-1bCd-kcod-YN96is


Com o VG Name que no meu caso é "system".

Podemos agora remover o Volume Group:

# vgremove system

Volume group "system" successfully removed


Se voltar a fazer o pvs, pvscan ou pvdisplay, verificamos que o disco já não tem o VG Name (Volume Group Name).

Falta remover definitivamente a partição da LVM, com o seguinte comando:

# pvremove /dev/sdb1

Labels on physical volume "/dev/sdb1" successfully wiped


Se tentar montar a partição agora não vai ser possível, vai dar sempre esta mensagem, mesmo definindo o type:

# mount /dev/sdb1 /mnt/hd1

mount: you must specify the filesystem type


Então é preciso fazer um reboot, para que os dispositivos dos discos sejam recarregados:

# reboot

Depois do reboot verifique com o pvs, pvscan ou pvdisplay, para ter a certeza que a partição já não esta registrada.

Agora só falta montar a partição normalmente:

# mount /dev/sdb1 /mnt/hd1

Para mais informações veja a documentação:
http://tldp.org/HOWTO/LVM-HOWTO/

E para saber para que serve a LVM e mais informções:
http://en.wikipedia.org/wiki/Logical_Volume_Manager_(Linux)

Friday, March 28, 2008

Que tal uma sintaxe em Portugues?


IMPORTANTE: O conteúdo deste post é sempre atualizado para a última versão do CajuScript.


Exemplo de uma sintaxe em Português usando o CajuScript.

Faça o download do CajuScript.

Na mesma pasta em que esta o jar do CajuScript crie o arquivo "carregaSintaxePortugues.cj", com o seguinte conteúdo:

[CODE]
$java.util.regex

syntaxPT = org.cajuscript.Syntax()
syntaxPT.setIf(Pattern.compile("^[\\s+s|s]e\\s*([\\s+|[\\s*\\(]].+)\\s*faz"))
syntaxPT.setElseIf(Pattern.compile("^[\\s+o|o]u\s+se\\s*([\\s+|[\\s*\\(]].+)\\s*faz"))
syntaxPT.setElse(Pattern.compile("^[\\s+o|o]u\\s+senao\\s+fa[z\\s+|z]$"))
syntaxPT.setIfEnd(Pattern.compile("^[\\s+f|f]i[m\\s+|m]$"))
syntaxPT.setLoop(Pattern.compile("^[\\s+e|e]nquanto\\s*([\\s+|[\\s*\\(]].+)\\s*faz"))
syntaxPT.setLoopEnd(Pattern.compile("^[\\s+f|f]i[m\\s+|m]$"))
syntaxPT.setTry(Pattern.compile("^[\\s+t|t]enta\\s*([\\s+|[\\s*\\(]].+)\\s*faz"))
syntaxPT.setTryCatch(Pattern.compile("^[\\s+p|p]ega\\s+o\\s+err[o\\s+|o]$"))
syntaxPT.setTryFinally(Pattern.compile("^[\\s+f|f]inalment[e\\s+|e]$"))
syntaxPT.setTryEnd(Pattern.compile("^[\\s+f|f]i[m\\s+|m]$"))
syntaxPT.setFunction(Pattern.compile("^[\\s+f|f]uncao\\s*([\\s+|[\\s*\\(]].+)\\s*faz"))
syntaxPT.setFunctionEnd(Pattern.compile("^[\\s+f|f]i[m\\s+|m]$"))
syntaxPT.setNull(Pattern.compile("nulo"))
syntaxPT.setReturn(Pattern.compile("retorna"))
syntaxPT.setImport(Pattern.compile("importa\\s+"))
syntaxPT.setRootContext(Pattern.compile("raiz\\."))
syntaxPT.setContinue(Pattern.compile("continua"))
syntaxPT.setBreak(Pattern.compile("para"))
syntaxPT.setOperatorOr(Pattern.compile("[\\s+|)\\s*]ou[\\s+|(\\s*]"))
syntaxPT.setOperatorAnd(Pattern.compile("[\\s+|)\\s*]e[\\s+|(\\s*]"))

org.cajuscript.CajuScript.addGlobalSyntax("PT", syntaxPT)

$"exemploSintaxePortugues.cj"
[/CODE]

E também o arquivo "exemploSintaxePortugues.cj", com o seguinte conteúdo:

[CODE]
caju.syntax: PT

importa java.lang

// IF = SE
x = 10
se x < 10 e x > 0 faz
System.out.println("X menor que 10!")
ou se x > 10 e x ! 10 faz
System.out.println("X maior que 10!")
ou se x = 10 ou x ! 0 faz
System.out.println("X igual 10!")
ou senao faz
System.out.println("X menor que 1!")
fim

// LOOP = ENQUANTO
x = 0
enquanto x < 100 e x >= 0 faz
System.out.println(x)
x += 1
se x = 10 faz
para
ou senao faz
continua
fim
fim

// FUNCTION = FUNCAO
x = 5
funcao addWithX(v1, v2) faz
retorna raiz.x + v1 + v2
fim
x = addWithX(10, 20)
System.out.println("X = "+ x)

// TRY/CATCH = TENTA/PEGA
tenta e faz
"".substring(0, -1)
pega o erro
System.out.println("Erro: "+ e.getMessage())
finalmente
System.out.println("Finalmente...")
fim

System.out.println("\n\nSyntax em portugues executada com sucesso!\n")

Thread.sleep(10000)
[/CODE]

Agora é só executar com o comando:

[CODE]
java -jar cajuscript.jar carregaSintaxePortugues.cj
[/CODE]

Pronto! :P

Não convêm usar acentos na sintaxe, por que pode dar alguns problemas de encoding ao transportar o arquivo por vários sistemas operacionais, como do linux para o windows. Mas quem não arrisca não petisca.

Toda sugestão é bem vinda.

Saturday, February 23, 2008

Apache 2.2 - Modules

No Apache 2.2 resolveram mudar os nomes dos modulos, o que tem dado alguma dor de cabeça...

Lista da mudanças nos nomes dos modulos.

Se tiver o seguinte erro:

[CODE]

Starting httpd: httpd: Syntax error on line 170 of /etc/httpd/conf/httpd.conf: Cannot load /etc/httpd/modules/mod_access.so into server: /etc/httpd/modules/mod_access.so: cannot open shared object file: No such file or directory

[/CODE]

Segue a lista dos modulos corrigido:

[CODE]
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule authn_anon_module modules/mod_authn_anon.so
LoadModule authn_dbm_module modules/mod_authn_dbm.so
LoadModule auth_digest_module modules/mod_auth_digest.so
LoadModule ldap_module modules/mod_ldap.so
LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
LoadModule include_module modules/mod_include.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule env_module modules/mod_env.so
LoadModule mime_magic_module modules/mod_mime_magic.so
LoadModule cern_meta_module modules/mod_cern_meta.so
LoadModule expires_module modules/mod_expires.so
LoadModule deflate_module modules/mod_deflate.so
LoadModule headers_module modules/mod_headers.so
LoadModule usertrack_module modules/mod_usertrack.so
LoadModule unique_id_module modules/mod_unique_id.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule mime_module modules/mod_mime.so
LoadModule dav_module modules/mod_dav.so
LoadModule status_module modules/mod_status.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule asis_module modules/mod_asis.so
LoadModule info_module modules/mod_info.so
LoadModule dav_fs_module modules/mod_dav_fs.so
LoadModule vhost_alias_module modules/mod_vhost_alias.so
LoadModule negotiation_module modules/mod_negotiation.so
LoadModule dir_module modules/mod_dir.so
LoadModule imagemap_module modules/mod_imagemap.so
LoadModule actions_module modules/mod_actions.so
LoadModule speling_module modules/mod_speling.so
LoadModule userdir_module modules/mod_userdir.so
LoadModule alias_module modules/mod_alias.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so
LoadModule cache_module modules/mod_cache.so
LoadModule suexec_module modules/mod_suexec.so
LoadModule disk_cache_module modules/mod_disk_cache.so
LoadModule file_cache_module modules/mod_file_cache.so
LoadModule mem_cache_module modules/mod_mem_cache.so
LoadModule cgi_module modules/mod_cgi.so
[/CODE]

Fiz isto no CentOS 5.1, mas deve ajudar na configuração em outras distribuições.

Wednesday, February 13, 2008

Anaconda? Sucuri? Ou história de pescador?

Acho que toda gente já deve ter recebido algum e-mail falando sobre esta cobrinha:

E acompanha um texto do gênero:

[CODE]

Anaconda...
Sucuri em Barra do Piraí - RJ
VEJAM SÓ O TAMANHO DA
"BOQUINHA" DA CRIANÇA.


Acreditem, esta sucuri morreu eletrocutada na cerca elétrica
que separa a empresa Thyssen, em Barra do Piraí - RJ, de uma
fazenda vizinha.
O acontecimento parou a fábrica, e o dia inteiro
foi o maior entra e sai de biólogos do Rio e São Paulo,
para analisarem a cena que se tornou motivo de
preocupação para todos.

Será preciso rever conceitos sobre acampar e passar a noite às
margens de represa pescando.
Reparem no formato de sua barriga, que ela estava bem alimentada.
Segundo a turma da segurança da Thyssen e o pessoal da prefeitura
de Barra do Piraí, os órgãos responsáveis estão assustados,
pois este animal, segundo os especialistas, só vive na Amazônia e Pantanal.
É, os especialistas também se enganam.

[/CODE]

Como já tinha recebebido vários e-mails com estas imagens, e desta vez me chamou a atenção no título dizer "Anaconda" e no texto dizer "Sucuri", eu pensava que Anaconda e Sucuri fossem espécies diferentes, mas o wikipedia diz que Sucuri é uma espécie de Anaconda:
http://pt.wikipedia.org/wiki/Anaconda

Ok, boa, aprendi qualquer coisa, agora e o resto?

Joguei no Google: "sucuri morreu eletrocutada" e também "anaconda morreu eletrocutada"...

Aparece varios links, e comecei a ver o que diziam:

...cerca elétrica que separa a
empresa Thyssen, em Barra do Piraí - RJ...

Há foi daqui que o e-mail veio. -.-

...Fábrica da Votorantim em Resende (RJ), de uma fazenda vizinha próxima ao Rio Paraíba do Sul...
Opa afinal foi em Resende no Rio de Janeiro, só que na fábrica Votorantim! -.^

...Siderúrgica Thyssen, de Barra do Piraí (PR)...
Não não, foi na Siderúrgica Thyssen e foi na barra do Piraí mesmo... só que fica no Pará!?!?! o.O

E eu garanto que estas fotos foram tiradas lá me casa, num domingo de manhã quando faltou a luz fui no quintal e vi lá a cobra na cerca elétrica, tinha acabado de comer o meu cão, o problema é saber como ela conseguio entrar e depois não conseguio sair, e coitadinho do meu cão Fubá... :P

Mais um daqueles e-mails com informação bem informativa! As fotos impressionam, mas o texto... vai na volta até foi na Bolívia ou EUA...

Apagão mundial a 29 Fev 08 (PELO NOSSO PLANETA) ???

Recebi um e-mail bem engraçado dizendo o seguinte:

[CODE]
Apagão mundial a 29 Fev 08 (PELO NOSSO PLANETA)
Apagão mundial: No dia 29 de Fevereiro de 2008 das 19:55 às 20:00 horas
propõe-se apagar todas as luzes e se possível todos os aparelhos
eléctricos, para o nosso planeta poder 'respirar'.

MARCAR NA AGENDA!!!!!

Se a resposta for massiva, a poupança energética pode ser brutal.
Só 5 minutos, para ver o que acontece.
Sim, estaremos 5 minutos às escuras, podemos acender uma vela e
simplesmente ficar a olhar para ela, estaremos a respirar nós e o
planeta.
Lembrem-se que a união faz a força e a Internet pode ter muito poder
e podemos mesmo fazer algo em grande.
Passa a notícia, se tiveres amigos a viver noutros países envia-lhes e
pede-lhes que façam a tradução e adaptem as horas.

[/CODE]

Claro que para averiguar a veracidade dos fatos fui jogar no Google e numa pesquisa rápida a única referência a isto que encontrei foi:
http://tresemdezembro.blogspot.com/2008/02/what-do-you-say.html

Não há link para uma notícia de um jornal sério por exemplo, e como é óbvio é mais uma daquelas coisas que alguém resolveu inventar.

Fiquei a pensar como isto não faz sentido, por exemplo, sempre que vou dormir tudo em casa fica desligado, logo faço um grande apagão lá em casa (afinal a conta da luz não é barata), se eu dormir 5 minutos a mais (como custumo fazer todos os dias e saio sempre atrasado) já estou colaborando com o planeta!

Agora vai ser lindo ver um bando de gente desligando tudo durante 5 minutos. E eu vou fazer o contrário, vou ligar tudo! Por isso em vez de desligar tudo no dia 29, vamos liguar tudo e vamos ver se a companhia elétrica aguenta :P

Mas pelo que parece houve uma iniciativa mundial com esta finalidade, mas em 1 de fevereiro de 2007. Como pode ser verificado aqui. Então parece que gostaram da idéia e resolveram organizar um evento destes todo ano, neste ano já vai com atraso...

Monday, January 14, 2008

Restaurar Base de Dados no SQLServer

Podia ser muito mais simples, mas para que facilitar se da para complicar? E para eu nunca esquecer como restaurar uma base de dados no SQLServer, resolvi fazer este post.

Quando se tenta pelas vias normais e da o erro:
Restore failed for Server...
E tenta por script e da outro erro:
Directory lookup for the file...
E se a base de dados esta em uso:
Exclusive access could not be obtained because the database is in use.

Então esta faltando é os comandos corretos...

Limpar as conexões ativas:

USE Master

ALTER DATABASE YOUR_DATABASE_NAME SET SINGLE_USER WITH ROLLBACK IMMEDIATE

GO

USE Master

ALTER DATABASE YOUR_DATABASE_NAME SET MULTI_USER WITH ROLLBACK IMMEDIATE

GO

Para poder ver o nome do Data e do Log, e ainda outros dados do backup, informações precisosas para o próximo passo:

RESTORE FILELISTONLY FROM DISK = 'C:\BACKUP.bak'

Agora é so fazer o restore assim:

RESTORE DATABASE NewDataBaseName FROM DISK = 'C:\BACKUP.bak'
WITH
MOVE 'BackupDatabase_Data' TO 'C:\MSSQL\Data\NewDataBaseName.mdf',
MOVE 'BackupDatabase_Log' TO 'C:\MSSQL\Data\NewDataBaseName.ldf'


Agora já sei aonde encontrar isto mais rápido da próxima vez :P

Sunday, January 13, 2008

NetBeans 6 vs OpenSuse 10.3

Se tiver problemas com OpenSuse 10.3 para rodar o NetBeans 6, o bug-buddy acusando um bug e parando a execução logo na inicialização. Então vou explicar como instalar o JDK 6 e o NetBeans 6 no OpenSuse 10.3 e resolver este problema.

Instalação JDK 6:
- Em java.sun.com abrir o link para o Java SE, depois fazer o download do JDK 6 Update 4 versão para Linux o que tem a extenção .rpm.bin:
jdk-6u4-linux-x64-rpm.bin
- Dar permissões de execução para o arquivo:
chmod +x jdk-6u4-linux-x64-rpm.bin
- Executar:
./jdk-6u4-linux-x64-rpm.bin
- Vai ser criado no mesmo diretório varios arquivos *.rpm, para instalar execute:
sudo /sbin/yast2 -i jdk-6u4-linux-amd64.rpm
- O JDK 6 será instalado em:
/usr/java/jdk1.6.0_04
- E também terá estes atalhos para o jdk:
/usr/java/latest
/usr/java/default

Instalação NetBeans 6:
- Em www.netbeans.org faça o download do NetBeans 6 versão Linux, eu usei a versão "All".
- Dar permissões de execução para o arquivo:
chmod +x netbeans-6.0-linux.sh
- Eu instalei em /opt, caso queira instalar ai também faça assim:
sudo mkdir /opt/netbeans-6.0
sudo chmod a+rwx /opt/netbeans-6.0
sudo mkdir /opt/glassfish-v2
sudo chmod a+rwx /opt/glassfish-v2
- Agora execute o arquivo de instalação do NetBeans 6, e escolha a pasta de instalação, se for no /opt/netbeans-6.0 escolha esta pasta e o GlassFish também /opt/glassfish-v2, e eu coloquei em JDK /usr/java/latest.
- Será criado atalhos no desktop e nos programas.
- Execute...

Caso de Error, do bug-buddy, como aconteceu no meu caso, ele pode ser removido, não vai fazer falta, para o remover execute:
sudo zypper rm bug-buddy

Agora é só executar outra vez e deverá ter o problema resolvido, e o NetBeans 6 a funcionar perfeitamente.

Friday, January 11, 2008

TextBoxRevolution

Precisei fazer uma TextBox com fundo transparente e também imagem de fundo, totalmente customizada, procurei na net e encontrei uma base, então resolvi melhorar e organizar bem o código, e esta ai o resultado.

Uma coisa que as vezes faz falta no Windows.Form, é o Attributes nos Controls, algo que temos no Asp.Net mas não no Windows.Form, e como eu também precisava deste recurso na TextBox então resolvi implementar isto também, por isso esta TextBox também suporta o Attributes, TextBoxRevolution.Attributes, assim já é possível anexar outros objetos ao Control.

[CODE]
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.ComponentModel;

namespace TextBoxRevolutionTest
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form form = new Form();
form.Text = "TextBoxRevolution";
form.Width = 450;
form.Height = 250;
string text = @"
The Foundations of the GPL
Nobody should be restricted by the software they use. There are four freedoms that every user should have:
* the freedom to use the software for any purpose,
* the freedom to share the software with your friends and neighbors,
* the freedom to change the software to suit your needs, and
* the freedom to share the changes you make.
When a program offers users all of these freedoms, we call it free software.
Developers who write software can release it under the terms of the GNU GPL. When they do, it will be free software and stay free software, no matter who changes or distributes the program. We call this copyleft: the software is copyrighted, but instead of using those rights to restrict users like proprietary software does, we use them to ensure that every user has freedom.
";
TextBoxRevolution textBoxRevolution = new TextBoxRevolution();
textBoxRevolution.Name = "textBoxRevolution";
textBoxRevolution.Dock = DockStyle.Fill;
textBoxRevolution.Control.Name = "textBoxRevolutionOut";
textBoxRevolution.Transparent = true;
textBoxRevolution.Height = 0;
textBoxRevolution.TopMargin = 5;
textBoxRevolution.BorderStyle = BorderStyle.None;
textBoxRevolution.Multiline = true;
textBoxRevolution.ForeColor = Color.FromArgb(0, 0, 0);
textBoxRevolution.Text = text;
textBoxRevolution.Select(0, 0);
textBoxRevolution.Background += new TextBoxRevolution.OnBackground(textBoxRevolution_Background);
form.Controls.Add(textBoxRevolution);
Application.Run(form);
}
static Image textBoxRevolution_Background(TextBoxRevolution textBoxRevolution)
{
Color topColor = Color.FromArgb(235, 237, 241);
Color bottomColor = Color.FromArgb(225, 229, 232);
if (textBoxRevolution.Control.Name.EndsWith("Over"))
{
topColor = Color.FromArgb(249, 247, 255);
bottomColor = Color.FromArgb(238, 234, 255);
}
Bitmap img = new Bitmap(textBoxRevolution.Width, textBoxRevolution.Height);
Graphics g = Graphics.FromImage(img);
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.FillRectangle(new SolidBrush(topColor), 0, 0, textBoxRevolution.Width, textBoxRevolution.Height);
g.FillRectangle(new SolidBrush(bottomColor), 0, textBoxRevolution.Height / 2, textBoxRevolution.Width - 50, textBoxRevolution.Height / 2);
g.FillEllipse(new SolidBrush(bottomColor), textBoxRevolution.Width - 100, textBoxRevolution.Height / 2, 100, 20);
g.FillRectangle(new SolidBrush(bottomColor), textBoxRevolution.Width - 50, (textBoxRevolution.Height / 2) + 10, textBoxRevolution.Width, textBoxRevolution.Height / 2);
return img;
}
}
}

namespace System.Windows.Forms
{
public class TextBoxRevolution : TextBox
{

public delegate Image OnBackground(TextBoxRevolution textBoxRevolution);
public event OnBackground Background;

PictureBox pictureBox = null;
Dictionary<string, object> attributes = new Dictionary<string, object>();

public TextBoxRevolution()
{
pictureBox = new PictureBox();
pictureBox.Dock = DockStyle.Fill;
this.ShortcutsEnabled = false;
this.Cursor = Cursors.Arrow;
this.Controls.Add(pictureBox);
}

public Dictionary<string, object> Attributes
{
get
{
return attributes;
}
set
{
attributes = value;
}
}

bool transparent = false;
public bool Transparent
{
get
{
return transparent;
}
set
{
transparent = value;
}
}

public PictureBox Control
{
get
{
return pictureBox;
}
}

int topMargin = 0;
public int TopMargin
{
get
{
return topMargin * -1;
}
set
{
topMargin = value;
}
}

protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch (m.Msg)
{
case Win32.WM_PAINT:
Draw();
break;
case Win32.WM_HSCROLL:

case Win32.WM_VSCROLL:
this.Invalidate();
break;
}
}

public void Draw()
{
Bitmap bmpCaptured = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height);
Bitmap bmpResult = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height);
Rectangle r = new Rectangle(0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height);
Win32.CaptureWindow(this, ref bmpCaptured);
if (Transparent)
{
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.BackColor = Color.Transparent;
}
ImageAttributes imgAttrib = new ImageAttributes();

if (Transparent)
{
ColorMap[] colorMap = new ColorMap[1];
colorMap[0] = new ColorMap();
colorMap[0].OldColor = Color.White;
colorMap[0].NewColor = Color.Transparent;
imgAttrib.SetRemapTable(colorMap);
}
Graphics g = Graphics.FromImage(bmpResult);


try
{
g.DrawImage(Background(this), r, 0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height, GraphicsUnit.Pixel, imgAttrib);
}
catch
{
}
g.DrawImage(bmpCaptured, r, 0, TopMargin, this.ClientRectangle.Width, this.ClientRectangle.Height, GraphicsUnit.Pixel, imgAttrib);
g.Dispose();
pictureBox.Image = (Image)bmpResult.Clone();
}

public int ContentHeight
{
get
{
return LinesCount * base.Font.Height;
}
}

public int LinesCount
{
get
{
const int EM_GETLINECOUNT = 186;
int lineCount = Win32.SendMessage(base.Handle, EM_GETLINECOUNT, IntPtr.Zero, IntPtr.Zero);
return lineCount + 1;
}
}
}

public class Win32
{
public const int WM_MOUSEMOVE = 0x0200;
public const int WM_LBUTTONDOWN = 0x0201;
public const int WM_LBUTTONUP = 0x0202;
public const int WM_RBUTTONDOWN = 0x0204;
public const int WM_LBUTTONDBLCLK = 0x0203;
public const int WM_MOUSELEAVE = 0x02A3;
public const int WM_PAINT = 0x000F;
public const int WM_ERASEBKGND = 0x0014;
public const int WM_PRINT = 0x0317;
public const int EN_HSCROLL = 0x0601;
public const int EN_VSCROLL = 0x0602;
public const int WM_HSCROLL = 0x0114;
public const int WM_VSCROLL = 0x0115;
public const int EM_GETSEL = 0x00B0;
public const int EM_LINEINDEX = 0x00BB;
public const int EM_LINEFROMCHAR = 0x00C9;
public const int EM_POSFROMCHAR = 0x00D6;
[DllImport("USER32.DLL", EntryPoint = "PostMessage")]
public static extern bool PostMessage(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam);
[DllImport("USER32.DLL", EntryPoint = "SendMessage")]
public static extern int SendMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("USER32.DLL", EntryPoint = "GetCaretBlinkTime")]
public static extern uint GetCaretBlinkTime();
public const int WM_PRINTCLIENT = 0x0318;
public const long PRF_CHECKVISIBLE = 0x00000001L;
public const long PRF_NONCLIENT = 0x00000002L;
public const long PRF_CLIENT = 0x00000004L;
public const long PRF_ERASEBKGND = 0x00000008L;
public const long PRF_CHILDREN = 0x00000010L;
public const long PRF_OWNED = 0x00000020L;
public static bool CaptureWindow(System.Windows.Forms.Control control, ref System.Drawing.Bitmap bitmap)
{
Graphics g2 = Graphics.FromImage(bitmap);
int meint = (int)(PRF_CLIENT | PRF_ERASEBKGND);
System.IntPtr meptr = new System.IntPtr(meint);
System.IntPtr hdc = g2.GetHdc();
Win32.SendMessage(control.Handle, Win32.WM_PRINT, hdc, meptr);
g2.ReleaseHdc(hdc);
g2.Dispose();
return true;
}
}
}
[/CODE]