Stack Overflow profile for md5sum

Monday, December 7, 2009

StackOverflow Scoring Flaw

<rant>

Recently, I had posted that I had joined StackOverflow, and that I was starting to gain reputation in the community. Yesterday, I encountered two things, which make me wonder about the validity of the scoring system at StackOverflow.

Apparently, as the current scoring system stands, people can do what has been referred to as "Tactical Downvoting", and also a user can wreak havoc on a newer user's reputation without consequences.

Tactical Downvoting:

When a user finds an unanswered question to which they know or think they know the answer, they can post their own answer, and then downvote all other answers. While this may cost them a limited amount of their own reputation (-1 for each downvote), this costs the other users twice as much for each downvote. This also increases the visibility of the user's post, as posts with higher votes are displayed first by default (0 being higher than -1).

So, if I and 3 other users post answers to the same question, and I immediately downvote the other answers, mine will then show at the top, increasing the chances that it will be voted up and/or accepted. My reputation will get -3 for the downvotes. The other users will each suffer a -2 loss. For each time my answer is voted up, I get +10 reputation. If my answer is accepted, I get an additional +15 reputation.

Therfore, for a small loss, I can potentially rule out other valid (possibly MORE valid) answers, and have my reputation raised higher.

Wreaking Havoc:

My reputation suffered a nearly 10% loss after apparently irritating someone with a reputation quite a bit higher than mine by questioning the syntax he had used in his posting. I found that about half of my posted answers had been downvoted shortly after this encounter, and the user all but admitted it in answer to my asking why. Now, StackOverflow runs scripts to detect this sort of malicious behavior, and removes the downvotes, however, their script does NOT restore reputation.

So, for a sacrifice of all of my current reputation on the site (559 at the time of this writing), I could effectively bring someone with a reputation of 1000 down to 0. Yes, it's true that my reputation would suffer too... but after having gotten more reputation, it would be pretty easy to wipe out a newer user.

Summary:

While I definitely think that the StackOverflow team's hearts are in the right place (for the most part), I think that there's still quite a bit of fine tuning to be done to the scoring system, to ensure that users with high reputation actually SHOULD have a high reputation.

For instance, making it where you can't downvote answers for a question you've answered, and vice versa. This would ENTIRELY prevent tactical downvoting. If you think your answer is right, and the others are wrong, let the community decide. You wouldn't let an interviewee interview your other applicants...

Also, your downvote to upvote ratio should be set to ensure that you're not only casting downvotes. Case in point, the user who downvoted all my answers has a +15/-24 ratio, meaning he's cast nearly twice as many downvotes as upvotes. And that's AFTER the other downvotes were removed. My current ratio at the time of this writing is +40/-2. While this wouldn't entirely stop a user from mass downvoting, it would certainly stop it in certain circumstances.

Additionally, the penalty of casting a downvote should be equal to the reward from receiving an upvote (-10). The penalty for receiving a downvote should be an equal penalty to casting a downvote. Thus, a user casting downvotes could never gain an edge over a user they cast against. Why shouldn't someone agreeing with you be equal to someone DISagreeing with you?

</rant>

Thursday, November 19, 2009

Submissions Wanted!

I'm looking for contributors to help me make this into a daily blog with unique content. I'm wanting unique code snippets/tips... something preferably 50 lines or less... If you submit something that gets used, you will receive... "A warm fuzzy feeling when you look at the 'Submitted by:' line of the articles". Thanks!

~md5sum~

Tuesday, November 17, 2009

New Job, New Stuff

So lately I have found myself once again too busy to post on here. This seems like a recurring theme in my life, no matter how I try to post regularly. Since my last full post, I've changed to a new job. I'm now working as a Senior Application Developer for a company which manufactures digital x-ray equipment for veterinarians. It's been quite a lot of fun, and I've gotten to learn a lot.

I've also joined StackOverflow as a true user, and started asking and answering questions there. My WootOff script hit 1800 installs this morning in the wave of a new WootOff over at Woot.com.

This post is actually intended to tell you about some of my experiences using some of the new Google products, so I'm going to stop rambling now, and get to the good stuff.

I've been testing out Google Voice now for several months, and I must say, I absolutely love it. Call presentation has saved me from talking to people I want nothing to do with more than once, and unlimited free texts without cost is awesome. However much I may love this service though, I don't think it will really take off with the general public. It will be great for businesses that need to roll phones around for helpdesk or secretaries. I can also see people like myself who end up carrying up to 3 phones with him quite often using it to consolidate calls to a single phone. The ability to record calls with the press of a button is nice too, but there's a notification that totally sucks. I have an invite to the first 2 people to comment on this post and ask for them.

The other product that I've been testing is Google Wave. Google wave is pretty impressive. It still has a few things they're going to have to work out as of this posting, but the overall interface is quite impressive, and the functionality is astounding. Google Wave allows other users on a wave to see changes as they're made by anyone. Users can also make a "sub-wave" inside a wave, and only include some (or none) of the users on the main wave. Files can be directly inserted into a wave, making collaboration a simple thing. Played right, I can see this platform replacing all social networking sites, email, and chat all in one swift motion.

Until next time!

~md5sum~

Monday, October 26, 2009

Serialize Objects Manually

Edit (27 Oct, 2009 14:31 GMT-600): I realized earlier that this solution doesn't handle arrays and generics. However, I don't really need that functionality, and therefore won't be updating this post with the information. If I need it later, I'll implement it.

I recently found an instance in which I needed to pass a System.Windows.Shapes (part of the PresentationFramework) object through WCF and store it in a database. Shortly after starting with this problem, I realized that not only were all the shapes not marked Serializable, but the classes were also sealed, preventing inheritance. So now I had to dig deeper into my options to get these guys from my client to my server.

My first few attempts at this were hardly heartfelt, and didn't succeed at all, as I was just trying to get it done as fast as possible (the worst thing a programmer can do... good for me). Finally, I realized I wasn't making any headway on this problem, and I started reading other people's experiences, as well as asking if anyone had any tips on several forums. The best advice I could find in all of this was just to use Reflection and serialize the object myself. So, that's just what I did. And, since I'm so fond of sharing the coolest things I find to do, I'm sharing how to do this, both for my own future reference and for yours. Enjoy!


/// <summary>
/// Serializes and Deserializes objects not marked with the Serializable attribute.
/// NOTE: Named Serialize to prevent interference with the
/// System.Runtime.Serialization namespace.
/// </summary>
public static class Serialize
{
    /// <summary>
    /// Used for thread safety on the SerializeObject(object obj) method.
    /// </summary>
    private static object serializeSync = new object();

    /// <summary>
    /// Used for thread safety on the DeserializeObject(string s) method.
    /// </summary>
    private static object deserializeSync = new object();

    /// <summary>
    /// Serializes an object into an xml formatted string.
    /// </summary>
    /// <param name="obj">The object to serialize.</param>
    /// <returns>Xml formatted string representing the "obj" parameter</returns>
    public static string SerializeObject(object obj)
    {
        // Make this thread safe.
        lock (serializeSync)
        {
        // Make a new StringBuilder seeded with a default xml root
        StringBuilder sb = new StringBuilder("<object type=\"" +
            obj.GetType().Namespace + "." + obj.GetType().Name + ", " +
            obj.GetType().Assembly.FullName + "\">");

        // Get the PropertyInfos from the object.
        PropertyInfo[] pInfos = obj.GetType().GetProperties();

        // Make sure there are properties.
        if (pInfos.Length > 0)
        {
            // Loop through each property.
            foreach (PropertyInfo pi in pInfos)
            {
                try
                {
                    // Make sure you can write to the property, and
                    // that it isn't null or empty.
                    if (pi.CanWrite && pi.GetValue(obj, null) != null &&
                        pi.GetValue(obj, null).ToString() != "")
                    {
                        // Get the property value, make sure it's
                        // serialized as well.
                        string tmp = SerializeObject(pi.GetValue(obj, null));

                        // Make sure that the property was properly serialized.
                        if (tmp != "")
                        // Add it to the xml string.
                        sb.Append("<property name=\"" + pi.Name + "\">" +
                            tmp + "</property>");
                    }
                }
                catch
                {
                    // TODO: Implement error logging.
                }
            }
        }
        // If there are no properties, treat it as a low level type.
        else
        {
            // See if it was an enumeration member.
            if (obj.GetType().IsEnum)
                // Return the int value of the enumeration member.
                return ((int)obj).ToString();
            else
                // Return the string value of the object.
                return obj.ToString();
        }

        // Make sure we're not returning an empty object.
        if (sb.Length == ("<object type=\"" + obj.GetType().Namespace + "." +
            obj.GetType().Name + ", " + obj.GetType().Assembly.FullName +
            "\">").Length)
        {
            // Return an empty string, rather than the empty object tag.
            return "";
        }

        // End the root element.
        sb.Append("</object>");

        // Return the xml.
        return sb.ToString();
    }
}


    /// <summary>
    /// Deserializes a string created using the SerializeObject(object obj) method.
    /// </summary>
    /// <param name="s">The string returned by the SerializeObject(object obj)
    /// method.</param>
    /// <returns>The object which was formerly serialized.</returns>
    public static object DeserializeObject(string s)
    {
        // Make this thread safe.
        lock (deserializeSync)
        {
            // Make a new XmlDocument.
            XmlDocument xDoc = new XmlDocument();

            try
            {
                // Try to load the xml formatted string.
                xDoc.LoadXml(s);
            }
            catch
            {
                // TODO: Implement error logging.
                return null;
            }

            // Make sure something got loaded.
            if (xDoc.OuterXml != null && xDoc.OuterXml != "")
            {
                // Get the type of object being deserialized.
                Type t = Type.GetType(xDoc.ChildNodes[0].Attributes["type"].Value);
                // Make a new instance of the object.
                object o = Activator.CreateInstance(t);

                // Get a list of the property nodes.
                XmlNodeList xNodeList = xDoc.ChildNodes[0].ChildNodes;

                // Make sure there are child nodes.
                if (xNodeList.Count > 0)
                {
                    // Loop through all the properties.
                    foreach (XmlNode xNode in xDoc.ChildNodes[0].ChildNodes)
                    {
                        // Make sure the node meets the base criteria.
                        if (xNode.Name == "property" &&
                            xNode.Attributes.Count == 1)
                        {
                            // Loop through all the properties of the current
                            // instance of the serializesd object.
                            foreach (PropertyInfo pi in o.GetType().GetProperties())
                            {
                                // Make sure the property name and the node's property name match, and
                                // you can write to the property.
                                if (xNode.Attributes["name"].Value == pi.Name && pi.CanWrite)
                                {
                                    try
                                    {
                                        // See if the property is an enumeration.
                                        if (pi.PropertyType.IsEnum)
                                        {
                                            // Set the value of the property in our new
                                            // object to the int value of the serialized object.
                                            pi.SetValue(o, Convert.ToInt32(DeserializeObject(xNode.InnerXml)), null);
                                        }
                                        else
                                        {
                                            // Set the value of the property in our new object to the properly
                                            // typed value of the serialized object.
                                            pi.SetValue(o, Convert.ChangeType(
                                                DeserializeObject(xNode.InnerXml), pi.PropertyType), null);
                                            }
                                        }
                                        catch
                                        {
                                            // Set the value to whatever the deserialization
                                            // method returns (last ditch effort).
                                            pi.SetValue(o, DeserializeObject(xNode.InnerXml), null);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    // If there were no serialized properties, treat it as a low level type.
                    else
                    {
                        // Make sure there was a value stored.
                        if (xDoc.InnerText != "")
                        {
                            // Properly type the object and set it's value.
                            o = Convert.ChangeType(xDoc.InnerText, o.GetType());
                        }
                    }

                    // Return our new object.
                    return o;
                }
                // Our document loaded successfully, but was empty.
                else
                {
                    // Return an empty object.
                    return null;
                }
            }
        }
    }
}

Friday, July 17, 2009

My Morning Comedy & Cool Deals Lineup

Every morning, I like to spice up my day by checking in on some sites with some nice daily content. Sometimes these are pretty cool, and so I thought that my readers might be interested in some of these.

1. The Daily WTF. This is a fun site where people send in the insane things that they come across in their day-to-day dealings with other people's code and strange other stuff. This is an especially great read when you think that one of coworkers has just done the dumbest thing you've ever seen.

2. UserFriendly.org. This is a geeky comic strip. Usually has content based on current things going on in the tech world, and it's usually very funny.

3. Woot. This is a deals site. They sell one item per day until it sells out, with the exception of once a month, when they have a "Woot-Off" and sell all the remaining items one-by-one until they sell out from the items that didn't sell out on previous days. Prices are typically very decent, and the items range from completely geeky to random household items.

4. I Have To Have THAT. A very Woot-like site, but I've never seen them do anything like a Woot-Off on there.

I'd love to hear of more fun sites from my readers, so feel free to send them in!

Until next time, my best regards to all of you.

~ Nathan ~

Sunday, January 11, 2009

Free Exercise Bike w/ Laptop Stand

I was working on a lady's laptop, and we got to talking about exercise, and I mentioned my plans to purchase an exercise bike that fit under my desk so that I could exercise on the couch or at work. She said that she had an old exercise bike in her basement that I could have if I wanted. Me, never turning down anything free, took her up on the deal, and I returned to my house with an old DP brand AIR EX2000. Sorry I didn't take any "before" pictures of the bike, but I didn't realize how cool and easy this mod would be.

I did this entire mod in about 1 hour, including finding my tools, disassembling, reassembling, and then taking pictures. I will be uploading the pictures in the morning, but here's the basic walk-through.

Tools Required: 1/2" socket/wrench, adjustable wrench, 14 zip ties, 1 metal coat hanger, exercise bike.

Step 1 - Remove Arms and Pedal Attachments:
On the AIR EX2000 the handles are attached to the pedals via a shaped metal bar. Use the adjustable wrench to remove the nut from the back side of the pedals, and then remove the pedals. Take the attachment bars from the pedals, you won't need the washer and grommet, so you can put them back in the space on the pedals, and then put the pedals back on. Take the arms off the bike with the 1/2" socket/wrench and adjustable wrench. The bar attaching them runs the width of the bike, so it is only necessary to remove one side, then just pull the bar through.

Step 2 - Put Arms On:
Put the arms back on the opposite side they came off of, using the same hardware. make sure the part where you would normally place your hands faces out. Use 2 zip ties on each side to hold the arm bars to the leg bars to prevent the stand from swiveling on the bike.

Step 3 - Attach Pedal Attachments as Stand:
On the AIR EX2000, the braces which attach the pedals to the arm bars have about a 1" zig-zag in them, with one end being about 10", and the other about 4". Using 4 zip ties on each side, attach the holes on the long side of the bracer bars to the holes in the (now) top of the handle bars. Make sure the zig-zag is curved up first, so that your laptop can rest on it. Using 2 more zip ties, tie the holes in the short ends of the braces together in a point (I did mine side-by-side, to make it level).

Step 4 - Laptop Clasp:
To prevent the laptop from sliding from side to side, and also to keep it from accidentally sliding off in case of shock (cats jumping on it), cut the hook part of the hanger off, and straighten it out. Run it through both holes on both sides of the handle bars (the same holes you zip tied the braces to). Bend it up at the width of your laptop, and hook the corners in enough to allow it to snap over the edges of your laptop.

Now my legs are all rubbery, since I've been on the bike the entire time I've been writing this. The seat isn't that comfy, so I'm gonna have to make some modifications to it too, but for now, I have an exercise bike with a laptop stand, completely free of charge.