Normally for technical work I just use redmine to keep track of working tasks, and I use mGSD for administrative stuff or for writing agenda outlines or reminders to send emails. And that works most of the time.
Now I am currently having to manage a big amount of issues because there were changes in the working environment recently. So now I find that I have too many issues to handle on redmine. What to do?
Ah, mGSD (the app formerly known as MonkeyGTD) to the rescue.
I have copied the titles of the issues into my mGSD copy. mGSD is a Getting Things Done (Registered Trademark) app that I have been using for about 3 years now. It is based on tiddly wiki, a client-side javascript powered wiki. It is really good. It fits into GTD methodology very well.
So now instead of having to look and keep track of several projects on redmine, I can see everything that I need to do at a glance on my mGSD.
So here are the instructions on opening existing projects into Eclipse.
If you are a Visual Studio developer you are here because you can't open an existing project in Eclipse. You are probably 5 minutes away from giving up on eclipse and tweeting about how Eclipse sucks.
I was there too.
And then, after attempting it again and again, I finally figured it out. I am going to translate opening an existing project from Eclispese into Visual Studioese here. Think about these two IDEs as cars: Visual Studio is an automatic, eclipse is manual transmission.
There are two things you got to know:
A) Workspace = Solution
B) You got to set it by hand
I don't normally don't think about the solution because Visual Studio lovingly just creates one for me. If I need to add projects to it, it can be done easily. It makes me happy; it has made you happy too. When it comes to creating solution and project spaces, Visual Studio is like an automatic car: it just does it for you.
But in eclipse you got to do it by hand. Maybe there is a plugin that will make it behave like Visual Studio, but in most distributions you will have to do it manually. It is not hard, but you got to do it. On this issue, eclipse is like a manual transmission car: you got to know and be aware of different gears and when to switch them.
So let's learn how to drive stick by learning how to set up your workspace/solution and how to add existing projects to it:
Create a new workspace by clicking
File -> Swith Workspaces -> Other
Browse to where you want your workspace (solution) folder to live in, where you have the existing project folder. This is the equivalent of Add Project in Visual Studio.
Add a project to the workspace by clicking
File-> Import-> General-> Import Existing Projects into Workspace
And navigate to the existing project root folder.
And you are done.
Now let's learn how to switch gears. In Visual Studio you will have your landing page with a list of previous projects. When you click on the project, the solution automatically switches. That is our automatic car. With our stick vehicle, to switch from one workspace(solution) to another you do it by clicking
File -> Swith Workspaces -> >>Select workspace that you want to go to<<
Remember, you got to manually change the workspace(solution). Attempting to switch solutions in the Visual Studio way, that is, by "opening" another project via project import, will result into adding that project into the workspace, not into an automatic workspace switch.
References:
I found the specific instructions on how to do open an existing project on this book Android Application Development, 1st. Edition
This is my implementation of Eliza, the affordable computer shrink. I wrote this as an exercise in Test Driven Design(TDD). I will write about my experience with TTD later. I can say that it was very positive, and that I learned a lot working through this exercise than I would have by spending the same amount of time reading about it.
To use it, you must click on the web form button. Don't type the Enter button on your keyboard; it will reload the page. I got to fix that.
Type 'Hello' to start, talk, and then type 'Bye' to end.
Today I grabbed another low hanging fruit. This time it is Selenium. I had played with Selenium recorder a long time ago; I got to use Selenium recently, in a previous iteration of the current project that I am working on. At the time though, I was using Selenium mainly as a way to quickly populate a form before I actually tested it.
Even using Selenium IDE in this manner, just too quickly populate a form for manual testing, it is a huge time saver. Rather than testing every 10 minutes, one can test every couple of minutes.
But today I started moving towards using it for actual testing.
There are some issues that slow down quick adoption of the tool though.
Selenium IDE is quirky in my opinion. It doesn't behave the way I expected it to behave. I expect that the test, after I record it, will be saved. Instead, I have to manually save each case. Also, it would be nice if one could easily move the order of the tests around in a test suite. I found myself in the last few days having to create new suites just to switch the order.
And there is a conceptual switch that has to happen as well. It was only in the last few days that I realized that if the task cannot be completed, that is a test failure, not the equivalent of compilation error.
But even with these small limitations, and using it in this limited capacity, Selenium has already saved me a lot of time, and helped to bring my current project to successfully meet a very tight deadline. It has also been helpful in debugging a hard to find error, and helped to speed up integrating the system on the deployment site.
So you are going to hear a lot more about Selenium here in the near future.
This was a comment to @geobabbler 's entry on GIS for Kids
I have been thinking about teaching the children of Crunchy Granola Academy more about GIS, and I was also thinking about having some GIS activities for my daughter's Brownie meeting.
Here is the comment that I wrote on the site:
We should exchange some ideas.
You probably want to move from the concrete physical to physical maps and then into gis. And if possible, being physically present in the grounds of the place where they are mapping would be good to help the kids make the mental leap that gis translates into the real world.
I have done walking papers with my children, and that is something that they really enjoyed. It is Concrete, they have a physical map, and they get to walk around some area.
I also have had my kids in the OSM parties. In one we got the hike Rock Creek Park and in another we hiked the zoo.
I would say that the gps unit is not really that interesting to them because it doesn’t seem to do much except to show a tiny map.
However, they did like entering notes for different points on the way in a notebook.
A possible activity that you can have for them, although this will take a little bit of planning is to create a short orienteering course. We could skip the compass if that is a problem and the area is small enough, the most important thing would be to use a map to find different points in a playground or a room.
Another activity, if these are taking place at a school, would be to map their classroom, first creating maps, and then adding points of interest, then adding demographic data, such as how many children are in different parts of the classroom.
If this could then be translated into software, then the basic concepts should be understood when you move into mapping a school grounds or some local park or area.
I will have to look at Portable GIS to see if I think my kids could handle it.
I will probably cross post this comment as an entry in my website.
I noticed today that my statement about why I had to adopt best practices was very similar in emotional content to this famous moment in American cinema. Please hum the theme music as you read the text:

"As God is my witness, as God is my witness they're not going to lick me. I'm going to live through this and when it's all over, I'll never let a project become a death march again. No, nor any of my folk. If I have to lie, steal, cheat or kill. As God is my witness, I'll never let a project become a death march again..."
That is what she said. Or something very similar, I don't recall correctly.
In any case, today I aggressively used redmine, the open source project management software, to track every activity that I am doing for my current project. This is part of my efforts not to let my current project become a death march.
Redmine was introduced to me by @GeoDAWG. He set it up for the project that I am using and for the another project. If we had actually kept using redmine in the other project, we would have saved ourselves from a lot of grief.
Strengthening a practice that already exists is low hanging fruit, so I am going to go for it.
What has changed right now is that now I have the strong motivation to keep it up to date. So that is what I did today: I updated tickets, wrote new tickets, and added more items and reorganized the wiki for the project.
Before I thought updating tickets was boring; now I think it is boring, but critical.
So I am going to get serious about adopting agile practices.
Since I first read about agile development, a lot of it made sense to me. I attempted to embrace many of its practices. Some have become habits; most of them are still goals.
Since the zombie project, that has changed. Now I know that it is not only something nice to strive for, but that it is necessary, important.
And that is something that one can only earn via experience: to get that full, instant, visceral reaction to something that makes us act.
My favorite analogies to this are economic crises: most people know that they are wrong, and that they should be avoided, but those who can control the economy just don't care as long as they are making money. It is only those who have lived through deep economic crises who know the deep pain, the massive social change, and the lost opportunities that come with them. That is probably why the post-Depression political and business leaders were so careful with the economy; the boomer generation of leaders never really lived through that. But ask a person who lived through the Depression about another one, and they will passionately say that it should be avoided at all costs.
That is how I feel about software development now: crisis projects should be avoided at all costs. And that is what agile practices attempt to prevent or attempt to manage in a rational manner.
So here I go, ready to start embracing agile practices. I will be documenting my experience here. Hopefully it will be done quite regularly since I will attempt to do one action to move towards agile practices every day.
After doing some research, it seems that there is no clear way to unit test asp .net WebForms.
ASP .Net web forms behavior collides with the current testing principles. The big one being that you only test public methods. Well, it seems that most Web Form pages don't have ANY public methods, making it impossible to test following the unit test principle. For those developers that want to do testing, it means that they have to expose the different private methods that they are using as public methods, breaking a big principle in OOD, which is that public methods are the interface to the object. So the developer who wants to unit test their code either breaks the principle of not testing privates or breaks the OOD principle of exposing as little interface as possible.
So the solutions that I have found either involves some complex code bending to allow for the testing of private methods, doing weird practices such as exposing private methods as public.
The other big solution seems to be to move to the MVC framework. Ideal solution for new projects if one has the time to learn the framework, but won't help that much if one has to work with legacy code.
The one idea that popped into my mind as I was writing this is that maybe it is possible to mvc-ize a bit the code. If every interaction of the page has to rely on objects, then we can test those objects. This seems to have some limitation in that separating database interactions may be difficult, impossible, or create greater problems that it attempts to solve. But at least it, if used properly, allow for testing of potentially breakable parts of the code.
I will experiment with this idea and see what happens.
Okay, this is something I was going to blog about a month ago, but then the January storm hit and derailed that.
So, these are the first 22 exercises of the 99 Prolog Problems. I am doing them in Erlang. I know, I know, this is super cryptic by naming the functions after its problem number rather than by nice descriptive problems, but I was taking the easy way out; I just wanted to do them pretty quickly rather than show them off as an exercise on proper programming technique.
For what it is worth, here they are:
-module(p99a).
-export([a1/1, a2/1, a3/2, a4/1, a4b/1, a5/1,
a6/1, a7/1, a7b/1, a8/1, a8b/1, a9/1, a10/1,
a11/1, a12/1, a13/1, a14/1, a15/2,
a16/2, a17/2, a18/3, a19/2, a20/2,
a21/3, a22/2]).%Find the last element of a list.
a1([], Result) -> Result;
a1([H|T], _) -> a1(T,H).a1(List) -> a1(List, "Not a list").
%Find the last but one element of a list.
a2([_|[]], Result) -> Result;
a2([H|T], _) -> a2(T,H).a2(List) -> a2(List, "not a list").
%Find the K'th element
a3([], _, _) -> {error, "out of range"};
a3([H|T], Nth, Index) ->
if Index == Nth -> H;
true -> a3(T, Nth, Index + 1)
end.a3(List, Nth) -> a3(List, Nth, 1).
%Find the number of elements of a list.
a4([], Result) -> Result;
a4([_|T], Result) -> a4(T, Result + 1).a4(L) -> a4(L, 0).
a4b([]) -> 0;
a4b([_|T]) -> a4b(T) + 1.%Reverse a list.
a5([], R) -> R;
a5([H|T], R) -> a5(T, [H|R]).a5(L) -> a5(L, []).
%Find out whether a list is a palindrome.
equal([], []) -> true;
equal([H|T], [H1|T1]) ->
if H == H1 -> equal(T, T1);
true -> false
end.a6(L) -> equal(L, a5(L)).
%Flatten a nested list structure.
% a7 is concat in the O'Reilly Erlang book
% a7b is flatten per se
strip([], R) -> a5(R);
strip([H|T], R) -> strip(T, [H|R]).a7([], R) -> R;
a7([H|T], R) -> a7(T, strip(H, R)).a7(L) -> a7(L, []).
a7b([],R) -> R;
a7b([H|T], R) when is_list(H) -> a7b(T, a7b(H, R));
a7b([H|T], R) -> a7b(T, [H|R]).a7b(L) -> a5(a7b(L, [])).
% Eliminate consecutive duplicates of list elements.
a8([], _, R) -> R;
a8([H|T], P, R) when P == H -> a8(T, P, R);
a8([H|T], P, R) when P /= H -> a8(T, H, [H | R]).a8([H|T]) -> a5(a8(T, H, [H|[]])).
a8b([], _) -> [];
a8b([H|T], P) when P == H -> a8b(T, P);
a8b([H|T], P) when P /= H -> [H|a8b(T, H)].a8b([H|T]) -> [H|a8b(T,H)].
% Pack consecutive duplicates of list elements into sublists.
pack([], _, R) -> [R];
pack([H|T], P, R) when H == P -> pack(T, P, [H|R]);
pack([H|T], _, R) -> [R| a9([H|T], H)].a9([], _) -> [];
a9([H|T], P) when H == P -> pack([H|T], P, []);
a9([H|T], _) -> a9(T, H).a9([H|T]) -> a9([H|T], H).
% Run-length encoding of a list.
a4c(L,[H|_]) -> [a4(L), H].
a10h([]) -> [];
a10h([H|T]) -> [a4c(H,H)| a10h(T)].a10(L) -> a10h(a9(L)).
% Run-length encoding of a list.
a4d(L,[H|_]) ->
X = a4(L),
case X of
1 -> H;
_Other -> [X,H]
end.a11h([]) -> [];
a11h([H|T]) -> [a4d(H,H)| a11h(T)].a11(L) -> a11h(a9(L)).
% Decode a run-length encoded list.
unpack([0,_], R) -> R;
unpack([N,C|_],R) -> unpack([N-1,C], [C|R]).a12([], R) -> R;
a12([H|T], R) when is_list(H) -> a12(T, unpack(H,R));
a12([H|T], R) -> a12(T, [H|R]).a12(L) -> a5(a12(L, [])).
% Run-length encoding of a list (direct solution).
a13([],P,C, R) ->
case C of
1 -> [P|R];
_Other -> [[C,P]|R]
end;
a13([H|T], P, C, R) when H =:= P -> a13(T, P, C+1, R);
a13([H|T], P, C, R) when H =/= P ->
case C of
1 -> a13(T,H,1,[P|R]);
_Other -> a13(T,H,1,[[C,P]|R])
end.a13([H|T]) -> a5(a13([H|T], H, 0, [])).
% Duplicate the elements of a list.
a14([]) -> [];
a14([H|T]) -> [H,H|a14(T)].% https://prof.ti.bfh.ch/hew1/informatik3/prolog/p-99/
repeat(_,0) -> [];
repeat(C,T) -> [C|repeat(C, T-1)].a15([],_) -> [];
a15([H|T],C) -> a7b([repeat(H,C)|a15(T, C)]).% Drop every N'th element from a list.
a16([], _, _) -> [];
a16([_|T],C,N) when N rem C =:= 0 -> a16(T, C, N+1);
a16([H|T],C,N) -> [H|a16(T,C,N+1)].a16(L,C) -> a16(L,C,1).
% Split a list into two parts; the length of the first part is given.
a17([],_,_,L) -> {a5(L),[]};
a17([H|T],N,R,L) when N =:= R -> {a5([H|L]), a5(T)};
a17([H|T],N,R,L) -> a17(T,N,R+1,[H|L]).a17(L, 0) -> {L, []};
a17(L,N) -> a17(L,N,1,[]).% Extract a slice from a list.
a18([],_,_,_) -> [];
a18([H|T],I,K,N) when N >= I, N =< K -> [H|a18(T,I,K,N+1)];
a18([_|T],I,K,N) -> a18(T,I,K,N+1).a18(L,I,K) ->a18(L,I,K,1).
% Rotate a list N places to the left.
a19(L, N) -> SP = N rem a4(L),
if
SP < 0 -> S = a4(L) + SP;
true -> S = SP
end,
{H, T} = a17(L, S),
a7([T,H]).% Remove the K'th element from a list.
a20([],_,_, L) -> L;
a20([H|T],N,I,L) when N =:= I -> {H, a5(a20(T,N,I+1,L))};
a20([H|T],N,I, L) -> a20(T,N, I+1, [H|L]).a20(L,N) -> a20(L,N,1,[]).
% Insert an element at a given position into a list.
a21([],E,P,N) when P =:= N -> [E];
a21([],_,_,_) -> [];
a21([H|T], E, P, N) when P =:= N -> [E,H| a21(T,E,P,N + 1)];
a21([H|T], E, P, N) -> [H|a21(T, E, P, N+1)].a21(L, E, P) -> a21(L, E, P, 1).
%*) Create a list containing all integers within a given range.
a22(A,B) when A > B -> [];
a22(A,B) -> [A|a22(A+1,B)].