Monday, October 19, 2009

Kayaking in Ganga

Just back from a roller-coaster holiday in the roaring waters of Ganga!
We enrolled for a basic level course on "Kayaking", yes the exciting cute colorful boats that run along with rafts for rescue.

We stayed in a most beautiful camp on white sand beach of Ganga. Camp was some 16-20 kms from Rishikesh. It could be reached only by a boat from the road. That gave it an exciting feeling of remoteness. We reached the camp in the evening, unpacked, had food, and enjoyed the camp-fire.


Next day Dharmendra, our instructor arrived with the gear. Things started with learning the 5 basic necessities for a kayaker - kayak, paddle, helmet, life-jacket, and the skirt. We learnt simple paddling, how to keep the kayak steady, and how to paddle upstream. We were also shown how to exit from the kayak if it topples over - the wet exit. I must say, it was all more difficult than I had imagined.


Second day morning... Trying to catch some sun, relaxing our torn muscles, we were praying for Dharmendra (our instructor) to get a little delayed :)


But he was as always punctual, and had no mercies. We learned to ferry across the river the second day. I liked ferrying. In a flowing river, if you want to reach the opposite bank, you have to take a sort of triangle (remember school day physics?). This, unlike paddling upstream, was more of balancing than muscle power. We were also taught "T-rescue". This is a technique where you can get your kayak straightened with the help of another kayak, without exiting from it. Saves a lot of time, which will otherwise be spent in emptying your kayak of water and setting it up again.

Third day, and we were doing much better in taking our kayak where we wanted it to go. And, were ready to do peel into and out of "eddies". This was a little risky. Including me, most of us toppled during this practice. We were introduced to a third and the optimal way of reinstating the kayak on topple - the eskimo roll. Though, none of us could get it going correctly :( Chetan tried most sincerely. One signal from the instructor, and he would topple his kayak! And, then try to come back doing the roll. I was pretty uncomfortable toppling myself.

From Shivpuri


Fourth day, and we were pretty much enjoying the paddling. We went to our first rapids today - the "Shivpuri rapids". I came out unscathed :) Chetan had a pretty difficult experience. He toppled, and had no place to set it up again. Dharmendra and he somehow managed.

Fifth day was the most exciting one. We went for a 10Km river run, starting from the "marine drive". This had about 4 distinct rapids. One of them - the 3 blind mice was a 2+ rapid, consisting of 3 rapids one after another. All of us toppled in this one by one, crossed one or more rapids in our life-jackets, rocketing on the waves. Pretty horrifying experience..., though seemed pretty exciting once rescued :)
From Shivpuri


In all it was a lifetime experience. I hope I continue kayaking in future too!
From Shivpuri


All photos

Monday, July 13, 2009

DevD and Gulaal

Anurag Kashyap's movie grows on you. For both DevD and Gulaal, I did not like them that much on first viewing. Probaly, shocked by the "randomness". But, the scenes kept coming back to my mind. And, DevD felt absolutely brilliant on second time. Haven't had a second take on Gulaal yet :)
And, music..., don't know how Anurag Kashyap manages to do this every time! If you haven't yet heard Gulaal's music, please do this the first thing. Absolutely "Aarambh hai Prachand!"

Thursday, May 14, 2009

vim tip: generate get-set functions

Been programming in java now for some time. And, as it happens java needs a lot of get-set functions. Yes, I know you can generate them easily in Eclipse, but as it happens I love vi (or may be I am too lazy to switch ;)) So, here is a tip for all those vi lovers out there. To generate get set functions from your variable definitions:

1. Write all variable definitions.
Example:

1 public class KeywordDimension extends Model implements Serializable
2 {
3 private Long m_vendorId;
4 private Long m_keywordId;
5 private String m_vendor;
6 private String m_keyword;


2. Copy them once more below where you want to generate get-functions.

1 public class KeywordDimension extends Model implements Serializable
2 {
3 private Long m_vendorId;
4 private Long m_keywordId;
5 private String m_vendor;
6 private String m_keyword;
7
8 private Long m_vendorId;
9 private Long m_keywordId;
10 private String m_vendor;
11 private String m_keyword;


3. Run this substitute command in vi:

:8,11s/private \(.*\) m_\(.*\);/public \1 get\2() \r {\r return m_\2;\r }/gc


4. You will get this:

1 public class KeywordDimension extends Model implements Serializable
2 {
3 private Long m_vendorId;
4 private Long m_keywordId;
5 private String m_vendor;
6 private String m_keyword;
7
8 public Long getvendorId()
9 {
10 return m_vendorId;
11 }
12 public Long getkeywordId()
13 {
14 return m_keywordId;
15 }
16 public String getvendor()
17 {
18 return m_vendor;
19 }
20 public String getkeyword()
21 {
22 return m_keyword;
23 }


4. Now run this to replace getk by getK (capital) for example:
:8,23s/get\([a-z]\)/get\u\1/gc


You get this:

1 public class KeywordDimension extends Model implements Serializable
2 {
3 private Long m_vendorId;
4 private Long m_keywordId;
5 private String m_vendor;
6 private String m_keyword;
7
8 public Long getVendorId()
9 {
10 return m_vendorId;
11 }
12 public Long getKeywordId()
13 {
14 return m_keywordId;
15 }
16 public String getVendor()
17 {
18 return m_vendor;
19 }
20 public String getKeyword()
21 {
22 return m_keyword;
23 }

Voila! Just two vim substitutes and you are done! Repeat similar stuff for sets, replacing get by set, and substituting by assignments:


:25,28s/private \(.*\) m_\(.*\);/public void set\2(\1 \2) \r {\r m_\2 = \2;\r }/gc
:25,40s/set\([a-z]\)/set\u\1/gc

Friday, May 08, 2009

BLogging from Nokia E63

This can be great if I can post pictures too!

--
Sent from my mobile device

Shweta Agrawal (Vaity)
http://blog.ashweta.com

Sunday, March 01, 2009

Warli on Laptop



A quick paint job on Chetan's laptop over the weekend!

Tuesday, February 03, 2009

MySQL vs Sybase IQ

In my new role, I am playing around with mysql for managing our data, which is not very huge per se, but since we are running our db on tiny hosts (2GB memory etc), the performance tuning requirement is significant.
Now, being a former Sybase IQ developer, I cannot help but compare Sybase IQ with MySQL. Some of these comparison points are also inherent differences between a row-based and a column-based DBMS (column-based dbs rule!!), and I do not claim to be unbiased :) Being a amateur in MySQL, I might be missing some better ways in MySQL, feel free to point out!

1. In a row based DB, it's always a compromise between wide tables (and hence huge IO cost), and expensive joins.
We want to store de-normalized data in our datawarehouse tables, to accelerate our query performance. But that makes the table very wide, making the queries slow due to huge IO in even querying a few columns. While, if we break the table, we end of joining them while querying, again expensive. Column-based Sybase IQ is an answer!

2. In MySQL, your query will use only one index per table in a query!
Probably, this is something obvious for a row based DB, but it came as a shock to me. Being used to Sybase IQ way of using indexes, I was happily creating individual indexes on columns assuming that the query will use all that are required. (IQ gets found-sets using multiple indexes and use them for reducing selected sets). But MySQL does not do that. Result: my table has something like 6 indexes with various combinations of 3 columns, while all I would have need in IQ would be 3.

3. Mysql writers block readers.
We use INNODB, which claims to have row level locking. Also the mysql documentation says that if you are using a repeatable read isolation level, your reading transaction will work on a snapshot of data. But I never saw that in action. There are numerous "special cases" where INNODB takes a table-level lock for writing (auto-inc columns, probably duplicate key update), which ends up into the query getting blocked, waiting on lock to be released. IQ has "snapshot-versioning", not "locking", which means your readers will "never" be blocked on writers, unless you explicitly say so by locking table.

4. Mysql backup is great.
I can say that mysql is better than probably any other dbms in one thing. Simplicity. You can backup, migrate mysql dbs very easily by using mysqldump. IQ's backup procedure was confusing, even for me as a developer.

Tuesday, November 18, 2008

Rating Lenders in a Mutual Trust System

I am creating a book sharing system. A problem I am facing is how would I reward my lenders. This is a mutual trust system, where the system does not have any direct way of verifying whether the lends were genuine. For example, I can create 10 fake accounts, lend books to those accounts, and increase my rating to get rewards.

It struck me that this is a generic problem, and must be faced by all systems which are trust based.

Is it possible to write an algorithm to rate the lenders in such a way that it catches/penalizes the malicious/fake lenders, or may be just make the fake lending expensive enough?
For example, suppose I reward my best lender over a month with a 200Rs crossword voucher, and if I feel that I can spend 200Rs on a person who spends 10 hours on my website distributed over 10 days within a month (as that might increase my advertising revenue), I just need to make the fake lending that much expensive.

So, how do we define "good" lends? What are the factors that define a genuine lend?

Requirements:
1. These factors should be implicit/natural for genuine lends but take extra cost for fake ones.
2. These factors should reinforce healthy lending trends into the system.

Here is a list of such factors I can think of:

1. The simplest one - number of lends
Factor: "number of total lends made"
Cost for fake lender: Time to put requests and approvals.
Healthy trend: Rewards lenders who lend more.

2. Lends to different unique borrowers
Factor: "number of borrower with a unique mail id lender lends to"
(Any lends to a user with same mail id as lender not counted)
Cost for fake lender: Time to create unique mail id's + time to create accounts with those mail id's.
Healthy trend: Reward lenders who lend to various people, instead of a fixed closed group.

3. Number of different items lent
Factor: "number of unique items lent by the lender"
Cost for fake lender: Time to add different items in collection.
Healthy trend: Reward people who increase number of unique items available in the system.

4. How distributed lends are over time.
Factor: "number of unique days" on which lends were made.
Cost for fake lender: Time for logging into website on different days.
Healthy trend: Reward people for being prompt with approvals (if people check their inbox every day their approvals will be distributed, if they check for example once a week, they will be clustered).

5. Last but the best, "lend rating" of borrowers.
Factor: "sum of ratings of all borrower's with unique email id's"
Cost for fake lender: All the above costs added for all the fake borrower accounts!
Healthy trend: Encourages people to lend to good lenders. So, lenders get rewarded for doing genuine lending.

So, a simplistic formula taking in all the above factors goes something like:
lender's rating = "number of lends" * "number of unique borrower mail-id's" * "number of unique items lent" * "number of unique days on which lends were made" * "sum of ratings of borrowers with unique mail-id's"

As, you can see, this formula is recursive. If we are calculating the rating for all the users on our system, we start with a rating of 1 everybody, and do a first pass of rating calculation. Then we do a second pass to get final ratings.

Would love to hear more thoughts on this... so do share!