Friday, October 29, 2010

Four Steps

Debt is a form of enslavement, the victim is deceived into breaking a simple rule:
Spend less than you earn.

Spending less than you earn is very similar to another simple rule many struggle with when overweight:
Eat less than you burn.

Health and wealth and happiness are very inter-related. Getting control of your health can help you to get control of other areas of your life. Taking control of my eating habits helped me break away from other bad behaviors and get my financial situation under control.

With any change in life, you start by learning, then setting goals, making a plan to achieve them, and acting on your plan. The last step is critical, never wait to act. So learn what you should learn, get a plan for your goal, and GO!

1 Learn
You have to learn a better way, you can't keep doing the same thing and expect a different outcome. Learn what to do. For example, don't buy a gym membership and never learn how to safely exercise because you may hurt yourself and be worse off than before. Similarly, you should research budget plans or debt elimination strategies and pick one that you firmly believe will work for you, one that people like you have been successful with. This is also a time to get motivated and inspired by others who have been successful at making the change you are making. Finally, write a list of what benefits you will have from making the change (or start with this list), but keep it handy.

2 Goal != Dream
Good goals should be a specific and small, they should be steps on your journey toward your dreams and desires, their should be a deadline or target date for your goal. A dream to be a millionaire is not a goal. Good example of a goal would be to lose 10 lbs by December 2010, or pay off all credit card balances before July 2011.

3 Plan
Very important third step is to plan, be aware of your life and the obstacles you already have to accomplishing your goal, account for those in your plan. Some unexpected obstacles will blindside you, you may get pregnant, you may have a huge unexpected expense, or experience a job loss. Things happen that are out of your control and can impede your progress, expect them to happen but realize they happen to EVERYONE, and realize obstacles happened to people who were still successful with their goals. Decide to be one of those people, the ones that didn't give up or give in to challenges. Use the knowledge you gained to make a detailed plan. Keep in mind that your plan should not be unreasonable, your plan should be actually physically possible for you to do 100% of the time. Your plan should make sense to you, you need to believe that following the plan will work, not just hope that it will.

4 Act
Make a commitment to accomplish your goal with your plan. Think no-matter-what-I-am-doing-this, then as you act, no-matter-what, do it, stay committed. Decide now that you will always decide to go on, then never change your mind about it. You have to be a stubborn, hard-nosed jerk about it, because excess fat and debt are stubborn hard-nosed jerks too. Use the inspiration and motivation from other successful people to support you and help you to avoid falling backwards into addictive behaviors that take you away from your goal. If you look, you can find inspirational stories from people who had challenges accomplishing the very same thing you are trying to accomplish. Keep at it until you see movement, until you see a change you really are proud of, until you reach that goal, then immediately start over with step one and do it again. Don't bask in your awesomeness for a second, because that's a great time for an old behavior to creep back into your life. You achieved something, it felt great, it was great, don't ruin it by undoing that hard work.

Tuesday, September 14, 2010

Tynt programming assignment (Part 5)

Here is my implementation of a Hash collection for Integers:
package com.tynt.app.util;

public class IntegerHash {
public static final int BUFFER_SIZE = 100;

private IntegerList values;
private IntegerList valueCounts;

public IntegerHash() {
values = new IntegerList();
valueCounts = new IntegerList();
}

public boolean hasInteger(Integer value) {
if (value == null) {
return false;
}
for(int i=0;i < values.size();i++) {
if (values.get(i).compareTo(value) == 0) {
return true;
}
}
return false;
}

public Integer getIntegerCount(int index) {
return valueCounts.get(index);
}

public Integer getIntegerIndex(Integer value) {
for(int i=0;i < values.size();i++) {
if (values.get(i).compareTo(value) == 0) {
return i;
}
}
return -1;
}

public void incrementIntegerCount(Integer value) {
int integerIndex = getIntegerIndex(value);
valueCounts.put(integerIndex, getIntegerCount(integerIndex)+1);
}

public void addInteger(Integer value) {
if (!hasInteger(value)) {
values.concatenate(value);
valueCounts.concatenate(1);
} else {
incrementIntegerCount(value);
}
}

public IntegerList getIntegers() {
IntegerList vals = new IntegerList();
for(int i = 0; i < values.size(); i++) {
vals.concatenate(values.get(i));
}
return vals;
}

public Integer getIntegerFrequency(Integer value) {
if (hasInteger(value)) {
int index = getIntegerIndex(value);
return getIntegerCount(index);
} else {
return 0;
}
}
}

As you can see, I re-used the IntegerList collection in the Hash collection. Since I am not sorting the IntegerList, I have to iterate through the entire key IntegerList to check for a key in the hash, with a sorted key IntegerList, I could short circuit after the key was larger than the sorted key it was compared with. I am also not implementing a hash algorithm at all, so the collection was not named very well. Implementing a true hash collection was not part of the assignment so I didn't worry about it.

Here is assignment5 using the above collection:
package com.tynt.app;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import com.tynt.app.util.*;

public class Assignment5 implements InputReader {

public String readFile(InputStream is) {
BufferedReader d = new BufferedReader(new InputStreamReader(is));
String line;
IntegerHash unsortedHash = new IntegerHash();
try {
line = d.readLine();
while (line != null) {
Integer value = null;
try {
value = new Integer(Integer.parseInt(line));
} catch (NumberFormatException e) {
throw new RuntimeException(e);
}
unsortedHash.addInteger(value);
line = d.readLine();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
StringBuilder sb = new StringBuilder();
IntegerList sortedList = IntegerList.quicksort(unsortedHash.getIntegers());
if (sortedList == null) {
sortedList = new IntegerList();
}
for (int i=0;i < sortedList.size();i++) {
sb.append(sortedList.get(i));
sb.append(" - ");
sb.append(unsortedHash.getIntegerFrequency(sortedList.get(i)));
sb.append(NEW_LINE);
}
return sb.toString();
}

}

Finally, with all of the Assignment objects implemented and the tests passing, I can implement the Driver for the project:
package com.tynt.app;

import java.io.*;
import com.tynt.app.util.*;

/**
* Tynt programming challenge
*
* @author Four Gables Guy
*
*/
public class App {
public static final String header = "********************";

public static void main(String[] args) throws IOException {
String choice = displayChoices();
while (choice.equals("1") || choice.equals("2") || choice.equals("ALL")) {
parseChoice(choice);
if (choice.equals("ALL")) {
break;
}
choice = displayChoices();
}
}

public static void parseChoice(String choice) throws IOException {
if (choice.equals("1")) {
doAssignment2();
} else if (choice.equals("2")) {
doAssignment3();
} else if (choice.equals("ALL")) {
doAssignment2();
doAssignment3();
}
}

public static String displayChoices() {
System.out.println(header);
System.out.println("Enter 1 to parse " + InputReader.INPUT_FILE
+ " and print numbers sorted ascending.");
System.out.println("Enter 2 to parse " + InputReader.INPUT_FILE
+ " and print numbers sorted ascending.");
System.out.println("Enter any other characters to quit.");
System.out.println(header);
Console console = System.console();
if (console == null) {
return "ALL";
} else {
String line = console.readLine();
line = line.trim();
return line;
}
}

public static void doAssignment2() throws IOException {
Assignment4 assignment4 = new Assignment4();
FileInputStream is = new FileInputStream(new File(
InputReader.INPUT_FILE));
System.out.println(assignment4.readFile(is));
}

public static void doAssignment3() throws IOException {
Assignment5 assignment5 = new Assignment5();
FileInputStream is = new FileInputStream(new File(
InputReader.INPUT_FILE));
FileOutputStream os = new FileOutputStream(new File(
InputReader.OUTPUT_FILE));
String output = assignment5.readFile(is);
System.out.println(output);
os.write(output.getBytes());
os.flush();
os.close();
}
}

It is a bit confusing that I named the method's doAssignment2 and doAssignment3 but use Assignment4 and Assignment5 objects. I should have named these assignment classes better. Again it was a small programming assignment, and an easy refactor. Overall, I do think I did a decent job with this assignment and benefitted from the effort.

I created a handy batch file to execute the code called tynt.bat which does this:
java -cp target\program_assignment-1.0-SNAPSHOT.jar com.tynt.app.App

Monday, September 13, 2010

Tynt programming assignment (Part 4)

Finally, here is where I have to implement the sorting algorithm and collection. I created a List collection I called IntegerList:
package com.tynt.app.util;

public class IntegerList {
public static final int BUFFER_SIZE = 100;
private Integer[] internalArray;
private int size;

public IntegerList() {
internalArray = new Integer[BUFFER_SIZE];
size = 0;
}

public IntegerList(int size) {
if (size < 0) {
throw new RuntimeException("Cannot create IntegerList with negative size");
}
internalArray = new Integer[size];
size = 0;
}

public int size() {
return size;
}

public void put(int index, Integer value) {
if (index > -1 && index < size) {
internalArray[index] = value;
} else {
throw new RuntimeException("Cannot put value "+value+" at index "+index+" IntegerList has size "+size);
}
}

public void concatenate(Integer value) {
if (value == null) {
throw new RuntimeException("Cannot concatenate null values");
}
if (size + 1 == internalArray.length) {
Integer[] temp = new Integer[internalArray.length + BUFFER_SIZE];
System.arraycopy(internalArray, 0, temp, 0,
internalArray.length);
internalArray = temp;
}
internalArray[size++] = value;
}

public void concatenate(IntegerList values) {
for (int i = 0 ; i < values.size(); i++) {
concatenate(values.get(i));
}
}

public Integer get(int index) {
if (index > -1 && index < size) {
return internalArray[index];
} else {
throw new RuntimeException("Cannot access value at "+index+" in IntegerList size "+size);
}
}

public Integer remove(int index) {
if (index > -1 && index < size) {
Integer result = get(index);
IntegerList integerList = new IntegerList();
for(int i = 0; i < size; i++) {
if (i != index) {
integerList.concatenate(get(i));
}
}
internalArray = integerList.internalArray;
size = size - 1;
return result;
} else {
throw new RuntimeException("Cannot access value at "+index+" in IntegerList size "+size);
}
}

public static IntegerList quicksort(IntegerList unsorted) {
IntegerList less = new IntegerList();
IntegerList greater = new IntegerList();
if (unsorted.size() <= 1) {
return unsorted;
}
Integer pivot = selectPivot(unsorted);
for(int i = 0; i < unsorted.size(); i++) {
Integer value = unsorted.get(i);
if (value <= pivot) {
less.concatenate(value);
} else {
greater.concatenate(value);
}
}
return concatenate(quicksort(less), pivot, quicksort(greater));
}

public static Integer selectPivot(IntegerList unsorted) {
if (unsorted == null || unsorted.size() < 2) {
throw new RuntimeException("Cannot select pivot on empty or single element list");
}
int pivotIndex = unsorted.size() / 2;
return unsorted.remove(pivotIndex);
}

public static IntegerList concatenate(IntegerList less, Integer pivot, IntegerList greater) {
if (less == null | pivot == null || greater == null) {
throw new RuntimeException("Cannot concatenate null values");
}
IntegerList finalList = new IntegerList(less.size()+1+greater.size());
finalList.concatenate(less);
finalList.concatenate(pivot);
finalList.concatenate(greater);
return finalList;
}
}

IntegerList implements a quicksort method which returns the IntegerList as a sorted IntegerList. My implementation of quicksort has several drawbacks:

  • I create additional collections (less,greater,etc...) for each invocation of quicksort and concatenate, so lots of memory could be used up with a long list to sort. It would be less memory to sort the list in-place without recursion/extra collections.
  • Speaking of recursion, too much recursion could cause a stack overflow as well.
With IntegerList implemented, I can use it to implement Assignment4:
package com.tynt.app;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import com.tynt.app.util.*;

public class Assignment4 implements InputReader {

public String readFile(InputStream is) {
BufferedReader d = new BufferedReader(new InputStreamReader(is));
String line;
IntegerList unsortedList = new IntegerList();
try {
line = d.readLine();
while (line != null) {
Integer value = null;
try {
value = new Integer(Integer.parseInt(line));
} catch (NumberFormatException e) {
throw new RuntimeException(e);
}
unsortedList.concatenate(value);
line = d.readLine();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
StringBuilder sb = new StringBuilder();
IntegerList sortedList = IntegerList.quicksort(unsortedList);
if (sortedList == null) {
sortedList = new IntegerList();
}
for (int i=0;i < sortedList.size();i++) {
sb.append(sortedList.get(i));
sb.append(NEW_LINE);
}
return sb.toString();
}

}

Still need to implement the Hash collection and driver.

Sunday, September 12, 2010

Tynt programming assignment (Part 3)

I glossed over creating the Assignment1-5 java files in the last post, this was done by first right clicking in eclipse and creating a package under this folder:
src\main\java\com\tynt\app
called
com.tynt.app
Then right clicking the empty package and creating new Class (Assignment1) adding the InputReader interface to the class and stubbing out the interface method:
public String readFile(InputStream is) {
return null;
}

Just so you know.

For Assignment1 I just wanted to get the code for reading and creating a string from the input stream working:

package com.tynt.app;

import java.io.*;

import com.tynt.app.util.InputReader;

public class Assignment1 implements InputReader {

/**
* @return contents of the InputStream as a String
*/
public String readFile(InputStream is) {
BufferedReader d = new BufferedReader(new InputStreamReader(is));
String line;
StringBuilder sb = new StringBuilder();
try {
line = d.readLine();
while (line != null) {
sb.append(line);
sb.append(NEW_LINE);
line = d.readLine();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return sb.toString();
}
}
For Assignment2 I decided to use the built-in Java collections classes to test what the output of my custom collection should look like:
package com.tynt.app;

import java.io.*;
import java.util.*;

import com.tynt.app.util.InputReader;

public class Assignment2 implements InputReader {

/**
* @return is list of numbers sorted in ascending order
*/
public String readFile(InputStream is) {
BufferedReader d = new BufferedReader(new InputStreamReader(is));
String line;
SortedSet sortedList = Collections.synchronizedSortedSet(new TreeSet());
try {
line = d.readLine();
while (line != null) {
Integer value = null;
try {
value = new Integer(Integer.parseInt(line));
} catch (NumberFormatException e) {
throw new RuntimeException(e);
}
sortedList.add(value);
line = d.readLine();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
StringBuilder sb = new StringBuilder();
for(Integer i: sortedList) {
sb.append(i);
sb.append(NEW_LINE);
}
return sb.toString();
}

}
Again with Assignment3, I used built-in collections to check what the output should be for the histogram:
package com.tynt.app;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;

import com.tynt.app.util.InputReader;

public class Assignment3 implements InputReader {

/**
* @return sorted list of numbers and their frequency
*/
public String readFile(InputStream is) {
BufferedReader d = new BufferedReader(new InputStreamReader(is));
String line;
SortedMap sortedMap = Collections.synchronizedSortedMap(new TreeMap());
try {
line = d.readLine();
while (line != null) {
Integer value = null;
try {
value = new Integer(Integer.parseInt(line));
} catch (NumberFormatException e) {
throw new RuntimeException(e);
}
Integer frequency = 1;
if (sortedMap.containsKey(value)) {
frequency = sortedMap.get(value);
frequency += 1;
}
sortedMap.put(value, frequency);
line = d.readLine();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
StringBuilder sb = new StringBuilder();
for(Integer key: sortedMap.keySet()) {
Integer frequency = sortedMap.get(key);
sb.append(key);
sb.append(" - ");
sb.append(frequency);
sb.append(NEW_LINE);
}
return sb.toString();
}

}
Assignment4 and Assignment5 actually adhered to the restriction of no built-in collections.

Saturday, September 11, 2010

Tynt programming assignment (Part 2)

Next I generated an eclipse project file for the maven project with this command:

mvn eclipse:eclipse

I opened the projet in eclipse. For the Junit tests I created some test input files here:
src\test\resources\TestData.txt
src\test\resources\BadInput.txt

I then created the unit test java file here:
src\test\java\com\tynt\app\AppTest.java

Here is the source for my unit test:
package com.tynt.app;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import java.io.*;
import java.util.*;

import com.tynt.app.util.*;

/**
* Unit test for simple App.
*/
public class AppTest
extends TestCase
{
/**
* Create the test case
*
* @param testName name of the test case
*/
public AppTest( String testName )
{
super( testName );
}

/**
* @return the suite of tests being tested
*/
public static Test suite()
{
return new TestSuite( AppTest.class );
}

/**
* Test each assignment with input files
*/
public void testApp()
{
List readers = new ArrayList();
Assignment1 assignment1 = new Assignment1();
Assignment2 assignment2 = new Assignment2();
Assignment3 assignment3 = new Assignment3();
Assignment4 assignment4 = new Assignment4();
Assignment5 assignment5 = new Assignment5();
readers.add(assignment1);
readers.add(assignment2);
readers.add(assignment3);
readers.add(assignment4);
readers.add(assignment5);
readerTest(readers,"TestData.txt");
try {
readerTest(readers,"BadInput.txt");
fail("Bad input should throw RuntimeException");
} catch (RuntimeException e) {
assertTrue(true);
}
}

public void readerTest(List readers, String resource) {
for (InputReader inputReader : readers) {
InputStream is = getClass().getClassLoader().getResourceAsStream(resource);
String result = inputReader.readFile(is);
System.out.println(result);
}
}
}
I created an interface I called InputReader to help me test the different assignments against the same input files.

package com.tynt.app.util;

import java.io.*;

public interface InputReader {

public static final String INPUT_FILE = "THire_input.txt";
public static final String OUTPUT_FILE = "THire_histogram.txt";
public static final String NEW_LINE = System.getProperty("line.separator");

/**
* Reads the InputStream parameter and returns a string of the contents
*
* @param is
* InputStream to read from
* @return String of the processed contents of InputStream
*/
public String readFile(InputStream is);
}
I then stubbed out the Assignment1-5 java classes which implement the InputReader interface and ran the package goal for maven using a maven eclipse plugin to fix any typos and get a baseline for beginning implementation.

Friday, September 10, 2010

Tynt programming assignment (Part 1)

I was a approached by a recruiter for a position at a company in Draper called Tynt.

As part of the hiring process I was given this coding assignment.
Coding Assignment #1
Thank you for your interest in Tynt. As part of our recruitment process we ask candidates to complete a small programming assignment. The assignment is technically easy, but is intended to provide enough scope to allow you to demonstrate your knowledge of good programming practices. Assume that the code you are writing will reside in Tynt's main production codebase.
Development Notes
• There is no time limit to complete this exercise.
• If there are errors in the example, state your assumptions and continue.
• No user interface is required; the program will be run from the console and should
require no command line parameters to execute normally
• Assume that all files (input and output) will be found/created in the same directory as the program executes
• As part of the exercise, you may choose to write unit tests appropriate for the task.
• Use the development tools of your choice, but please write the software in Java.
• You may not use any external libraries with the exception of standard I/O and possibly a unit testing framework.
• You may not use any built-in data structures such as lists, vectors, queues etc. You
must build your solution using basic types such as integers, strings and arrays.
• You may not use any built-in sort or histogram functions.
• Please submit all available aspects of your work (source, buildfiles, executables, test
input/output etc)
• Have Fun!
====================================================================
1) Read an ascii text file named "THire_input.txt" that contains a list of numbers with integer
values, each number separated by a cr/lf
Sample input (THire_input.txt)
6
54
12
22
1
6
2) Sort the numbers in ascending order and write the results to an output file named
"THire_Ascending.txt". Format the file in the same manner as the input file (cr/lf delimiters).
Sample output (THire_Ascending.txt)
1
6
6
12
22
I completed the assignment and submitted my solution but never heard from them, then the recruiter told me they went with someone else. Since I never had the opportunity to hear back from Tynt's hiring team, I decided to blog about my solution and solicit feedback on how I could do a better job.

The assignment tied my hands by not allowing external libraries or built-in Java collections. This is done to make an otherwise simple programming assignment much more labor intensive and error prone in college CS classes. Java loses much of it's value as a programming language when you eliminate the vast libraries available. Ultimately, the code I ended up writing would not belong in an actual enterprise code base precisely because I was required to implement functionality that is provided by the language libraries. Typically you don't roll-your-own implementation of a collection unless you have a very specific need to do it, which this assignment lacks. There was no time limit to complete the exercise (a bit discouraging in that you would think Tynt would have an idea of when they needed to hire the candidate), but that didn't matter because I received five-ten nagging emails from the headhunter asking for status on my progress with it.

On to the implementation, I decided that since this was to be considered code I would put in production, Junit tests were mandatory, as well as a build script. Maven is a fantastic build tool for Java development so I created a new project using Maven as follows:

mvn archetype:create -DgroupId=com.tynt.app -DartifactId=program_assignment


This generated the structure of the project. I edited the maven pom.xml file to add a Junit dependency as well as configure the maven-pmd-plugin, which will evaluate your source and report on potential bugs or bad source formatting. Here is my final pom:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tynt.app</groupId>
<artifactId>program_assignment</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>program_assignment</name>
<description>FourGablesGuy's implementation of programming assignment for Tynt. Reading and parsing text files for numbers.</description>
<url>http://maven.apache.org</url>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<compilerVersion>1.5</compilerVersion>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<id>pmd_check</id>
<phase>package</phase>
<goals>
<goal>pmd</goal>
</goals>
</execution>
</executions>
<configuration>
<sourceEncoding>UTF-8</sourceEncoding>
<outputEncoding>UTF-8</outputEncoding>
<targetJdk>1.5</targetJdk>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.4.3</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>


To build/update the artifact Jar, you simply run:


mvn package


which will compile source files, run any unit tests, and package the final code.

Thursday, September 9, 2010

startSQLRepository can fail to mark ATG Content Administration projects as deployed

Maybe this will help someone dealing with issues in ATG Service 2006.3.2 or ATG Service 2007.1

Symptom:

The symptom is that a solution is reporting it is not visible in ATG SelfService.You search for the solution but cannot view it and get a message that it is not visible for the current user.

Also, if you look up the solution in dynamo administrator for the j2ee instance running SelfService, it will be missing the status property.

This is an indication that the solution is not marked as deployed in the SolutionSolutionStatus Item Descriptor of the ServiceSharedRepository.

The solution can have audience Everyone-External set, in both Knowledge and SelfService which can make the error a head scratcher.

One way to check this is by connecting to dynamo admin for SelfService and in the /atg/svc/shared/ServiceSharedRepository execute

solutionId = "soln_id" AND deployed = true

If you do not get any rows back, then you probably have this problem, unless you just have not invalidated the caches.

Resolution:

connect to the shared schema with a database tool

update svc_soln_sstatus

set deployed = 0

where soln_id = 'soln_id' and

soln_version = version

where soln_id is the solution having the issue.

and version is the number of the version of the solution that should have been marked as deployed. To find it checked the last_modify_date and status_id columns of the rows returned from the query:

select * from svc_soln_sstatus where

soln_id = 'soln_id'

Make sure to commit the update. And clear the repository caches before rechecking.

Really the two ways you will get the message that a solution is not visible are:

1 the audience property is empty or only contains audiences that the current SelfService user is not a member of.

2 the solution is not marked as deployed in the ServiceSharedRepository SolutionSolutionStatus deployed = 1

Cause:

I suspect bulk importing solutions in with repository XML using startSQLRepository can leave solutions in this state where they are deployed but their status property was not set as deployed. Also messing around with ATG Service data using straight SQL on the database is a dangerous game that can burn you in countless ways.

Disclaimer

I do not accept liability for the consequences of any actions taken on the basis of the information provided by this blog.

Thursday, August 26, 2010

The two big questions



Image: Danilo Rizzuti / FreeDigitalPhotos.net

There are two questions that should be asked of each developer involved before a new software product is launched to clients:

  • Are you proud of the product you created?
  • Would you enjoy using it and/or recommend that your family/friends use it?

Asking yourself these two questions while developing and testing the product will change how you program and benefit the project immensely. Why? You must write good code to be proud of it. You will be motivated to do it right the first time. You will think about how your code impacts your reputation as a developer. Also, you must know how you and others would use the product to answer YES to the second question. The best written code won't help anyone if it is for a useless feature. The best written code won't matter if the whole thing becomes painfully slow to use. If their are reasons you don't enjoy the product and love it, then those should be called out sooner rather than later. Answering these questions honestly will reveal problems that testing didn't catch because nobody knows the product better than the developers. If you answer NO, then you should have some specific reasons why. Those reasons for the NO should often become the priority one (P1) issues to fix.

So often, right before a project is to release, only the testers and the managers decide if something should go live. The attitude is almost like, "Thank you Mr. Developer for your work, now we'll take it from here." A few developers will secretly cringe in horror (or internally panic) when it is decided to launch. They have been feverishly working on P1 bugs from the QA team while other severe problems in the product remain unaddressed or untested. Often QA's P1 bugs are, in the developer's opinion, the P5 bugs. Also, there sometimes is this feeling of an adversarial relationship between testing resources and developers as bugs found create more work for developers and bugs missed reflect poorly on the testers. By involving developers in the go-live decision, they are automatically held more accountible for problems in the live code, after all, it got their stamp of approval along with testing and management.

PureText

Formatted text in the clipboard can be very annoying to paste into rich-text-aware destination applications. Here's a scenario I see a lot, you ctrl+c some information from a Microsoft Word document, your clipboard has all that information as well as formatting information, junk like this is sitting in the clipboard:
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span  lang="DE" ><o:p><span > </span></o:p></span></p>

You then open your Microsoft Exchange email client and paste in the text and yuck, the font has changed to comic sans at 44 point size in bright Green. You just wanted the text to paste in, but you got a lot more.

The quick and dirty solution is to open a plain text editor and paste the text there, then replace the clipboard with a ctrl+c from the plain text editor.
  1. Ctrl+c the formatted text
  2. Open notepad
  3. Ctrl+v, the formatting is gone
  4. Ctrl+a, to select all unformatted text
  5. Ctrl+c, replace the clipboard with unformatted text
  6. Alt+Tab,Tab,Tab to get the target Application window
  7. Ctrl+v, paste in unformatted text into the target application

Microsoft has provided a quick menu when pasting text that you can use to remove formatting, eliminating some of the annoyance but that only helps when you use their software. If you aren't able to eliminate the formatting, you could be left with having to manually re-style the pasted text, which is painfully time-consuming and frustratingly unnecessary busy work.

PureText can help out here, it essentially performs the steps to remove formatting for you each time you press ctrl+v. So to paste plain text copied from a richly formatted source with PureText installed you simple do this:
  1. Highlight the text to copy
  2. Ctrl+c, clipboard has the formatted text
  3. Switch to the target application
  4. Ctrl+v, glorious unformatted plain text is magically pasted in
The program can be mapped to a different keyboard shortcut from ctrl+v in case you want to sometimes preserve the formatting of copied text. In that situation ctrl+v works as usual, ctrl+p (or whatever key press you decide to use) will paste in the plain text.

A tool like this would be an excellent productivity enhancer for anyone who is authoring with browser WYSIWYG text editors like TinyMCE, and having to cut and paste between other sources. These in-browser editors are have some rich text functionality, but usually just enough to cause problems when pasting and you end up putting a lot of junk like special font settings and “Microsoft specific characters” into your application database by using ctrl+c, ctrl+v without it. This invisible styling then rears it's ugly head when you try to present the material in a browser, you get lots of square boxes in contractions or hyphenations as well as mysterious font changes as the styling interacts in unpredictable ways with the HTML page styles and CSS.

Saturday, August 21, 2010

Keeping your resume fresh

Image: Image: Tom Curtis / FreeDigitalPhotos.net

Your resume and portfolio is a marketing tool for you. Keep it fresh with your latest victories. It does not look good for a resume to only have three year old accomplishments (it's akin to a neglected castle). It is a shame when the best candidates for an opportunity are overlooked because of a stale resume and a lesser-skilled but better documented person will get the job instead. I have not been perfect at this, but I do keep a screenshot archive of web applications I was involved with. Each time a big project is completed or even when a big undertaking is conquered, I take that as a cue to update my resume with some important descriptive words about the project and what I did to help bring it home. I usually pick up a few new technologies with each project that also have helped fill out my documented developer skills.

Keeping it fresh is also a good idea because you never know when you will be asked to pack up and get out, US companies are loyal only to themselves and their shareholders and will layoff good employees at the first sign of trouble. Letting your resume go stale or failing to document your completed projects, new skills, and personal wins will impact your own professional success.

I also solicit feedback from managers and developers I work with and use the positive comments they make in my references section. I try to time my request for feedback such that I get a good positive note and the person can easily remember a specific positive thing to say about me. The manager or developer is usually are happy to do that for me, after all, I just helped them out.

You can't escape single quotes in SQL inserts with \

To escape single quote marks in DB2 SQL inserts you cannot use the backslash character. This will NOT work:

insert into LCDDB_NCD_BNFT_CTGRY_REF (BNFT_CTGRY_CD,BNFT_CTGRY_DESC,BNFT_CTGRY_EFCTV_DT,BNFT_CTGRY_TRMNTN_DT)
values (52,'Physicians\' Services','2002-8-2',null)

To insert a single quote mark in DB2 with SQL insert you have to replace single quotes with two (2) single quotes.

insert into LCDDB_NCD_BNFT_CTGRY_REF (BNFT_CTGRY_CD,BNFT_CTGRY_DESC,BNFT_CTGRY_EFCTV_DT,BNFT_CTGRY_TRMNTN_DT)
values (52,'Physicians'' Services','2002-8-2',null)


Thursday, August 5, 2010

OpenDNS Family Shield Setup guide

I learned recently of a free service to help protect my family from explicit web content. In this post I want to explain how it works and how to set it up.

Access to the Internet is no longer restricted to personal computers, you can connect game systems (XBOX 360, Playstation 3, Nintendo Wii), you can connect blue ray players and watch movies transmitted over the internet, you can tether your cell phone to use your home internet and browse web sites, your iTouch can wirelessly connect to the Internet, the list goes on. Their is no 100% guaranteed way to protect all of these devices at all times from all explicit or harmful content that may exist other than turning them all off or never having them.
However, it is possible to filter out known hazards and setting up your computer with a filter takes minutes to do.

There are programs you can install on your computer like NetNanny which will protect that machine only, but you would have to find software for each device connecting to the Internet to use that method. Most modern setups for Internet access will have what is called a network router, all devices within your home, that use the same internet service, will connect to this common device. It is here at the router that the filter will be the most effective, essentially limiting and protecting all devices that may make Internet requests. I use Comcast for my Internet service and have a cheap Microsoft router for my home network.

If you only have one device in your home on the Internet OpenDNS Family Shield will also work for it and it is even less complex to setup. Go here: http://www.opendns.com/start and click sign up under the "OpenDNS Basic" option. Follow the steps to change your DNS on your router or computer. Essentially I needed to change my routers DNS settings from automatic to manual and give these two DNS server IP addresses:
  • 208.67.222.222
  • 208.67.220.220
There is a test page as part of the setup guide openDNS provides that will show you if you are successful in changing the DNS servers to openDNS. Routers will have passwords to protect them from being configured, when you try to configure your router, you will be prompted to login, if the password has never been set, it will be a factory password like user: admin password: admin or even blank; each brand is different. If you cannot login to the router because you forgot or never knew the password, then you may have to reset the router by holding down a button on the actual router device. This will clear all settings and you may have to reconfigure the router just to get back on the Internet again, get your internet service provider on the phone to help you do this or recruit a local tech to help out.

If you are still following along the setup and got the successful page, you should be able to click to open the OpenDNS Dashboard. If you ran into problems getting the test page to report success, try restarting your computer first then check the test page again, if still not working try restarting the router. If still not working, try the single-computer-only setup instructions. If still having trouble, recruit a local computer savvy individual to help you.

Once successful, the openDNS success page will have a link to launch the OpenDNS Dashboard, do it! In here you need to click Settings and add your IP address as a named network, it will already be filled in and you just click "add this network" and give it the name "Home". On that same settings tab, click the link to download an important program to keep your computer protected, the link is at the bottom near the text
Keep your network's IP up-to-date with our free software.
If you use Windows Operating system, click Windows link for the Windows version of the software, if you use Mac click the Mac link. Run the program to install the IP updater software, this is critical for most Internet connections because your dynamic IP address will change periodically and OpenDNS has to associate your Internet filter preferences with your ever-changing IP address. If you have paid for a static IP address, you don't need the IP updater software.
Again on the settings tab, click the dropdown box for your networks, pick the named network called "Home" you created earlier. On the left you can pick "Web Content Filtering" and select how locked down you want the Internet, some preconfigured options are categorized as High, Med, Low. It defaults to NONE which is no better than where you started, so change it to something above NONE at least!


On the left menus, pick Stats and Logs and check the box to enable Stats and Logs and click Apply button. Now all requests from all devices connected to your router are logged! This is good because if someone tried to access explicit web sites, you will be able to see when this occurred and what site was attempted. Keep in mind sometimes sites will show up in the list that the user did not intend to access, they may have gone to espn.com and an advertiser pulled an ad from an explicit site. This ad would be blocked and show up in the log. So don't automatically ground someone for a week because of a log entry.

Hope this helps you out.

Tuesday, May 4, 2010

71st Tuesday weigh-in

223.0 lb

Worked out today on treadmill for 30 minutes at 11, the machine had puddles of my sweat by the end.

I have not been feeling great since about mid February, so I am trying to reboot my workouts now to see if it helps.

that's not the whole story... I've been thinking a lot about Steve too:

Pheysey, Stephen Grant Stephen Grant Pheysey Stephen Grant Pheysey, 23,
died Saturday, May 7, 2005, at his home, of alcohol poisoning. Steve was a
wonderful son, brother, and friend, and will be sorely missed. Steve was
born on November 24, 1981, in Provo, Utah to James H. and Rebecca Duckett
Pheysey. Steve attended Cascade Elementary, Canyon View Junior High, and
graduated from Orem High School in 1999. He was awarded the Heritage
scholarship to Brigham Young University and the Honors at Entrance
scholarship to the University of Utah. He was currently a senior, majoring
in Business Administration at the University of Utah. Steve was a brilliant
young man with many interests and hobbies. He loved buying and fixing
European sports cars, going rock and ice climbing with his brothers and
friends, preparing gourmet and ethnic food for family and friends,
flyfishing, bowhunting, and most outdoor activities. He loved learning and
was an avid reader. He enjoyed using his talents and knowledge to help
others. He was preceded in death by his grandparents, Harriett Pheysey,
Jack Duckett, Irene Duckett, and a younger brother, William Robert Pheysey.
Steve is survived by his parents, Jim and Becky Pheysey, three brothers,
Michael (April) Pheysey, David Pheysey, Matthew Pheysey, one sister, Andie
Pheysey, grandfather, Herbert Pheysey, and numerous aunts, uncles and
cousins. Family services were held Saturday, May 14, 2005, at Berg Mortuary
in Provo. Interment was at Provo City Cemetery. Published in the Daily
Herald on 5/17/2005.
I wish I had reached out to him and I want a do over, I want him to be rescued if not by me then someone else. I need a time machine.

Friday, March 26, 2010

69th & 70th weigh-in

69th 222.0 lb

70th 221.5 lb

I did a Golds Gym corporate wellness fitness test yesterday and here were my stats:

Flexibility test: 15 in (ranking: Average, 20 is Excellent)
Three minute stair step test: 84 beats per minute (ranking: Good, <81 is Excellent)
One minute push up test: 41 (ranking: Good, >45 is Excellent)

Today I ran 3.55 miles in 30 minutes, it kicked my butt.

Tuesday, March 9, 2010

68th Tuesday weigh-in

223.0 lb

Back up a bit from 221.0 lb. I have made a personal commitment to a 12 week body for life program, my free day is Tuesday. I have been successful on the body for life plan in the past, having lost 60lbs, my goal is to lose 6% bodyfat (17% bodyfat). I'll post some pictures at the end of the 12 weeks as well.

I plan to eat 5-6 meals a day six days a week, and have a free-day once a week. I plan to weigh in each Tuesday to track my progress on weight-loss. I will also take some pictures as well periodically during the 3 month program. Thanks in advance for your support.

Tuesday, March 2, 2010

Coping with requirement descoping

Image: FreeDigitalPhotos.net

I am in the middle of a frantic ATG code push. The QA cycle (as usual) was a painfully short 2 days. Since the project is pretty large and was months in development, many areas of the UI were changed. Some of the changes were accepted by the QA and business team, but other changes were found to be too wonky to rollout live to thousands of agents. It was inevitable that the business side would request à la carte features from the overal design implemented to roll live (due to the short qa and hard deadline). Problems arise when removing (descoping) a rejected UI change which breaks other features because of dependencies.

I was able to deliever a rapid turnaround on descoping large functional sections of a code push. I did this by keeping a record of each file that was add/changed/removed for the project as well as correlated which business requirement(s) were the motivation behind the file's change.

Traceability saved the day.

I have not been as diciplined in the past with keeping track of changes for a project, let along keeping record of how the changes correlate to the busines requirements. Now, having done this, it is something that has helped me in the following specific ways:

  1. fulfill all the documented requirements of the project,
  2. quickly descope rejected code,
  3. rapidly find and fix bugs found against requirements,
  4. perform code reviews and explain the moving parts quickly,
  5. provide detailed rollout plans for the changes,
  6. merge in other changes into the project with ease

Not every project may be large enough to require record keeping like this. Keeping track of this stuff is boring but the benefits of doing it really make it worth the effort for me. (Just like documenting my knowledge has.)

Saturday, February 27, 2010

67th Tuesday weigh-in

221.0 lb

Down 3 lbs. Worked out the whole week and was careful my food. A very good week for me.

Monday, February 22, 2010

66th Tuesday weigh-in

224.0 lb

Up 1.0 and I blame the deep dish pizza at Gino's East in downtown Chicago. At least I exercised at the hotel gym while I was on the road. By the way, traveling while sick really sucks. The best food I ate in the windy city was the deep dish pizza at Gino's followed by fantastic burger at Rock Bottom. I really hated the ribs at Weber Grill or whatever that place was called... I like moist sweet ribs but these were much too dry, spicy and tough, that didn't prevent me from eating them all anyway for some reason...

Tuesday, February 9, 2010

FourGablesGuy's Best Practice tip #1478: Don't use email clients to store your knowledge

Image: FreeDigitalPhotos.net

If you were to lose all your email messages today, how high of a disaster would that be for you:

  • as an employee or
  • personally?

Scale where 1 is "no big deal" and 10 being "I am ruined, RUINED!!!"


If I am tempted to save an email after I have read it, I stop and think:
"Why do I want to save this? "
"Oh, it is because I will/might need this info again later."
"Well, if that is the case, it should then be put in a secure place or made into a blog post, forum post, document, etc.. on a knowledge site."

I don't always put important learned information in a blog post or in a secure archive, and sometimes I am searching my email for something that I didn't put in a place I could easily find later... However, I think the more consistently I avoid storing knowledge in my email box (either in folders, sent items, trash, etc..) the better off I will be. It takes some time up front to move knowledge to the place it belongs but it takes even more time to scour your email folders for the one bit of info out of your email-haystack when you need later. If I do have to search and find information in my email, then I always move that data into a better place, because the fact I needed the information twice indicates I will need it yet again.

In my opinion we should treat email as an ephemeral messaging tool, not as a personal knowledge compendium. So until Google Wave gets broad adoption, email is like a sticky note on your desk, neither should be used to preserve important knowledge.

Addendum: Email is a bad choice, but some do survive using it as a knowledge base tool. However, the absolute worst place to maintain important knowledge would be your IM chat history. IM chat toools are great and I use them to ask and answer questions, but I kick myself when I am looking through old chat history for a nugget of information to reuse that I neglected to preserve better. I also am frustrated when managers/coworkers repeatedly ask me questions in chat that I have answered weeks or months previously. I am trying to establish the habit to put the answers I give/receive in IM chat on a wiki or (maybe an email..) or somewhere more permanent so that I can refer back to the more stable place later. IM chat is a double-edged sword, it is fast and convenient in the short term, but you can be hurt long term by failing to capture knowledge from your chat sessions.

Awesome Personal Finance Tool

I have been using an online personal finance software program for about 5 years now and love it. The tool is called Mvelopes and was started by a company in Draper, UT (Finicity). The CEO is Steven Smith last time I checked. The biggest reason I have continued to use Mvelopes is because I am lazy. I don't ever want to manually enter in receipts. I don't want to keep a log book of checks I write either. Mvelopes takes away 99% of the effort required to keep track of your family spending because the software crawls your online banks, credit cards, mortgages, 401Ks, auto loans, student loans, etc.. and digests the transactions from them presenting all of them in a consolidated simple interface. I don't have to do anything but setup my accounts in Mvelopes and login once or twice a month to reconcile spending to my budget goals (or the buckets I have setup for types of spending.)

If you are looking for a tool that can help you plan and coordinate your spending, reconcile purchases so you can always pay off your card balances and always have money for the charges and checks you and your spouse make, Mvelopes is it. You can use if from any computer, Linux, Windows or Mac (you just need a browser with Adobe flash extension.) I would recommend getting coaching sessions as well to help you get the most from the tool. Mvelopes does provide free online chat support as well.

If you use the software consistently, then it will pay for itself 10 times over time.

I think another similar web-based tool exists called Mint but I have never tried that one to know how it compares.

65th Tuesday weigh-in

223.0 lb

No change from last week, I think I would have been down had I laid off Rebecca's brownies. The superbowl party was in Eagle Mountain and the location was really swank. Food was great and I think I did well avoiding over indulging, fast Sunday probably helped a lot too.

Friday, February 5, 2010

64th Tuesday weigh-in

223.0 lb

Up 0.5 again. So I was sick and stayed up too late and missed some workouts, and yes, I am like a broken record on my blog writing that. Winter sucks. Ran 3.5 miles in under 30 minutes today so I am still feeling good about my exercise, I just need to be consistent about going to bed and going to the gym. I am torn a bit because I want to work on a side project for my company (and my career) which cuts into my family/sleep time. I did track my food on the daily plate, but I really only track M-F and don't track dinner, which I plan to change to track EVERYTHING... the annoyance of having to input and track my chocolate-covered almonds should help me from eating them, right? I do feel good when I am able to track exercise on the dailyplate, seeing those extra calories show up is a nice bonus, seeing some better results would be nice too.

I hope when they say, "You change from the inside out", it is really true. Nothing big or earth shattering has happened to myself on the outside, body fat and scale measurements don't seem to move much for me either. But on the inside I am establishing a habit to exercise and monitor my food intake.

Thursday, January 28, 2010

63rd Tuesday weigh-in

222.5 lb

Up 0.5 lb due to some illness and missing workouts. I have been keeping up on tracking food on the daily plate website (on weekdays at least). I have a new Golds corporate wellness personal trainer (no explanation for why the other trainer is gone), she is mostly a cookie cutter version of the previous one... with the same advice as trainer before. I am motivated to post better numbers, nothing I have done seems to have moved the needle on my body fat measurement, which I think is strange. At least over the past month I lost almost 2 lbs from the previous weigh-in.

She did have a good comment about workouts... you have to push yourself hard to make improvements. I think some of my workouts got repetitive and weren't challenging like workouts challenged me when I first started so long ago. I may need to try something drastic break out of the rut.

Tuesday, January 19, 2010

62nd Tuesday weigh-in

222.0 lb

Yay I am down again. I have a monthly weigh-in next week with with my impersonal trainer so I hope to post some good numbers there. I also did check my bodyfat at the annual Lehi legacy center fitness expo: it was 23.1 % which is less than it was back in January of 2009 but not by much, only about 0.4% lower. However this year I did the fitness test as well. I did 25 push-ups in 30 seconds which I am pretty confident I would not have been able to do last January.

Thursday, January 14, 2010

61st Tuesday weigh-in

224.5 lb

Up 2.5 lb. Did well on exercise and just slacked off on tracking food. Eleanor was up vomiting Monday night, we thought the worst was over then Wednesday around 6PM I got stomach cramps and at around 2AM I gave in and puked my guts out. This morning Rebecca is throwing up, oh and J threw up last night as well.

Despite all this, I still have it way better than those in Haiti..

Friday, January 1, 2010

59th Tuesday weigh-in

225.5 lb

Up 3.0 lbs! Yeah... I wasn't very cautious with portion size this last week over the holidays and ended up bloated for my weigh-in. I did well on my exercise plan and only missed on Christmas day. Today I forgot a belt and some old jeans of mine I was wearing kept slipping down, which is a great problem to have.

About Me

My photo
Lead Java Developer Husband and Father

Tags

Blog Archive