What happened to Newegg?

Something is very wrong with Newegg. They used to be one of the best places to buy computers and electronics online. Now they are horrible.

Here’s my list of issues with them:

  • Lots of misleading product information.
    • We recently bought a monitor that claimed it supported 2560×1440 resolution when in fact it didn’t. The DisplayPort upscaled a 1080p signal to 1440 and it looked horrible. I had to read through a ton of the reviews to figured out that someone else had the same issue and they had done a bunch of research to find out the monitor didn’t truly support 1440.
  • They now charge large return shipping fees
  • They are also charge restocking fees on everything
  • Their support system is essentially worthless.
    • While you can contact support via a web form, it only allows 300 characters in the message. How can you possibly describe an issue clearly in 300 characters? That’s like 2 tweets.
What we were hoping would be a great price on an awesome monitor turned out to cost us nearly $80 for nothing. That’s the same as if I went to an ATM, pulled out four $20s and burned them.
Thanks Newegg for sucking. I’ll be buying everything on Amazon from now on.

Friendster can't even send email

I’m surprised that Friendster is even still around, but today I got an email from their CEO and it had the entire MIME body in the message. These guys can’t even figure out how to send email.

X-Campaign-ID: 8002
X-Campaign-Type: 1
X-Message-Ref: 19lGRwmaJkSjEf8FZP7XSCijJOJhOejGu832ySW13bA*
Content-Type: multipart/alternative; boundary="----_=_FSter_001_3251309519900466"
MIME-Version: 1.0

This is a MIME email, the first part is the text message.

------_=_FSter_001_3251309519900466
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: 7bit

Friendster www.friendster.com July 2011

A Personal Message from Friendster's CEO

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Dear fellow Friendster members,
As many of you may know, Friendster announced that it is re-launching itself as a social gaming portal and launched a beta version of the new Friendster a couple of weeks ago. The beta version was well received. I am pleased to announce that the new Friendster is going live thereby enabling all our users to login to the new Friendster using your existing Friendster username and password.
Friendster has touched the lives of many. Since MOL, the company I founded acquired Friendster in early last year; many people have come up to me to tell me how Friendster has changed their lives. Many have told me that they have found their life partners over Friendster. Just last week, a successful Internet entrepreneur in Singapore told me that her success was triggered by promoting her business on Friendster. Friendster pioneered social networking and ignited the social media industry that has created billion dollar companies such as Facebook and Twitter, companies that may not have existed in their present form if not for Friendster's early innovation.
Today, Friendster is in a unique position to take advantage on the growth of social gaming. Through its relationship with MOL, which has a 10 year history in working with gaming companies, Friendster has both the experience and track record to make innovations in this space.
Today, as Friendster reinvents itself as a social gaming destination that enables its users to create multiple avatars, play games and enjoy rewards; I hope that all of you will wish us luck and continue to support us in our new reincarnation. The new Friendster is not perfect and we will continue to add new games and features such as localization and rewards over the next few months. Our team is working hard on adding these features and welcomes your suggestions and comments on how we can better serve your needs as a social gaming and entertainment destination.
I would like to take this opportunity to thank all of you for your support and hope that all of you will enjoy the new Friendster as Friendster continues to innovate to serve and entertain you better.
Yours truly,
Ganesh Kumar Bangah
Chief Executive Officer
ceo@friendster.com

****************************************************************
To manage your notification preferences go to: http://www.friendster.com/account/notifications
Copyright 2002-2011 Friendster, Inc. All rights reserved.
****************************************************************

------_=_FSter_001_3251309519900466
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: 7bit

[SNIP - I cut out the HTML so I didn't have to escape everything by hand]

------_=_FSter_001_3251309519900466--

 

Restoring a SubVersion repository from an old backup

I have recently gone through the exercise of restoring a medium sized SubVersion repository from an older backup and wanted to share my experience with everyone. First, the problem:

The problem

After you restore the older backup, if any work was performed between the last backup and when the repository crashed, the repository will be “older” than what developers have on their boxes. Here is an example:

  • Let’s say you have a backup from Monday evening
  • The repository crashed sometime Tuesday
  • There was work done during the day Monday

Now, let’s say there is a project A that looks like this:

  • The last change to the project was at revision 100 just before the repository crashed
  • The last change to the project from the backup was 80
  • Frank’s computer contains a checkout of the project at revision 85
  • Mary’s computer contains a checkout of the project at revision 100

This means that both Frank and Mary’s computers contain newer code than the repository, but not the latest code. Mary’s computer contains newer code than the repository, but might not be a complete snapshot of what version 100 was before the repository was corrupt. The reason why Mary’s computer might not be 100% correct is that Mary might have committed files to the repository but not performed a “svn update” prior to committing.

SubVersion is like CVS in that each file contains a version number. So, you might have a local checkout that contains version 100 for one file and 90 of another file. Therefore, you might be missing an updated version of the file from revision 93 when it was checked in.

Okay, now onto the fix:

The fix

Each developer’s computer must be analyzed before anything new is put into the repository. You must have a complete picture of the entire company, otherwise you might miss some changes. These changes can be merged in by hand from each developers machine, but this could be error prone and lengthy process. It is usually better to script out as much as possible.

Step 1

In order to determine the local “revision” of a project on a developers computer, you will need to look at each file in the checkout. You can run an ‘svn stat’ on each file to determine the version number of that file. Write a script to output a file like this for each local checked out project on all developers machines:

src/java/foo.java: 90

The first part is the file and the second part is the revision of that file.

Next, once you have the complete list of revisions for all projects on all developer’s computers in the entire company, you can compare each file with the current revision in the restored repository to determine if the developer has a later version of a file than the repository. This should ignore all files that the developer has modified locally, but not committed.

This comparison will look like this:

Restored repository
src/java/foo.java: 80

Mary's checkout
src/java/foo.java: 90

Mary has a later version of foo.java!

You should script all of these comparisons out. If a developer doesn’t have later revisions than the repository or any locally modified files, they can safely take these steps:

  1. Make a backup of the local checkout
  2. Delete the local checkout
  3. Re-checkout the project
  4. Don’t do anything until the restore is complete

Step 2

The next step is to make a list of the revision that each file in the project was lasted changed on in the restored repository. This report will look like this:

build.xml: 10
src/java/main/foo.java: 16293
src/conf/main/logging.properties: 12093

Next, for each project, collect all of the revision reports from the previous step into a single location. These reports look like this:

frank-project-a-report.txt
build.xml: 10
src/java/main/foo.java: 16301
src/conf/main/logging.properties: 16405
mary-project-a-report.txt
build.xml: 10
src/java/main/foo.java: 16410
src/conf/main/logging.properties: 16321

Combine each of the developer reports into a global report that gives you the revision number for each file on every developers computer. Next, use this global developer report to determine whose computer contains the latest version for each file in the project. Based on the examples above, you can see that build.xml didn’t change recently enough to matter since the version in the repository is the same as the version on Frank’s and Mary’s computers. However, Frank made the most recent commit in revision 16405 to logging.properties and Mary made the most recent commit in revision 16410 to foo.java. Both of these files are more current that the repository and therefore need to be re-committed.

Step 3

Finally, setup a staging area that contains a copy of every checked out project from every developers computer who has a later revision than the repository (from step 1). This will be pretty large, but necessary. Based on the results from step 2, copy the latest version of each file over to a clean checkout of the project from the restored repository. Once you have all of the changes copied over for a single project, commit all of those files for that project back to TRUNK.

You should now have a fully restored repository based on the files from various developers computers.

Locking down a shared MySQL database server without firewalls, routers, etc.

I’m setting up a shared database server in a data center and I don’t have any direct connections between the machines that are local (i.e. meaning they only connect between boxes and don’t let external traffic in), no firewalls, no routes or any networking goodies. These machines only have a single ethernet card that accepts connections from anywhere. So, my concern is that my new database server needs to allow the other servers in the cluster access to MySQL without opening it up to everyone in the world, which might allow hackers access. Instead, I want to lock things down so that only certain machines can connect to MySQL and everyone else is rejected.

In order to pull this off, I’m making use of iptables, which allow me to control how IP packets are handled by the kernel. There are loads of materials out there on iptables, so I won’t go into how it works exactly. Instead, I’ll just show you all how I did it. All these commands are run as root (via sudo or as root directly):

$ iptables -A INPUT -s <ip-of-current-box> -p tcp --dport 3306 -j ACCEPT
$ iptables -A INPUT -s <ip-of-other-box> -p tcp --dport 3306 -j ACCEPT
$ iptables -A INPUT -p tcp --dport 3306 -j DROP

This allows access on port 3306 (MySQL default) to only two IP addresses and drops all other traffic on the floor. I can add as many IPs as I want by repeating the second command with a different IP.

Mozilla Thunderbird image in signature

Adding an image to you HTML signature in Thunderbird requires a slight HTML hackery. You need to locate the image on disk and add the IMG tag with the src attribute using the file URL of the image:

Linux:

<IMG src="file:///home/brian/.mozilla-thunderbird/image.jpg" alt="Cool"/>

Windows:

<IMG src="file://c:/foobar/image.jpg" alt="Cool"/>