Dynamic DNS in Hostmonster with Ruby(easily extensible to any cpanel)

It’s been awhile since I wrote something. Now I wanna show you how to make changes into DNS records managed by CPanel with Ruby and Mechanize.

Everyone remembers services like dyndns and no-ip, but when we got a hosting and a domain name at some place like Hostmonster, we still want to point a subdomain to our home server. But it’s pretty annoying to log into Cpanel and change the records manually. So I wrote this little tool.

This specific code works for Hostmonster, but it’s easily extensible to any(I guess) Cpanel based hosting.

First you need to install ruby with mechanize and json libraries. In a Debian/Mint/Ubuntu way you can do typing the next on console:

sudo apt-get install ruby ruby-mechanize ruby-json

Next you need the following code:

#!/usr/bin/env ruby

require 'mechanize'
require 'json'

USERNAME	= 'MY_USERNAME'
PASSWORD	= 'MY_PASSWD'
DOMAIN		= 'positrones.net'
SUBDOMAIN	= 'my_subdomain'
ADDRESS		= '0.0.0.0' # If nil then try to get automagicaly

URLS = {
			'login'		=> 'https://login.hostmonster.com/?',
			'drecords'	=> 'https://my.hostmonster.com/cgi/dm/zoneedit/ajax'
		}

USER_AGENT = 'Windows IE 9'

m = Mechanize.new do |a|
	a.verify_mode = OpenSSL::SSL::VERIFY_NONE
	a.user_agent_alias = USER_AGENT
end

def get_ip
  r = Net::HTTP.get('myip.positrones.net', '/')
  ip = r.match(/\d{1,4}\.\d{1,4}\.\d{1,4}\.\d{1,4}/)

  ip[0].to_s
end

# Do the login stuff
print "Checking user and password... "
page = m.get( URLS['login'] );
form = page.form_with( :name => 'theform' )
form['login'] = USERNAME
form['password'] = PASSWORD
send_button = form.button_with(:value => 'Login')
form.click_button(send_button)
page = page.links[0].click
puts "done!"

# Edit the DNS Zone
page = page.link_with(:text => 'DNS Zone Editor').click
print "Getting old zone records... "
json = JSON.parse( m.post( URLS['drecords'], {'op' => 'getzonerecords', 'domain' => DOMAIN} ).body )
puts "done!"

print "Trying to get subdomain old info... "
json['data'].each do |r|
	if r['name'] == SUBDOMAIN
		print "done!\nSaving new address[#{r['address']} => #{ADDRESS||get_ip}]... "
		json = m.post( URLS['drecords'], {'op'		=> 'editzonerecord',
									'domain'		=> DOMAIN,
									'name'			=> SUBDOMAIN,
									'orig__name'	=> SUBDOMAIN,
									'address'		=> ADDRESS||get_ip,
									'orig__adress'	=> r['address'],
									'ttl'			=> r['ttl'],
									'orig__ttl'		=> r['ttl'],
									'Line'			=> r['Line'],
									'type'			=> r['type']}
			)
		json = JSON.parse(json.body)

		if( json['result'] == 1 )
			puts "done!\nAddress changed succesfully!"
			Kernel::exit(0)
		else
			puts "\nAn error has ocurred trying to save new address :("
			Kernel::exit(1)
		end
	end
end

puts "The subdomain #{SUBDOMAIN} cannot be found!"
Kernel::exit(1)

The first lines just load the libraries «mechanize» and «json».
Then we stablish the data of the hosting provider, the names are self explanatory, just few points:

  1. The domain must not have the www
  2. The subdomain must be alone. If you wanna change «code.positrones.net» just type «code»
  3. You can specify the new IP address of the A record. If you wanna use your public IP address to be detected, change to nil

The URLS hash contains the information of the login page and the ajax DNS editor of the Cpanel, change it to fit your needs ;)

The USER_AGENT it’s an id defined in the Mechanize library, in this case we want to identify as IE 9.

The login process usually takes place through an encrypted connection(HTTPS), then, for reasons not exposed here, we deactivate the verification of the SSL certificate and then set the USER_AGENT.

Then we define a method called get_ip, this method connects to a site which only returns the IP address of the client.

The rest of code log in into Cpanel, go to DNS Zone Editor and change the information of the given subdomain. The use Mechanize library it’s exposed in other post, you can read it if you wanna know the details.

The program returns 0 if everything goes fine, 1 in other case. By the way, I didn’t write some error management sentences, so be careful when use this code.

You can download from here.

Enjoy. :)

Watching files with ruby and fssm

On GNU/Linux exists a library called inotify which does that, notifies for changes(change, create, delete) of files into a directory. Over Mac there is FSEvents, which essentially do the same as inotify, with some exceptions of course.

Now, what happened if I have 2 servers which I want to monitor for file changes?. You could say: «write one app and run on 2 servers». Yeah!, nice answer, but 1 of them is running GNU/Linux and the other one is running MacOS, so we need something like Ruby to do so.

First we install fssm(File System State Monitor) from rubygems:

gem install fssm

Maybe you need do the above as root. Next go to your favorite editor, I use Geany.

Of course, the first lines will be:

#!/usr/bin/env ruby

require 'rubygems'
require 'fssm'

The first line calls for the ruby interpreter and the next 2 loads rubygems and fssm ruby extensions.

Now go to the magic code, it’s pretty simple and easy to undestand.


FSSM.monitor("/tmp/test") do
	update do |b, r|
		puts "Someone changes the file '#{r}' into '#{b}'"
	end

	create do |b, r|
		puts "Someone creates the file '#{r}' into '#{b}'"
	end

	delete do |b, r|
		puts "Someone deletes the file '#{r}' into '#{b}'"
	end
end

The first line enters to a loop that watch for filesystem changes only into /tmp/test directory.

The second line states which actions gonna take the program if the some file inside the /tmp/test directory has been updated and passes the variables b and r to the block(in this case just line number 3). r is the relative path to the updated, b is the absolute path(/tmp/test in this case); then a message is printed on the screen.

The code for the created and deleted files are the same.

Now, the FSSM.monitor has 3 possible arguments, we just use 1 of them in the above example.

The second parameter is a glob pattern(or array of glob patterns) that the files must match to be watched by fssm, if this parameter is not specified, the default is **/*.

The third parameter is for watching directories. By default, fssm watch just for file changes, if we want to watch directories too we need to pass the option here, doing this :directories => true, and additionally, the blocks for update, delete and create must have another block variable:

delete do |b, r, t|
	puts "Someone delete #{r} into #{b} which is a #{t == :directory ? 'directory' : 'file'}"
end

Where t is the type, it means if is a directory or a file, we check for this in a «short» if statement. t variable can be the symbols :directory or :file. AFAIK this will not work as expected on MacOS, I appreciate if someone can confirm, I’m a poor guy and I don’t own a Mac. :P . Anyway it don’t watch for created, deleted or updated directories, but if you create a directory inside /tmp/test and then create a file inside, it will be detected.

So, the complete code with checking for directories is:

#!/usr/bin/env ruby

require 'rubygems'
require 'fssm'

FSSM.monitor("/tmp/test", '**/*', :directories => true) do
 update do |b, r, t|
 puts "Someone changes #{r} into #{b} which is a #{t == :directory ? 'directory' : 'file'}"
 end

 create do |b, r, t|
 puts "Someone create #{r} into #{b} which is a #{t == :directory ? 'directory' : 'file'}"
 end

 delete do |b, r, t|
 puts "Someone delete #{r} into #{b} which is a #{t == :directory ? 'directory' : 'file'}"
 end
end

That’s it!. Now we can watch for filesystem changes in many different systems. It’s so nice and useful. Of course we need to develop and work a little more to do something nicer.

I hope this will help someone, works for me.

See you soon.

Changing IP Address of a Thomson TG585-V8 Router

My old ADSL internet modem HG2701was burned for some reason and I requested for a replacement to my ISP and it gave me a Thomson TG585-V8 modem which makes useles a little python script that I found around to change the IP and keep downloading… backup copies of something.

As a coincidence some days ago I read about a library called mechanize and of course using one of my favorite languages(ruby) I decided to write a little program to change my IP address.

Here, the description of mechanize library stolen from it’s website:

«The Mechanize library is used for automating interaction with websites. Mechanize automatically stores and sends cookies, follows redirects, can follow links, and submit forms. Form fields can be populated and submitted. Mechanize also keeps track of the sites that you have visited as a history.»

After read some examples and write some testing code I reach to a very simple script that does the magic:

require 'mechanize'

USER = 'USERNAME'
PASSWORD = 'PASSWORD'

URL = 'http://192.168.1.254/cgi/b/is/_pppoe_/ov/?be=0&l0=2&l1=2&name=Internet'

BUTTONS = ['13', '12'] #First is to deconnect, next for reconnect

FORM = 'PPPConn'
SNAME = 'Internet'

m = Mechanize.new

m.user_agent_alias = 'Windows IE 7'
m.auth(USER, PASSWORD)

BUTTONS.each do |bn|
 page = m.get(URL)
 f = page.form_with(FORM)

 f['0'] = bn
 f['1'] = SNAME

 b = f.button_with(:name => bn)
 f.click_button(b)
end

A basic explanation of the above code:

  • We create an instance of the Mechanize class
  • Now we inform to the website which interact to us that we are some kind of webbrowser
  • And then we need to autenticate to the site
  • Then we get the page, the form and fill the correct values
  • Now we click the button to kill the connection
  • So, we repeat the page, form, button, and click the connect button to get a new IP address

Of course, the code has no error checking, it’s a really basic version. But I like it ’cause it’s just a few code.

You can get the code from my bitbucket utils repository and of course I hope to add some features, not so much, it does what suppose to do.

Happy hollidays!.

Generate «secure» passwords

It’s been awhile since I posted something, and even more since I posted computer stuff.

Well, this time I make a little script to generate «secure» passwords from command line with options to modify the number of generated passwords and the number of characters in each password.

The real trick it’s done through a combination of a few shell tools.

  • < : The redirection symbol, it means, send from one side to another.
  • /dev/urandom : «Unblocked» random source
  • tr : Translate or delete characters
  • head : Output the first part of files

So, let’s build the expression which brings to us the passwords. First of all we use

</dev/urandom

to send /dev/urandom output to stdout. The next step is to process the chars dropped by urandom, this can be made with tr command  and the -dc options, d deletes chars and c takes the complement of the given parameter,

</dev/urandom tr -dc '1234567890!@#$%&/()=qwertyuiopQWERTYUIOPasdfghjklASDFGHJKLzxcvbnmZXCVBNM'

, so, tr will take the complement of that ugly string and then delete it, so it removes all the chars that are not inside the long string above, leaving just an «easily» read string.

Now, if we leave the command as is, we get an extremely large string and of course, unusable as password, so we need to cut it, then we pipe to head command with the -cn option, it says «just take the first n characters of anything is given to you». By this time we set n=8, a nice length for a good password.

</dev/urandom tr -dc  '1234567890!@#$%&/()=qwertyuiopQWERTYUIOPasdfghjklASDFGHJKLzxcvbnmZXCVBNM' | head -c8

Now, you can try it!. It gives you a 8 char length password and as you can see, it can be considered(most times) a good password. As an extra, you can put an echo “” at the end of the command to tell bash that puts a new line before the prompt.

</dev/urandom tr -dc   '1234567890!@#$%&/()=qwertyuiopQWERTYUIOPasdfghjklASDFGHJKLzxcvbnmZXCVBNM'  | head -c8; echo ""

And if you want to automatize the generation of passwords and variate the number of generated passwords and the length of it, you can build a little script, I’m not gonna explain to you, but I leave it here, use it and enjoy it.

#!/usr/bin/env bash

genpass()
{
 </dev/urandom tr -dc '1234567890!@#$%&/()=qwertyuiopQWERTYUIOPasdfghjklASDFGHJKLzxcvbnmZXCVBNM' | head -c${1}
}

usage()
{
 echo "${0##*/} c p"
 echo -e "\tc is the number of chars in each generated password"
 echo -e "\tp is the number of password to be generated\n"
 exit 1
}

control()
{
 if [ "$#" = "0" ];then
 npass=1
 cpass=8
 elif [ "$#" = "1" ];then
 if [ "$1" = "-h" ];then
 usage
 elif [ "$1" = "--help" ];then
 usage
 fi

 cpass=$1
 npass=1
 else
 cpass=$1
 npass=$2
 fi

 echo "Chars in each password: ${cpass}"
 echo "Number of passwords to generate: ${npass}"
 echo -e "Generating...\n"

 i=1
 while [ ${i} -le ${npass} ];do
 echo -n -e "\t${i}: "
 genpass ${cpass}
 echo ""
 let i=i+1;
 done

 echo ""
}

control $1 $2

See you soon!.

Signing Java Applets

When you need that your applet uses some features like access to client machine files or remote files outer applet base directory it’s mandatory to configure the client virtual machine to allow this(craziest thing) or sign our applet and hope that the user click over «Run» button that appears after the applet loads. Of course the last one option it’s best just because practical reasons.

Now, imagine that we already finish our applet, now we have to pack it to a jar file, that’s just a zip format file with the extension jar. How do that?, simple!, imagine that we gonna pack the ImageViewer applet:

$ jar cf ImageViewer.jar ImageViewer.class ImageTest.jpg

Remember that $ it’s your terminal, command line or whathever prompt, so, don’t write it. The command it’s so simple jar, and the options are «c» that means create a new jar file and «f» means that we gonna indicate the name of the new jar file, in this case «ImageViewer.jar». Next we have ImageViewer.class and ImageTest.jpg which are the files that our applet needs to run. That’s all! now we have a jar file. An important thing to do it’s modify our html page(here just the applet tag) that used to be:

<applet code="ImageViewer.class" width="320" height="240"></applet>

Now become:

<applet code="ImageViewer.class" archive="ImageViewer.jar" width="320" height="240"></applet>

Notice that just added the «archive» stuff, it says to web browser where to find the jar file.

But still we have an unsigned applet, to sign we need first to generate a key, yep, just like our ssh keys and that.

$ keytool -genkey -alias "deathwarrior"

The keytool app it’s provided with the JDK and the options are genkey to(guess what?) generate key and alias which it’s a name that identify that new key, next several data are asked as well a password to secure our keystore and a password for the new key(yes, could be the same).

Now our key is created, let’s sign our applet:

$ jarsigner ImageViewer.jar deathwarrior

Again, jarsigner it’s JDK provided, ImageViewer.jar it’s the jar file that we want to sign and «deathwarrior» it’s the alias of the key which will be used to sign the jar file.

We already done!. Now the applet could be authorized by the user just clicking on the «Run» button and we have access to certain options limited by default.

Hope be helpful.

Greets.

Loading Images into a Java Applet

Now we are back to the Applet’s World, Yay!. Let’s write some little app which just load an image and show us.

If you don’t know which’s the basic structure of a Java Applet, please read this first.

First of all, we need to import our basic libraries to work, so, the begin of your file, let’s say ImageViewer.java needs to looks like:

import java.applet.*;
import java.awt.*;

Next it’s needed to declare our class, remember that Java just allows one class per file and the class must be named exactly like file(or file like class), then you now have next thing:

import java.applet.*;
import java.awt.*;

public class ImageViewer extends Applet
{
}

The extends Applet thing it’s just a manner to say: hey!, Applet it’s my daddy and because of him I got his whole properties and habilities.

In this specific case, we gonna need three applet specific methods: init, start and paint, but before that, let’s declare the variables that we are gonna use.

import java.applet.*;
import java.awt.*;

public class ImageViewer extends Applet
{
    int maxX, maxY;
    Image image;
    MediaTracker mt;
}

The two integer variables are used to store the image width and height respectively. The Image class variable are used to store the information of the image that can be painted on the screen. And the MediaTracker variable is used to “track” some aspects of media, you’ll see it’s utility after.

Going to our first method: init().

As you can remember, init() method is executed when the applet is created, so we can look it like a “contructor”.

public void init()
{
    showStatus("Getting image...");
    mt = new MediaTracker(this);
    image = getImage(getDocumentBase(), "ImageTest.jpg");
    mt.addImage(image, 0);
}

The showStatus thing show us a message in the web browser status bar.
MediaTracker stuff creates a new object of the named class, and the only parameter to the constructor is this, if we read the java documentation says that MediaTracker contructor receives an ImageObserver variable type, but… let’s leave that for another season, in this case(and in every Applet AFAIK) just pass this.
The image line says that obtain an image with absolute path based on getDocumentBase() (this is a URL, not a String) and relative path “ImageTest.jpg”. Here it is an important thing, the getImage method returns inmediatly and it doesn’t care if the image exists, is loaded and other important things that really matters, and that’s the reason of MediaTracker to be, besides we can always use images without MediaTracker but it’s not really sane.
mt.addImage(image, 0) adds the image that just said to load into MediaTracker so we don’t loose the clue of it, the second argument it’s an integer used as a “group identifier”, normally set to zero.

Next is start() method, this is called afted init() method.

showStatus("Loading image...");
try
{
    mt.waitForAll();
}
catch(Exception e)
{
    e.printStackTrace();
}
while(!mt.checkAll(true))
{
}
imageX = image.getWidth(this);
imageY = image.getHeight(this);
showStatus("Resizing Applet image size: " + imageX + "x" + imageY);
resize(imageX, imageY);

showStatus() again.
Inside the try block we can find mt.waitForAll() which starts to load all images registered into MediaTracker.
The while loop with the mt.checkAll(true) check if all images are loaded and the parameter true said that if some are not loaded, then load!, that’s why inside the loop, to wait until every image are ready.
Next lines just store the width and height of the image then we paint in status bar the dimensions and then resize the applet to fit the image to it.

paint() method do that: paint the image on the screen, of course, first we inform to user that we’re going to paint it, and then paint the image.

That’s all!. Now you have complete code:

import java.applet.*;
import java.awt.*;

public class ImageViewer extends Applet
{
    Image image;
    int imageX, imageY;
    MediaTracker mt;
    
    public void init()
    {
	showStatus("Getting image...");
	mt = new MediaTracker(this);
	image = getImage(getDocumentBase(), "ImageTest.jpg");
	mt.addImage(image, 0);
    }
    
    public void start()
    {
	showStatus("Loading image...");
	try
	    {
		mt.waitForAll();
	    }
	catch(Exception e)
	    {
		e.printStackTrace();
	    }
	while(!mt.checkAll(true)){}
	imageX = image.getWidth(this);
	imageY = image.getHeight(this);
	showStatus("Resizing Applet image size: " + imageX + "x" + imageY);
	resize(imageX, imageY);
    }
    
    public void paint(Graphics g)
    {
	showStatus("Drawing image...");
	g.drawImage(image, 0, 0, this);
    }
      
}

It’s fun to look the applet doing nothing but painting an image, but it’s a nice start, maybe you can figure out how to make a simple game.

Greets.

Uploading Files through Ruby CGI

Hi again fellows. Well this time bringing to you the marvelous method to upload a file through Ruby CGI, yep, as you seen on… well I don’t know where.

If you dont know how to make a basic CGI app in Ruby, please read this.

Now, if we have the next HTML form to upload files:

<form method="POST" enctype="multipart/form-data" action="uploader.rb">
<label>File:<input type="file" name="file" size="100"/></label> <br />
<input type="submit" value="Go!" />
</form>

It’s easy to know which that form sends the data to uploader.rb. So let’s take a look into that Ruby script.

#!/usr/bin/env ruby

cgi = CGI.new
puts cgi.header
params = cgi.params

So far nothing new. But now lets check if someone send us a file:

if params.has_key?"file"
 #do something with that
end

Again, nothing new. Now comes funny part.

file = params["file"].first
server_file = 'files/' + file.original_filename

First line takes a Ruby object of a class StringIO(not String!) that’s something like a mutant, a mix between an IO object and a String, but none of them… weird class, here is the file that user uploads.

Second line it’s the name(path included) which we are to save the file into the server, yes, this is just a String.

Now we want to save the file in the server, to do that we just take the original file and write it’s content to the server file:

File.open(server_file.untaint, "w") do |f|
    f << file.read
end

Now the job it’s done, your code now looks like:

#!/usr/bin/env ruby

cgi = CGI.new
puts cgi.header
params = cgi.params

if params.has_key?"file"
    file = params["file"].first
    server_file = 'files/' + file.original_filename
    File.open(server_file.untaint, "w") do |f|
        f << file.read
    end
end

Now you can do something with that file.

Happy hacking!.

Ruby CGI’s

Hi all. After a long time without publish any tech doc, I’m back!.

Today will see how to use Ruby(yes, Ruby) to make our CGI tools. As you already know, CGI’s are traditional written in Perl, but if we check some Ruby’s history we can find next statement:

Ruby takes best of several worlds: Perl, Python and SmallTalk

So if we have best of Perl I think we have powerful CGI’s.

First of all we need to know that just a few free hosting services provide Ruby as an allowed scripting language, but we can always get cheap hosting(I got mine into 1 USD per month). Besides you can use your own webserver.

Suppose that we already configure our webserver to execute CGI programs, so let’s write code!.

Every script that you write into an interpreted language begins with a line like this:

#!/usr/bin/env ruby

which says: hey! run my amazing code with Ruby(this specific case).
Now you can start write your pages in a similar way what you do into PHP, except you have to require an specific library to make the work less painful: cgi(hard to figure out, isn’t?).

#!/usr/bin/env ruby

require 'cgi'

cgi = CGI.new

Last line of code it’s just used to create a new object of class CGI.

Now, as HTTP protocol requires, our script must send the headers to web browser, if we need a custom headers must read some RFC’s and that boring stuff, instead just tell Ruby to send “standard” headers doing:

puts cgi.header

By the way, if we need to print some to the webpage just do like if you print something into terminal, I mean puts, print, printf and a lot of functions which Ruby provides.

At this point your code looks like:

#!/usr/bin/env ruby

require 'cgi'

cgi = CGI.new
puts cgi.header

Now let’s try something more interesting, assume that we got some parameters from a webform, let’s say we asked to user… mmmh, name and email, classic fields in a webform.

In HTML code the form looks like:

<form method="GET" action="myRubyScript.rb">
<label>Name: <input type="text" name="name" /></label>
<br />
<label>Email: <input type="text" name="email" /></label>
</form>

If the above form sends data to our script, then we need to catch and do something with it. So do the next thing:

params = cgi.params
name = params["name"][0]
email = params["email"][0]

May you think what if I need to check the existence of some params?, well we can do that:

params = cgi.params
name = params["name"][0] if params.has_key?"name"
email = params["email"][0] if params.has_key?"email"

Nice, isn’t?. But now you can think… Yep, params it’s a Ruby hash(like an associative array in PHP), why are we processing it first like a hash and then like an array?. Well, the answer comes really faster and hits you hard…

What happened if the parameter values are several to the same parameter name?. Well, Ruby can manage that stuff, that’s why Ruby stores an array as a value of a hash. So if someone passes several names like Sheldon, Raj, Leonard and Howard we can access pretty easy:

params = cgi.params
name1 = params["name"][0]
name2 = params["name"][1]
name3 = params["name"][2]
...

Some of you can ask how Ruby figures out if the request was made by POST method or GET method, well, at this point Ruby takes every request type as the same. But if you wanna look which type of request the client did you can check it like this:

case ENV['REQUEST_METHOD']
when "GET"
#Do something with GET
when "POST"
#Do POST stuff
end

So, do you think that Ruby CGI stuff is really hard?.
Please take a look into Ruby CGI Library Documentation

Greets folks!

[UPDATE] Thanks to Dave B for the corrections. :D

Java Applets

La mayoría de las personas que me conocen saben que no soy muy fan de Java, aunque en fechas recientes he estado haciendo algunas cosas con uno de los hijos predilectos de Sun. El punto es que, como dijo alguna vez Clmns, «Java es como una caja de legos, ya está todo hecho, nada más armas», y es verdad, será feo, lento, horrible y chillón, pero te da la facilidad y rapidéz de desarrollo, lo cual busco en estos momentos por necesitar centrarme en otras cosas como la física del problema o algunas cuestiones pedagógicas y didácticas.

Además, si tomamos un subconjunto de Java hecho especialmente para el internet, podemos ir aún más rápido, éstos son los ya famosísimos Applets, que al tener ya una estructura definida y muchas facilidades incluidas, el tiempo de desarrollo se reduce considerablemente cuando se trata de trabajos o proyectos que requieren un mínimo tiempo de implementación.

La estructura básica de un applet es la siguiente:


import java.applet.*;   //Es un applet, era de esperarse

import java.awt.*;        //Toda la cuestión gráfica.

public class miApplet extends Applet{//Definición de la clase de nuestro Applet y heredamos de la clase Applet

public void init(){

//Es la parte donde se inicializa el Applet, podría verse como el constructor

}

public void start(){

//Aquí comienza a correr el Applet, sería algo así como el main

}

public void stop(){

//El Applet se detiene, es como ponerlo en pausa

}

public void destroy(){

//Cuando se cierra el Applet

}

public void paint(Graphics g){

//En este método gestionaremos la parte gráfica del Applet, por eso importamos al inicio java.awt.*.

}

}

El código anterior puede copiarse, pegarse y compilarse como sigue:


javac miApplet.java

Lo cual, si todo va bien, generará un archivo llamado miApplet.class.

Ahora bien, al ser una tecnología hecha para la web, se necesita una página web para incrustar el applet ya compilado, la página es como la siguiente:


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

<head>
 <title>miApplet</title>
 <meta http-equiv="content-type" content="text/html;charset=utf-8" />
 <meta name="generator" content="Geany 0.14" />
</head>

<body>
 <applet code="miApplet.class" width="640" height="480"></applet>
</body>
</html>

Pueden notar que utilizo Geany como editor, una belleza. Y en realidad aquí es donde se define el tamaño de la ventana del Applet, como se ve en la etiqueta correspondiente.

Existe un pequeño detalle al querer verlo en el navegador, la primera vez lo hará de una manera correcta, pero si poco tiempo después hacemos una modificación al applet, cargará la versión vieja(no sé si sólo tenga yo el problema del caché con firefox). Además, me es más comodo al trabajar con Geany, utilizar la herramienta appletviewer, la cual ejecutamos del siguiente modo:


appletviewer pagina.html

Como pueden ver, se utiliza la página para cargar el applet, no cargamos el applet de manera directa. Por defecto, el applet tiene un área designada del tamaño que indicamos en la página web y proporciona un chulo fondo gris, lo cual, evidentemente puede ser cambiado.

Ese es el applet más básico que podemos crear, uno que no hace nada… bueno, come memoria y hace lento mi firefox.

Espero seguir mostrando como funcionan estas cosas.

Saludos.