May 16 2008

Gwt-Ext and Number Madness

Tag: Ext, Gwt, Java, Javascript, Programming, WebAbhijeet Maharana @ 11:52 pm

Gwt-Ext Number Madness screenshotThis is the 3rd form of my game Number madness. I had first written it using TurboC during the vacation after junior college. And then as a Firefox extension. Both are available in the projects section.

Using Gwt-Ext for writing something like this sounds a bit silly. But it did make me learn something new: button templates; thanks to gwtext+ and sjivan. I have described the program below in brief. You can download Eclipse project from the link at the end of this post.

An Ext button is made up of a table with 3 columns. All three columns have parts of the button sprite as their background image and the center TD holds a <button> element. You can see this template in Button.java above the setTemplate() method definition:

1
2
3
4
5
6
7
8
9
10
<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap">
	<tbody>
		<tr>
	     		<td class="x-btn-left"><i>&#160;</i></td>
	     		<td class="x-btn-center">
	     			<em unselectable="on"><button class="x-btn-text" type="{1}">{0}</button></em></td>
	     		<td class="x-btn-right"><i>&#160;</i></td>
	     	</tr>
	</tbody>
</table>

We can override this template to make the button look as we want it to. My modified template looks as shown below. There is only one extra CSS class for the table (see notes at end):

1
2
3
4
5
6
7
8
9
10
<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap mybutton">
	<tbody>
		<tr>
	     		<td class="x-btn-left"><i>&#160;</i></td>
	     		<td class="x-btn-center">
	     			<em unselectable="on"><button class="x-btn-text" type="{1}">{0}</button></em></td>
	     		<td class="x-btn-right"><i>&#160;</i></td>
	     	</tr>
	</tbody>
</table>

This enables us to use CSS nesting to define x-btn-left, x-btn-center, x-btn-right and x-btn-text with the attributes we want while preventing the normal buttons from being affected. Thus we can use both Ext’s buttons and out custom buttons at the same time. I have defined them as:

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
.mybutton .x-btn-right {
	background: transparent url('button_right_06.png') no-repeat scroll right; 
	height: 150px;
	padding-right: 15px;
}
 
.mybutton .x-btn-left {
	background: transparent url('button_left_06.png') no-repeat scroll right; 
	height: 150px;
	padding-right: 15px;
}
 
.mybutton .x-btn-center {
	background: transparent url('button_06.png') repeat-x center; 
	height:150px;
	width:80px;
	text-align:center;
}
 
.mybutton .x-btn-text {
	line-height: 150px;
	font-family: Arial, Helvetica, sans-serif;
	font-size:60px;
	font-weight:bold;
}

I have used custom images that make up the button’s left, center and right components. I have also changed the appearance of the text displayed on the button.

Now that we have the buttons which make up the game board, lets take a brief look at the rest of the game. An integer array holds the numbers that map to each button on the board. This array is populated randomly at start. Although the board is 2D, I decided to use a 1D array as it turned out to be slightly simpler while populating the random numbers. So arr2D[i][j] becomes arr1D[i * numcols + j] where numcols is the number of columns in each row.

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
private void generateRandomNumbers()
{
	int i,j;
	int temp;
	boolean suitable;
	int total = numRows*numCols-1;
 
	for(i=0;i<=total;i++)
	{
		do
		{
			suitable = true;
			temp = (int) Math.round(Math.random() * total);
			for(j=0;j<i;j++)
			{
				if(numbers[j] == temp)
				{
					suitable = false;
					break;
				}
			}
		}while(!suitable);
 
		numbers[i] = temp;
	}
}

Once the array is ready, I set the Panel’s layout to TableLayout with 3 columns and call createGrid() to create buttons that make up the grid. Every button knows its (row,column) position and the blank square is made up of an invisible button.

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
private void createGrid()
{
	for(int i=0; i<numRows; ++i)
	{
		for(int j=0; j<numCols; ++j)
		{
			int index = i*numCols + j;
 
			String label = String.valueOf(numbers[i*numCols + j]);
			final Button btn = new Button(label);
			btn.setTemplate(buttonTemplate);
 
			// listener is an instance of SquareListener
			btn.addListener(listener);
 
			// every button keeps track of its row and column number
			final int finali = i, finalj=j;
			btn.addListener("render", new Function(){
				public void execute() {
					JavaScriptObjectHelper.setAttribute(btn.getJsObj(), "row", finali);
					JavaScriptObjectHelper.setAttribute(btn.getJsObj(), "col", finalj);
				}
			});
 
			// empty square = invisible button
			// maintain a class-level reference to the empty square
			if (numbers[index] == 0)
			{
				emptyButton = btn;
				btn.setVisible(false);
			}
 
			add(btn);
		}
	}
}

The button listener checks if the clicked button is adjacent to the empty square. If it is, it swaps numbers in the array and on the buttons. The invisible button is now made visible and clicked button becomes invisible. I have added a fade in and fade out effect. However, this is shaky and sometimes the button doesn’t fade in for too long. It does irritate a bit. After this, the endgame is checked i.e. if numbers in the array are in ascending order.

I have left out some code to keep the post short. You can download the complete project from rapidshare.

Note:

  1. Since our new template just has an extra CSS class, the whole template thing could be avoided by calling btn.setCls(”mybutton”). This was an after-thought when I was done playing with the template.
  2. When you change the template, keep the <button> element otherwise you will get an exception at load time
    1
    2
    3
    4
    5
    
    [ERROR] Unable to load module entry point class com.maharana.gwtextnumbermadness.client.MainModule (see associated exception for details)
    com.google.gwt.core.client.JavaScriptException: JavaScript TypeError exception: btnEl has no properties
    	at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:481)
    	at com.google.gwt.dev.shell.ModuleSpace.invokeNativeHandle(ModuleSpace.java:225)
    	...
  3. Also keep the x-btn-center CSS class name otherwise you will get an exception when the button is clicked
    1
    2
    3
    4
    5
    
    [WARN] Exception thrown into JavaScript
    com.google.gwt.core.client.JavaScriptException: JavaScript TypeError exception: this.el.child("td.x-btn-center " + this.buttonSelector) has no properties
    	at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:481)
    	at com.google.gwt.dev.shell.ModuleSpace.invokeNativeVoid(ModuleSpace.java:270)
    	...

References:

  1. Images for new button template: http://www.jankoatwarpspeed.com/post/2008/04/30/make-fancy-buttons-using-css-sliding-doors-technique.aspx
  2. CSS nesting: http://webdesignfromscratch.com/css-inheritance-cascade.cfm
  3. Centering block level elements: http://dorward.me.uk/www/centre/#content

Do let me know if you have any corrections or suggestions.


May 01 2008

Gwt-Ext and Google Maps - II (handle click)

Tag: Ext, Gwt, Java, Javascript, Maps, Programming, WebAbhijeet Maharana @ 5:54 pm

Lat and Lon info being shown in a message box
This post is related to my earlier post on Gwt-Ext and Google Maps. While browsing the Gwt-Ext forum, I came across this thread with a simple-looking question from Martin: How can I get the LatLonPoint from a map when a user clicks on the map ??

I looked at the available methods to see if I could figure this out. When I realized I wasn’t getting anywhere, I tried looking at the source to figure out what was going on. I found that Mapstraction does have a facility to register callback functions for events. Below code snippets are from mapstraction.js.

1
2
3
4
5
6
7
8
9
10
11
Mapstraction.prototype.addEventListener = function(type, func) {
    var listener = new Array();
    listener.push(func);
    listener.push(type);
    this.eventListeners.push(listener);
    switch (this.api) {
    case 'openlayers':
        this.maps[this.api].events.register(type, this, func);
        break;
    }
}

When the callback functions registered for ‘click’ event are invoked, they are supplied with a LatLonPoint instance with the latitude and longitude information of the location which was clicked. See line 4 below.

1
2
3
4
5
6
7
Mapstraction.prototype.clickHandler = function(lat, lon, me) {
    for (var i = 0; i < this.eventListeners.length; i++) {
        if (this.eventListeners[i][1] == 'click') {
            this.eventListeners[i][0](new LatLonPoint(lat, lon));
        }
    }
}

However, this argument is lost because of the way Gwt-Ext API exposes this functionality: MapPanel class registers a function with no parameters. Below code snippet is from MapPanel.java. Note the native method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void addEventListener(final String event, final Function listener) {
	if (!mapRendered) {
		addListener(MAP_RENDERED_EVENT, new Function() {
			public void execute() {
				doAddEventListener(event, listener);
			}
		});
	} else {
		doAddEventListener(event, listener);
	}
}
 
private native void doAddEventListener(String event, Function listener) /*-{
        var map = this.@com.gwtext.client.widgets.map.MapPanel::mapJS;
        map.addEventListener(event, function() {
            listener.@com.gwtext.client.core.Function::execute()();
        });
}-*/;

The solution is to override these two methods. For that we need an interface with an execute() method that can accept arguments. I added an interface ‘OneArgFunction’ that does this. We need a proper fix for this so that we can handle more arguments. For now, a one-argument method will suffice.

1
2
3
4
5
package com.maharana.gwtextmaps.client;
 
public interface OneArgFunction {
	public void execute(com.google.gwt.core.client.JavaScriptObject arg);
}

In the overridden methods below, I register a function which accepts the LatLonPoint instance as parameter and hands it over to the execute() method for further processing. Then I invoke the overridden addEventListener() to register an event handler that places a new marker and centers the map on the clicked location. GoogleMap inherits from MapPanel.

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
mapPanel = new GoogleMap() {
	public void addEventListener(final String event, final OneArgFunction listener) {
		if (!this.isRendered()) {
			addListener(MAP_RENDERED_EVENT, new Function() {
				public void execute() {
					doAddEventListener(event, listener);
				}
			});
		} else {
			doAddEventListener(event, listener);
		}
	}
 
	private native void doAddEventListener(String event, OneArgFunction listener) /*-{
	      	var map = this.@com.gwtext.client.widgets.map.MapPanel::mapJS;
	      	map.addEventListener(event, function(llp) {
	            	listener.@com.maharana.gwtextmaps.client.OneArgFunction::execute(Lcom/google/gwt/core/client/JavaScriptObject;)(llp);
	      	});
	}-*/;
 
	// constructor - attach event listener
	{
		addEventListener("click", new OneArgFunction(){
			public void execute(JavaScriptObject arg) {
				LatLonPoint llp = new LatLonPoint(arg);
				mapPanel.setCenterAndZoom(llp, mapPanel.getZoom());
				mapPanel.addMarker(new Marker(llp));
				MessageBox.alert("Clicked Location", "Lat: " + llp.getLat() + "<br>Lon: " + llp.getLon());
			}
		});
	}
};

This does the trick. I am not using any Google Maps specific code here so it should work for other providers as well. Do let me know if I have missed something obvious or got something wrong.

I have modified the demo I posted in my earlier blog entry to include this. You can download it from rapidshare.com.


Apr 07 2008

Gwt-Ext and Google Maps

Tag: Ext, Gwt, Java, Maps, Programming, WebAbhijeet Maharana @ 9:14 pm

Dahisar on a Google Map

Sometime back, I uploaded few pics to Picasa. While creating an album, it asked for an optional “Location” information. I did provide it and when I went to view the album, it displayed the location on a map. I liked it. Few days later, Gwt-Ext 2.0.3 got released with some cool features. One of them is a map API built on top of Mapstraction. Mapstraction lets you use maps from different providers such as Yahoo, Google, Microsoft and lets you switch between them easily. I had not worked with maps before and thought this would be a good opportunity to try it. I wanted to create something like the one I had seen on Picasa.

I have written a small Gwt-Ext application which marks user supplied addresses on a Google Map. Click thumbnail above for a larger image of the output. It took quite some time to figure out how to geocode an address to obtain the latitude and longitude information. But at the end, it works! I have used Google Maps specific code. However, Gwt-Ext provides powerful abstraction, thanks to Mapstraction, and you may want to use that instead.

Code is given below with brief explanation. The entry point looks like this:

1
2
3
4
5
6
public void onModuleLoad() {
	createMapPanel();
	addMapControls();
	new Viewport(mapPanel);
	updateMap("mumbai", JavaScriptObjectHelper.createObject(), this);
}

In createMapPanel(), I create the panel which will hold the map:

1
2
3
4
5
6
7
8
private void createMapPanel()
{
	mapPanel = new GoogleMap();
	mapPanel.setTitle("Google Maps using Gwt-Ext [http://abhijeetmaharana.com]");
	mapPanel.setHeight(400);
	mapPanel.setWidth(400);
	mapPanel.addLargeControls();
}

mapPanel.addLargeControls() adds controls to the map which let you zoom, pan and select image type (map / satellite / hybrid).

Then, I add a textfield and a button in the top toolbar of the panel to accept user input:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private void addMapControls()
{
	final MainModule thisModule = this;
 
	addressField = new TextField();
	addressField.setValue("mumbai");
	refreshMapButton = new ToolbarButton("Refresh map", new ButtonListenerAdapter() {
		public void onClick(Button button, EventObject e) {
			String address = addressField.getText();
			if (!address.trim().equals(""))
				updateMap(address, JavaScriptObjectHelper.createObject(), thisModule);
		}
	});
 
	Toolbar toolbar = new Toolbar();
	toolbar.addText("Enter an address: ");
	toolbar.addField(addressField);
	toolbar.addSpacer();
	toolbar.addButton(refreshMapButton);
 
	mapPanel.setTopToolbar(toolbar);
}

On line 11, updateMap() is called when user clicks “Refresh map” after supplying an address. This is a native method which uses has Javascript code to obtain the latitude and longitude of the provided address. If it can obtain valid results, it calls renderMap() to display the location. I had to resort to JSNI to geocode the address. There might be a cleaner way which would avoid any native code. I have posted a question in the Gwt-Ext forum. Lets see what comes up.

Below is the code for updateMap() and renderMap():

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
public native void updateMap(String locationAddress, JavaScriptObject llp, MainModule thisModule) /*-{
	var geo = new $wnd.GClientGeocoder();
 
	geo.getLocations(locationAddress, 
		function(response) 		// callback method to be executed when result arrives from server
		{
			if (!response || response.Status.code != 200) 
			{
   				alert("Unable to geocode that address");
			} 
			else 
	      		{
		    		var place = response.Placemark[0];
		    		llp.lat = place.Point.coordinates[1];
		    		llp.lon = place.Point.coordinates[0];
 
		    		thisModule.@com.maharana.gwtextmaps.client.MainModule::renderMap(Lcom/google/gwt/core/client/JavaScriptObject;)(llp);
	      		}
      		}
      	);
}-*/;
 
 
public void renderMap(JavaScriptObject jsObj)
{
	double lat = Double.parseDouble(JavaScriptObjectHelper.getAttribute(jsObj, "lat"));
	double lon = Double.parseDouble(JavaScriptObjectHelper.getAttribute(jsObj, "lon"));
 
	LatLonPoint latLonPoint = new LatLonPoint(lat, lon);
	mapPanel.setCenterAndZoom(latLonPoint, 12);
	mapPanel.addMarker(new Marker(latLonPoint));
}

You will need to include code below in the host HTML file to use GClientGeocoder and other Google Maps / Mapstraction related Javascript objects:

<script type="text/javascript" src="js/map/mapstraction.js"></script>
 
<!-- Replace **PLACEHOLDER** in this line with your API key -->
<script type="text/javascript" src="http://maps.google.com/maps?file=api&amp;v=2.x&amp;key=**PLACEHOLDER**"></script>

You can obtain a Google Maps API key from http://code.google.com/apis/maps/signup.html.
Do let me know what you think. Specially about geocoding addresses without making a JSNI call.

Download Eclipse project: http://rapidshare.com/files/105600709/GwtExtMaps.zip

UPDATE (8 Apr):
Sanjiv has clarified in the forum that geocoding support is not available yet. So we will have to stick with JSNI code for the time being. Also, since the url in host mode is localhost:8888, you can use this key for Google Maps:

<script type="text/javascript" src="http://maps.google.com/maps?file=api&amp;v=2.x&amp;key=ABQIAAAARrCK38aboqQKDotehUjrPhTb-vLQlFZmc2N8bgWI8YDPp5FEVBQ-MFjXfKfAvdbsbp3pa0q7fQNDDA">
</script>

Apr 02 2008

Gwt-Ext solutions by forum community

Tag: Ext, Gwt, Java, Links, Programming, WebAbhijeet Maharana @ 11:45 pm

The Gwt-Ext forum is very active and I try to participate when I can. In the process, I have bookmarked a few threads with solutions that I could use later. I am posting some of them below so that more people can stumble upon them. Within brackets is the forum id of the community member who suggested the solution.

  1. Expand / collapse a panel on button click in another panel (daverh and sjivan)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    panelB.setCollapsible(true);
    ...
    panelA.getSaveButton().addListener(new ButtonListenerAdapter(){
                public void onClick(Button button, EventObject e) {   
                   panelB.setCollapsed(false);
                   panelA.setTitle("Saved");
                   panelB.doLayout();
                   panelA.doLayout();
                }
    });
  2. Attach a clicklistener to a panel (me)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    panel.addListener(new ContainerListenerAdapter(){
       public void onRender(Component component) {
          panel.getEl().addListener("click", new EventCallback(){
             public void execute(EventObject e) {
                MessageBox.alert("Panel clicked");
             }   
          });
       }
    });
  3. Force a combo box to always go back to the server for the list items (sjivan)

    1
    2
    3
    4
    5
    
    cb.addListener(new ComboBoxListenerAdapter() {
        public void onExpand(ComboBox comboBox) {
            store.reload();
        }
    });
  4. BorderLayout throws an exception when nothing is added to its center region (sjivan)

    When using BorderLayout, you *must* have a Panel assigned to the CENTER region.

  5. Update a text field’s contents (e.g. force all lowercase) when user leaves text field (takeustoyourleader)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    final TextField lcaseTextField = new TextField();
    lcaseTextField.addListener(new TextFieldListenerAdapter(){
    	public void onBlur(Field field) {
    		updateValue();
    	}
     
    	public void onSpecialKey(Field field, EventObject e){
    		updateValue();
    	}
     
    	private void updateValue(){
    		lcaseTextField.setRawValue(lcaseTextField.getValueAsString().toLowerCase());
    	}
    });

    The “onBlur” catches the user leaving the field by clicking off, the onSpecialKey catches them leaving by enter or tab or anything like that.

  6. Wait for an IFrame to load and then execute some code (grabka)

    1
    2
    3
    4
    5
    
    EventManager.addListener(frame.getElement(), "load", new EventCallback() {
                public void execute(EventObject e) {
                   /* do some stuff */
                }
             }, new ListenerConfig());

I may post some more links as and when I bookmark them.


Mar 26 2008

Gwt-Ext screencasts on showmedo.com

Tag: Ext, Gwt, Java, Programming, Ubuntu, WebAbhijeet Maharana @ 11:23 pm

In addition to hosting the Gwt-Ext screencasts at http://gwt-ext.com/screencasts/, Sanjiv has also made them available at showmedo.com. So you can watch them online without having to download first.

Here are the direct links:

  1. Setup GWT and Cypal studio in Eclipse on Ubuntu
    http://showmedo.com/videos/video?name=2040000;fromSeriesID=204

  2. Add Ext and Gwt-Ext to the project
    http://showmedo.com/videos/video?name=2040010&fromSeriesID=204

  3. Add basic client side regex validation, remote service and save form data in Oracle database
    http://showmedo.com/videos/video?name=2040020&fromSeriesID=204

Thanks Sanjiv for the appreciation. And more importantly, for putting in lots of hard work to produce Gwt-Ext.


Mar 17 2008

Gwt-Ext screencasts for beginners

Tag: Ext, Gwt, Java, Javascript, Links, Programming, Ubuntu, WebAbhijeet Maharana @ 8:51 pm

I have started out with Gwt-Ext and thought I will record some screencasts. These are for beginners who may need a hand when they are starting out and are anxious to jump right into code. The screencasts have been recorded on Ubuntu Feisty with Eclipse Europa.

There are 3 screencasts in avi and ogg format.

  1. First screencast shows the installation of Gwt 1.4 and Cypal Studio for Gwt. Cypal Studio is an Eclipse plugin that automates most of the tasks associated with GWT like adding a module and adding a remote service. In the screencast, I create a Gwt project using this plugin.
  2. Second screencast shows how to add the ExtJS Javascript library (2.0) and Gwt-Ext Java library (2.0.1) to the project. In the screencast, I create a simple Ext form with some text fields and a button.
  3. Third screencast (added on March 22) shows how to send form data back to the server. In the screencast, I validate form fields using regular expressions / Ext Vtype, add a remote service and then save form data in an Oracle database using the remote service.

    You can read this post for installing Oracle 10g XE on Ubuntu Feisty.

All screencasts are hosted at Rapidshare. Sanjiv Jivan, the author of Gwt-Ext has offered to host them at gwt-ext.com. I think the files are quite big and I am not well-versed with audio/video formats and parameters. If you know any way to reduce file size while maintaining the quality of screencasts, do let me know.

Download screencasts from rapidshare

Update:
Sanjiv has been kind to host them at http://www.gwt-ext.com/screencasts/.
I have also edited the gwt-ext wiki accordingly. (See comments)

Related links:
Google Web Toolkit
ExtJS Javascript library
Gwt-Ext
Cypal Studio for Gwt


Feb 23 2008

VirtualBox: Disappearing mouse pointer over text

Tag: Virtualization, WindowsAbhijeet Maharana @ 11:24 am

I recently came across a virtual Windows XP setup with an annoying issue: mouse pointer disappears when over a text field / label. Text could be selected provided one knew where to start selecting.

Configuration:

  • Hardware: Dell Latitude D630 laptop with Intel Core 2 Duo 1.80 GHz
  • Host: Windows Vista Business 32-bit
  • VirtualBox: 1.5.0
  • Guest: Windows XP Pro 32-bit with Service Pack 2

Googling for “virtualbox disappearing pointer” showed that VirtualBox eats up the pointer far too often. Users had reported various issues from pointer disappearing completely to pointer disappearing after switching users. I also came across a “Disappearing mouse pointer over text” thread but it didn’t solve the problem.

With a few trials and errors, I found that changing the text pointer solves the issue. Though at this point, I can’t explain why.

  1. Go to Control Panel >> Mouse >> Pointers tab.
  2. Select “Text Select” under Customize and click on browse.
  3. Select a pointer other that the default such as “beam_r.cur”.

Jan 21 2008

OpenOffice woes

Tag: Linux, UbuntuAbhijeet Maharana @ 9:10 pm

I am running Ubuntu 7.04 - Feisty Fawn. Applications from OpenOffice.org 2.2 crashed on my face with the error message:

The application cannot be started.
An internal error occurred.
OpenOffice.org 2.2 error

On running it from a terminal, it became evident that the problem was with user settings

$ oowriter
[Java framework] Error in function createUserSettingsDocument (elements.cxx).javaldx failed!
GTK Accessibility Module initialized
[Java framework] Error in function createUserSettingsDocument (elements.cxx).GTK Accessibility Module shutdown
 
** (process:9274): WARNING **: Unknown error forking main binary / abnormal early exit ...

A search for “Error in function createUserSettingsDocument (elements.cxx).javaldx failed!” led me to this thread where the answer was in the 6th post:

Become root, delete “/home/<username>/.openoffice.org2″ and then start OpenOffice. The folder is recreated and all works well.


Jan 07 2008

Ubuntu Feisty + Squid proxy

Tag: Linux, Ubuntu, WebAbhijeet Maharana @ 12:43 am

I have a LAN at home and one of my machines is connected to the Internet. I wanted to share this connection with the other machines.

When I had Ubuntu Edgy earlier, I had set up Internet Connection Sharing, referring this thread at Ubuntuforums.org. Now I am using Feisty and thought I will set up a proxy server this time. So I went with Squid. My installation log (for plain http access) is given below.

  1. Install Squid. Open a terminal and type
  2. sudo apt-get install squid
  3. Set visible_hostname
    If you got the below error message after installation, you will need to set visible_hostname.
  4. FATAL: Could not determine fully qualified hostname.  Please set 'visible_hostname'

    Edit /etc/squid/squid.conf as root and add a hostname (line 2899 on my system - line numbers are wrt the config file that is created when Squid 2.6.5-4 is installed from the Feisty repository)

    visible_hostname newpc
  5. Grant access to machines on your LAN
    Add the following lines to squid.conf to create an acl and grant http_access to it (you can find a commented example around line 2590 in this file). Replace the IP address range as required.

    acl my_network src 192.168.1.0/24
    http_access allow my_network
  6. (Re)start squid
    sudo /etc/init.d/squid restart

Now you can point the browsers on your LAN machines to port 3128 on the machine where squid is running.


Dec 29 2007

Command not found … do the following!

Tag: Linux, UbuntuAbhijeet Maharana @ 11:04 pm

I was working with a script and had to do a quick float calculation. I knew Accessories >> Calculator but wanted a command line utility. Struggling to remember the syntax for using bc, I tried

$ bc 2.38987 + 5.43534
File 2.38987 is unavailable.

Not quite amused with the response, I was wondering if it always has to be as geeky as

echo 2.38987 + 5.43534 | bc

or

bc -i
2.38987 + 5.43534

and not something like

calc 2.38987 + 5.43534

I happened to type ‘calc’ and hit return without really thinking about it, and Ubuntu promptly reported

The program 'calc' is currently not installed.  You can install it by typing:
sudo apt-get install apcalc
Make sure you have the 'universe' component enabled
bash: calc: command not found

I was impressed! It doesn’t just tell me “command not found” but also tells me how to enable it to find it! Given Ubuntu’s packaging and software repository system this may be simple to achieve but these “simple” little things are what make exploring Ubuntu a joy. I took my OS’s advice and in no time I was using “calc 2.38987 + 5.43534″ (I am using Ubuntu 7.04).


Next Page »