Sunday, October 22, 2006

Tech spec sheets...

Need to be made out of HTML.

I'll SED.EXE the text out of the generated scores and replace place-holder text in the tech spec HTML page... That should make generating spec sheets extremely easy...

Back to Voodoo...

Well... Guess I'm going back to Voodoo. To be in the R&D portion of it all along with maintaining the Voodoo softwaring and testing system.

To give you an idea about the inner workings of our softwaring process works:

1) Technician enters the customers WO number.
2) The computer pulls the system configuration from the database
3) The machine then reads the system configuration and installs the correct OS.
4) Upon reboot the machine parses the configuration and installs the cusomers chosen software and hardware drivers. For the hardware we follow the "failing gracefully" guideline. We actually enable SLI in all Nvidia configurations. The Nvidia drivers will detect that it should have SLI but in a single card configuration it will throw up a dialog box stating that SLI will be auto-disabled. And upon reboot the machine is correctly configured without adding any more detection/complexity. Ahhh, failing gracefully :)
5) Second QC is a script that checks all the "optical" portions of the computer. This includes things like paint color, tattoo's, liquid color, etc. Everything physical. This test, when I return, will start to include things like counting video cards, ensuring SLI and crossfire is enabled, etc.
6) Lastly is Haiti. Originally designed by Casey Inlow and myself, it is a comprehensive test suite of games, real-world and artificial applications. Artificial applications include CPU Burn, Prime 95, etc.

With HP, it will be nice and interesting to see what they think of all this work and effort. I'm sure they have some very smart guys who might just laugh at all of this effort, or they might be blown away...?

I guess time will tell... Very shortly.

Friday, September 15, 2006

The Unbeatable Problem.

No problem is unbeatable if you look at it as files and registry entries (in Windows).   I recently came across a very, very pain in the ass problem that hasn't seemed to have been resolved anywhere.  Microsoft has a solution for it, but Microsoft's solution did not resolve the issue I was having.  The interface on the clipart window worked-- to an extent.  You could NOT open any of the folders in the collection list.  My collections, Office collections, Web collections, none of them were expandable.  The user was getting this error message:

Clip art organizer cannot complete the requested task.
Class not registered. Error code 0x80040154

The solution for me?  Doing registry traces using Regmon to find out what registry keys it was using (using filemon revealed that there were no missing files).

Initially I found the error message repeated itself BEFORE drawing the collection list but then would continue after the message was displayed.  I then tried to time Regmon to monitor only MSTORE.EXE (the clip organizer app) to only monitor just before and then stop when the message was displayed.  The list of registry keys I got were HKCR and HKCU CLSID registry keys (Class ID's -- class not registered --> we're close here :)).  I went through each registry key but they all seemed fine (ie, they opened without issue).  So, step 2 was to repeat the process on a working machine.  There was no errors and the regmon dump looked almost identical on both machines with the differences being negligible.

Time to get into the nitty gritty.  So I opened each CLSID registry key found in the regmon dump in a working machine and the non-working machine.  I found TWO keys that did not match.  These were those keys:

 

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\CLSID\{ef636390-f343-11d0-9477-00c04fd36226}]
@="OLE DB Rowset Proxy"

[HKEY_CLASSES_ROOT\CLSID\{ef636390-f343-11d0-9477-00c04fd36226}\Implemented Categories]

[HKEY_CLASSES_ROOT\CLSID\{ef636390-f343-11d0-9477-00c04fd36226}\Implemented Categories\{00000003-0000-0000-C000-000000000046}]

[HKEY_CLASSES_ROOT\CLSID\{ef636390-f343-11d0-9477-00c04fd36226}\InprocServer32]
@="C:\\Program Files\\Common Files\\System\\Ole DB\\msdaps.dll"
"ThreadingModel"="Both"

[HKEY_CLASSES_ROOT\CLSID\{ef636390-f343-11d0-9477-00c04fd36226}\ProgID]
@="DBRSTPRX.AsProxy.1"

[HKEY_CLASSES_ROOT\CLSID\{ef636390-f343-11d0-9477-00c04fd36226}\VersionIndependentProgID]
@="DBRSTPRX.AsProxy"

AND:

 

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\CLSID\{ef636392-f343-11d0-9477-00c04fd36226}]
@="OLE DB Row Proxy"

[HKEY_CLASSES_ROOT\CLSID\{ef636392-f343-11d0-9477-00c04fd36226}\Implemented Categories]

[HKEY_CLASSES_ROOT\CLSID\{ef636392-f343-11d0-9477-00c04fd36226}\Implemented Categories\{00000003-0000-0000-C000-000000000046}]

[HKEY_CLASSES_ROOT\CLSID\{ef636392-f343-11d0-9477-00c04fd36226}\InprocServer32]
@="C:\\Program Files\\Common Files\\System\\Ole DB\\msdaps.dll"
"ThreadingModel"="Both"

[HKEY_CLASSES_ROOT\CLSID\{ef636392-f343-11d0-9477-00c04fd36226}\ProgID]
@="DBROWPRX.AsProxy.1"

[HKEY_CLASSES_ROOT\CLSID\{ef636392-f343-11d0-9477-00c04fd36226}\VersionIndependentProgID]
@="DBROWPRX.AsProxy"

The "non-working" computer only had the Implemented Categories subkey in each of the main keys, missing InproceServer32, ProgID and VersionIndependentProgID.

Added those keys and alls well :)

Thursday, August 31, 2006

I'M NOT THE ONLY ONE!!!!

Who gets it ;)

Google gets it too. Some excerpts that follow my philosphy:

Sometimes, value can be bought off the shelf, Merrill says, holding up a plastic fork as an example. But there are times when off-the-shelf software won't do. "Our culture is pretty deeply embedded in many of our processes," he says. "So what we don't want to do is buy a tool, which by extension changes the cultural aspects of the way we do things."

It is my experience that off-the-shelf rarely works completely. It can work in some capacity, but what good is using 40% of a product that lacks 60% of the features you need?

What I like about the Google example is, like a plastic fork, the best commercial products you can purchase is simple "blocks" whose value becomes the way it helps you go from A to B. Not A to C,D,E,1,3,5,6,7 but never getting to B or only doing it partially (or too much).

Google's unorthodox approach to managing its Ph.D.s drove its decision not to budget research and development separately, as most tech companies do. "You end up in many companies with this divide between research and engineering," explains Alan Eustace, senior VP of engineering and research. By dividing those budgets, he says, "you're pretty much guaranteeing institutionally that you won't be solving interesting problems."

And it's true where I was previously employed and am employed now. A divide between people who fix problems and those who work on ensuring those problems don't happen again.

"Our goal is to automate as many things as we can because it makes unfun things not happen," Merrill says. "Nobody wants to have a boring job, right?"

Creating automation IS fun! Doing repetitive tasks is not.

Merrill is evasive when asked what kinds of commercial PC software are used at Google. "More important than what we put on each desktop is how we think about what to put on each desktop," he says obliquely. "Goo-gle's philosophy is that choice is always better than control. Tightly centralized control gets in the way of innovation."

He then takes a jab at CIOs--which he describes as a title used by "old-world companies"--at other companies. "Most people in my job try to control. 'Here are the three things you can buy.'" Merrill explains. "I try to control as a little as I possibly can but make it easy to work within parameters that I know how to work with."

Merrill sees a distinction between tools that tell you something and tools that stop you from doing something. For example, he observes that some financial services institutions block instant messaging because of they way they interpret regulations. "We don't think that's the right approach here," he says.

The right approach, as Merrill sees it: Talk a lot; use data, not intuition; automate wherever you can.


That faith in group intelligence manifests itself in the lunch line. Google provides free meals to employees partly as a perk and to enhance productivity, but also to encourage interaction. It's about the pollination of ideas over salads and sandwiches. "If you want people to talk, if you want people to engage, how do you do that?" Merrill asks. "You give them lunch."

Interaction is the bane of all businesses. NO ONE in a business wants to communicate -- you have to force them in some capacity.

Wednesday, August 16, 2006

AutoCAD is a devil in saint's clothing

Whenever problems arrise with AutoCAD it's a frustrating experience. I'm sure that is coupled with my inexperience with troubleshooting this particular program. It all boils down to two things (in Windows) when a program fails:

1) It's a registry key gone crazy (incorrect permissions, wrong setting, wrong type, etc.)
2) It's a file that's become mangled (incorrect permissions, wrong version)

That's it. Every problem in Windows is related to one (or both) of those two issues.

AutoCAD is intimidating at first having never dealt with it. We have a custom menu that is activated when AutoCAD is run. On one particular user's machine, her AutoCAD was throwing up errors when trying to build this menu (cui file is write protected). In attempting to troubleshoot this, I found the cui file referenced is indeed write protected. But that wasn't the problem. Checking with other users, they could not write to the file so her AutoCAD was trying to write to the file for some reason. Launching her AutoCAD under my user account resulted in success... So it could not have been the AutoCAD program installed on the machine. This left two things:

1) Some file in her profile is causing the issue and AutoCAD calls that file
2) A registry key is incorrectly set

Removing AutoCAD from her HKCU resulted in AutoCAD reconfiguring itself on launch and we did not get the error message but got a very slimmed down menu missing many functions.

This indirectly is telling me that the registry is not the issue. If the registry was the issue, the total removal of AutoCAD from HKCU should have resulted in it coming up no problem. This leaves the other issue... A file is causing the headaches. But, before I continued I had the user log on to another machine to ensure it was not her account causing the issue --> AutoCAD worked fine on another machine under her account. So it was computer specific. Some file in her profile...

AutoCAD keeps files in the following two folders in the users profile:
C:\Documents and Settings\USER ACCOUNT\Local Settings\Application Data\AutoDesk
and
C:\Documents and Settings\USER ACCOUNT\Application Data\AutoDesk

A file or couple of files in one (or both) of those folders must be causing my issue.

Renaming those two folders to AutoDesk--old should resolve the issue if my troubleshooting is correct.

Because I haven't and won't troubleshoot further to determine the exact file I won't know exactly which file caused or causes that issue but the solution is effective and cheap anyways.

Other places preferences maybe stored are the My Documents folder. So watch out there as well if your still having problems.

Tuesday, August 08, 2006

The Upwards War And Downwards Cycle

Everything you face today is a struggle. Without clout, you ride the coattails of others until you can achieve clout enough to force issues out or complete them. I face that ride pretty quickly. Being with a company for six months and trying to offer new ideas to problems I had faced (and solved) previously can result in resentment. It took me a year to build up enough clout at Voodoo, a company of 25 or so employees, to start enabling changes. Can I do the same working at a company for only 3 months (+ 3 on contract)?

The people around me who've seen my work are sold on it. Unfortunately, it's the people who haven't seen it that make the decisions.

This Friday will tell.

Wednesday, August 02, 2006

Single Image Hardware Independent Operating System Independent Deployment

HOW TO:

1) Make a OPK share (usually OPKTOOLS)
2) Make a CFGSET and set it to be able to do Media Center / Tablet (use a Media Center 2005 CD's and combine the two CD's) IF possible. (optionalsources=YES under [WINPE] in Winbom.ini)
3) Boot a VM into WinPE and use the Winbom.ini created by the CFGSET to copy all the necessary files over. Once that's done the system should reboot, go back into WinPE immediantely.
4) Kill FACTORY.EXE upon entering WinPE *IF* it's going to "Install Configuration Set"
5) Make an IMAGE of the hard disk and call this "VIRGIN" (or clean or blank or whatever).
6) Copy out winnt.sif located in the $WIN_NT.~BT$ folder to a network share. Within this one single file is the product key that determines what version of Windows you are going to have (Pro, Tablet or Media Center --> as far as I know [but haven't tried] this will not work for HOME).

7) You can now image a machine with the VIRGIN image and then copy over a WINNT.SIF to $WIN_NT$.~BT that has the proper product key using WinPE and FIRM. Since this is before the blue text-mode setup it is hardware independent and Windows will automatically configure itself for the number of processors it can support automatically. As well, because it's before the GUI mode configures itself via the product key, changing the WINNT.SIF file will change the type of Windows it will install itself as!

Single Image Hardware Independent Operating System Independent Deployment (SIHIOSID)

Boom baby! :D

One Image to Rule them All!

Another blog that discusses WinPE!

And other technical things! Finally :)

Utilizing WinPE in deployments

Browsing the web I found a good page highlighting some advantages of WinPE.

The article is a little old and WinPE is now available to downlad from MS sites and will be available with Vista. As well there is now a way to load the whole WINPE CD image into RAM so you don't require a CD drive.

In my environment I use WinPE to help with the deployment process and it does it's job wonderfully. I've modified it to use Windows Post Installer (WPI) to give an interface for the apps that should be deployed to the target system.

My current environment is setup as follows:

1) WinPE boots and logs the IP address of the present machine onto a network share. Our company has a site license for RAdmin so that is installed on WinPE. This logging of its IP Address allows me to RAdmin into it and administer the WinPE environment without being physically present.

2) WinPE presents a batch file "choices" screen, Reimaging is one of the options.

Choosing reimage causes the following to happen:

3) WinPE prompts for your user name, password and computer name which are stored in text files on a RAM drive in WinPE.

4) WinPE opens up WPI with a list of programs.

5) Clicking "Begin install" causes WPI to output the programs selected into a text file on the WinPE RAM Drive.

6) RDeploy is then called to image the drive with the corporate standard image (I've learned I may need to add a choice to select between Tablet, MultiProcessor or Single Processor soon. I've thought another way around it I'll describe later).

7) After imaging the drive, FIRM.EXE (File System Independent Resource Management) copies over the approriate sysprep.inf while which contains your user name, password and parses the computer name you entered earlier to determine the correct OU that the system will be placed under. With this information the sysprep file contains enough information to join the machine to the domain without user intervention.

FIRM also copies over all the text files that contain your user name and password onto the machine for parsing later (this later is to map file shares and execute commands under a domain account).

8) The machine reboots and joins to the domain as per the sysprep script.

More to come later.

Filter orders down to the hardware level

So we have basic detection based on customer orders but there is a way to do it based on hardware configuration. I consider hardware configuration to be a poor way of filtering, but it is sometimes necessary as a company won't always update SKU's or the file that we filter fast enough (bad business process in that case). Sometimes though, it's required if you want to limit installs to useful software. If you were an OEM and shipped NERO with every system, NERO may not be useful to users who have only CD drives (non-writeable). To filter thourgh to ensure usefullness, it now becomes a two stage process:

Find the SKU or customer order to ensure he gets, say, NERO.

--------------------------------
:Customer order file
:responses.txt
NERO-Y
--------------------------------

So we check to ensure that the client/customer has requested NERO:

------------------------------
:Check for NERO
findstr /I /C:"NERO-Y" responses.txtIF '%ERRORLEVEL%' == '0' (
SET NERO-FOUND=1
ECHO Nero was found!
) ELSE (
SET NERO-FOUND=0
ECHO Nero was NOT found!
)
------------------------------
And now we filter for the hardware ID using DevCon:

------------------------------
:Find the CD Burning Hardware ID
Devcon findall hwids * > "%userprofile%\desktop\HWIDS.TXT"

IF '%NERO-FOUND%' == '1' (
findstr /I /C:"IDE\CDROMSONY_CD-RW__CRX230ED" HWIDS.TXT
)
IF '%ERRORLEVEL%' == '0' (
:run silent setup command
NERO.EXE /S
ECHO Nero was installed!
)
---------------------------------

We don't need an "ELSE" in the above as we expect it to fail gracefully and not require more code to tell it to simply continue as it will do so anyways.

And now the OEM or corporation won't install useless software unless hardware that can take advantage of it is present. :)

Tuesday, August 01, 2006

Failing Gracefully is the essence of life

To someone like myself whose never taken a programming course, this is revitalizing stuff:

I am very much in awe of the guy who invented barcodes; they are incredibly elegant. One trick is to notice that every digit in a barcode is two black stripes and two white stripes, so if you've read black-white-black-white you know you have a digit, no matter how quickly it happened. (If it happened too quickly, you can decide you're reading garbage and just bail.)
One of the rules of writing algorithms that I've recently been sort of toying with is that we (as programmers) spend too much time trying to find provably correct solutions, when what we need to do is write really fast heuristics that fail incredibly gracefully.
This is almost always how nature works. You don't have to have every cell in your eye working perfectly to be able to see. We can put together images with an incredible amount of damage to the mechanism, because it fails so gracefully and organically.
This is, I am convinced, the next generation of programming, and it's something we're already starting to see: for instance, vision algorithms today are modeled much more closely after the workings of the eye, and are much more successful than they were twenty years ago.
Wait wait wait, can you elaborate on this heuristics bit being the next big thing, because you just bent some people's brains. When I normally think of heuristics in computer science, I think of either "an educated guess" or "good enough".
I.E., a game programmer doesn't have to run out Pi to the Nth degree to calculate the slope of a hill in a physics engine, because they can get something 'good enough' for the screen using a rougher calculation... but hasn't it always been like that out of necessity?

Heuristics (the way I'm using them) are basically algorithms that are not guaranteed to get the right answer all the time. Sometimes you can have a heuristic that gets you something close to the answer, and you (as the programmer) say, "This is close enough for government work."
This is a very old trick of programming, and it's a very powerful one on its own. Trying to make algorithms that never fail, and proving that they can never fail, is an entire branch of computer science and frankly one that I think is a dead end. Because that's not the way the world works.
When you look at biological systems, they are usually perfect machines; they have all these heuristics to deal with a variety of situations (hey, our core temperature is too hot, let's release sweat, which should cool us off) but none of them are anywhere near provably correct in all circumstances (hey, we're actually submerged in hot water, so sweat isn't effective in cooling us off). But they're good enough, and they fail gracefully.
You don't die immediately if sweating fails to cool you; you just grow uncomfortable and have to make a conscious reponse (hey, I think I'll get out of this hot tub now).
Programs need to be written this way. In the case of reading bar codes, you don't care if you read garbage a thousand times a second. It doesn't hurt you. If you write an algorithm that looks for barcodes everywhere in the image, even in the sky or in a face or a cup of coffee, it's not going to hurt anything. Eventually the user will hold up a valid barcode, it'll read it, the checksum will verify, and you're in business.
And the barcode recognizer doesn't have to understand every conceivable way a barcode can be screwed up. If the lighting is totally wrong, or the barcode is moving, the user has to take conscious action and, like, tilt the book differently or hold it still. But this kind of feedback is immediately evident, and it's totally natural.
Because I can try 1,000 times a second, I can give immediate feedback on whether I have a good enough image or not, so the user doesn't, like, take a picture, hold her breath for four seconds, have the software go "WRONG," try adjusting the book, take another picture, hold her breath...
Humans are incredibly good at trying new and random things when they get instant feedback. It's the basis of all learning for us, and it's an absolutely fundamental rule of UI design. (This is also the basis of the movement away from having modal dialogs that pop up and say, "Hey, you pressed a bad key!" If you have to pause and read and dismiss the dialog, the lesson you get is, "Stop trying to learn this program," not, "Try a different key."
The Mac and NeXTstep were pioneers in getting this right -- just beep if the user hits a wrong key, so if she wants she can lean on the whole keyboard and see if ANY keys are valid, and there's no punishment phase for it.)


Failing gracefully... That's key. It's in our blood ;)

Flexibility and accomdating clients

Last entry I covered the differences between flexible and static methods of deployment and the conclusion at the end was a mix of the two. It has been my experience that the best way to mix the two is ensure all variable information is gathered from the start. This does two things:

1) Eliminates technician wait time in that you shouldn't have to wait for a task to "catch up" till you can respond to it
2) Removes pauses that can extend the length of time an unsupervised process

To accomplish this we need ways of storing data from the client when they order the machine and a system of pulling the data out and configuring the machine.

STORING DATA:

Data can be stored in various fashions, a text-file is the fashion I use the most as it's simple, quick, and easy to parse. To generate a text file from a user's response we can use a simple batch script:
---------------------------
@ECHO OFF
set /p NAME=What is your name?
set /p OFFICE=Do you want MS OFFICE [y/n]?

ECHO %NAME% > "%userprofile%\desktop\responses.txt"
ECHO OFFICE-%OFFICE% >> "%userprofile%\desktop\responses.txt"
----------------------------

This will generate a text file that we can parse. The text file should look like this:

----------------------------
Trentent
OFFICE-y
----------------------------

We've now recorded some essential information to store for later when the time is required to utilize those responses.

To parse the file we can use tools such as find.exe the command FOR or IF.

Examples:
cd /d "%userprofile%\desktop"
for /f "tokens=*" %A IN (responses.txt) DO ECHO %A

This will bring two responses:
ECHO Trentent
ECHO OFFICE y

If we parse the file for known static "headers" (such as OFFICE) we can set variables for the stored responses.

FOR /F "TOKENS=* DELIMS= EOL=" %A IN ('findstr.exe /I "OFFICE" "%userprofile%\desktop\responses.txt"') DO SET OFFICE=%A

Now we can compare that value to determine if Office should be installed:
if /i '%OFFICE%' == 'OFFICE-y' (
ECHO Found Office
) ELSE (
ECHO Office NOT found
)

So if Office is found we can install it via a silent install command line.

So this lesson taught us to store reponses to be retrieved later. Stored responses can happen at any time -- when a user configures a system off a website, off a spreadsheet. These responses need to be stored in a known location such as a file share, in a database or downloaded off a webpage (wget.exe).

Monday, July 31, 2006

Working oneself out of a job

While working at Voodoo I've befriended an extremely bright individual, Trevor K. I dont' believe he has a blog but he is an extermely interesting person with the way he is able to describe situations. He puts into words a very simple explanation of a complex idea. One of his ideas that he has told me I've put into a personal mission of mine:

To work myself out of my current job.

Now, it may sound crazy but if I can do that, I'll must have done something amazing. Staples takes this concept and runs with it a little bit with their easy button concept. If you could develop your job into something so easy to do that all you had to do was push a button, wouldn't that be incredible. Now, offer that up to companies and see what they'll say. I'm sure they'd jump at the chance to take on someone with such a vision. Truly, I'm blessed to have such a visionary friend :)

Anyways, this takes me to my current post and my current topic of discussion. At Voodoo I developed a software and testing system that would completely software a machine based on the SKU's you ordered and then run a whole suite of applications and games to test the machines. It did this all based on your order number. All the technician had to do was type the number in and he was done. As a customer you could change your order and software mix right up to the day of testing and the technician didn't have to worry about double or triple checking each and every order to ensure it was correct, the system did it for you. Even better was ensuring each machine was softwared the same way excluding the variations between orders. After softwaring all scores and hardware were recorded with future plans to give the sales people that information to better make a sale.

Anyways, I've now moved on from Voodoo but am bringing my skills with me to help push for a flexible automated system of deployment in a corporate environment. My ideal system of deployment would be as such:

1. Client orders a system
2. System is ordered
3. System arrives, plug system into network
4. System is softwared automatically with the clients choices

At Voodoo I got very close to accomplishing this before I left. At Haworth it is an interesting challenge to get Haworth up to and hopefully surpass this.

So, lets look at some methods of softwaring (which, BTW is NOT a word as I learned very rudely one day) systems.

Starting from the very beginning is the plain jane off a CD. It's very slow and time consuming having to manually enter and install each piece of software, but it's EXTERMELY flexible.

There are ways of speeding it up, though that usually takes away flexibility. Going along with it for now, some low-hanging fruit is to automate the entry of common data. In Windows this is most easily done by using unattend.txt files or sysprep.inf files which contain answers to those annoying dialog boxes. So that's low-hanging fruit number one. The other is to automate duplicated procedures. This is having to install the same application over and over and over again. In Windows you can automate this process with silent installs. Differing installers have different ways of automating (or silencing) installs. Some have no way of being silent at all! Those that don't have a way of being automated require tools such as AutoIt.

So what do we have thus far? A very static way of doing installations. Flexibilty is a premium (if lean has taught me anything) and should be strived for as much as possible. There will always be information that will be the same across systems, but at the same time there will almost always be one thing that is different. So the best method is a mix of the two.

How can we mix the two? Well, we should start with some scenarios to help illustrate some pretty basic but creative ways of resolving this issue.

Corporation Fubar has two lines of desktop and a line of laptops they use in their organization. The desktops are completely different, ones an AMD with NVidia chipset and graphics while the other is an Intel with an Intel chipset and ATI graphics. The laptop is a basic intel system that requires special software.

Some corporations will use 3 base images for each of the three systems (very static) and update them as different hardware and software come in. Eventually, problems arise because one version gets of sync, a alot of effort is required to maintain them or different hardware requires even more images (say, the Intel desktop now comes with an Nvidia chipset and graphics).

What can you do? You could restrict employees to only use certain computers and start taking away their choices (but flexibility is a good thing right?) or we can come up with an IT solution that will give them their choice and make life equally easy (or dare I say easier) for us.

More for tomorrow, it's bed time right now ;)