Creating a "favicon" for your website or web app

by timvasil 5/17/2011 11:18:00 PM

Dynamic Drive has a great tool for converting images to "favicon" icon files that appear in the tab/address bar of browsers. Simply upload the desired image (such as a PNG with alpha channel), and you can see the results in a simulated address bar and download a Windows-compliant .ico file.  Nice!

You can find it here: http://tools.dynamicdrive.com/favicon/.

Here's a preview of the interface with an icon I've created for use with collabormate.com:

Tags:

Graphic design

CSS Reset

by timvasil 5/16/2011 9:03:00 PM

Here are a few simple CSS rules to "reset" various browsers' settings to a common baseline.  I've adapted this from what I spotted on Kyle Neath's blog here: http://warpspire.com/posts/css-frameworks/, who did a nice job at concise definitions (compared with what I've seen from the YUI toolkit and elsewhere).

* { padding:0; margin:0; }

h1, h2, h3, h4, h5, h6, p, pre, blockquote, label, ul, ol, dl, fieldset, address { margin:1em 0; }

li, dd { margin-left:5%; }

fieldset { padding: .5em; }

select option{ padding:0 5px; }

.hide { display:none; }

.left { float:left; }

.right { float:right; }

.clear { clear:both; height:1px; font-size:1px; line-height:1px; }

a img { border:none; }

Tags:

CSS

10 tips for conducting an effective phone screen interview

by timvasil 5/16/2011 4:40:00 PM

My past colleagues and I have found that a 30 minute (or less!) phone screen is a great way to make the interview process more efficient.  While it cannot necessarily assess cultural fit, it can certainly weed out applicants who do not meet a minimum level of technical proficiency, saving everyone time.  From the candidate's perspective, a day is not lost in travel and in-person interviews.  From the firm's perspective, 3-6 people do not have to take time out of their day to quiz the person -- avoiding hours of lost productivity.

I've had to conduct plenty of phone screens over the last several years, and I've found the following practices most effective:

  1. Follow a 5-20-5 rule -- that is, spend 5 minutes talking about the company and the job opportunity background, 20 minutes asking questions, and 5 minutes answering the candidate's questions.  That first 5 minutes is a nice way to relax the candidate and get him or her excited about the job.  Part of the process is "selling" the candidate on the job, of course!

  2. Do not exceed 30 minutes.  In other words, stick to that 5-20-5 rule.  Yes, this is redundant, but it's important!  The phone screen exists to make the process more efficient, not less; so if you're spending more than 30 minutes, you need to speak more concisely and choose your questions more carefully.

  3. Be prepared to pass.  If you are indecisive and would feel uncomfortable with terminating a candidacy unilaterally, you should not be conducting phone screens; instead, ask a coworker to do it or have a coworker on the call with you to "train" you.  By the end of the 30 minutes, you should have a clear idea in your head about whether or not to proceed.

  4. Standardize the questions.  This is especially important for cases where several people on a team may be dividing phone screen responsibilities.  To ensure the bar is set consistently, come up with a stock of questions to ask during the phone screen -- and organize them by level of difficulty.  The questions should be specific to the job, of course.  This doesn't mean you have to ask all the questions or cannot deviate from the questions during the call, but for an appropriate baseline at least some of the standardized questions should be asked.

  5. Test the questions.  Ask coworkers holding the targeted job -- or a similar one -- the questions.  You may be surprised to learn that the questions are too hard, or better left to an on-site setting with a whiteboard nearby.  Vetting the questions before a phone screen will give you confidence.  If the candidate falters, you'll know whether it's because the question is difficult or because the candidate is lacking a critical skill.

  6. Go in prepared -- know the candidate.  Take the time to look over the candidate's resume (and portfolio, if applicable) before the interview.  A quick Google or social network search may add some color.  Use this prep to focus the discussion.  Make sure you ask the subset of standardized questions that will verify some of the claims on the resume.

  7. Start with a simple question.  This is not just to put the candidate at ease, it's also to cut through any B.S.  Sometimes difficult questions can be easy to answer, especially if a candidate is a smooth talker.  A simple question has a nice advantage:  it demands a simple answer.  For example, when hiring for a web UI developer role, here's a simple question:  "Which HTML tag would you use to represent a button?"  Someone applying for this position would certainly need to know meatier things, like design patterns and programming language constructs.  But start with the simple.  In this example, valid answers would include "BUTTON," "INPUT" with a type attribute of "submit" or "button" or "image", or even "A" if styled properly.  If a candidate says, "Well, I don't know.  I leave that to the designers," then you may not need to ask any more questions!
     
  8. Write down your thoughts during (or immediately after) the call.  The paper trail is important so you can communicate the results with others, especially the recruiter/HR rep suggesting candidates.  The feedback will (ideally) help them improve the candidate pool over time.  Don't wait until later when your memory of the conversation will not be as vivid. Come up with a standard form that you and others can use to quickly record your thoughts on areas such as technical competence (score of 1-5, with optional comments), communication skils (1-5), engagement (1-5), and perhaps experience (1-5).

  9. Do not end on a negative note.  If you are excited about the candidate and would like them to move forward in the process, feel free to say so.  But do not do the opposite when you are not excited about them.  Leave that task to the recruiter/HR -- it's their job.  Otherwise you may find yourself spending extra time trying to justify your decision to the candidate.  Instead, end with a thank you and indicate the recruiter/HR will follow up with them on next steps shortly.

  10. Never share your interview questions with recruiters/HR sourcing the position.  While often well-intentioned, I've found recruiters tend to tip off the candidates if given the chance.  Their incentives, after all, are based on these people getting hired!  This also means keeping the feedback generic.  Do not tell a recruitier that a candidate couldn't name an HTML tag to represent a button, for example; just indicate that the candidate did not meet the minimum level of technical proficiency.  The corallary here is:  don't let recuiters/HR listen in on the call.

While I think the intent of the phone screen is to assess technical competence, sometimes you can glean some insight into professionalism or cultural fit.  Some examples:

  1. Engagement and the drive-by interviewee:  If the candidate is talking to you while driving, the message here is that they are not seriously interested in the job. 
     
  2. Professionalism and the tardy interviewee:  If the candidate is more than a couple minutes late dialing in to the conference call number, or doesn't pick up when you call him/her, it demonstrates a lack of professionalism -- especially if the candidate does not apologize.
  3. Ethics and the Googling interviewee:  If the candidate is dumbfounded by a question, only to miraculously arrive at the right answer a minute (or 20) later, question whether this candidate can be trusted to stay on  moral high ground.

The phone screen may be stressful for the candidate, so try to keep it casual and not be too serious.  Have fun!

(Photo credit: graphiteBP)

Tags:

Interviewing

Interrupting Sphinx-4 speech recognition in continuous recognition mode

by timvasil 5/14/2011 8:20:00 PM

Sphinx-4 is a speech recognizer developed at Carnegie Mellon University.  Out of the box, it offers two modes of operation: batch ("frontend") and continuous ("epFrontEnd").  In contiuous mode, it performs decoding live based on, say, microphone input.

Unfortunately for me, epFrontEnd turns the Recognizer.recognize() method into a blocking call, and Sphinx-4's API provides no way of interrupting this method. I find this problematic in various scenarios, such as automated tests.  In such a test, I want to determine whether the recognizer recognizes the command correctly, incorrectly, or misses it entirely.  The "miss" case is the tricky one, as in this case the recognize() method just hangs indefinitely, waiting for more audio input.  

I found a way to work around this problem.  It involves inserting a custom data processor into Sphinx-4's data processing stack.

Here's how to do it in three steps:

Step 1:  Implement a custom data processor 

public class InsertableDataBlocker extends BaseDataProcessor
{
    List<Data> insertionDatas = new LinkedList<Data>();

    @Override
    public Data getData() throws DataProcessingException
    {
        if (!insertionDatas.isEmpty())
        {
            insertionDatas.remove(0);
            throw new InterruptException();
        }
        return getPredecessor().getData();
    }

    public void injectInterrupt()
    {
        insertionDatas.add(new DataEndSignal(0));
    }
}

Step 2:  Add this data processor to the processing stack

In the Sphinx-4 XML configuration file, place the processor right after the microphone processor in the stack.  

    <component name="epFrontEnd" type="edu.cmu.sphinx.frontend.FrontEnd">
        <propertylist name="pipeline">
            <item>microphone </item>
            <item>insertableDataBlocker </item> 
            <item>dataBlocker </item>
            <item>speechClassifier </item>
            <item>speechMarker </item>
            <item>nonSpeechDataFilter </item>
            <item>preemphasizer </item>
            <item>windower </item>
            <item>fft </item>
            <item>melFilterBank </item>
            <item>dct </item>
            <item>liveCMN </item>
            <item>featureExtraction </item>
        </propertylist>
    </component> 
 

Step 3:  Interrupt the recognize() method when desired

ConfigurationManager cm = new ConfigurationManager(getClass().getResource("config.xml"));
InsertableDataBlocker inserter = (InsertableDataBlocker)cm.lookup("insertableDataBlocker");
inserter.injectInterrupt(); 

Tags:

Java | Speech

Screen scraping authenticated HTTPS ASP.NET web pages with view state and ScriptManager

by timvasil 12/20/2010 1:45:00 AM

To screen scrape web pages generated by ASP.NET and delivered via HTTPS, you can still use HttpWebRequest, but there are several "gotchas" to keep in mind:

  1. For basic authentication to work, you have to add the "Authorization" HTTP request header manually. The HttpWebRequest.Credentials property is ignored (.NET bug?).
  2. For authenticated sessions to remain alive, you need to associate a common CookieContainer object with each request.
  3. To handle view state paramters, you can build a regex to grab all hidden field values and then submit them in URL-encoded form along with the next request.
  4. To interpret responses by the ScriptManager (i.e. when used with UpdatePanels), you have to parse the pipe-delimted response which will contain both HTML and updated form field values (including view state).
  5. For ASP.NET to honor the AJAX request, you must specify a User-Agent header it thinks will support AJAX functionality (e.g. Firefox), and an X-Microsoft-Ajax header it thinks was set on the client-side by JavaScript.

Putting it all together, here's how I got it to work:

private static void Main()
{
    request = CreateRequest("https://url-here");
    request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes("username:password")));
    HttpWebResponse resp = (HttpWebResponse)request.GetResponse();
    string respHtml = new StreamReader(resp.GetResponseStream()).ReadToEnd();
    ParseHtml(respHtml);  // TODO:  implement your parser function here
    NameValueCollection form = ExtractHiddenFields(respHtml);

    // For paginated responses, get next page (TODO:  replace my "next page available" logic with your own)
    while (respHtml.IndexOf("<a id=\"ctl00_ContentPlaceHolder2_lbNext\" disabled=\"disabled\">Next</a></li>") < 0)
    {
        request = CreateRequest("https://url-here");
        request.Method = "POST";
        request.Headers.Add("X-MicrosoftAjax", "Delta=true");
        request.ContentType = "application/x-www-form-urlencoded";
        using (StreamWriter w = new StreamWriter(request.GetRequestStream()))
        {
            form["__EVENTTARGET"] = "ctl00$ContentPlaceHolder2$lbNext";  // TODO:  replace my event target with yours
            form["ctl00$ScriptManager1"] = "ctl00$ContentPlaceHolder2$UpdatePanel1|ctl00$ContentPlaceHolder2$lbNext"; // TODO:  same here
            w.Write(GetPayloadString(form));
            w.Flush();
        }
        resp = (HttpWebResponse)request.GetResponse();
        respHtml = new StreamReader(resp.GetResponseStream()).ReadToEnd();
        ParseHtml(respHtml);
        ExtractHiddenFieldsFromAjax(respHtml, form);
    }
}

public static NameValueCollection ExtractHiddenFields(string html)
{
    NameValueCollection form = new NameValueCollection();
    Regex hiddenPattern = new Regex("<input type=\"hidden\" name=\"([^\"]*)\" id=\"[^\"]*\" value=\"([^\"]*)\" />");
    MatchCollection matches = hiddenPattern.Matches(html);
    foreach (Match match in matches)
    {
        form.Add(match.Groups[1].Value, match.Groups[2].Value);
    }
    return form;
}

public static NameValueCollection ExtractHiddenFieldsFromAjax(string html, NameValueCollection form)
{
    form = form ?? new NameValueCollection();
    while (html.Length > 0)
    {
        string[] parts = html.Split(new[] { '|' }, 4);
        int valueLength = int.Parse(parts[0]);
        if (parts[1] == "hiddenField")
        {
            form[parts[2]] = parts[3].Substring(0, valueLength);
        }
        html = html.Substring(parts[0].Length + parts[1].Length + parts[2].Length + 4 + valueLength);
    }
    return form;
}

public static HttpWebRequest CreateRequest(string uri)
{
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
    request.CookieContainer = s_cc; // reuse cookie contianer across requests
    request.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.13) Gecko/20100914 Firefox/3.5.13 (.NET CLR 3.5.30729)";
    return request;
}

public static string GetPayloadString(NameValueCollection form)
{
    if (form == null)
    {
        return String.Empty;
    }

    StringBuilder buff = new StringBuilder();
    buff.Length = 0;
    foreach (string key in form.Keys)
    {
        string[] values = form.GetValues(key);
        if (values != null)
        {
            foreach (string val in values)
            {
                if (buff.Length > 0)
                {
                    buff.Append("&");
                }
                buff.Append(HttpUtility.UrlEncode(key));
                buff.Append("=");
                buff.Append(HttpUtility.UrlEncode(val));
            }
        }
    }
    return buff.ToString();

Tags:

ASP.NET | .NET Framework

Tablet Roundup

by timvasil 7/13/2010 1:18:00 PM

This summer, Dell will be launching Streak in the U.S., a very slick 5" tablet + smarphone running Android 2.0 1.6 (but Dell may upgrade it to 2.2 later this year).  This may be welcome news for people looking for an alternative to the iPhone or iPad, given Apple's recently revealed iPhone 4 design flaws, cover up, and overall disrespect for its customers.

Here's an unboxing/review of the phone I found on YouTube: 

These other tablets (aka oversized smartphones) are hitting the market soon too:

The New York Times reported on April 10 that Google, Microsoft, and Nokia are working on tablets as well, but with no release dates available.

Tags:

Mobile phones

Encrypting files as a different user

by timvasil 4/28/2009 12:08:00 AM

I'm running a C# application that needs to encrypt/decrypt files (using NTFS's EFS encryption) on behalf of a specific user account--a user account other than the one under which the application is running.  I didn't want to go through the hassle of firing up a new process (using CreateProcessAsUser) because I'd have to worry about IPC and it'd be less performant.  The question I had was:  is it possible to encrypt/decrypt files as a user other than the one under which the process is running within that process?  I couldn't find any resource on the web that stated an answer definitively, so I wrote some code to try it.  The answer is:  yes.

Here are the steps (it involves a mix of Interop and managed methods):

  1. Get a handle to the desired user (the one whose encryption key you want to use) by calling LogonUser.  (You'll need the user's password.)
  2. Load the user's profile (aka registry hive) by calling LoadUserProfile.
  3. Construct a WindowsIdentity object using the handle provided by the call in step 1.
  4. Invoke WindowsIdentity.Impersonate().
  5. Perform any file I/O -- it'll be in the context of that user.  The user's encryption key will be used with any File.Encrypt() / FileInfo.Encrypt() invocation.
  6. Unload the profile by calling UnloadUserProfile.
  7. Close the user handle by calling CloseHandle.

You can do steps 1-4 in the constructor of an IDisposable object and do steps 5-7 in the Dispose() method to ensure proper resource cleanup. 

Tags:

Windows | .NET Framework | C# | Security

User-defined function to convert from RAW(16) to a GUID in Oracle

by timvasil 1/20/2009 11:32:00 AM

CREATE OR REPLACE
FUNCTION RAWTOGUID
( RawData IN RAW
) RETURN VARCHAR AS

BEGIN

declare HexData varchar(32) := rawtohex(RawData);

begin
return
    substr(HexData, 7, 2)
    || substr(HexData, 5, 2)
    || substr(HexData, 3, 2)
    || substr(HexData, 1, 2)
    || '-'
    || substr(HexData, 11, 2)
    || substr(HexData, 9, 2)
    || '-'
    || substr(HexData, 15, 2)
    || substr(HexData, 13, 2)
    || '-'
    || substr(HexData, 17, 4)
    || '-'
    || substr(HexData, 21, 12);
end;

END RAWTOGUID;

 

Tags:

Oracle

JavaScript functions to escape and unescape HTML

by timvasil 12/28/2008 9:10:00 PM

JavaScript doesn't have built-in functions to escape or unescape HTML, which may come in handy for certain DOM manipulations or AJAX scripting.  Here are the custom functions I wrote to handle these tasks.  I've tested the implementation with both IE and Firefox.

var g_oHtmlEncodeElement;

function htmlEscape(text)
{
    g_oHtmlEncodeElement = g_oHtmlEncodeElement || document.createElement("div");
    g_oHtmlEncodeElement.innerText = g_oHtmlEncodeElement.textContent = text;
    return g_oHtmlEncodeElement.innerHTML;
}

function htmlUnescape(html)
{
    g_oHtmlEncodeElement = g_oHtmlEncodeElement || document.createElement("div");
    g_oHtmlEncodeElement.textContent = g_oHtmlEncodeElement.innerText = "";
    g_oHtmlEncodeElement.innerHTML = html;
    return g_oHtmlEncodeElement.innerText || g_oHtmlEncodeElement.textContent;
}

Tags:

JavaScript | AJAX | IE | Firefox

Converting an Oracle interval to total seconds

by timvasil 12/22/2008 5:19:00 PM

If you subtract one timestamp from another in Oracle, the result is an interval type.  This is similar to how subtracting a DateTime from another in .NET yields a TimeSpan.  Unfortunately, unlike .NET, Oracle provides no simple equivalent to TimeSpan.TotalSeconds.

Here's the SQL to accomplish it.  Note that fractions of a second are included in the result.

declare
  diff interval day to second :=
        cast('18-DEC-08 11.00.00 PM' as timestamp) - cast('18-DEC-08 9.59.58.5 PM' as timestamp);
  secs number;
begin
  select
    extract(day from diff) * 86400
    + extract(hour from diff) * 3600
    + extract(minute from diff) * 60
    + extract(second from diff)
 into
  secs
  from dual;
 dbms_output.put_line(secs);
end;

Tags:

Oracle

Search

Calendar

«  February 2012  »
SuMoTuWeThFrSa
2930311234
567891011
12131415161718
19202122232425
26272829123
45678910

View posts in large calendar

Recent comments

Archive