Archivo

Archivo para mayo, 2010

¿Como diseñar un firewall de bajo costo con Linux?

Martes, 18 de mayo de 2010

Es curioso las cosas que le saltan a uno a la cabeza cuando se está haciendo ejercicio en el gimnasio :) . Por alguna razón recordé un articulo es escribí para el blog ya hace 5 años atrás sobre Iptables en Linux y la excelente herramienta Firewall Builder.

De cualquier modo, después de leer el articulo de nuevo me di cuenta que nunca enumeré varias cosas importantes a la hora de configurar el firewall:

  • Utilice tarjetas de red buenas. En serio, no utilice las que vienen con la tarjeta madre, por lo general es mejor buscar tarjetas dedicadas las cuales tienen buen rendimiento (las basadas en Intel de 1GB aguantan mucha carga antes de comenzar a botar paquetes. Mi experiencia con las del chip Broadcom no es muy buena).
  • Asegúrese de instalar TCPWrappers en el firewall y de configurarlo apropiadamente para restringir servicios, entre esos el acceso a SSH. También juegue con el acceso de seguridad de sshd.conf.
  • No deje corriendo demonios que no necesite como servidores de ftp (ftpd == ¡no!), impresión (lpd) o X-Windows
  • Instale Nmap, Tcpdump, Ethereal. En serio, cuando alguna de las reglas le empiece a dar problemas estas herramientas lo van a sacar de apuros.

Yo en particular utilizaba el siguiente truco para instalar reglas de firewall en un servidor que tenia corriendo en Chenay (India):

  • Copiaba las reglas compiladas con firewall builder en el servidor usando scp
  • Un segundo script escrito por mi arrancaba un contador de 60 segundos. Durante ese tiempo las nuevas reglas eran ejecutadas en el servidor remoto.
  • Si durante ese tiempo yo no podía crear un archivo que le decia al firewall que todo estaba bien, entonces el script desactivaba todas las reglas de firewall para permitir de nuevo la entrada por SSH. Si habían reglas anteriores estas eran ejecutadas. Esto era crítico pues más de una vez una regla me dejaba sin conexión a mi servidor (mi regla de firewall era bastante estricta para evitar que me atacaran usando SSH)

Suena a mucho trabajo, pero esta solución le ahorró a la compañía en la que trabajaba como $50K en licencias con una solución que tenían cuando yo comencé a trabajar allí como administrador de sistemas (la licencia habia que renovarla y ellos tenían como dos años que no lo hacian por el costo). Eso sin contar la flexibilidad que yo tenía para instalar herramientas (por ejemplo, al final yo le monté Snort para detectar ataques en tiempo real y yo le mandaba reportes a dshield.org para poner a los hackers en su sitio :) )

¿Y ustedes, que trucos tienen con sus firewall de Linux? (Firewall builder ha evolucionado mucho desde hace 5 años y ahora hay soluciones en Linux por todos lados)

–Jose

java, linux , , ,

Grupo de Mazinger Z en Flickr: ¿Quieres compartir?

Domingo, 16 de mayo de 2010

¿En donde están los trabajos?: Java Swing vs JavaFX vs Flex vs Silverlight

Jueves, 6 de mayo de 2010

Si esto es un indicativo de donde invertir el tiempo, por los momentos Java Swing y Adobe Flex son opciones seguras. JavaFX está aún en pañales…

java, javafx , , , ,

Programando en JavaFX: Enlaces recomendados, libros y un poco de Alpha Geeks

Martes, 4 de mayo de 2010

Bueno, esta semana he estado tratando es escribir código en serio con JavaFX en vez de pedazos de código; El resultado ha sido una combinación de alegría (la plataforma promete mucho) y frustración (debido a que la documentación y ejemplos están rotos debido a que el API está cambiando).

JavaFX en este momento es una herramienta para Alpha Geeks. En serio. Pese a estar en su versión 1.3 aún hay cosas importantes por mejorar, ademas de que el API pareciera estar cambiando. Si a eso se le suma el hecho de que ningún vendedor le está dando soporte serio en los teléfonos celulares (a diferencia de Android) no creo que nadie lo tome en serio para un proyecto empresarial.

¿Está todo perdido? Yo creo que el primer lugar en donde JavaFX va a tener precedencia va a ser en el escritorio, antes que los celulares. Sin embargo una mejor integración con Java y Swing (hay muchísimo código que no se va a evaporar de la noche a la mañana) además de mejoras en el soporte de Eclipse y NetBeans son necesarias. Con todo y eso, un lenguaje fresco para hacer interfaces gráficas era necesario y JavaFX parece ser un paso en la dirección correcta.

Pero bueno, no me extiendo más y los dejo con lo que en mi opinión son los mejores enlaces y libros sobre el lenguaje:

  • JavaFX layout secrets (Amy Fowlert). En mi opinión lectura obligada para entender como funcionan, en especial si usted hace aplicaciones empresariales.
  • JavaFX in Action: Muy buenos ejemplos, buena cobertura del API. No es un libro de principantes, aunque es increíblemente fácil de digerir.
  • Sitio oficial de JavaFX: Es la referencia obligada, sin embargo desde que sacaron la versión 1.3 retiraron un montón de ejemplos debido a que el API cambió. Un fastidio :(
  • El blog de Jim Weaver: Tuve la suerte de estar en una clase con Jim en JavaOne del 2008. Es un evangelista del lenguaje, tiene mucha experiencia práctica (y un libro para respaldarlo, Pro JavaFX 1.2 Book). Mucha información útil en su blog.

¿Y usted, tiene algún recurso interesante que quiera compartir?

–Jose

javafx, programación , , ,

¿Qué hacer mientras esperamos que Halo Reach beta arranque?

Lunes, 3 de mayo de 2010

Downloading Halo Reach Beta
Bajándome el Beta, como otro de los millones de fanáticos de este juego

Bueno, ya a esta hora el beta de Halo Reach está en pleno apogeo. Los gráficos simplemente no decepcionan, aunque como buen beta tiene varias verrugas (el servidor se cayó en más de una ocasión, los controles son un poco distintos, etc). Pero en general, se ve prometedor.

Para celebrar, les invito a que corran esta aplicación escrita en JavaFX, la cual escribí para la ocasión: HaloWeb.

Si les gusto les puedo explicar el código a continuación:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
package haloweb;
 
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.image.ImageView;
import javafx.scene.image.Image;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.scene.shape.Rectangle;
import javafx.scene.effect.DropShadow;
import javafx.animation.Interpolator;
import javafx.animation.Timeline;
import javafx.scene.control.Button;
import javafx.scene.control.Tooltip;
import javafx.scene.Cursor;
 
var isPlaying = false;
 
var currentCursor = Cursor.WAIT;
 
/**
 * Simple application that plays a Halo Reach video while doing other eye candy
 * effects, or an excuse to do something while Bungie keeps rebooting the Halo
 * Reach Beta every 10 minutes :)
 * @author josevnz at kodegeek dot com, http://kodegeek.com/
 * License: BSD
 */
 
 
def const = Constants {
    videoUrl: "http://download.halowaypoint.com/content/waypoint/assets/videos/web/032373081197/Halo_Reach_Multiplayer_Trailer_ESRB_360p_ST.wmv";
    backgroundUrl: [
        "http://www.bungie.net/images/Games/Reach/images/visualID/REACH_KeyArt_Horizontal_1920x1080.jpg",
        "http://www.bungie.net/images/Games/Reach/images/concept_art/ReachConcept_NobleTeam.jpg"
        ];
    width:800;
    height: 600;
}
 
 
def videoWidth = 640;
def videoHeight = 360;
 
def backImage1 = Image {
		url: const.backgroundUrl[0]
};
 
def backImage2 = Image {
		url: const.backgroundUrl[1]
};
 
var backOpacity: Number = 0.0;
 
// Animation to show transition between the two images
var backgroundTimeline = Timeline {
    keyFrames: [
        at(0s) {
        backOpacity => 0.0;
        },
        at(1s) {
        backOpacity => 1.0 tween Interpolator.LINEAR;
        }
    ]
};
 
// First background
var backgroundView1 = ImageView {
	image: backImage1
        fitHeight: const.height
        fitWidth: const.width
        preserveRatio: true
        opacity: 1.0
        clip: Rectangle {
            height:const.height
            width: const.width
            arcWidth: 50,
            arcHeight: 50
        }
        effect: DropShadow {
            offsetX:10
            offsetY:10
            color: Color.BLACK
        }
 
}
 
// Background with rollover
var backgroundView2 = ImageView {
	image: backImage2
        fitHeight: const.height
        fitWidth: const.width
        preserveRatio: true
        opacity: bind backOpacity
        clip: Rectangle {
            height:const.height 
            width: const.width
            arcWidth: 50,
            arcHeight: 50
        }
        effect: DropShadow {
            offsetX:10
            offsetY:10
            color: Color.BLACK
        }
 
        // The second image is added last, run transition from there
        onMouseEntered: function(event):Void {
            backgroundTimeline.rate = 1; // Forward
            backgroundTimeline.play();
        }
 
        onMouseExited: function(event):Void {
            backgroundTimeline.rate = -1; // Backwards
            backgroundTimeline.play();
        }
}
 
def video = Media {
		source: const.videoUrl
                onError: function(error):Void {
                    println("No se pudo cargar el video: {error.message}");
                }
	}
 
def videoPlayer = MediaPlayer {
	media : video
        autoPlay:false
        volume:0.6
        repeatCount: MediaPlayer.REPEAT_NONE
}
 
var isVisible: Boolean = false;
 
def haloVideoView = MediaView {
	preserveRatio: true
	mediaPlayer : videoPlayer
        visible:bind isVisible
        fitHeight: videoHeight;
        fitWidth: videoWidth;
        translateX: (const.width - videoWidth) / 2
        translateY: ((const.height - videoHeight) / 2) - 60 // Little hack here
 
        // Control the video replay
        onMousePressed: function(event):Void {
            if (isPlaying) {
                videoPlayer.pause();
            } else {
                videoPlayer.play();
            }
            isPlaying = not isPlaying;
            currentCursor = Cursor.DEFAULT
        }
 
        onMouseEntered:function(event): Void {
            if (not isPlaying) {
                currentCursor = Cursor.CROSSHAIR
            }
        }
 
        onMouseExited:function(event): Void {
            currentCursor = Cursor.DEFAULT
        }
 
}
 
// Prepare the glowing text
def kodegeekText = GlowingText {
    height: const.height
    width: const.width
    text: "http://KodeGeek.com/"
}
 
def exitButton = Button {
	text: "!Salir¡"
        translateX: const.width - (const.width * .10)
        translateY: 20
        visible: bind isVisible
	action: function() {
		FX.exit();
	}
        tooltip: Tooltip {
           text: "Haga click aquí para salir de esta aplicación"
        }
 
}
 
var videoTimeline = Timeline {
    keyFrames: [
        at (5s) {
            isVisible => true;
            currentCursor => Cursor.DEFAULT;
        }
    ]
}
 
 
// Show the final scene
Stage {
 
    title: "KodeGeek está emocionado con Halo Reach!"
    scene: Scene {
        width: const.width
        height: const.height
        fill: Color.TRANSPARENT
        content: [
            backgroundView1,
            backgroundView2,
            haloVideoView,
            kodegeekText,
            exitButton
        ]
        cursor: bind currentCursor;
    }
 
}
 
videoTimeline.play();

Básicamente tenemos 2 fondos (backgroundView1, backgroundView2) de los cuales uno de ellos tiene opacidad variable, la cual cambia en cuando el usuario pone el cursor del ratón en el área de la aplicación. Los otros elementos son el vídeo (haloVideoView, el cual se puede parar o arrancar al hacer click en este), un texto “que brilla” (kodegeekText, con super publicidad :) ), y botón que mata la aplicación (exitButton). Si usted tiene familiaridad con otros lenguajes como Flash o JavaScript entonces no debería tener problemas leyendo el código.

¿Como hacemos que el texto brille? Es sencillo, creamos un nodo a la medida el cual corre una animación infinita la cual tiene un efecto especial (Glow) sobre el texto (la variable del efecto cambia ya que le hacemos un ‘bind’ con el nivel de brillo):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package haloweb;
import javafx.scene.CustomNode;
import javafx.scene.Node;
import javafx.scene.effect.Glow;
import javafx.scene.effect.Lighting;
import javafx.scene.effect.light.DistantLight;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
 
/**
 * Simple glowing text node
 * @author josevnz at kodegeek dot com, http://kodegeek.com/
 * License: BSD
 */
 
var glowLevel: Number = 1.0;
 
var glowTimeline: Timeline = Timeline {
    repeatCount: Timeline.INDEFINITE
    keyFrames: [
        KeyFrame {
            time: 600ms
            values: [
                glowLevel => .7 tween Interpolator.EASEBOTH
            ]
        }
    ]
}
 
public class GlowingText extends CustomNode {
 
    public-init var width: Number;
    public-init var height: Number;
    public-init var text: String;
 
    public override function create() :Node {
 
        glowTimeline.play();
 
        Text {
            font : Font {
		size: 24
            }
            translateX: width - (width * 0.30)
            translateY: height - (height * 0.25)
            content: text
            fill: Color.DARKORANGE
            effect: Glow {
                level: bind glowLevel
                input: Lighting {
                    light: DistantLight {azimuth: -135}
                    surfaceScale: 3
                    diffuseConstant: 1.8
                }
            }
        }
   }
 
}

Y una clase de constantes que escribí para este programa. Inútil, en algún momento puliré más la aplicación:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package haloweb;
 
/**
 * Useful constant for the HaloWeb project
 * @author josevnz at kodegeek dot com, http://kodegeek.com/
 * License: BSD
 */
 
public class Constants {
    public-init var videoUrl: String;
    public-init var backgroundUrl: String [];
    public-init var width: Number;
    public-init var height: Number;
    public-init var backgroundWidth: Number;
    public-init var backgroundHeight: Number;
}

No me tomó mucho tiempo escribir el código, pero debo decir que NeBeans 6.9 es una porquería. A cada rató se caia, me daba errores por todos lados y su creador de interfaces gráficas tiene demasiados problemas. A la final armé la aplicación a pedal y bomba, como los machos :) . Por ahora no tengo intenciones de meter este código en Subversion, me da flojera. Avisenme si de verdad quieren este código y con gusto hago el esfuerzo ;)

Ahora los dejo, vamos a ver si el servidor de Bungie está funcionando para continuar jugando el nuevo beta :D

–Jose

java, javafx , , , ,

Aventuras con JavaFX 1.3 y NetBean 6.9

Sábado, 1 de mayo de 2010

Bueno, después de una larga espera Oracle nos trae JavaFX 1.3. El entorno de ejecución promete muchas mejoras, lo único es que el entorno de desarrollo es NetBeans 6.9 BETA.

Si, beta. Tiene una lista de problemas (entre esos la depuración de programas). Sin embargo, si escribo mis ‘unit tests’ debería estar más o menos bien, ¿no es así?

Lo primero que intenté hacer es convertir el método ‘main’ de una de mis clases en Java (no JavaFX) a Junit:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/*
 * Helper class used to parse and process CVS data comming from an InputStream
 * License: GPL
 * @author josevnz at kodegeek dot com
 */
 
package com.kodegeek.blog.javafx.workout.app;
 
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;
 
 
/**
 *
 * @author josevnz
 */
final public class CsvDataParser {
 
private List <list <Object>>data;
private static final Pattern splitPattern = Pattern.compile(",\\s*");
private SimpleDateFormat format;
private Pattern skipNonNumberPatter = Pattern.compile("^\\D+");
 
/**
 * Expected default number of data observations
 */
public static final int DEFAULT_DAY_COUNT = 365;
 
/**
 * Expected default number of series to display on the same chart
 */
public static final int DEFAULT_SERIES = 50;
 
    /**
     * Constructor
     * @param numSeries expected number of series on the stream
     */
    public CsvDataParser(int numSeries) {
 
        /*
         * Ddata is a list of lists where:
         * data(0): List of dates
         * data(n): Values of each series.
         * data is a rectangular array, every value matches a date
         */
        data = new ArrayList</list><list <Object>>();
        List<object> dates = new ArrayList</object><object>();
        data.add(0, dates);
        for (int i = 1; i < numSeries; i++) {
            List<Object> values =
                    new ArrayList</object><object>();
            data.add(i, values);
        }
 
        format = new SimpleDateFormat("MM/dd/yy");
    }
 
    /**
     * Parse a given input stream for data. Not thread safe. It is assumed than
     * the number of tokens on the stream is constant and there
     * are no data holes. The caller is responsible from closing the stream
     * @param io The data source
     * @throws Exception If there is a problem reading the stream
     */
    public void parse(InputStream io) throws Exception {
        BufferedReader lineRdr = new BufferedReader(new InputStreamReader(io));
        String line = null;
 
        try {
 
            while ((line = lineRdr.readLine()) != null) {
 
                if (skipNonNumberPatter.matcher(line).find()) {
                    continue;
                }
 
                String[] tokens = splitPattern.split(line, -1);
                int numSeries = tokens.length;
                if (numSeries ==0 || tokens[0] == null) {
                    return;
                }
 
                if (numSeries != data.size()) {
                    String error = String.format(
                            "Number of expected tokens is %s, got %s",
                            data.size(),
                            numSeries);
                    throw new Exception(error);
                }
 
                // Store dates as numbers, let the caller do any conversions
                List</object><object> dates = (List</object><object>) data.get(0);
                dates.add(format.parse(tokens[0]).getTime());
 
                // Get the values for each series now (rest of the tokens)
                for (int i = 1; i < numSeries; i++) {
                    List<Object> values = (List</object><object>) data.get(i);
                    values.add(Float.parseFloat(tokens[i]));
                }
 
            }
        } catch (Exception exp) {
            throw exp;
        }
 
    }
 
    /**
     * Get the collected data as a List of Lists. First element of the returned
     * list contains the dates as Epoch long dates, after that the series
     * @return Array of dates as epoch long
     */
    public Long [] getDates() {
        return data.get(0).toArray(new Long[0]);
    }
 
    /**
     * Get the values as a list of
     * @param index Valid ranges go from 1 to n
     * @return Array of float series values
     */
    public Float [] getSeriesValues(int index) {
        if (index < 1 || index > data.size()) {
            throw new IllegalArgumentException(
                    String.format("Invalid series index %d", index));
        }
        return data.get(index).toArray(new Float[0]);
    }
 
 
    /**
     * Unit test, show how the parser works on a CSV file. THIS SHOULD BE A
     * JUNIT TEST INSTEAD!!!
     * Program expects the property.
     * @param args List of files to parse. Each one like: numTokens:fullpathFile
     * @throws Exception If there are any problems
     */
    public static void main(final String [] tokens) throws Exception {
        for (String token: tokens) {
            String [] parts = token.split(":", -1);
            InputStream in = null;
            try {
                int nTokens = Integer.parseInt(parts[0]);
                File f = new File(parts[1]);
                if (f.canRead() && f.isFile()) {
                    in = new FileInputStream(f);
                    CsvDataParser instance = new CsvDataParser(nTokens);
                    instance.parse(in);
                    in.close();
                    Long [] dates = instance.getDates();
                    Float [] values = instance.getSeriesValues(1);
                    for (int i = 0; i < dates.length; i++) {
                        System.out.println(
                                String.format("%s -> %s",
                                new Date(dates[i]), values[i]));
                    }
                }
            } catch (NumberFormatException nfe) {
                System.err.println(
                        String.format(
                        "Invalid expected token value: '%s'", parts[0]));
            } catch (Exception exp) {
                throw exp;
            } finally {
                if (in != null) {
                    in.close();
                }
            }
        }
    }
 
}
</object></list>

Sin embargo la interfaz gráfica me abofetea con este error: No tests root folder was found

Que fastidio. No soy un experto en NetBeans (me defiendo mucho más con Eclipse), así que en vez de estar echando código ando resolviendo estos problemas. ¡Que perdida de tiempo!

Me pregunto si Oracle piensa competir en serio con Adobe Flash si su editor principal aún tiene este tipo de problemas.

Amanecerá y veremos, por los momentos ando tratando de resolver el asunto yo mismo, al mismo tiempo pedí ayuda en los foros oficiales. Una vez resuelto, podré correr Junit para JavaFX como lo indica este excelente blog.

java, javafx, kodegeek, oracle