tag:blogger.com,1999:blog-31639029765008756902024-03-13T16:18:30.651-06:00Maricel Quesada's BlogTechnical blog to share some useful information regarding technologies like Java, Grails, JavaScript, etc.Anonymoushttp://www.blogger.com/profile/08204368870896239348noreply@blogger.comBlogger20125tag:blogger.com,1999:blog-3163902976500875690.post-87838924811609596792013-02-08T17:01:00.000-06:002013-02-12T11:12:06.701-06:00N Disks K RodsI found this exercise online, it looks interesting so I decided to solve it.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">There are K pegs. Each peg can hold discs in decreasing order of radius when looked from bottom to top of the peg. There are N discs which have radius 1 to N; Given the initial configuration of the pegs and the final configuration of the pegs, output the moves required to transform from the initial to final configuration. You are required to do the transformations in minimal number of moves.</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">A move consists of picking the topmost disc of any one of the pegs and placing it on top of any other peg.
At any point of time, the decreasing radius property of all the pegs must be maintained.</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">Constraints:</span><br />
<span style="font-family: Courier New, Courier, monospace;">1<=N<=8</span><br />
<span style="font-family: Courier New, Courier, monospace;">3<=K<=5</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">Input Format:</span><br />
<span style="font-family: Courier New, Courier, monospace;">N K</span><br />
<span style="font-family: Courier New, Courier, monospace;">2nd line contains N integers.
Each integer in the second line is in the range 1 to K where the i-th integer denotes the peg to which disc of radius i is present in the initial configuration.</span><br />
<span style="font-family: Courier New, Courier, monospace;">3rd line denotes the final configuration in a format similar to the initial configuration.</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">Output Format:</span><br />
<span style="font-family: Courier New, Courier, monospace;">The first line contains M - The minimal number of moves required to complete the transformation.</span><br />
<span style="font-family: Courier New, Courier, monospace;">The following M lines describe a move, by a peg number to pick from and a peg number to place on.</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">If there are more than one solutions, it's sufficient to output any one of them. You can assume, there is always a solution with less than 7 moves and the initial confirguration will not be same as the final one.
</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">Sample Input #00:</span><br />
<span style="font-family: Courier New, Courier, monospace;">2 3</span><br />
<span style="font-family: Courier New, Courier, monospace;">1 1</span><br />
<span style="font-family: Courier New, Courier, monospace;">2 2</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">Sample Output #00:</span><br />
<span style="font-family: Courier New, Courier, monospace;">3</span><br />
<span style="font-family: Courier New, Courier, monospace;">1 3</span><br />
<span style="font-family: Courier New, Courier, monospace;">1 2</span><br />
<span style="font-family: Courier New, Courier, monospace;">3 2</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">Sample Input #01:</span><br />
<span style="font-family: Courier New, Courier, monospace;">6 4</span><br />
<span style="font-family: Courier New, Courier, monospace;">4 2 4 3 1 1</span><br />
<span style="font-family: Courier New, Courier, monospace;">1 1 1 1 1 1</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">Sample Output #01:</span><br />
<span style="font-family: Courier New, Courier, monospace;">5</span><br />
<span style="font-family: Courier New, Courier, monospace;">3 1</span><br />
<span style="font-family: Courier New, Courier, monospace;">4 3</span><br />
<span style="font-family: Courier New, Courier, monospace;">4 1</span><br />
<span style="font-family: Courier New, Courier, monospace;">2 1</span><br />
<span style="font-family: Courier New, Courier, monospace;">3 1</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">NOTE: You need to write the full code taking all inputs are from stdin and outputs to stdout</span>
<br />
<br />
I came up with a solution doing a combinatorial search using breath-first search, basically looking for the shortest path from the initial state to the goal. I learned this technique in the class <a href="https://www.udacity.com/course/cs212">Design of Computer Programs</a> with Peter Norvig at <a href="http://www.udacity.com/">Udacity.com</a>
Here it is the code in Java.
<br />
<pre class="java" name="code">
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Scanner;
import java.util.Set;
public class DisksAndRods {
private static final int EMPTY = -1;
private int n;
private int k;
private int[] initial;
private int[] goal;
public DisksAndRods(int n, int k, int[] initial, int[] goal) {
this.n = n;
this.k = k;
this.initial = initial;
this.goal = goal;
validate();
}
/**
* Validate the input
*/
private void validate() {
if (n < 1 || n > 8) throw new IllegalArgumentException("1 <= N <= 8");
if (k < 3 || k > 5) throw new IllegalArgumentException("3 <= K <= 5");
if (initial.length != n || goal.length != n) {
throw new IllegalArgumentException("Initial and goal disks configuration must be equal to N");
}
for (int i = 0; i < n; i++) {
if ((initial[i] < 1 || initial[i] > k) || (goal[i] < 1 || goal[i] > k)) {
throw new IllegalArgumentException("Invalid rod number!");
}
}
}
/**
* Checks if a given state is the goal that we are looking for.
*
* @param state The state to check
* @return True if we reached the goal, false otherwise.
*/
private boolean isGoal(State state) {
return Arrays.equals(goal, state.disks);
}
/**
* Checks if given a configuration of the disks and rods if the disk can be moved.
*
* @param disk The disk to check
* @param disks The configuration for the disks
* @param rodTops What are the disks tops in each rod
* @return True if it can be moved, false otherwise.
*/
private boolean canMoveDisk(int disk, int[] disks, int[] rodTops) {
if (disk == 0) return true; // It is the smallest disk
// Check if the disk is under a smaller disk
for (int i = disk - 1; i >= 0; i--) {
if (disks[i] == disks[disk]) {
return false;
}
}
// Check if there are rods where the disk can be placed
// i.e. a rod that is empty or with a bigger disk
int count = 0;
for (int i = 0; i < k; i++) {
if (rodTops[i] == EMPTY || rodTops[i] > disk) {
count++;
}
}
return count > 0;
}
/**
* Given a configuration of the disks, calculates what is the top disk in each rod, -1 if the rod is empty.
*
* @param disks The configuration of disks.
* @return An array of k rods with the tops.
*/
private int[] getRodsTop(int[] disks) {
int[] rods = new int[k];
Arrays.fill(rods, EMPTY);
for (int i = 0; i < n; i++) {
if (rods[disks[i] - 1] == EMPTY || i < rods[disks[i] - 1]) {
rods[disks[i] - 1] = i;
}
}
return rods;
}
/**
* Given a state determines its successors.
*
* @param current The state to get the successors from.
* @return A set with the successor states.
*/
private Set<State> successors(State current) {
Set<State> successors = new HashSet<State>();
int[] tops = getRodsTop(current.disks);
for (int i = 0; i < n; i++) {
if (canMoveDisk(i, current.disks, tops)) {
for (int j = 0; j < k; j++) {
if (tops[j] == EMPTY || tops[j] > i) {
int[] newDisks = Arrays.copyOf(current.disks, n);
newDisks[i] = j + 1;
successors.add(new State(newDisks, current.disks[i], j + 1));
}
}
}
}
return successors;
}
/**
* Solves the problem using shortest path problem.
*
* @return A list of State objects indicating the steps to follow to solve the problem.
*/
public List<State> solve() {
State start = new State(initial);
if (isGoal(start)) {
return Arrays.asList(start);
}
// Keep track of the states already explored
Set<State> explored = new HashSet<State>();
// Keep track of the paths that we are evaluating
Queue<List<State>> frontier = new LinkedList<List<State>>();
// First path starts from the start state
frontier.add(Arrays.asList(start));
// Evaluate all paths until done or until we found the goal
while (!frontier.isEmpty()) {
List<State> path = frontier.poll();
State lastStatePath = path.get(path.size() - 1);
// Get the successor states for the last state in the current path state
for (State state : successors(lastStatePath)) {
// Don't explore states that we have already explored
if (!explored.contains(state)) {
explored.add(state);
List<State> newPath = new ArrayList<State>(path);
newPath.add(state);
if (isGoal(state)) {
return newPath;
} else {
frontier.add(newPath);
}
}
}
}
return new ArrayList<State>();
}
/**
* Class to represent a state.
*/
public static class State {
private int[] disks;
private int from;
private int to;
public State(int[] disks) {
this.disks = disks;
}
public State(int[] disks, int from, int to) {
this.disks = disks;
this.from = from;
this.to = to;
}
public int getFrom() {
return from;
}
public int getTo() {
return to;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof State)) return false;
State state = (State) o;
if (from != state.from) return false;
if (to != state.to) return false;
if (!Arrays.equals(disks, state.disks)) return false;
return true;
}
@Override
public int hashCode() {
int result = 17;
result = 31 * result + (disks != null ? Arrays.hashCode(disks) : 0);
result = 31 * result + from;
result = 31 * result + to;
return result;
}
@Override
public String toString() {
return "State{" +
"disks=" + Arrays.toString(disks) +
", from=" + from +
", to=" + to +
'}';
}
}
public static void main(String[] args) {
Scanner reader = new Scanner(System.in);
int n = reader.nextInt();
int k = reader.nextInt();
int[] initial = new int[n];
for (int i = 0; i < n; i++) {
initial[i] = reader.nextInt();
}
int[] goal = new int[n];
for (int i = 0; i < n; i++) {
goal[i] = reader.nextInt();
}
DisksAndRods disksAndRods = new DisksAndRods(n, k, initial, goal);
List<State> path = disksAndRods.solve();
if (path.size() > 0) {
System.out.println(path.size() - 1);
for (int i = 1; i < path.size(); i++) {
State step = path.get(i);
System.out.printf("%d %d\n", step.getFrom(), step.getTo());
}
}
}
}
</pre>
Have fun!Anonymoushttp://www.blogger.com/profile/08204368870896239348noreply@blogger.com2tag:blogger.com,1999:blog-3163902976500875690.post-45607196191584501912011-06-20T20:15:00.002-06:002011-06-20T21:25:16.715-06:00Grails - Spring Security with Spring Cache: Caching content per user [Updated]In my <a href="http://maricel-tech.blogspot.com/2011/02/grails-spring-security-with-spring.html">previous post</a> I explained how to customize the <a href="http://www.grails.org/plugin/springcache">Spring Cache plug in</a> so we could cache content considering what user is logged in or not. However, that code was written using the version 1.2.1 of the plug in and if you want to upgrade to the latest version, which currently is 1.3.1, then a few changes need to happen in the code for this to work. Because of this I am going to explain what these changes are so this customization continues working for you.<br />
<br />
In the original example I mentioned that we needed to extend the class <i>MimeTypeAwareKeyGenerator</i>, we used this class specifically because we need to handle different content types. However, in the new version of the plug in this class no longer exists, what we have now is a class called <i>WebContentKeyGenerator</i> that extends <i>DefaultKeyGenerator</i>.<br />
<br />
The <i>WebContentKeyGenerator</i> is a multipurpose implementation of the KeyGenerator interface. The different purposes of the key generator are managed through several boolean properties, all false by default, these properties are: [1]<br />
<ul><li><b>ajax</b>: If set to true then keys will differ depending on the presence or absence of the <i>X-Requested-With</i> request header so AJAX requests will be cached separately from regular requests. This is useful when you have an action that renders different content when it is requested via AJAX.</li>
<li><b>contentType</b>: If true keys will differ depending on the requested content format as determined by the format <i>meta-property</i> on HttpServletRequest. This is useful when you use content negotiation in a request so that responses with different formats are cached separately.</li>
<li><b>requestMethod</b>: If true keys will differ depending on the request HTTP method. This is useful for some RESTful controllers (although if different request methods are mapped to different actions you do not need to use this mechanism). GET and HEAD requests are considered the same for the purposes of key generation.</li>
</ul><br />
So our new key generator class should look like this:<br />
<pre class="java" name="code">public class MimeTypeAndAuthenticationAwareKeyGenerator extends WebContentKeyGenerator {
@Override
protected void generateKeyInternal(CacheKeyBuilder builder, ContentCacheParameters context) {
super.generateKeyInternal(builder, context)
def springSecurityService = ApplicationHolder.application.mainContext.getBean('springSecurityService')
if (springSecurityService?.isLoggedIn()) {
builder << "authUserId=${springSecurityService.principal.getId()}".toString()
}
}
}
</pre>As you can see the code is still very similar, but besides extending a different class, the signature of the <i>generateKeyInternal</i> method has also changed, instead of receiving a <i>FilterContext</i> object as a second parameter, you need to receive a <i>ContentCacheParameters</i> object. <br />
<br />
To configure the plug in to use our class we used the Config.groovy configuration to tell the <i>springcacheFilter</i> what key generator to use. However, this needs to be done differently now, you have two options:<br />
<br />
<b>1. Setting the key generator by action: </b>You can specify your key generator for a specific action by adding the <i>keyGenerator</i> element to the <i>@Cacheable</i> annotation specifying the name of a Spring bean that implements the <i>KeyGenerator</i> interface, something like:<br />
<br />
<pre class="java" name="code">@Cacheable(cache = "albumControllerCache", keyGenerator = "mySpecialKeyGenerator")
def doSomething = {
// …
}
</pre><br />
<b>2. Overriding the default key generator:</b> You can also override the default key generator instance in the resources.groovy file, which is named <i>springcacheDefaultKeyGenerator</i>. You can do something like:<br />
<pre class="java" name="code">springcacheDefaultKeyGenerator(MimeTypeAndAuthenticationAwareKeyGenerator) {
ajax = true
contentType = true
}
</pre><br />
As you can see we now have different options that allow us to have more control on how caching is managed for different actions giving us more flexibility.<br />
<br />
[1] Taken from <a href="http://gpc.github.com/grails-springcache/docs/guide/4.%20Content%20Caching.html#4.5. Content Cache Keys">Spring Cache Plug in documentation</a>.Anonymoushttp://www.blogger.com/profile/08204368870896239348noreply@blogger.com20tag:blogger.com,1999:blog-3163902976500875690.post-76488779554002048802011-02-08T11:20:00.012-06:002011-03-06T23:33:52.336-06:00Grails - Spring Security with Spring Cache: Caching content per userWe are using Spring Security in one Grails project, we needed to integrate Spring Cache to cache content, but we had the problem that certain information on the page depends on the user logged in like the user name that is displayed on the header of the page, among other things for instance. The problem was that for example if you load the page being not logged in, the page gets cached and then you logged in and access the page again, you will see the cached page and it will not show your user name because the first time you accessed it since you were not logged in the user name was not there. Because of this we needed a way to consider the user when caching the page, so we will get a cached page for a not logged in user and a cached page for the user logged in.<br /><br />Originally we were using the MimeTypeAwareKeyGenerator class to generate the cache keys, we used this generator because some of our actions are used as REST services as well that can be used with JSON or XML, so what we did was to create a new generator that extended this class and made it not only mime type aware but also user aware, our class looked like this:<br /><pre name="code" class="java"><br />public class MimeTypeAndAuthenticationAwareKeyGenerator extends MimeTypeAwareKeyGenerator {<br /><br /> @Override<br /> protected void generateKeyInternal(CacheKeyBuilder builder, FilterContext context) {<br /> super.generateKeyInternal(builder, context)<br /> def springSecurityService = ApplicationHolder.application.mainContext.getBean('springSecurityService')<br /> if (springSecurityService?.isLoggedIn()) {<br /> builder << "authUserId=${springSecurityService.principal.getId()}".toString() <br /> } <br /> } <br />} <br /></pre><br />With this approach we are considering the user id in the key for the caching allowing us to create separate cache entries if the user is logged in or not. So, now if you access a page and you are not logged in you will get a cached page with no user name on the top, but if you logged in you will get a page with your user name on the top that will be cached for the next time you access it.<br /><br />Now you need to tell your Grails application to use this new class you created and to do it you just need to set the keyGenerator attribute of the springcacheFilter, you can do this via the Config.groovy, like this:<br /><pre name="code" class="java"><br />beans {<br /> springcacheFilter {<br /> keyGenerator = new MimeTypeAndAuthenticationAwareKeyGenerator()<br /> }<br />}<br /></pre>Anonymoushttp://www.blogger.com/profile/08204368870896239348noreply@blogger.com7tag:blogger.com,1999:blog-3163902976500875690.post-5406974592670736372011-01-05T22:43:00.035-06:002011-03-06T23:34:21.565-06:00Using multiple datasources in a Grails project: Datasources pluginGrails only supports the use of one Datasource and one SessionFactory and all classes use them, which might cause some problems when you have the need to work with multiple databases in the same project. This can be solved thanks to <a href="http://burtbeckwith.com/resume/">Burt Beckwith</a>, he developed the <a href="http://www.grails.org/plugin/datasources">Datasources plug in</a> that allows you to configure multiple datasources in the same Grails project letting you define a set of classes to use one datasource and another set to use another datasource, for instance. In this article will review some benefits, issues and some tips and tricks that might help you get the best out of this plug in.<br /><br /><b>Benefits</b><br />There are multiple benefits when using the Datasources plug in:<ul><li>You can connect to multiple databases and use GORM to manage your data through domain classes, which gives you all the flexibility and ease-of-use that GORM offers.</li><li>You can set up your datasources to be read-only.</li><li>You can customize your datasources configuration per environment, which gives you a lot of flexibility.</li><li>The datasources created by the plugin are regular Spring beans, which allows you to override their properties if you need to.</li><li>You can specify a custom Hibernate configuration for each datasource by placing a Hibernate config file on the classpath.</li></ul><b><span class="Apple-style-span">Issues</span></b><br /><ul><li>In Grails you can set up the different settings for you application and your main Datasource in an external configuration file and Grails will overwrite those settings during startup. This is very helpful when you need to run the same WAR file in different servers that require different configuration. However, there is no easy way to externalize the configuration for the Datasources plug in since the plug in doesn't overwrite the Datasources configuration if an external config file exists.</li><li>You cannot specify a config location for the Hibernate custom configuration file, so for the Datasources plug in to pick it up you need to place the config file in the classpath and with a specific name, something like <span style="font-style:italic;">[datasource_name.hibernate.cfg.xml]</span>, otherwise it won't get picked up. This is problematic because if you want to use a custom config file for Hibernate that is different for each environment (dev, test, prod) you cannot easily do it since there is no way to specify in the datasource configuration a config location like you would do in the Datasource configuration file used by Grails by default.</li><li>There are other issues mentioned in the plug in page that I am not going to repeat here.</li></ul><br /><b>Tips and Tricks</b><br /><br /><b>Externalizing the configuration of the Datasources</b><br /><br />As mentioned before, the project configuration can be externalized so you can separate your configuration from your project WAR file, however this functionality is not included as part of the Datasources plug in, so here is a tip on how externalize the configuration of each different datasource you have. (You can find more information on how the externalized configuration works in the <a href="http://grails.org/doc/latest/guide/3.%20Configuration.html#3.4 Externalized Configuration">Grails documentation</a>)<br /><br />In order to do this, you need to overwrite the settings of the datasource bean on the Spring resources file, for example lets say you have the following configuration in your Datasources.groovy file:<br /><pre name="code" class="java"><br />datasources = {<br /> datasource(name: 'testDbReadOnly') {<br /> domainClasses([com.test.Person,<br /> com.test.Company,<br /> com.test.Deparment<br /> ])<br /> driverClassName('org.postgresql.Driver')<br /> readOnly(true)<br /> url('jdbc:postgresql://[server-name]:5432/test')<br /> pooled(true)<br /> username('test')<br /> password('test')<br /> logSql(false)<br /> dialect(org.hibernate.dialect.PostgreSQLDialect)<br /><br /> hibernate {<br /> cache {<br /> use_query_cache(true)<br /> use_second_level_cache(true)<br /> provider_class('net.sf.ehcache.hibernate.EhCacheProvider')<br /> }<br /> }<br /> }<br />}<br /></pre>Then in your spring resources file you would need something like this:<br /><pre name="code" class="java"><br /> dataSource_testDbReadOnly(BasicDataSource) {bean -><br /> bean.destroyMethod = 'close'<br /> username = GrailsConfig.get("testDbReadOnly.datasource.username", "sa")<br /> password = GrailsConfig.get("testDbReadOnly.datasource.password", "")<br /> driverClassName = GrailsConfig.get("testDbReadOnly.datasource.driver.name", "org.hsqldb.jdbcDriver")<br /> url = GrailsConfig.get("testDbReadOnly.datasource.url", "jdbc:h2:mem:testDb")<br /> maxWait = -1<br /> minEvictableIdleTimeMillis = (1000 * 60 * 5) // 5 min<br /> timeBetweenEvictionRunsMillis = (1000 * 60 * 5) // 5 min<br /> numTestsPerEvictionRun = 3<br /> testOnBorrow = true<br /> testWhileIdle = false<br /> testOnReturn = false<br /> validationQuery = "SELECT 1"<br /> }<br /></pre><br />As you can see you need to specify the name of the bean as dataSource_nameOfYourDataSource, in our example would be dataSource_testDbReadOnly.<br /><br />What we are doing here is changing the Datasource bean properties and setting them based on values defined in the Config.groovy file, values that will be defined differently depending on the environment that we are running. So for example in our Config.groovy we will have:<br /><pre name="code" class="java"><br />environments {<br /> production {<br /> testDbReadOnly {<br /> datasource {<br /> driver.name = 'org.postgresql.Driver'<br /> url = 'jdbc:postgresql://[production-server]:5432/[production-db]'<br /> username = '[production-username]'<br /> password = '[production-password]'<br /> }<br /> }<br /> }<br /> development {<br /> testDbReadOnly {<br /> datasource {<br /> driver.name = 'org.postgresql.Driver'<br /> url = 'jdbc:postgresql://[dev-server]:5432/[dev-db]'<br /> username = '[dev-username]'<br /> password = '[dev-password]'<br /> }<br /> }<br /> }<br /> test {<br /> testDbReadOnly {<br /> datasource {<br /> driver.name = 'org.postgresql.Driver'<br /> url = 'jdbc:postgresql://[test-server]:5432/[test-db]'<br /> username = '[test-username]'<br /> password = '[test-password]'<br /> }<br /> }<br /> }<br />}</pre><br />You are probably thinking that you can already do this in the Datasources.groovy file by specifying the configuration in different environments. However, since the Datasource configuration now depends on the configuration defined in Config.groovy file, you can overwrite these settings in your external configuration files, which give us what we want, move the configuration of the datasources to an external file.<br /><br />You would need to add the datasource properties in your external config file as:<br /><pre name="code" class="java">testDbReadOnly.datasource.driver.name=org.postgresql.Driver<br />testDbReadOnly.datasource.url=jdbc:postgresql://test.production.server:5432/testDb<br />testDbReadOnly.datasource.username=test<br />testDbReadOnly.datasource.password=test</pre>So for example, if you need to deploy the same WAR file in different servers, you can have an external properties files with a different set of settings in each one of those servers without having to generate a different WAR for each.<br /><br />As discussed, the Datasources plug ins have some issues, but none of them are things that you cannot find a workaround for. It offers great benefits and it is very easy to use. Hopefully it will get integrated as part of Grails core one day, so you can manage different datasources without having to install a plug in to accomplish it.Anonymoushttp://www.blogger.com/profile/08204368870896239348noreply@blogger.com4tag:blogger.com,1999:blog-3163902976500875690.post-55326400129417609192010-06-25T13:05:00.001-06:002011-03-06T23:34:47.267-06:00JavaZone Trailer: Java 4-ever<object style="background-image:url(http://i4.ytimg.com/vi/KrfpnbGXL70/hqdefault.jpg)" width="480" height="295"><param name="movie" value="http://www.youtube.com/v/KrfpnbGXL70&hl=en_US&fs=1"><param name="allowFullScreen" value="true"><param name="allowscriptaccess" value="always"><embed src="http://www.youtube.com/v/KrfpnbGXL70&hl=en_US&fs=1" width="480" height="295" allowScriptAccess="never" allowFullScreen="true" wmode="transparent" type="application/x-shockwave-flash"></embed></object><br /><br />Very funny!! :DAnonymoushttp://www.blogger.com/profile/08204368870896239348noreply@blogger.com0tag:blogger.com,1999:blog-3163902976500875690.post-26959800603858756452010-06-15T23:20:00.002-06:002011-03-06T23:35:09.124-06:00RSA Animate - Drive: The surprising truth about what motivates us<object style="background-image:url(http://i2.ytimg.com/vi/u6XAPnuFjJc/hqdefault.jpg)" width="480" height="295"><param name="movie" value="http://www.youtube.com/v/u6XAPnuFjJc&hl=en_US&fs=1"><param name="allowFullScreen" value="true"><param name="allowscriptaccess" value="always"><embed src="http://www.youtube.com/v/u6XAPnuFjJc&hl=en_US&fs=1" width="480" height="295" allowScriptAccess="never" allowFullScreen="true" wmode="transparent" type="application/x-shockwave-flash"></embed></object><br /><br />This video is simply amazing and worth watching!Anonymoushttp://www.blogger.com/profile/08204368870896239348noreply@blogger.com1tag:blogger.com,1999:blog-3163902976500875690.post-7211187980927713712010-05-14T21:05:00.021-06:002010-09-07T14:37:10.265-06:00Using more than one Datasource in a Grails projectGrails is designed to work with one DataSource and one SessionFactory which are the ones used by all domain classes to execute all the operations in the database, so there is no easy way to set up a second or more datasources to allow different domain objects to connect to different databases to read and store data.<br /><br />One approach is to inject a second datasource and use it with Groovy Sql to retrieve data. For this what we do is create the datasource in the Spring resources file so we can get it later using dependency injection either in a Grails service, a controller or a domain class.<br /><br />My example is simple, in my database I have a table user that is related to a person table, but the person table is not in my database is in another database and I need to read some person information like the name and email to display on my system, so I am going to create a service that is going to be the one in charge of connecting to this other database using the injected dataSource. This service is then going to be injected in my domain class to set up the data I need into specific transient properties.<br /><br />So the first thing we need to do is to create my new dataSource in my Spring resources file, something like this:<br /><br /><pre name="code" class="java"><br />import org.apache.commons.dbcp.BasicDataSource<br /><br />// Place your Spring DSL code here<br />beans = {<br /><br /> dataSourcePostgresql(BasicDataSource) {<br /> driverClassName = "org.postgresql.Driver"<br /> url = "jdbc:postgresql://testserver:5432/test"<br /> username = "username"<br /> password = "password"<br /> }<br />}<br /></pre><br /><br />Then, I need to create a Grails service class to connect to the database and get me the data I need:<br /><br /><pre name="code" class="java"><br />import groovy.sql.Sql<br /><br />class MyPostgreSQLService {<br /><br /> def dataSourcePostgresql<br /><br /> boolean transactional = true<br /><br /> def getPersonData(long personId) {<br /> if (dataSourcePostgresql) {<br /> def sql = Sql.newInstance(dataSourcePostgresql)<br /> def row = sql.firstRow("select fname, lname, email from person where id = ${personId}")<br /> if (row) {<br /> return [firstName: row.fname, lastName: row.lname, email: row.email]<br /> }<br /> }<br /> return null<br /> }<br />}<br /></pre><br /><br />As you can see I am connecting to the PostgreSQL database using my new dataSource using Groovy Sql and executing a direct query to the "person" table.<br /><br />Finally in my domain class I inject the service and populate the properties firstName, lastName and email with what the service is providing me. I am setting these properties transient because I don't really need to store them in my database, I just need to have them for display.<br /><br /><pre name="code" class="java"><br />class User {<br /><br /> def myPostgreSQLService<br /><br /> String firstName<br /> String lastName<br /> String email<br /> String userName<br /> Date createdDate<br /> Date lastUpdated<br /><br /> static transients = ["firstName", "lastName", "email"]<br /><br /> def String getFirstName() {<br /> getPersonData()<br /> return this.firstName<br /> }<br /><br /> def void setFirstName(String name) {}<br /><br /> def String getLastName() {<br /> getPersonData()<br /> return this.lastName<br /> }<br /><br /> def void setLastName(String name) {}<br /><br /> def String getEmail() {<br /> getPersonData()<br /> return this.email<br /> }<br /><br /> def void setEmail(String email) {}<br /><br /> private def getPersonData() {<br /> // Make the service call only if these values haven't been set yet<br /> if (!firstName || !lastName || !email) {<br /> def personData = myPostgreSQLService.getPersonData(id)<br /> if (personData) {<br /> this.firstName = personData.firstName<br /> this.lastName = personData.lastName<br /> this.email = personData.email<br /> }<br /> }<br /> }<br /> ...<br />}<br /></pre><br /><br />And that is it, next time you do user.firstName, the service will query the database and get the person first name for display and that operation would be totally transparent for the controller or whenever you are using this domain class.<br /><br />The downside here is that we cannot integrate this DataSource with GORM and use all its advantages, so i would say that this is an easy way to retrieve read-only data, specially if the amount of data you are retrieving is not much, you could use it as well to insert data into this other database, however if you need to read and write data I would recommend you to take a look at the <a href="http://grails.org/plugin/datasources">Grails DataSources plug in</a> that allows you to use multiple data sources with GORM. You can check it out hereAnonymoushttp://www.blogger.com/profile/08204368870896239348noreply@blogger.com0tag:blogger.com,1999:blog-3163902976500875690.post-15792158040653259302009-09-08T20:26:00.009-06:002011-01-10T12:18:21.992-06:00Grails - How to execute the parameters data binding process in an integration testWhen executing a request in a web application in Grails there is a process that binds the request parameters with the controller "params" object. Grails have different listeners that are notified and then execute the binding.<br /><br />The class UrlMappingsFilter, which is a Servlet filter that uses the Grails UrlMappings to match and forward requests to a relevant controller and action, is the one in charge of notifying these listeners so they execute the data binding. However, this step is not executed in an integration test by default, therefore if you need to test a controller action in an integration test, you need to notify these listeners manually so the binding is done and you can access the controller "params" object inside your test. The way to do this notification is by executing the following line of code:<br /><pre name="code" class="java"><br />controller.request.getAttribute("org.codehaus.groovy.grails.WEB_REQUEST").informParameterCreationListeners()<br /></pre><br />So for example if you were using a JSON content type the listener JSONParsingParameterCreationListener would be notified and then it would do the request parameters parsing allowing you to use the controller.params object on your test.<br /><br />It is important to execute this code before actually calling the controller action method that you want to test so the "params" object is available when you need it. Also, to set the controller content-type to JSON doing something like:<br /><pre name="code" class="java"><br />controller.request.content-type = "text/json"<br /></pre><br />Where controller is the instance of your controller class.Anonymoushttp://www.blogger.com/profile/08204368870896239348noreply@blogger.com0tag:blogger.com,1999:blog-3163902976500875690.post-56586832651144497682009-05-19T17:46:00.010-06:002010-09-07T14:40:38.021-06:00How to play a sound in a Firefox extensionWhat if you are working on a Firefox extension that needs to play a sound when an event occurs? Do you know what libraries to use or what you should do to accomplish this simple task? I am going to answer these questions for you!<br /><br />Let's assume that the sound that we are going to play is in our content folder inside the extension, how do we retrieve the file path dynamically, i.e, depending on where the extension was installed? <br /><br />First of all you have to know that Mozilla has a service called <a href="https://developer.mozilla.org/en/nsIExtensionManager" target="_blank">nsIExtensionManager</a> that provides you with functions to execute tasks related to the extension like for example getting the path to the extension installation folder, so how do we use it?<br /><br />We need to first instantiate the extension manager interface this way:<br /><pre name="code" class="javascript"><br />var em = Components.classes["@mozilla.org/extensions/manager;1"].getService(Components.interfaces.nsIExtensionManager);<br /></pre><br />Then to get the installation folder of our extension we do this:<br /><pre name="code" class="javascript"><br />var installationLocation = em.getInstallLocation(EXTENSION_ID);<br /></pre><br />As you can see in this code we are using a constant called EXTENSION_ID, you need to set this constant in your code with the ID of your extension. The ID of your extension is the ID you defined in your install.rdf file.<br /><br />OK, we now have the installation location of our extension, so we now have to get the full location of the sound file we want to use and for that we are going to use the <span style="font-weight:bold;">getItemFile</span> function.<br /><pre name="code" class="javascript"><br />installationLocation.getItemFile(EXTENSION_ID, "chrome/chromeFiles/content/sound.wav");<br /></pre><br />As you can see here, we are looking for the file based on the extension installation location and we are indicating where in the extension to look. We said before we have our file in the content folder of the extension, so we pass that path as a parameter.<br /><br />Until now what we have is the file location inside the extension, but we still need to create a file object to play the sound, right? Well, to create a file we use the Mozilla interface <a href="https://developer.mozilla.org/En/NsILocalFile" target="_blank">nsILocalFile</a> and we instantiate and set the path contained in the fileLocation object like this:<br /><pre name="code" class="javascript"><br />var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);<br /><br />file.initWithPath(fileLocation.path);<br /></pre><br /><br />We can double check and make sure that the file really exists:<br /><pre name="code" class="javascript"><br />if (!file.exists()) {<br /> // If the file doesn't exists, then return null<br /> return null;<br />}<br /></pre><br />Now, if the file exists we can then play it, but how? Mozilla provides with an interface to play sounds, it is called <a href="https://developer.mozilla.org/en/NsISound" target="_blank">nsISound</a> and we instantiate it like this:<br /><pre name="code" class="javascript"><br />var player = Components.classes["@mozilla.org/sound;1"].createInstance(Components.interfaces.nsISound);<br /></pre><br />When playing a sound, the player needs to receive the location of the file as a <a href="https://developer.mozilla.org/en/nsIURI" target="_blank">nsIURI</a> object, so we still need to convert our file into a nsIURI object and we do this by using the <a href="https://developer.mozilla.org/en/nsIIOService" target="_blank">nsIIOService</a> interface.<br /><pre name="code" class="javascript"><br />var ios = Components.classes['@mozilla.org/network/io-service;1'].getService(Components.interfaces.nsIIOService);<br />var sound = ios.newFileURI(file);<br /></pre><br />Now we just need to play it!<br /><pre name="code" class="javascript"><br />player.play(sound);<br /></pre><br /><br />...and that is it! Very simple!!Anonymoushttp://www.blogger.com/profile/08204368870896239348noreply@blogger.com1tag:blogger.com,1999:blog-3163902976500875690.post-60186892797063291682009-05-04T18:00:00.016-06:002010-09-07T14:42:25.398-06:00How to create a Windows Vista GadgetWe have discussed in previous posts how to create a very simple Google Gadget and how to add preferences to it, but in this post we are going to discuss how to create Windows Vista Gadget that you can place on your Windows Vista Sidebar or desktop.<br /><br />Vista Gadgets are created using XML, HTML, CSS and Javascript, so if you are familiar with all these technologies, you won't have any problem.<br /><br />OK, now I am going to guide you through the steps of creating a very simple Windows Vista Gadget that displays the current time based on your computer's clock.<br /><br />So let's first start by creating a new folder with the name of your gadget, in our case let's call the gadget MyClock. Under our root gadget folder, create two folders one named css and the other one named js.<br /><br />Vista Gadgets use a XML file as a descriptor for the gadget, so let's create a new file under the gadget root folder called myclock.xml with the following content:<br /><pre name="code" class="xml"><br /><?xml version="1.0" encoding="utf-8" ?><br /><gadget><br /> <name>My Clock</name><br /> <namespace>com.mycompany.myclock</namespace><br /> <version>1.0.0</version><br /> <author><br /> <info url="www.mycompany.com" /><br /> <logo src="logo.png" /><br /> </author><br /> <copyright>MyCompany © 2009</copyright><br /> <description>Windows Vista Gadget to check the current time.</description><br /> <icons><br /> <icon width="80" height="80" src="icon.png" /><br /> </icons><br /> <hosts><br /> <host name="sidebar"><br /> <base type="HTML" apiVersion="1.0.0" src="myclock.html" /><br /> <permissions>full</permissions><br /> <platform minPlatformVersion="0.3" /><br /> </host><br /> </hosts><br /></gadget><br /></pre><br />In the gadget manifest above we are saying that our gadget is named My Clock, we are also providing information about the author and most importantly we are saying that this gadget is going to reside on the sidebar and that the base point is the file named myclock.html.<br /><br />As you can see, in the manifest we are referring to two images: logo.png and icon.png. The file logo.png is used when displaying the author information inside the Vista Gadgets directory, it is generally your company's logo, and icon.png is used on the Vista Gadgets gallery to describe the gadget, it is basically the gadget's icon. For these just create a couple of PNG files and place them on the gadget root folder.<br /><br />For more information about the gadgets manifest check <a href="http://msdn.microsoft.com/en-us/library/aa965879(VS.85).aspx" target="_blank">http://msdn.microsoft.com/en-us/library/aa965879(VS.85).aspx</a><br /><br />Our next step is to create a Javascript file where we are going to place all the necessary Javascript code to create and to display the clock. Just create a new file under the js directory and name it myclock.js and add the following code to it:<br /><pre name="code" class="javascript"><br />var clockContainer = "";<br /><br />function gadgetSetup(clockId) {<br /> clockContainer = document.getElementById(clockId);<br /> setClock();<br />}<br /><br />function setClock(){<br /> var mytime = new Date();<br /> var hours = mytime.getHours();<br /> var minutes = mytime.getMinutes();<br /> var seconds = mytime.getSeconds();<br /> <br /> var label = "AM"; <br /> if (hours > 12){<br /> label = "PM";<br /> hours = hours-12;<br /> }<br /> if (hours == 0) {<br /> hours = 12;<br /> }<br /> if (minutes <= 9) {<br /> minutes = "0" + minutes;<br /> }<br /> if (seconds <= 9) {<br /> seconds = "0" + seconds;<br /> }<br /> clockContainer.innerHTML = hours + ":" + minutes + ":" + seconds + " " + label;<br /> <br /> setTimeout("setClock()", 1000);<br />}<br /></pre><br />Now that we have the necessary Javascript code, let's create a new file under the root folder named myclock.html, this file is the main HTML file that acts as base point for the gadget. <br /><br />Now that you have the HTML file created, add the following code:<br /><pre name="code" class="xml"><br /><html><br /><head><br /> <meta http-equiv="content-type" content="text/html; charset=utf-8"><br /> <link href="css/myclock.css" rel="stylesheet" type="text/css" /><br /> <script type='text/javascript' src='js/myclock.js' charset="utf-8"></script><br /></head><br /><br /><body onLoad="gadgetSetup('myclock');"><br /> <div id="myclock" class="clock"><br /><br /> </div><br /></body><br /><br /></html><br /></pre><br />In the HTML file what we have a DIV tag that is going to hold the clock, also we are saying that when the page is being loaded, call the gadgetSetup function that we previously defined in myclock.js.<br /><br />Now we have the HTML and the Javascript code to display the clock, but we haven't done much to make it look nice, so let's create a new file under the css directory and name it myclock.css. Add the following code to this file:<br /><pre name="code" class="css"><br />body {<br /> margin: 0px;<br /> width: 120px;<br /> height: 50px;<br /> border: 2px solid #000;<br />}<br /><br />#myclock {<br /> width: 120px;<br /> height: 50px;<br /> background: red;<br /> color: FFF;<br /> text-align: center;<br /> padding: 20px;<br />}</pre><br />We are giving the gadget a size of 120px by 50px and we want to make it red and the text is going to be displayed in white.<br /><br />Ok, we now have the main contents of our vista gadget clock, so how we install it? Very simple, take all the contents of the gadget root folder and compress it into a zip file named MyClock.zip, change the compressed file extension from .zip to .gadget and double click on the file. Windows Vista will recognize the .gadget file as a Vista Gadget installer and it would ask you if you really want to install this gadget, so click yes. <br /><br />You should now see your new gadget on your sidebar. If you want you can drag it out the sidebar and put it into your desktop.<br /><br />Hope this helps!!Anonymoushttp://www.blogger.com/profile/08204368870896239348noreply@blogger.com0tag:blogger.com,1999:blog-3163902976500875690.post-56377226283806286662008-11-25T13:28:00.021-06:002010-09-07T16:10:27.479-06:00How to add user preferences to your Google GadgetIn the previous post, we saw how to create a simple Google Gadget that reads the CNN.com Top Stories feeds and display them. We make it by default to display only 10 stories and to display the summaries, but what about if I want to see some more stories or less? or if I don't want to the see the summary, only the story headline? Well, there is a way for the user to customize the gadget , we just need to use User Preferences.<br /><br />With user preferences we can set information in the gadget that is specific to the user. To have user preferences you just need to specify them inside the Module tag of the gadget. See the following example:<br /><br /> <pre name="code" class="xml"><UserPref name="show_summ" display_name="Show Summaries?" datatype="bool" default_value="false" required="true"/></pre><br /><br />As you can see what you need to specify is the name of the preference, the display name, the data type, the default value and if it is required or not. The data type, the default value and required attributes are optional. The default value for data type is string and the default value for required is false.<br /><br />Let's see how our CNN.com Top Stories gadget would look with preferences that will allow the user to set how many stories wants to see and if he/she wants to see the summary or not.<br /><pre name="code" class="xml"><?xml version="1.0" encoding="UTF-8"?><br /><Module><br /> <ModulePrefs <br /> title="CNN.com Top Stories" <br /> title_url="http://www.cnn.com/" <br /> author="Your name" <br /> author_email="youremail@domain.com" <br /> description="Gadget to see the current CNN.com top stories." <br /> width="450" <br /> height="350" <br /> scrolling="true"><br /> <Require feature="dynamic-height"/><br /> </ModulePrefs><br /> <UserPref name="num_entries" display_name="Number of Entries:" default_value="5"/><br /> <UserPref name="show_summ" display_name="Show Summaries?" datatype="bool" default_value="false"/><br /> <br /> <Content type="html"><br /> <![CDATA[<br /> <style><br /> div#main_container {<br /> font-size:12px;<br /> font-family:Arial;<br /> margin: 5px;<br /> text-align: left;<br /> text-decoration: none;<br /> }<br /><br /> div#main_container h2 {<br /> background: url(http://i2.cdn.turner.com/cnn/.element/img/1.0/logo/cnn.logo.rss.gif) no-repeat left top;<br /> display: block;<br /> height: 33px;<br /> text-indent: -100000;<br /> width: 144px;<br /> } <br /> <br /> </style><br /> <script type="text/javascript"><br /> <br /> // Get userprefs<br /> var prefs = new _IG_Prefs();<br /> var summary = prefs.getBool("show_summ");<br /> var entries = prefs.getInt("num_entries"); <br /> <br /> // Function to dipslay content retrieved from XML feed<br /> function displayContent() {<br /><br /> // If user wants to display more than 50 entries, display an error<br /> // and set the value to 50, the max allowed.<br /> if (entries > 50)<br /> {<br /> alert("You cannot display more than 50 entries.");<br /> entries = 50;<br /> }<br /> <br /> var url = "http://rss.cnn.com/rss/edition.rss";<br /><br /> // Use the _IG_FetchFeedAsJSON() function to retrieve core feed data from<br /> // the specified URL. Then combine the data with HTML markup for display in<br /> // the gadget.<br /> _IG_FetchFeedAsJSON(url, processFeed, entries, summary);<br /><br /> }<br /><br /> // Function to process the feed<br /> function processFeed(feed) { <br /> var contentDiv = _gel("main_container");<br /><br /> if (feed == null) {<br /> contentDiv.innerHTML = "Invalid data.";<br /> return;<br /> } <br /> <br /> // Start building HTML string that will be displayed in gadget.<br /> var html = "";<br /><br /> // Access the fields in the feed<br /> html += "<h2>" + feed.Title + "</h2>";<br /> html += "<div>" + feed.Description + "</div><br>";<br /> <br /> // Access the data for a given entry<br /> if (feed.Entry) { <br /> for (var i = 0; i < feed.Entry.length; i++) {<br /> html += "<div>" + "<a target='_blank' href='" + feed.Entry[i].Link + "'>" + feed.Entry[i].Title + "</a> ";<br /> // The feed entry Date field contains the timestamp in seconds<br /> // since Jan. 1, 1970. To convert it to the milliseconds needed<br /> // to initialize the JavaScript Date object with the correct date, <br /> // multiply by 1000.<br /> var milliseconds = (feed.Entry[i].Date) * 1000; <br /> var date = new Date(milliseconds); <br /> html += date.toLocaleDateString();<br /> html += " ";<br /> html += date.toLocaleTimeString(); <br /> <span style="font-weight:bold;">if (summary == true) {<br /> html += "<br><i>" + feed.Entry[i].Summary + "</i>";<br /> }</span><br /> html += "</div>";<br /> }<br /> }<br /><br /> contentDiv.innerHTML = html; <br /> <br /> // Adjust gadget height according to contents<br /> _IG_AdjustIFrameHeight();<br /><br /> }<br /><br /> _IG_RegisterOnloadHandler(displayContent);<br /><br /><br /> </script><br /><br /> <div id="main_container"></div><br /><br />]]><br /></Content><br /></Module></pre><br />As you saw in the code we need the following code to retrieve the user preferences:<br /><pre name="code" class="javascript"><br />var prefs = new _IG_Prefs();<br />var summary = prefs.getBool("show_summ");<br />var entries = prefs.getInt("num_entries"); </pre><br /><br />There is a "get" method for each data type available. To get more information about user preferences click <a href="http://code.google.com/apis/gadgets/docs/legacy/reference.html#Userprefs_Ref" target="_blank">here</a>.<br /><br />Allowing the user to set up its preferences is really simple and it adds a lot value to the gadget functionality!Anonymoushttp://www.blogger.com/profile/08204368870896239348noreply@blogger.com0tag:blogger.com,1999:blog-3163902976500875690.post-22780206688816334972008-11-21T13:26:00.034-06:002010-09-07T16:08:01.737-06:00How to create a Google GadgetGoogle Gadgets are a great tool, they allow you to have specific information in, what you could call, a small HTML page. You can export your gadgets to iGoogle, Google Desktop, Google Toolbar, to any web page and even you can create a Windows Vista Gadget based on them, isn't that great? <br /><br />In this post, I am going to walk you through the creation of a simple gadget, but first let's talk about what Google Gadgets are.<br /><br />Google gadgets are small pieces of code created using XML, HTML, CSS and Javascript that allow you to display data. These gadgets can be embedded in certain applications allowing you to export your information more easily. <br /><br />They are really easy to create, you just need basic knowledge of HTML and JavaScript and Google provides you with JavaScript APIs to you make your life easier, you can check them in their <a href="http://code.google.com/apis/gadgets/docs/legacy/dev_guide.html" target="_blank">Legacy Gadgets API Developer's Guide</a><br /><br />One of the greatest advantages about a gadget is that they can be used in so many places, but you manage only one source code, so if you need to apply a change to your gadget, you just do it and then all the places were the gadget is used would be updated with no new installation or update required.<br /><br />Before we start coding, let's talk about a little bit about the gadget components. A Google Gadget is a XML file that contains one big tag called Module that encloses the gadget, then we have two main different components, the module preferences and the gadget content.<br /><br />The module preferences are tags that you use to set the gadget information like title, author, width, height, etc. In our example, you will see this tag <span style="font-weight:bold;"><Require feature="dynamic-height"/></span>, this tells the gadget parser that the height should be dynamically changed depending on the size of the content. This feature only works with iGoogle though. <br /><br />The gadget content is where you do all the work, here you need to specify a type, mainly "html" if you want to have your HTML and JavaScript in your gadget or "url" if you want the gadget content to live on a remote web page referenced by a URL in the gadget spec. Inside this tag you can code JavaScript and HTML to layout your data, and CSS if you want to give some style to your content. You need to enclose your code into the tags <span style="font-weight:bold;">![CDATA[</span> and <span style="font-weight:bold;">]]</span>.<br /><br />For this post, we are going to create a simple gadget that reads the CNN.com top stories feed and display them using the API called _IG_FetchFeedAsJSON to read the feed as JSON. You will see that this code is really simple and easy to follow.<br /><br />To work with Google gadgets you need a proper editor, you could use notepad if you want at first, but then you would need a way to publish it. Google already provides a tool called Google Gadget Editor (GGE) which is a gadget itself, so you can embedded it in your iGoogle, which allows you to edit your gadget and preview it in the same editor if want to. You can add it to your iGoogle by clicking <a href="http://fusion.google.com/add?moduleurl=gge.xml" target="_blank">here</a>.<br /><br />Now that you have the GGE in your iGoogle page, copy the following code into your GGE. <br /><pre name="code" class="xml"><br /><?xml version="1.0" encoding="UTF-8"?><br /><Module><br /> <ModulePrefs <br /> title="CNN.com Top Stories" <br /> title_url="http://www.cnn.com/" <br /> author="Your name" <br /> author_email="youremail@domain.com" <br /> description="Gadget to see the current CNN.com top stories." <br /> width="450" <br /> height="350" <br /> scrolling="true"><br /> <Require feature="dynamic-height"/><br /> </ModulePrefs><br /> <br /> <Content type="html"><br /> <![CDATA[<br /> <style><br /> div#main_container {<br /> font-size:12px;<br /> font-family:Arial;<br /> margin: 5px;<br /> text-align: left;<br /> text-decoration: none;<br /> }<br /><br /> div#main_container h2 {<br /> background: url(http://i2.cdn.turner.com/cnn/.element/img/1.0/logo/cnn.logo.rss.gif) no-repeat left top;<br /> display: block;<br /> height: 33px;<br /> text-indent: -100000;<br /> width: 144px;<br /> } <br /> </style><br /><br /> <script type="text/javascript"> <br /><br /> // Function to dipslay content retrieved from XML feed<br /> function displayContent() {<br /> <br /> var url = "http://rss.cnn.com/rss/edition.rss";<br /> // Use the _IG_FetchFeedAsJSON() function to retrieve core feed data from<br /> // the specified URL. Then combine the data with HTML markup for display in<br /> // the gadget.<br /> // Let's say we want to display only 10 entries and that we want to display the summary<br /> var entries = 10;<br /> var summary = true;<br /> _IG_FetchFeedAsJSON(url, processFeed, entries, summary);<br /> }<br /><br /> // Function to process the feed<br /> function processFeed(feed) { <br /> var contentDiv = _gel("main_container");<br /><br /> if (feed == null) {<br /> contentDiv.innerHTML = "Invalid data.";<br /> return;<br /> }<br /><br /> // Start building HTML string that will be displayed in gadget.<br /> var html = "";<br /><br /> // Access the fields in the feed<br /> html += "<h2>" + feed.Title + "</h2>";<br /> html += "<div>" + feed.Description + "</div><br>";<br /> <br /> // Access the data for a given entry<br /> if (feed.Entry) {<br /> for (var i = 0; i < feed.Entry.length; i++) {<br /> html += "<div>" + "<a target='_blank' href='" + feed.Entry[i].Link + "'>" + feed.Entry[i].Title + "</a> ";<br /> // The feed entry Date field contains the timestamp in seconds<br /> // since Jan. 1, 1970. To convert it to the milliseconds needed<br /> // to initialize the JavaScript Date object with the correct date, <br /> // multiply by 1000.<br /> var milliseconds = (feed.Entry[i].Date) * 1000; <br /> var date = new Date(milliseconds); <br /> html += date.toLocaleDateString();<br /> html += " ";<br /> html += date.toLocaleTimeString(); <br /> html += "<br><i>" + feed.Entry[i].Summary + "</i>";<br /> html += "</div>";<br /> }<br /> }<br /> // Set the html into the main container<br /> contentDiv.innerHTML = html; <br /> <br /> // Adjust gadget height according to contents<br /> _IG_AdjustIFrameHeight();<br /> }<br /> // Register the function displayContent in the onLoad handler so it is called when the gadget is first loaded<br /> _IG_RegisterOnloadHandler(displayContent);<br /><br /> </script><br /><br /> <div id="main_container"></div><br /><br />]]><br /></Content><br /></Module><br /></pre><br />As you can see in the code, the function _IG_FetchFeedAsJSON receives as parameters the feed URL and the name of the callback function in charge of processing and displaying the data.<br /><br />In the callback function what we do first is to check if the JSON response we received is valid, if it isn't then we just display a message saying that the data is invalid. If the response is valid then we go through the JSON properties to retrieve the data and display it using HTML and CSS.<br /><br />As you can see this particular API is really easy to use and understand, you just need some basic knowledge of Javascript and that is it!<br /><br />Now that you have the code in your GGE, you can publish it to your iGoogle so you can see how the dynamic height works depending on the content. Also you can publish it to a web page. Just click on the File menu and select the Publish option. You will get a warning saying that we did not set the Thumbnail preference, but that is not going to affect the code itself, since the Thumbnail is used just to display the gadget Thumbnail in the Google Gadget Directory, so people know how the gadget looks like.<br /><br />I hope this helps! Post your comments and/or questions!Anonymoushttp://www.blogger.com/profile/08204368870896239348noreply@blogger.com2tag:blogger.com,1999:blog-3163902976500875690.post-49640436988784175492008-04-14T20:20:00.004-06:002009-05-12T14:39:44.600-06:00Working with Enumerations in JavaAn enumeration type is a Java type, which all values for the type are known when the type is defined. It is a special kind of class, with an instance that represents each value of the enumeration.<br /><br />An instance of the enum class is called an enum constant, we will be referring to this term along the article.<br /><br />There are some interesting things a developer must know when working with enums:<br /><ul><br /><li>When declaring an enumeration, it is like declaring a class but with two exceptions:<br /> - The keyword <span style="font-weight:bold;">enum </span>is used instead of <span style="font-weight:bold;">class</span>,<br /> - Before declaring any class members, an enum must declare first all its enum constants.<br /></li><br /><li>All enums implicitly extend java.lang.Enum. Since Java does not support multiple inheritance, an enum cannot extend anything else.</li><br /><li>All enum are implicitly Serializable and Comparable.</li><br /><li>Enums can have fields, methods and nested types, including nested enums.</li><br /><li>Two static methods are automatically generated by the compiler:<br /> - values: returns an array of the enum constansts<br /> - valueOf(String name): returns the enum constant for a given name.</li><br /><li>An enum type is not allowed to override the finalize method from Object.</li><br /><li>Enum instances may never be finalized.</li><br /><li>Nested enums can have any access modifier, while a top-level enum is public or package accessible.</li><br /><li>Enums are implicitly static.</li><br /><li>An enum cannot be declared abstract, but can declare abstract methods. Also, it cannot be declared final.</li><br /><li>An enum constant declaration cannot have modifiers applied to it, except for annotations.</li><br /><li>Restrictions of enum constructors:<br /> - All enum constructors are private.<br /> - An enum constructor cannot explicitly invoke a superclass constructor.<br /> - An enum constructor cannot use a non-constant static field of the enum.</li><br /><li>Enum constants can have constant-specific behavior.</li><br /><li>Some useful properties are set for enums:<br /> - The method clone is overriden to be declared final and to throw CloneNotSupported Exception.<br /> - The hasCode and equals method are overriden to be declared final.<br /> - The compareTo method is implemented and defined so that enum constants have a natural ordering based on their order of declaration (the first declared enum constant has the lowest position in the ordering).</li><br /><li>The toString method returns the name of the enum constant.</li><br /></ul><br />When using an enum will depend on how sophisticated is the behavior of type, because if the behavior is too sophisticated, it is more likely the application might need to specialize that behavior. Enums are suggested for simple types like card suits or the days of the week.Anonymoushttp://www.blogger.com/profile/08204368870896239348noreply@blogger.com0tag:blogger.com,1999:blog-3163902976500875690.post-78241267702003448922008-02-22T10:06:00.007-06:002013-03-15T13:20:46.624-06:00Professional Networking<b>Summary</b><br />
<br />
<i>“Many of the successful people in the world say that they owe their success not only to their own skills but to all the people that help them achieve their goals, others say that it is not enough being smart, you have to be surrounded by smart people. Given this, you can know how important is to have the right people near you, keeping a good network of friends, partners and clients can help achieve your goals faster and more efficiently. Nowadays there are lots of tools to help you manage your networks, you could take advantage of several options that they offer to their users. We are going to focus on these advantages and in the importance of having a solid professional network.”</i><br />
<br />
Keywords: professional networks, potential customers, colleagues, friends, profile, business, visibility.<br />
<br />
<span style="font-weight: bold;">1 Introduction</span><br />
<br />
Recently, the number of sites dedicated to social networking has been growing. Sites like Hi5 (<a href="http://www.hi5.com/">http://www.hi5.com/</a>) and Facebook (<a href="http://www.facebook.com/">http://www.facebook.com/</a>) have become really popular between Internet users of all ages, popularity that grows thanks to the fact that people can keep in touch with friends, meet new people, share pictures, hobbies and stories among other things.<br />
<br />
Along with social networking sites, the popularity of sites for professional networking has been growing as well; one example is LinkedIn (<a href="http://www.linkedin.com/">http://www.linkedin.com</a>), a professional networking site with thousands of users from all over the world.<br />
<br />
This type of sites have all the same advantages as social networking sites, but adding their own features and focusing mainly in professional people who wants to do business and keep in touch with colleagues and potential customers.<br />
<br />
In this article, we would be focusing on the main advantages of being part of a professional network and how this type of network can help your career.<br />
<br />
<span style="font-weight: bold;">2 Main Advantages</span><br />
<br />
A professional network offers a lot of advantages to all the people who are part of it and now you can find several sites in the Internet that work as tools, allowing professionals to create their networks easily.<br />
<br />
Some of the main advantages and features these sites offer are explained as follow.<br />
<br />
<span style="font-weight: bold;">2.1 Keep in touch</span><br />
<br />
The biggest advantage of a professional network site is that users can easily keep in touch with friends, colleagues or partners.<br />
<br />
Keep in touch with all the people you have known along your career is sometimes impossible, addresses and phone numbers change. Lost contact is sometimes inevitable, so having a site that gives you the ability to connect with those you lost contact over time is just a great advantage.<br />
<br />
On the other hand, you can keep your contact list in one place, knowing that it always will be up-to-date, since each contact information is updated by the actual contact letting you have reliable information almost all the time.<br />
<br />
<i>“Relationships are meaningful, in every aspect of life including career management. Networking is the key to discovery of our career selves and you never know, you might just make some friends and continue to find your path.” <a href="http://www.linkedin.com/profile?viewProfile=&key=13479723&authToken=TrI2&authType=name&goback=.amq.avq_140415_4969076_0_*2" target="_blank">Katie Metcalfe</a> (LinkedIn user)</i><br />
<br />
<span style="font-weight: bold;">2.2 Become visible</span><br />
<br />
Publishing your profile, having it up-to-date with relevant information about your education, experience and skills will make you visible to your network. Colleagues, classmates and partners will be able to reconnect with you and people that don’t know you will be able to get to know you better and even get interested in what you have to offer.<br />
<br />
Having a well-built profile will allow you to get job offers and business opportunities allowing you to grow your network and your business.<br />
<br />
Your profile will help you to promote yourself, to market your experience and brand your business.<br />
<br />
<span style="font-weight: bold;">2.3 Contact potential customers</span><br />
<br />
If you own a business with services to offer, you can use your network to promote your services and find potential customers.<br />
<br />
In a professional network site you can contact potential customers directly or by getting recommended by your actual customers or partners, getting a lot of benefits from something as easy as that.<br />
<br />
<i>“I have always been taught when selling to try to find common ground with potential customer. Haveing a business network in common can be a big help.” <a href="http://www.linkedin.com/profile?viewProfile=&key=10464046&authToken=jBOd&authType=name&goback=.amq.avq_140415_4969076_0_*2" target="_blank">Louis D'Esposito</a> (LinkedIn user)</i><br />
<br />
<span style="font-weight: bold;">2.4 Share ideas</span><br />
<br />
Most of these sites offer features that allow their users to share ideas or things that other people might find interesting.<br />
<br />
Some have forums, blogs or question and answers modules promoting the transfer of knowledge. These features allow their users to contact people who are experts in certain areas or even become experts themselves by sharing their answers and knowledge with others, winning recognition for their expertise.<br />
<br />
<i>“The knowledge that is freely shared both on the site and between connections off site is priceless. We can reach out to an almost unlimited number of great minds and share ideas, solve problems and do business.” <a href="http://www.linkedin.com/profile?viewProfile=&key=2308560&authToken=k3nW&authType=name&goback=.amq.avq_140415_4969076_0_*2" target="_blank">Sheilah Etheridge</a> (LinkedIn user)</i><br />
<br />
When professionals publish their articles or answer questions related to their fields, they are demonstrating that they have experience and expertise in a certain area, allowing others to get to know them and even maybe becoming a “go to guy” in that specific area creating a lot of opportunities for themselves and why not?, helping others with their knowledge.<br />
<br />
<span style="font-weight: bold;">2.5 Connect with international professionals</span><br />
<br />
<i>“To me, the biggest advantage is making international contacts that I otherwise wouldn't make. I appreciate the diverse insights and perspectives, and who knows how these contacts might pay off in the future? In business and in networking, there's rarely such a thing as incidental contact. Relationships are meaningful.” <a href="http://www.linkedin.com/profile?viewProfile=&key=13058162&authToken=D9eC&authType=name&goback=.amq.avq_140415_4969076_0_*2" target="_blank">Tom Field</a> (LinkedIn user)</i><br />
<br />
Since these sites are based on the Internet, they are accessible to everybody in the world, creating a network of a big number of users that you have access to. This gives the advantage that one user can easily connect to another no matter if the other user lives in a country in the other side of the world. Also, it allows getting different experiences from different professionals around the globe.<br />
<br />
<span style="font-weight: bold;">2.6 Recommendations</span><br />
<br />
Some of the professional networking sites offer the possibility of managing recommendations; users can give recommendations to their connections or get recommended.<br />
<br />
This type of features gives the user the chance to help others by giving their recommendations, which can be accounted on looking for a new job, a new business partner or a potential customer since recommendations add more completion and credibility to your profile.<br />
<br />
<span style="font-weight: bold;">2.7 Hiring people</span><br />
<br />
Since users of professional networking sites manage a public profile where they describe their education, experience and skills, recruiters can use these sites to look for potential candidates for the job positions they are offering.<br />
<br />
The good thing is that these recruiters can use the site to contact these potential candidates directly or through their connections. In addition to this, since these sites are used by a lot of people around the world, recruiters have access to a bigger number of potential candidates.<br />
<br />
Besides, if the users have a completed profile, just by reading their profiles, recruiters can get to know their potential candidates before even contact them, sometimes saving time in phone calls and emails.<br />
<br />
<span style="font-weight: bold;">2.8 Finding a job</span><br />
<br />
Some professional networking sites offer the opportunity for companies to promote their business and to public their job openings allowing professionals to apply to these jobs directly in the site.<br />
<br />
Having a completed profile and several recommendations will give the professional more chances to be selected for a job. You could be contacted directly by the recruiter; you might have been recommended by someone or be discovered through your participation in forums or blogs. It is all a matter of how much effort you put when you publish your profile or how much advantage you take of the features the site offers.<br />
<br />
<span style="font-weight: bold;">2.9 Quality of business</span><br />
<br />
This type of sites let you get leads on possible customers that are actually looking for a product or service that you could provide. Most of the time, these customers are referred by someone you know well, someone who is a mutual acquaintance of you and the prospect customer, which is something good for your business because it lets you save time in looking for new clients, spending less money in advertising and getting more profit since you are not investing resources in a prospect that is less probable would do business with you.<br />
<br />
<span style="font-weight: bold;">3 Conclusions</span><br />
<br />
Professional networking sites are great tools to keep in touch with colleagues, clients and partners, since they offer a lot of advantages that make things easier inside a network. However the use you do of these features is completely up to you. You can be an active user that takes advantage of all features and make them work for you by branding yourself, promoting your business and getting recognized for your expertise or you can be a user with an active account that is never updated and therefore not visible inside the network.<br />
<br />
Professional networking sites can create a lot of opportunities for you if you know how to take advantage of them. These opportunities can be used in the present or in the future, the bigger your network the bigger the number of opportunities you will have.<br />
<br />
"Knowing the right people" is one of the keys to success in today's world, especially because you need to work with partners to grow your business more quickly, so being part of a well developed and broad professional network is more important than ever. Keeping a large number of "business friends" is critical for your career, therefore the importance of professional networking tools.<br />
<br />
If you are an entrepreneur promoting your services or someone looking for a new job, these tools can really help you achieve your goals, but it is always up to you.Anonymoushttp://www.blogger.com/profile/08204368870896239348noreply@blogger.com0tag:blogger.com,1999:blog-3163902976500875690.post-4820069292447549992007-10-24T09:48:00.002-06:002009-05-12T14:39:00.288-06:00A Java Certification or Not?Lately I've been thinking about getting a Java Certification, but I've heard some opinions of people saying that a certification does not give an extra value to the person that has it, so I started thinking about it and it seems that some companies actually react when they see in your resume that you have certifications.<br /><br />To get some more opinions, I posted a question in LinkedIn, I asked this:<br /><br /><span style="font-style:italic;">For a Java programmer, do you think it really makes a difference to have a Java certification when looking for a new job?<br /><br />I am interested in knowing if a certification is actually considered when evaluating candidates or if the employers only care about their own evaluations and candidate's past experience. <br /></span><br />It was interesting because I got a lot of different opinions from people who are Java developers and from people who recruit.<br /><br />Most of the answers agreed in one thing, a certification can't hurt no one, so in most of the cases companies would check your experience, your ability to solve problems and some other skills before actually caring about the certification. However, if they are interviewing two people and both of them have the same qualifications, but one has a certification they would probably hire the one with the certification because it is a plus, it means that this person studied Java to pass the test.<br /><br />In my opinion, I don't think a certification would actually make a big different when your applying for a job if you don't have any experience. However, one of the biggest advantage of getting a certification is that you have to sit and study all the Java items required to pass this test and that gives you a big knowledge of the language because you are learning the theory and that is very important, since there are a lot of developers that can make things work but they don't know what is actually happening or how it is happening, they just know it works.<br /><br />If you want to check all the answers go to my question in <a href="http://www.linkedin.com/answers/technology/information-technology/computers-software/TCH_ITS_CMP/116207-4969076?goback=%2Eahp" target="_blank">LinkedIn</a>Anonymoushttp://www.blogger.com/profile/08204368870896239348noreply@blogger.com2tag:blogger.com,1999:blog-3163902976500875690.post-81570738774903246592007-07-25T23:06:00.001-06:002009-05-12T14:38:45.610-06:00Ruby on Rails - Up and Running Book ReviewRecently, I've been interested in learning Ruby on Rails, but at the beginning of my quest I wasn't sure where to begin, there are a lot of documentation in the Web that I could use but I wanted some structured tutorial that guide me through my first experiences with Rails.<br /><br />Fortunately, the company where I work bought the book Ruby on Rails Up and Running by Bruce A. Tate and Curt Hibbs, so I took it and started reading it and what I found was exactly what I was looking for, a beginners book.<br /><br />I give this book 4 starts because I think it's really good for someone who is just starting to learn about Rails. It explains the basics of the language and the authors use the same example along each chapter so you can learn all the concepts in the book in a very practical way. The example is a Photo Slideshow application, a very common example actually because it allows you to develop some business logic along with interesting views handled by Ajax and some Javascript effects.<br /><br />With this book, you can learn the basics of Active Record and Active Record Relationships, Scaffolding, Views, Migrations, Ajax and a bit of Testing.<br /><br />It is not too long, so you won't feel intimidated by it. It is a good place to start, trust me! <br /><br />I recommend it!Anonymoushttp://www.blogger.com/profile/08204368870896239348noreply@blogger.com0tag:blogger.com,1999:blog-3163902976500875690.post-53918098994641344652007-07-25T22:10:00.001-06:002009-05-12T14:38:27.217-06:00How to handle Time fields in MySQL and Ruby on RailsOne of these days while I was working in a small application created in Ruby on Rails I came across a field in the database with data type Time. The interesting thing was that Rails does not support Time fields, it supports only Date or Datetime, so what to do?<br /><br />Since I had to handle Time fields not dates, I had to do some tricks to make this work. I'm going to share with you, in a high level, what I did.<br /><br />First, in the RHTML page I handled the time (hour and minutes) using my own fields, maybe HTML selects with the possible time values. <br /><br />Next, I created some Javascript function which would post the time as a String or numeric value to the controller, then in the controller you convert the value to a String notation with the format "HH:MM", for example "08:30" or "14:25". <br /><br />Then, you create a Ruby Time object using your String time as follows: <br /><span style="font-style:italic;"><span style="font-weight:bold;">timeObj = Time.parse("8:15")</span></span><br /><br />This will create a Time object with the current system date and the given hour and minutes you set.<br /><br />Finally, when you store your Time object in database, MySQL will truncate the date and store only the time value which is exactly what you wanted to do in the first place.<br /><br />I hope this helps!!Anonymoushttp://www.blogger.com/profile/08204368870896239348noreply@blogger.com0tag:blogger.com,1999:blog-3163902976500875690.post-28310988996064026582007-07-25T14:46:00.001-06:002009-05-12T14:38:12.311-06:00Prototype Javascript Framework - Creating classesHere it is a quick review of how you can implement classes in Javascript using the Prototype Framework. (This was taken of the Prototype reference document that you can find in <a href="http://beta.bigmedium.com/projects/prototype-pdf/index.shtml">http://beta.bigmedium.com/projects/prototype-pdf/index.shtml</a>)<br /><br />If you are familiar with Object Oriented Programming, handling classes in Javascript would be really easy and Prototype makes easier.<br /><br />Another advantage of using classes in Javascript is that you can have cleaner code, easy to use and maintain.<br /><br />I'll show you now how to create a class using Prototype.<br /><br /><span style="font-weight:bold;">create() -> Function</span><br /><br />Returns an function that acts like a Ruby class.<br /><br />Class.create() returns a function that, when called, will fire its own initialize method.It also lets you more easily subclass by overriding a parent's constructor.<br /><br />Example:<br /><br />var Person = Class.create();<br />Person.prototype = {<br /> initialize: function(name, lastname, age) {<br /> this.name = name;<br /> this.lastname = lastname;<br /> this.age = age;<br /> },<br /> myAge: function() {<br /> alert("My age is " + this.age);<br /> }<br />};<br /><br />var john = new Person("John", "Doe", 25);<br />john.myAge();<br />// -> alerts "My age is 25"<br /><br />var Employee = Class.create();<br />Employee.prototype = Object.extend(new Person(), {<br /> initialize: function(name, lastname, age, job) {<br /> this.name = name;<br /> this.lastname= "lastname";<br /> this.age = age;<br /> this.job = job;<br /> },<br /><br /> myJob: function() {<br /> alert("I work as a " + this.job);<br /> }<br />});<br /><br />var susan = new Employee("Susan", "Smith", 30, "Teacher");<br />susan.myJob();<br />// -> alerts "I work as a Teacher"Anonymoushttp://www.blogger.com/profile/08204368870896239348noreply@blogger.com0tag:blogger.com,1999:blog-3163902976500875690.post-39041606448724632822007-07-13T11:34:00.002-06:002009-05-12T14:37:54.716-06:00Prototype Javascript Framework - Utility MethodsHere it is a quick review of the most important utility methods of the Prototype Framework. (This was taken of the Prototype reference document that you can find in <a href="http://beta.bigmedium.com/projects/prototype-pdf/index.shtml">http://beta.bigmedium.com/projects/prototype-pdf/index.shtml</a>)<br /><br /><span style="font-weight:bold;">$</span><br /><br /><span style="font-style:italic;">$(id | element) -> HTMLElement<br />$((id | element)...) -> [HTMLElement...]<br /></span><br />If provided with a string, returns the element in the document with matching ID; otherwise returns the passed element.<br /><br />The function also extends every returned element with Element.extend so you can use Prototype's DOM extensions on it.<br /><br /><span style="font-weight:bold;">$$</span><br /><br /><span style="font-style:italic;">$$(cssRule...) -> [HTMLElement...]</span><br /><br />Takes an arbitrary number of CSS selectors (strings) and returns a document-order array of extended DOM elements that match any of them.<br /><br />The $$ function searches, by default, the whole document.<br /><br />Current set of supported selectors:<ul><br /> <li>Type selector: tag names, as in div.</li><br /> <li>Descendant selector: the space(s) between other selectors, as in #a li.</li><br /> <li>Attribute selectors: the full CSS 2.1 set of [attr], [attr=value], [attr~=value] and [attr|=value]. It also supports [attr!=value]. If the value you're matching against includes a space, be sure to enclose the value in quotation marks ([title="Hello World!"]).</li><br /> <li>Class selector: CSS class names, as in .highlighted or .example.wrong.</li><br /> <li>ID selector: as in #item1.</li><br /></ul><br /><span style="font-weight:bold;">$A</span><br /><br /><span style="font-style:italic;">$A(iterable) -> actualArray</span><br /><br />Accepts an array-like collection (anything with numeric indices) and returns its equivalent as an actual Array object.<br /><br />$A doesn't perform DOM extensions, since the array could contain anything (not just DOM elements).<br /><br /><span style="font-weight:bold;">$F</span><br /><br /><span style="font-style:italic;">$F(element) -> value</span><br /><br />Returns the value of a form control. This is a convenience alias of form.Element.getValue. <br /><br /><span style="font-weight:bold;">$H</span><br /><br /><span style="font-style:italic;">$H([obj]) -> Hash</span><br /><br />Creates a Hash (which is synonymous to “map” or “associative array” for our purposes). <br /><br />A convenience wrapper around the Hash constructor, with a safeguard that lets you pass an existing Hash object and get it $F | 5 back untouched (instead of uselessly cloning it).<br /><br /><span style="font-weight:bold;">$R</span><br /><br /><span style="font-style:italic;">$R(start, end[, exclusive = false]) -> ObjectRange</span><br /><br />Creates a new ObjectRange object. This method is a convenience wrapper around the<br />[ObjectRange](/api/objectRange constructor, but $R is the preferred alias.<br /><br /><span style="font-weight:bold;">$w</span><br /><br /><span style="font-style:italic;">$w(String) -> Array</span><br /><br />Splits a string into an Array, treating all whitespace as delimiters. Equivalent to Ruby's %w{foo bar} or Perl's qw(foo bar).<br /><br /><span style="font-weight:bold;">Try.these</span><br /><br /><span style="font-style:italic;">Try.these(Function...) -> firstOKResult</span><br /><br />Accepts an arbitrary number of functions and returns the result of the first one that doesn't throw an error.<br /><br /><span style="font-weight:bold;">document.getElementsByClassName</span><br /><br /><span style="font-style:italic;">document.getElementsByClassName(className[, element]) -> [HTMLElement...]</span><br /><br />Retrieves (and extends) all the elements that have a CSS class name of className. The optional element parameter specifies a parent element to search under.Anonymoushttp://www.blogger.com/profile/08204368870896239348noreply@blogger.com1tag:blogger.com,1999:blog-3163902976500875690.post-10619705320457856182007-06-19T17:36:00.001-06:002009-05-12T14:37:38.768-06:00Ruby on Rails - Some tipsI've been trying to learn Ruby on Rails, it is an interesting framework that makes developers life a lot easier. <br /><br />I found some tips or notes that I think I can share with you so they might be helpful when you are doing some programming in Rails yourself.<br /><br />Hope this helps!!<br /><ul><br /><li>Name your tables in plural, the class would be generated in singular.</li><br /><li>When migrating a schema_info table is created to keep track of the schema version.</li><br /><li>The id column is an int and it's generated automatically, also it uses auto_increment so you don't have to worry to set this value.</li><br /><li>Foreign keys should be named using the name of the class plus "_id", for example product_id.</li><br /><li>Every ActiveRecord class has a transaction method to handle transactions.</li><br /><li>The relationship "belongs_to" corresponds to the "many" side of the many_to_one relationship.</li><br /><li>When you use acts_as_tree, the name convention is parent_id, it would recognize it by itself. This would create a <span style="font-style:italic;">parent </span>and children variables, where <span style="font-style:italic;">children </span>is an array.</li><br /><li>There is a layout file for each controller. You can create just one that can be used by every controller, setting the property layout in the application base controller or directly in every controller.</li><br /><li>In the routes file you can specify the default action to be executed when entering the site. When doing this remember to delete the index.html under the view directory root.</li><br /></ul><br />More coming later...Anonymoushttp://www.blogger.com/profile/08204368870896239348noreply@blogger.com0