A Telnet session is really nothing but a Socket to a server on port 23 in .NET-speak. This article applies to .NET 1.1, 2.0, and 3.0, I just wrote my version in 2.0.
For anyone wondering "Who is this guy and where did he come from?" I have an answer. I have been posting for a few months on Blogger but didn't really see any fruits of my labor- no comments, no way of knowing how many hits I was getting, etc. So, I found GWB and have relocated my stuff here.
So that brings me back to the original question. Part 1: Who am I? I'm a developer with the power company in SC. I love to teach and hope to be able to move into an instructor/evangelist position some day.
Part 2: Where did I come from? I actually opened this account close to a month ago but was trying to figure out how to get my postings migrated nicely. I realized that I was spending more time planning and thinking and scheming than it was going to take me to move the posts themselves. So yesterday I just moved them by hand. There are only about 8, so it didn't take long. But if you were just looking at which posts were new, I probably showed up a time or 8 yesterday. I doubt I'll continue such a marathon pace, but you never know...
Given the day of the year and the year (both as ints), return the date in “m/d/yyyy” (string) format without using the System.DateTime namespace or any other built-in date/time handler.
One solution (1858 IL characters)
static string g(int d, int y)
{
int l;
int i = 0;
if (d < 0) { i = 13; }
l = ((y % 400 == 0) | ((y % 100 != 0) & (y % 4 == 0))) ? 1 : 0;
int[] m = new int[13] { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
while (i < 13)
{
if (i > 1) { m[i] = m[i] + l; }
if (d <= (m[i])) { return i + "/" + (d - m[i - 1]) + "/" + y; }
i++;
}
return "e";
}
Another solution (1814 IL characters):
public string G(int d, int y)
{
if (d < 1 || y < 1)
return "e";
bool l = y % 4 == 0 && (y % 100 != 0 || y % 400 == 0) ? true : false;
d = l ? d - 1 : d;
int[] m = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int i = 0;
do
{
if (d > m[i])
d -= m[i];
else
break;
} while (++i < 12);
d = l ? i < 2 ? d + 1 : d : d;
return i > 11 ? "e" : String.Format("{0}/{1}/{2}", i + 1, d, y);
}
Another (1718 IL characters):
static string r(int d, int y)
{
int m = 0;
bool l = y % 4 == 0 && (y % 100 != 0 || y % 400 == 0) ? true : false;
int[] c = { 31, l ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
while (d > c[m < 11 ? m : 11])
{
d -= c[m < 11 ? m : 11];
m++;
}
return d < 1 || y < 1 || m > 11 ? "E" : String.Format("{0}/{1}/{2}", m + 1, d, y);
}
Winner (1538 IL characters)
static string D(int d, int y)
{
bool L = y % 4 == 0 && y % 100 != 0 || y % 400 == 0;
if (d > (L ? 366 : 365) || d <= 0 || y <= 0)
return null;
int x = 0, t = 3;
string i = string.Format("3{0}3232332323", L ? "1" : "0");
string s = "JFMAMJJASOND";
while (d > t + 28)
{
d -= t + 28;
t = int.Parse(i[++x].ToString());
}
return string.Format("{0}/{1}/{2}", s[x], d, y);
}
Given a color string in one of the formats listed below, return an array of the RGB elements that make it up.
For Example:
"RGB(255,255,255)"
"#FFFFFF"
"#FFF"
All of these examples return [255, 255, 255]
- Case does not matter
- #abc translates to #aabbcc
- There will be no spaces in the string
One solution (73 IL):
s = s.Replace("RGB(", "").Replace(")", "").Replace("#", "");
if (s.Contains(",")) { return s.Split(','); }
int[] a = new int[3];
int i = 0;
do { a[i] = (s.Length == 3 ? 17 : 1) * Convert.ToInt32(s.Substring(i * s.Length / 3, s.Length / 3), 16); } while (++i < 3);
return a;
Another (68 IL, I think):
object[] colorMyWorld(string htmlColor)
{
if (htmlColor.StartsWith("#"))
{
Color myColor = ColorTranslator.FromHtml(htmlColor);
return new object[] { myColor.R, myColor.G, myColor.B };
}
else
{
string[] components = htmlColor.Split("(),".ToCharArray());
return new object[] { components[1], components[2], components[3] };
}
}
Implement 2 algorithms and place them in separate methods.
1) Given a sentence, write an algorithm to reverse the order of the words.
Example: “My name is Chris” becomes “Chris name is My”.
2) Given the same sentence as in #1, write an algorithm to reverse each individual word, but not their order.
Example: “My name is Chris” becomes “yM eman si sirhC”.
Winner:
public static string W(string s){
char[] c = s.ToCharArray();
Array.Reverse(c);
return O(new string(c));
}
public static string O(string s){
string[] t = s.Split(' ');
Array.Reverse(t);
return string.Join(" ", t);
}
Another:
static void a(string s)
{
int i = s.LastIndexOf(' ');
c.Write(s.Substring(i + 1) + " ");
if (i < 0)
return;
a(s.Remove(i));
}
static void b(string s)
{
int i = s.LastIndexOf(' ');
if(i > 0)
b(s.Remove(i));
s = s.Substring(i + 1);
i = s.Length;
do
{
c.Write(s[--i]);
} while(i > 0)
c.Write(" ");
}
Another:
static void x(string l)
{
d[] b = l.ToCharArray();
a.Reverse(b);
y(new s(b));
}
static void y(string l)
{
s[] f = l.Split(new d[] { ' ' });
int i = f.Length - 1;
do
{
c.Write(f[i] + " ");
} while (--i > -1);
}
Given an arbitrary number of coins to use, print out a combination using that number that will add up to a dollar.
For instance, using the number 4:
Q : 4
D : 0
N : 0
P : 0
If the number is invalid, such as 5:
Invalid Number
- The method must take an Integer value with no restrictions.
- All data structures must be instantiated within the method.
- Only Pennies, Nickels, Dimes, and Quarters can be used. (No Half Dollars)
- The lowest IL wins.
One solution (103 IL)
static void Amount(int total)
{
bool invalid = true;
for (int quarters = 0; quarters <= 4; quarters++)
{
for (int dimes = 0; dimes <= 10; dimes++)
{
for (int nickels = 0; nickels <= 20; nickels++)
{
for (int pennies = 0; pennies <= 100; pennies++)
{
if ((quarters*25 + dimes * 10 + nickels * 5 + pennies == 100) &&
(total == quarters + dimes + nickels + pennies))
{
Console.WriteLine("Q: " + quarters);
Console.WriteLine("D: " + dimes);
Console.WriteLine("N: " + nickels);
Console.WriteLine("P: " + pennies);
invalid = false;
}
Winner (84 IL):
void getADollar(int coinCount)
{
int d, n, p, q = 0;
bool solution = true;
do
{
d = 0;
do
{
n = 0;
do
{
p = coinCount - q - d - n;
if ((((q * 25) + (d * 10) + (n * 5) + p) == 100) && p >= 0)
{
Console.WriteLine(String.Format("Q : {0}\nD : {1}\nN : {2}\nP : " + p, q, d, n));
solution = false;
}
n++;
} while (n <= coinCount);
d++;
} while (d <= coinCount);
q++;
} while (q <= coinCount);
if (solution)
Console.WriteLine("Invalid Number");
}
Write a method that takes two parameters, both positive integers, and returns each prime number that falls on or between these two numbers. Each number printed out should be on its own line, so that if the parameters were 1 and 20, the results would be:
2
3
5
7
11
13
17
19
The method must be able to handle both parameters being the same number. It should also be able to handle the first number passed being bigger or smaller than the second. EVERYTHING must happen within this method. Your Main should only be calling the method and passing the two numbers. Any other variables you use must be declared/initialized within the method.
One implementation (40 lines of IL):
void getPrime(int one, int two)
{
int j = Math.Min(one, two);
do
{
int i = 2;
while (i < j && (j % i) != 0)
{
i++;
}
if (i == j)
Console.WriteLine(j);
} while (++j <= Math.Max(one, two));
}
Another (50+ lines of IL):
public void prime(int min, int max)
{
if (min > max) {max=i ;min = max; i = min; }
n = min;
while(n < max)
{
isprime = true;
j = 2;
while(j < n)
{
if ((n % j) == 0)
{
isprime = false;
break;
}
j++;
}
if (isprime)
{
Console.WriteLine(n);
}
n++;
}
}
Another (43 lines of IL):
private void ReturnPrimes(int inta, int intb)
{
if (inta > intb)
{
ReturnPrimes(intb, inta);
}
else
{
int i = 2;
while (i < inta)
{
if (inta % i == 0) {i = inta;}
i++;
}
if (i == inta) {Console.WriteLine(inta);}
if (inta != intb) {ReturnPrimes(inta + 1, intb);}
}
}
The winner was VB.NET (39 lines of IL):
Sub PrimeChallengeIL(ByVal low As Integer, ByVal high As Integer)
If low > high Then
PrimeChallengeIL(high, low)
Else
If Not low = high Then PrimeChallengeIL(low, high - 1)
low = 2
Do
If low = high Then Console.WriteLine(low)
If high Mod low = 0 Then Exit Do
low += 1
Loop While low <= high
End If
End Sub
Given the lengths of the sides of a triangle, compute the area of the triangle.
Here's one implementation (based completely off a geometry formula):
double printArea(double a, double b, double c)
{
double s = (a + b + c) / 2;
return Math.Sqrt(s * (s - a) * (s - b) * (s - c));
}
Given a sorted list with duplicates, print out a list of just the unique elements.
For example:
Given (1, 1, 3, 3, 3, 5, 5, 5, 9, 9, 9, 9), the result would be (1, 3, 5, 9).
Here's one implementation:
int[] nums = new int[] { 1, 1, 1, 1, 2, 3, 3, 3, 4, 5, 5, 5, 5, 5, 6, 9, 9, 9, 9 };
int n = 1;
Console.Write(nums[0]);
do
{
Console.Write(nums[n] == nums[++n] ? "" : nums[n].ToString());
} while (n < nums.Length);
SITUATION:
I needed to find out how many people hit and stayed on an internal company site per day on average. So, I looked through the many MANY IIS log analyzers available on the nets to help me with the task.
SOLUTION:
While I was looking for a decent one I found the LogParser tool by Microsoft, which caught my eye because it's free. I ended up using a 30-day eval copy of something else, but I kept monkeying with LogParser because it survived the 30 days.
INFO:
http://www.logparser.com/ - The Unofficial Log Parser Support Site. Not really all that helpful directly, but if you do a Google Search looking for how to use it you'll land there alot and that's helpful. So, I give the site a B+: great content (A) but terrible layout and search (C). (Content weighs heavier, for you academia nuts out there.)
REVIEW:
The tool is great but not all that. If you know SQL, it's similar enough that the learning curve won't leave you AS winded. But the functions are different enough that it's not a snap either.
WHERE TO GET IT:
Get it here: http://www.microsoft.com/downloads/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07&displaylang=en
HOW I USED IT:
IIS logs track the following fields (pulled right from the log headers): date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) sc-status sc-substatus sc-win32-status. Wanna know more about those? Google that yourself, lazy.
USER NAMES:
Because the IIS logs track the username of the requestor, I figured I could take a look at exactly who visits my site each month. Here's the query:
logparser -i:iisw3c "select distinct to_uppercase(cs-username) as USER from R:\W3SVC1\ex070101.log where cs-method = 'GET' and cs-uri-stem = '/MyPopularSite/MyPopularPage.aspx'" -q:ON
- The -i switch tells logparser that it'll be looking at not just IIS logs but IIS logs in the "Extended W3C" format. Woohoo!
- The query basically says "Give me a roster of the individual users that loaded my page on this date (from the log file name)".
- I had to use the to_uppercase command because some NT users authenticated as lowercase and then later as UPPERCASE, which tricked the logs into thinking they were 2 distinct users. Sneaky, sneaky.
- MyPopularPage shares a log with many other LessPopularPages on our intranet, so the where clause separates the chaff.
- Oh, one more thing. If you look very carefully you'll see a single quote followed by a double quote just after MyPopularPage.aspx. The single quote finishes the string literal, and the double quote finishes the SQL-like statement.
BUT WAIT, THERE ARE MORE USERS:
My IIS admins reminded me that MyPopularSite is hosted on a web farm (that's how popular I am) and that I needed to check the logs of all three servers. Despair not! Here's the command:
logparser -i:iisw3c "select distinct to_uppercase(cs-username) as USER from R:\W3SVC1\ex070101.log, S:\W3SVC1\ex070101.log, T:\W3SVC1\ex070101.log where cs-method = 'GET' and cs-uri-stem = '/MyPopularSite/MyPopularPage.aspx'" -q:ON
- Just like I would query from multiple tables, I can query from multiple logs. I don't really care about joining them, so don't criticize my SQL. I want this thing out of my hair.
LOGGING LOGS INTO A LOG:
Yes, I know it sounds pretty silly to dump one log into another. But I'm not doing that- well, not exactly. What I want is a roster- one that I can view, sort, print, and post on my cube wall as My Fan Club. After all, these people love me! They deserve to have their names in 30-point font on my cube wall. They are my adoring public, after all, and I make them great...
Here's the command:
logparser -i:iisw3c -o:CSV "select distinct to_uppercase(cs-username) as USER, date into C:\temp\logger.csv from R:\W3SVC1\ex0701*.log, S:\W3SVC1\ex0701*.log, T:\W3SVC1\ex0701*.log where cs-method = 'GET' and cs-uri-stem = '/operatingsummary/mainform.aspx'" -q:ON
- The file logger.csv is created or overwritten by the results of this command.
I made another change, in case you didn't notice. I wrote the log name as "ex0701*.log" because the logs for the month of January are in the format ex070101.log, ex070102.log, etc. The * catches all of those logs. So that last command captures the user IDs of the people who visited MyPopularPage for the entire month of January. I could also have replaced the log name with "ex07*.log", which would have captured my popularity for the whole year.
CONCLUSION:
The LogParser tool is pretty handy and very customizable, allowing you to analyze your logs however you wish. But it also requires a great deal of knowledge of the logs before-hand. I picked a different tool because I didn't know what I was looking at right away. The other tool gave me the big picture and now I can wile away the hours in the minutia of the IIS logs for my site, or any other logs for that matter. Yay!
HARSH REALITY:
MyPopularSite manages to attract the attention of a pitiful 12 users a day, on average.
FOLLOW-UP NOTE:
My page refreshed every 6 minutes, so this is the number of times my page was requested without a user name in the month of January.
logparser -i:iisw3c "select count(*) as count, date, cs-username as user from R:\W3SVC1\ex0701*.log where cs-method='GET' and cs-uri-stem='/MyPopularSite/MyPopularPage.aspx' and cs-username=null group by date, cs-username"
The good news is that there are lots of these. So although there are only 12 new users per day, people are staying on my page for a very long time (days, usually).
A friend and mentor of mine took me to lunch one afternoon and asked me, over a plate of wings (mmmmm), this question:
If you wrote a program to print out the numbers 1-100 on one line each, replacing every number divisible by 3 with the word "fizz", every number divisible by 5 with the word "buzz", and every number divisible by both 3 and 5 with the word "fizzbuzz", how would you do that?
I didn't answer his question during that lunch, but the question stuck with me. He told me that his group has a regular "coding challenge" when things are slow at work. I was immediately enthralled with that idea and put it into practice the next week where I work.
The goal of this challenge was to produce the lowest number of lines of IL (CIL, MSIL, whatever you want to call it). The reason IL was chosen as the benchmark is because no matter what .NET language the code is written in, it all goes down to IL. Execution time isn't as baseline as one might think because of the difference in levels of performance due to hardware.
I do not claim that this solution was the winner of the challenge or that it's even a good one. This is simply one of the solutions. In future posts I will attempt to present only the best solutions. This is just the introductory challenge, so I'm not as concerned with fleshing it out as much as I will in the future. As far as C# is concerned, ternary expressions won out over if-else.
int i = 1;
do
{
Console.WriteLine(i % 3 == 0 ? (i % 5 == 0 ? "fizzbuzz" : "fizz") : (i % 5 == 0 ? "buzz" : i.ToString()));
i++;
} while (i < 101);