2013
02.17
This weekend I had some fun with the SiriProxy project. It is a neat little hack that allows you to intercept Siri commands on your iphone and handle them locally when applicable. The github project does a great job of helping you get up and running, but chances are there will be a few steps that are slightly off and will require some finesse. Don’t be intimidated, just read through the snippets and google when necessary. You can get it going, I promise.

Super short overview of steps (c’mon, read the docs from the siriproxy link above!):

  1. setup dns masq, either on yer linux/mac box, or on dd-wrt
  2. install the RVM (this might take a while if you aren’t familiar with it)
  3. install siriproxy following their steps, and realize halfway thru that they have some of them out of order, read more docs and swear a bit, but then realize it wasn’t that bad
  4. generate a siriproxy certificate, email it to your phone and click to install (no jailbreak needed!)
  5. launch the proxy, fiddle with your wifi and dns until the test phrase “test siri proxy” actually works
  6. rejoice
  7. download one of the available plugins and begin to learn ruby!


I already have a local linux fileserver on the network, so it was an easy decision for me to utilize that as the home for this thing.  I began setting up DNS Masquerading (to allow you to reroute the Siri calls to our proxy without having to jailbreak your phone), but then quickly remembered: I am running dd-wrt on my router.  This means that I have dns masquerading built in, so I was able to simply add the necessary arguments to the ‘optional’ field, and everything was magically being sent to the right place.

I already have about 10 lamps around my home plugged into Insteon modules, and I was given some great advice to try out Perceptive Automation’s Indigo server to tie them all together.  This has been great in of itself, because it allows me to create “Action Groups” to combine tasks together.  For example, I have simple things like “bedroom off” that turns off all of the lights in my room when I’m ready for sleep, or “Movie Time”, that turns off some of the living room lights, and dims others to an appropriate level for watching television.  Combine this with a great (and free!) iOS application and I thought my home automation needs were completely met.  That is, until I realized I could just use my voice.

More googling showed me that my awesome Indigo server allowed me to access it via REST’ish commands, even with the cheapest license!  I knew I liked these guys.  I checked out their guide on doing so, and saw that I could definitely hack together a quick proof of concept for this project.

Given that I’ve never touched Ruby before, I wanted to see how some others were approaching it.  Luckily, github came to the rescue again.  I found hoopty3‘s plugin that he had written for the ISY99i, which used a very similar methodology as I would need.  Honestly, at this point all I had to really do was take the same approach and change the URL structure to match my needs.  Dead simple.

All in all, it was about 4-5 hours of playing around.. most of which was me trying to wrap my head around Ruby and how to approach it.  I’m still not there yet, but I have some good ideas on what to do next.  The biggest problem for me is that I typically have multiple lamps in a room.  This means that I can’t simply say “dim the lights” and make a single call.  Instead, I’m going to have to write out a small configuration file that lets ruby know which lamps are in each room, and then poll them to see if they are currently on, and if so, dim them appropriately.  This doesn’t really sound too bad, I’m just worried that making a “separate database” (outside of Indigo) to store this information is going to lead to confusion down the road, and I’m concerned that having ruby check the various levels for the room before taking action is going to take too long.  Admittedly, we’re talking about seconds here, but hey, I want immediate response!

This was definitely fun and worth a shot if you’re looking for something to try out.  It’s not 100% accurate, as there are many moving parts that can cause this to fail, but it’s pretty darned good and gives you awesome geek cred.

Points of failure I’ve encountered so far:

  • Sometimes Siri bypasses your proxy and talks to the real server and gets stuck there.  I’ve found that if I lock my phone and then re-open it, and THEN try to access Siri, it will go back to my server again.  But if you just keep asking it, it maintains its persistent connection to the real deal.
  • Sometimes your DHCP might not be setup how you think it is.  Meaning, it points you to someone else first, and you have to make sure you are only talking to the host running dns masq.
  • Sometimes the SiriProxy app just crashes.  If I dive into this one more I’ll need to make a watchdog service.
  • It’s hard to think up all the possible ways you might ask it to turn the lights on.  The English language provides a LOT of flexibility in this regard, and creating the regex to capture the various syntaxes is kinda quirky.  But, oddly fun.
2012
11.16
TL;DR – It is critical that my XBMC Library stays up to date with my fileserver, but I don’t want to deal with restarting XBMC, initiating a scan while watching, or using plugins. So I chose to use a web call.

You have to tell your XBMC to rescan your video shares routinely so that it can detect when new videos have been added, but this can be a bit of a chore. Sure, you can setup your software so that it pushes a Growl notification to XBMC, but there can be times where this doesn’t work perfectly, and a full scan is preferred. I have also heard some good things about some of the plugins that are available to do this very thing, such as XBMC Library Auto Update. But, I personally prefer to keep my XBMC as true to the released branch as possible because I don’t like tracking down non-core features when they decide to break.

Updating your library is generally a pretty quick process (less than a minute on a decent sized share) if your XBMC is running on a computer with a good CPU. But, if you are running a smaller client for a secondary room (for example, my RaspberryPi in the bedroom), this will take a long time. So long that you’d rather stand up and walk to the other room to do it from there. So long that you decide to remove the option from the screen so that your significant-other doesn’t press it.

Now, there are several ways of being able to do this, but the reliability of it is going to depend largely on your setup and how things startup and shutdown. Barring all of that, I wanted a way to remotely initiate an Update that would always work on a schedule I could set.

As is often the case in my life, the answer turned out to be my linux fileserver and cron. In my house, my linux fileserver has the best uptime. Without it, none of my TVs are going to work anyway, so it made sense for me to set up the cron job on there. Some people will naturally scream that I am adding an unnecessary step to this procedure and that I should run it on the machine that is hosting XBMC. I don’t disagree, but I’m gonna do it my way anyway. Mostly because I’m more likely to remember that my linux fileserver has cron jobs set, and might forget that I’ve done so on my mac mini.

Important Note: this should be obvious, but you MUST have the XBMC Webserver enabled in the xbmc settings. You can easily tell if you do by loading up a browser and going to http://IP-OF-XBMC:8080/ — if you are greeted by an XBMC webpage, then you are already good. If not, go into your settings and enable it.

After a few minutes of reading the XBMC JSON API documentation, I finally started to get a handle on how to send this command. Honestly, it confused me quite a bit initially because I haven’t really worked with JSON before, but I’m a good googler and managed to put the pieces together. It wasn’t as straightforward as I had hoped, because you need to add some extra flags to curl to get it to post via json with the right method and content-type.

# curl -H “Accept: application/json” -H “Content-type: application/json” -X POST -d ‘{“jsonrpc”: “2.0″, “method”: “VideoLibrary.Scan”, “id”: 1}’ http://IP-OF-XBMC:8080/jsonrpc


Works great. So now let’s add it to cron so that it will update at least every hour, if all of my other methods fail.

# crontab -l 0 * * * * * curl -H “Accept: application/json” -H “Content-type: application/json” -X POST -d ‘{“jsonrpc”: “2.0″, “method”: “VideoLibrary.Scan”, “id”: 1}’ http://IP-OF-XBMC:8080/jsonrpc 1>/dev/null 2>/dev/null


Now I know that my library will never be more than an hour out of sync, and I can easily adjust the cron times as needed! Mission accomplished.

2012
11.01
I have been slowly migrating to a Raspberry Pi for my media front-end.  One of the final components that I have been waiting on was a USB IR receiver: FLIRC.  It arrived today, so off we go!  I have several Logitech Harmony One remotes that I use in different rooms, and some research showed that Flirc worked amazingly well as an XBMC remote receiver.  After a few minutes of working with logitech’s configuration software, I was up and running.

There is not currently a method of programming the FLIRC from the RPi, so you’re going to need another computer.  I pulled out my laptop and got started with it by downloading the appropriate software from FLIRC. FWIW, I used the Windows version because the one for OS X kept crashing.

Note: all of these steps work properly for any device that supports wireless keyboards (PC, Mac, RPi, etc). The Flirc simply emulates a usb keyboard when talking to the OS.

Step 1 – Open your logitech Harmony Remote Software and Add a new Device.  I found an interesting post over at the Flirc forums that explains which device you should select.

Unfortunately not all device settings for the harmony are they same – some better than others.

A super helpful forum user; Eskro, has found what I have verified as a better device setting for the following reasons:

  • It enables key repeat even on cheaper harmony remotes (e.g. 300i)
  • All remotes signals are recognised as different by FLIRC
Manufacturer: Panasonic
Device: TC-P65VT30

-or-

Manufacturer: Samsung
Device: LN46C650L1F
Add one of those 2 devices mentioned, and then rename the device to something more meaningful like “XBMC Remote”.

Step 2 – Add a new Activity that utilizes the Device you just setup.  Use the settings you would use to display XBMC on your TV (selecting the proper inputs, etc), and finally rename the Activity to something like “Watch XBMC”.

Step 3 – Customize the buttons to get the most out of Flirc.  You’ll want to add a few commands that are missing from the normal remote.  Again, it doesn’t matter what you associate them to, so long as it is not in use somewhere else on the remote. (eg, don’t map the up arrow to something, as it is already assigned to the up arrow on the remote).  For informational purposes, here is what I chose:

  • Assigned Rewind button to “Rewind”
  • Assigned Skip Back button to “InputHdmi1″
  • Assigned Fast Forward button to “FastForward”
  • Assigned Skip Forward button to “InputHdmi4″
  • Assigned Play button to “InputHdmi2″
  • Assigned Pause button to “InputHdmi2″ (intentionally)
  • Assigned Stop button to “Stop”
Step 4 – Click “Additional Buttons” and get rid of all of the default selections they have created, and replace it with something like the following:

  • Toggle Subtitles -> ClosedCaption
  • Mark as Watched -> SAP
  • Update Library -> SubMenu
For reference, I have included screenshots of my button configuration below.



Step 5 – Update Remote.

Step 6 – Grab a laptop and download and install the appropriate software from Flirc.. Launch the software, and plug in your Flirc to a usb port.  You should see the software say “Connected”.  Under the Controllers menu, you will see a few options.  The intuitive choice would be “XBMC” since it is listed there, but I decided to go with “Full Keyboard” instead after trying it out.  I didn’t like how limited the XBMC mapping was, and I wanted to control some of the deeper options; particularly the ability to do short jumps ahead and long jumps.

Step 7 – Grab a piece of paper to jot down some notes, and head over to the XBMC Wiki to view the full list of keyboard shortcuts.  Here are the ones that I chose:

  • BUTTON NAME | KEY | COMMAND SENT
  • Menu | C | Contextual Menu
  • Info | I | Info
  • OK | enter | Select
  • Prev | Esc | Previous Menu
  • Up | Up | Up
  • Right | Right | Right
  • Down | Down | Down
  • Left | Left | Left
  • Skip Back | ‘ |  | Small Step Back (7 sec)
  • Skip Forward | . | Skip Forward (30 sec)
  • Rewind | R | Rewind
  • Fast Forward | F | Fast Forward
  • Stop | X | Stop
  • Play | Space | Play/Pause
Step 8 – Return to your Flirc application, with the Full Keyboard up and begin clicking the keys corresponding to your list (or mine above) along with the appropriate buttons for your Harmony One remote. If you are using the same exact commands I have listed above, you can skip this part and download my flirc config, then apply it using the menu option to Load Configuration within the Flirc application.

Step 9 – Once you have completed this process, go into the Flirc menu and choose Save Configuration.

Step 10 – Unplug the Flirc and bring it to your Raspberry Pi (or whatever computer/device that is running XBMC). Plug it in, and give it a test! If you are having problems with scroll rates or multiple key presses (I didn’t) then be sure to check the Flirc forums for information on how to fix it – Flirc Forum post on Harmony Remotes.
2012
10.31
Note: This project has been changed a lot, and I need to rewrite this post. Until then, I suggest visiting my github page below
Updated: 11.17.2012 — Created github repo for cssterm package

Description:
web package to easily display a linux terminal with css and javascript — Read more

Download as zip Download as tar.gz


Don’t care about the background, and just want to see how to use it?

I know that I will be sharing a lot of linux tips, fixes, and information on here, since it is one of my primary passions and something I deal with on a daily basis.  So, I’ve been wondering how to best display linux commands in a meaningful and attractive way on a blog.  Over the years I’ve seen a lot of good methods for this used in tech books and random websites, but now that the task was set upon me I couldn’t think of a single one.  So I stalled while I thought of what to do.

After a lot of googling (to make sure there weren’t any clear suggestions out there; I didn’t find much with my search terms at least) and soul searching, I decided that I wanted to steal some of the clever CSS that is out there and morph it a bit to my purposes.

As I said, I wanted it to be very clear to the reader that the text they were reading were either commands that should be run, or output from having run a command.  There’s an awesome project that you are likely familiar with (and if not, scroll down a bit and you will be) called SyntaxHighlighter that does this for code.  JavaScript parses the webpage and reformats it based upon what language you are discussing, and it is very useful.  Sadly, nothing like this seems to exist for my purposes, so I figured I would put something together; the goal being to make it as easy as possible for others to follow suit.

The Requirements

  • Pure CSS if possible. I would rather avoid calling images (which in turn means I don’t have to see what the common thread is for image hosting amongst the various blog options.  See? I’m always thinking of you!)
  • Easy syntax.  I won’t remember the 15 layers of divs required, so I need some code to do that for me.  At this point, I’ve accepted that there is going to be javascript involved.
  • I’m not a great coder, so it should be based off an existing, common library.  Some of it is going to have to be mine, but why limit myself to my own talents (and follies) if it isn’t necessary.

Stealing from the community

We all post this stuff because we’re trying to make the web more useful, right?  So why start on my own when I can get some ideas from other people and avoid some of the grunt work.  I like to consider this a private brainstorming session between me and the rest of the world.

The first thing I searched for was some clever CSS.  That led me to CSS Deck which seems to have a lot of really amazing ideas and examples.  On there I actually found several examples that mimicked the OS X terminal, but none for linux.  But hey, close enough right?  At least, close enough for me to use what they have and just tweak it a bit..  The one that I liked most was the ‘pure css osx terminal’.

A few sample tests on my wordpress page and I could see that this was going to work just fine.  But, as I feared, it involved a lot of nested div tags.  This is perfectly understandable and acceptable for a random part of your website, but not for daily use.  So, we’re gonna have to use some javascript.

My mind immediately went to jQuery.  I’ve used it a few times on different websites and it is not only a pleasure to work with, but a very powerful tool.  At least, for a man of my ability.  I also seemed to recall a function within it that was used to look for tags in the html, and replace it with more complex (and dynamic) code.  This worked out quite well, and I’m happy with having jquery as a requirement given how widespread it is amongst sites to begin with.

The Methods

I quickly realized that this isn’t a one-size-fits-all problem.  You need to be able to easily note how a line should be displayed without doing more formatting on your own.  My first considerations were the differences between “commands”, “comments”, and “stdout”.  So, a bit more scripting and we were able to accomplish this.

Now the following changes are automatically made in the javascript based on the first character of the line:

  • # – line should be formatted as a ‘command’
  • ! – line should be formatted as a ‘comment’
  • (nothing) – line should be formatted as standard output
The next thing that occurred to me is that sometimes you want to be able to signify a command in the middle of a paragraph, without creating an entire terminal window, but still matching the overall theme. A few quick updates to the CSS, and then we had it.

This…

Lorem ipsum dolor sit amet, consectetur. Donec euismod, risus ac 
auctor posuere, enim dolor fermentum libero, ut sagittis dui neque 
vel magna. Fusce odio tellus,<div class="terminal-oneliner">ls -al 
/usr/local/etc/zones/rev/</div> faucibus sit amet cursus vitae, 
cursus ac ligula

Becomes this…

Lorem ipsum dolor sit amet, consectetur. Donec euismod, risus ac auctor posuere, enim dolor fermentum libero, ut sagittis dui neque vel magna. Fusce odio tellus,
ls -al /usr/local/etc/zones/rev/
faucibus sit amet cursus vitae, cursus ac ligula

Conclusion

All in all, this worked out quite well. It was a short, fun project to get under my belt and hopefully is something I will use in many posts in the future. With any luck, it will help some of you out there too!

I am certain I will continue to tweak this more as I figure out exactly what my needs are and encounter situations where it doesn’t work quite right, but I would also love to hear from you if you have any suggestions or concerns about the methodology.

Off the top of my head, the only initial concern I have is regarding SEO. I’m wondering if the way that I have this placed inside of a div will affect search engines crawling the page and being confused by the lack of line breaks. I could alleviate this by putting it inside of pre tags instead, but I’m not sure that is necessary. If it is, I’ll be sure to report back.



I don’t care about the process, give me the code!


Demo


This…

<!-- you MUST include jquery for the rest of the javascript to work -->
<script src="http://code.jquery.com/jquery-latest.js"></script>
<div class="terminal">
! use the 'uptime' command to check current basic system health
# uptime
14:16:34 up 90 days,  9:26,  8 users,  load average: 0.94, 0.88, 0.83
! if you need to find out the kernel information, you want 'uname'
# uname -a
Linux vertigo 2.6.32-5-686 #1 SMP Mon Jan 16 16:04:25 UTC 2012 i686 GNU/Linux
</div>

Becomes this…

! use the ‘uptime’ command to check current basic system health # uptime 14:16:34 up 90 days, 9:26, 8 users, load average: 0.94, 0.88, 0.83 ! if you need to find out the kernel information, you want ‘uname’ # uname -a Linux vertigo 2.6.32-5-686 #1 SMP Mon Jan 16 16:04:25 UTC 2012 i686 GNU/Linux

CSS

/* FINDER WINDOW */
.terminal-oneliner{
   color: #63de00!important;
    padding: 0 4px 0 4px!important;
    margin-top:4px!important;
        margin-left: auto!important;
        margin-right: auto!important;
    margin-bottom:4px!important;
    border-radius: 5px!important;
    -webkit-box-shadow: 0px 0px 10px rgba(0,0,0,0.75)!important;
    -moz-box-shadow: 0px 0px 10px rgba(0,0,0,0.75)!important;
    /*-webkit-transition:all 0.5s; */
    overflow: hidden!important;
    display: inline !important;
    border:1px solid #6e8ba1!important;
    background: #000!important;
}

#terminal-window{
    width: 98%;
    margin-top:10px;
	margin-left: auto;
	margin-right: auto;
    margin-bottom:10px;
    min-width: 500px; 
    background: #fff;
    border-radius: 5px;
    -webkit-box-shadow: 0px 0px 20px rgba(0,0,0,0.75);
    -moz-box-shadow: 0px 0px 20px rgba(0,0,0,0.75);
    /*-webkit-transition:all 0.5s; */
    overflow: hidden; 
}

/* TOP BAR */
#terminal-toolbar{
    width: 100%; 
    height: 25px;
    background: grey;
    border-radius:5px 5px 0 0;

    background: #cfcfcf; /* Old browsers */
    background: -moz-linear-gradient(top,  #cfcfcf 0%, #a8a8a8 100%); /* FF3.6+ */
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#cfcfcf), color-stop(100%,#a8a8a8)); /* Chrome,Safari4+ */
    background: -webkit-linear-gradient(top,  #cfcfcf 0%,#a8a8a8 100%); /* Chrome10+,Safari5.1+ */
    background: -o-linear-gradient(top,  #cfcfcf 0%,#a8a8a8 100%); /* Opera 11.10+ */
    background: -ms-linear-gradient(top,  #cfcfcf 0%,#a8a8a8 100%); /* IE10+ */
    background: linear-gradient(top,  #cfcfcf 0%,#a8a8a8 100%); /* W3C */
    
    -webkit-box-shadow:0px 1px 0px rgba(255,255,255,0.5) inset,0px 1px 0px #515151;
    -moz-box-shadow:0px 1px 0px rgba(255,255,255,0.5) inset,0px 1px 0px #515151;
    box-shadow:0px 1px 0px rgba(255,255,255,0.5) inset,0px 1px 0px #515151;        
    
}
#terminal-toolbar .top{
    float: left; 
    width: 100%; 
    height: 23px;
}
#terminal-toolbar .bottom{
    float: left; 
    width: 100%; 
    height: 30px;
}

/*-----TRAFFIC LIGHTS-----*/
#terminal-toolbar #terminal-lights{
    float: left;
    position:relative;
    top:4px;
    left:7px; 
}
.terminal-light{
    float:left;
    width:14px;
    height:14px;
    border-radius:14px;
    -webkit-box-shadow:0px 1px 0px rgba(255,255,255,0.5),0px 0px 3px #000 inset;
    -moz-box-shadow:0px 1px 0px rgba(255,255,255,0.5),0px 0px 3px #000 inset;
    box-shadow:0px 1px 0px rgba(255,255,255,0.5),0px 0px 3px #000 inset;
    overflow: hidden;
}
#terminal-lights:hover .glyph{
    opacity: 1;
    cursor:default;
    
}
.terminal-light .terminal-shine{
     width: 4px;
     height:3px;
     border-radius:10px;
     /*background-image: -webkit-gradient(radial, center center, 0, center center, 3, from(rgba(255,255,255,1)), to(rgba(255,255,255,0)));*/
     background: -moz-radial-gradient(center, ellipse cover,  rgba(255,255,255,1) 0%, rgba(255,255,255,0) 100%); /* FF3.6+ */    
     background-image: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%,rgba(255,255,255,1)), color-stop(100%,rgba(255,255,255,0))); /* Chrome,Safari4+ */
     background: -webkit-radial-gradient(center, ellipse cover,  rgba(255,255,255,1) 0%,rgba(255,255,255,0) 100%); /* Chrome10+,Safari5.1+ */
     background: -o-radial-gradient(center, ellipse cover,  rgba(255,255,255,1) 0%,rgba(255,255,255,0) 100%); /* Opera 12+ */
     background: -ms-radial-gradient(center, ellipse cover,  rgba(255,255,255,1) 0%,rgba(255,255,255,0) 100%); /* IE10+ */
     background: radial-gradient(center, ellipse cover,  rgba(255,255,255,1) 0%,rgba(255,255,255,0) 100%); /* W3C */
     
}
.terminal-light .terminal-glow{
    width:14px;
    height:8px; 
    background-image: -webkit-gradient(radial, center bottom, 0, center center, 5, from(rgba(255,255,255,0.75)), to(rgba(255,255,255,0)));
    background: 0px 0px -moz-radial-gradient(bottom, cover,  rgba(255,255,255,0.70) 0%, rgba(255,255,255,0) 80%); /* FF3.6+ */
   
}
/*--RED--*/
.terminal-red{
   background: #f41b16; /* Old browsers */
   background: -moz-linear-gradient(top,  #f41b16 0%, #fc7471 100%); /* FF3.6+ */
   background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f41b16), color-stop(100%,#fc7471)); /* Chrome,Safari4+ */
   background: -webkit-linear-gradient(top,  #f41b16 0%,#fc7471 100%); /* Chrome10+,Safari5.1+ */
   background: -o-linear-gradient(top,  #f41b16 0%,#fc7471 100%); /* Opera 11.10+ */
   background: -ms-linear-gradient(top,  #f41b16 0%,#fc7471 100%); /* IE10+ */
   background: linear-gradient(top,  #f41b16 0%,#fc7471 100%); /* W3C */   
}
.terminal-red:active{
     
    background: #972f2e; /* Old browsers */
    background: -moz-linear-gradient(top,  #972f2e 0%, #fc7471 100%); /* FF3.6+ */
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#972f2e), color-stop(100%,#fc7471)); /* Chrome,Safari4+ */
    background: -webkit-linear-gradient(top,  #972f2e 0%,#fc7471 100%); /* Chrome10+,Safari5.1+ */
    background: -o-linear-gradient(top,  #972f2e 0%,#fc7471 100%); /* Opera 11.10+ */
    background: -ms-linear-gradient(top,  #972f2e 0%,#fc7471 100%); /* IE10+ */
    background: linear-gradient(top,  #972f2e 0%,#fc7471 100%); /* W3C */    
}
.terminal-red .terminal-shine{    
    position: relative;
    top: -23px;
    left: 5px;  
}
.terminal-red .terminal-glow{
    position: relative;
    top: -22px;
}
.terminal-red .terminal-glyph{
    position: relative;
    top: -6px;
    left: 3px;
    font-size: 14px;
    font-weight: bold;
    color: #9b3a36;
    z-index: 50;
    opacity: 0;
}
/*--YELLOW--*/
.terminal-yellow{
    background: #f4a316; /* Old browsers */
    background: -moz-linear-gradient(left,  #f4a316 0%, #fcc371 100%); /* FF3.6+ */
    background: -webkit-gradient(linear, left top, right top, color-stop(0%,#f4a316), color-stop(100%,#fcc371)); /* Chrome,Safari4+ */
    background: -webkit-linear-gradient(left,  #f4a316 0%,#fcc371 100%); /* Chrome10+,Safari5.1+ */
    background: -o-linear-gradient(left,  #f4a316 0%,#fcc371 100%); /* Opera 11.10+ */
    background: -ms-linear-gradient(left,  #f4a316 0%,#fcc371 100%); /* IE10+ */
    background: linear-gradient(left,  #f4a316 0%,#fcc371 100%); /* W3C */  
    margin:0px 7px;
}
.terminal-yellow:active{
    background: #ae4f1e; /* Old browsers */
    background: -moz-linear-gradient(top,  #ae4f1e 0%, #fcc371 100%); /* FF3.6+ */
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ae4f1e), color-stop(100%,#fcc371)); /* Chrome,Safari4+ */
    background: -webkit-linear-gradient(top,  #ae4f1e 0%,#fcc371 100%); /* Chrome10+,Safari5.1+ */
    background: -o-linear-gradient(top,  #ae4f1e 0%,#fcc371 100%); /* Opera 11.10+ */
    background: -ms-linear-gradient(top,  #ae4f1e 0%,#fcc371 100%); /* IE10+ */
    background: linear-gradient(top,  #ae4f1e 0%,#fcc371 100%); /* W3C */    
}
.terminal-yellow .terminal-shine{ 
    position: relative;
    top: -23px;
    left: 5px;  
}
.terminal-yellow .terminal-glow{
    position: relative;
    top: -22px;
}


.terminal-yellow .terminal-glyph{
    position: relative;
    top: -7px;
    left: 4px;
    font-size: 24px;
    color: #854322;
    z-index: 50;
    opacity: 0;
    -webkit-transform: scaleY(1.5) scaleX(1.3);
}

/*--GREEN--*/
.terminal-green{
    
    background: #4cae2e; /* Old browsers */
    background: -moz-linear-gradient(top,  #4cae2e 0%, #dafc71 100%); /* FF3.6+ */
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#4cae2e), color-stop(100%,#dafc71)); /* Chrome,Safari4+ */
    background: -webkit-linear-gradient(top,  #4cae2e 0%,#dafc71 100%); /* Chrome10+,Safari5.1+ */
    background: -o-linear-gradient(top,  #4cae2e 0%,#dafc71 100%); /* Opera 11.10+ */
    background: -ms-linear-gradient(top,  #4cae2e 0%,#dafc71 100%); /* IE10+ */
    background: linear-gradient(top,  #4cae2e 0%,#dafc71 100%); /* W3C */
    
}
.terminal-green:active{
  background: #48752b; /* Old browsers */
  background: -moz-linear-gradient(top,  #48752b 0%, #dafc71 100%); /* FF3.6+ */
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#48752b), color-stop(100%,#dafc71)); /* Chrome,Safari4+ */
  background: -webkit-linear-gradient(top,  #48752b 0%,#dafc71 100%); /* Chrome10+,Safari5.1+ */
  background: -o-linear-gradient(top,  #48752b 0%,#dafc71 100%); /* Opera 11.10+ */
  background: -ms-linear-gradient(top,  #48752b 0%,#dafc71 100%); /* IE10+ */
  background: linear-gradient(top,  #48752b 0%,#dafc71 100%); /* W3C */
  
}
.terminal-green .terminal-shine{  
    position: relative;
    top: -22px;
    left: 5px; 
}
.terminal-green .terminal-glow{
    position: relative;
    top: -22px;
}
.terminal-green .terminal-glyph{
    position: relative;
    top: -6px;
    left: 3px;
    font-size: 14px;
    font-weight: bold;
    color: #25571d;
    z-index: 50;
    opacity: 0;
}

/* Horrible to do this for firefox */
@-moz-document url-prefix() {
  
  .terminal-red .terminal-glyph {
      position: relative;
      top: -4px;
  }  
  .terminal-yellow .terminal-glyph {
      top: -4px;
      left: 3px;
  }
    
  .terminal-green .terminal-glyph{
      position: relative;
      top: -4px;
  }
  
}

/*-----TITLE-----*/
#terminal-title{
    float: left; 
    position: relative;
    top:4px;
    width:40%;
    left: 30%;
    font-family: "Myriad Pro", sans-serif; 
    color: black;
    font-size: 14px; 
    text-shadow: 0px 1px 0px rgba(255,255,255,0.5);
    line-height: 14px; 
}
.terminal-body{
    width: 14px;
    height: 10px;
    border:1px solid #6e8ba1;
    
    background: #b8cfe0; /* Old browsers */
    background: -moz-linear-gradient(top,  #b8cfe0 0%, #86adc8 100%); /* FF3.6+ */
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b8cfe0), color-stop(100%,#86adc8)); /* Chrome,Safari4+ */
    background: -webkit-linear-gradient(top,  #b8cfe0 0%,#86adc8 100%); /* Chrome10+,Safari5.1+ */
    background: -o-linear-gradient(top,  #b8cfe0 0%,#86adc8 100%); /* Opera 11.10+ */
    background: -ms-linear-gradient(top,  #b8cfe0 0%,#86adc8 100%); /* IE10+ */
    background: linear-gradient(top,  #b8cfe0 0%,#86adc8 100%); /* W3C */    
    
    z-index: -50;
    
    -webkit-box-shadow:0px 1px 0px rgba(255,255,255,0.25) inset,0px 1px 0px rgba(0,0,0,0.2);
    -moz-box-shadow:0px 1px 0px rgba(255,255,255,0.25) inset,0px 1px 0px rgba(0,0,0,0.2);
}

#terminal-body {
    font-family: Andale Mono, monospace;  line-height: 1em;
    font-size:13px;
    float: left;
    width: 100%;
    min-height:130px;
    background:#000;
    padding:10px;
    line-height:1.5em;
}
#terminal-body p { 
   color: #63de00!important; 
   line-height: 200% !important;
}

@keyframes blink
{
	0%   {  background:rgba(99,222,0,100);  }
	100% {  background:rgba(99,222,0,0);  }
}

@-webkit-keyframes blink {
	0%   {  background:rgba(99,222,0,100);  }
	100% {  background:rgba(99,222,0,0);  }
}
@-moz-keyframes blink {
	0%   {  background:rgba(99,222,0,100);  }
	100% {  background:rgba(99,222,0,0);  }
}
.terminal-cursor {
  background:#63de00; 
  display:inline-block;
  width:11px;
  height:19px;
  margin-bottom:-3px;
}
#terminal-body:hover .terminal-cursor {
    -webkit-animation-name: blink;
    -webkit-animation-duration: 1.5s;
    -webkit-animation-iteration-count: infinite;
    -moz-animation-name: blink;
    -moz-animation-duration: 1.5s;
    -moz-animation-iteration-count: infinite;
}
  
#terminal-body p::-webkit-selection  {
    background:#0b209e;
}
#terminal-body p::selection { background:#0b209e; }
#terminal-body p::-moz-selection { background:#0b209e; }

#terminal-body p {
  margin-top:5px;
  margin-bottom:5px;
  font-size:11px;
}

.terminal-comment{
    border:solid 1px #666666; 
    background:#333333;
    color:#CCCCCC;
    margin-left:2px;
    width: 94%;
}

HTML

<!-- you MUST include jquery (somewhere on your site) for the rest of the javascript to work -->
<script src="http://code.jquery.com/jquery-latest.js"></script>
<div class="terminal">
! use the 'uptime' command to check current basic system health
# uptime
14:16:34 up 90 days,  9:26,  8 users,  load average: 0.94, 0.88, 0.83
! if you need to find out the kernel information, you want 'uname'
# uname -a
Linux vertigo 2.6.32-5-686 #1 SMP Mon Jan 16 16:04:25 UTC 2012 i686 GNU/Linux
</div>

JAVASCRIPT

$(document).ready(function(){
	var rstr = /^#/gi;
	var cstr = /^!/gi;
	var sstr = /^>/gi;

	var rprompt = "[root@localhost]# ";
	var comment = "<div class='terminal-comment'>";
	var stdout = "&nbsp;";

	var termTop = "<div id=\"terminal-window\"> \
 	<div id=\"terminal-toolbar\"> \
		<div class=\"terminal-top\"> \
			<div id=\"terminal-lights\"> \
				<div class=\"terminal-light terminal-red\"> \
					<div class=\"terminal-glyph\">×</div> \
					<div class=\"terminal-shine\"></div> \
					<div class=\"terminal-glow\"></div> \
				</div>				 \
				<div class=\"terminal-light terminal-yellow\"> \
					<div class=\"terminal-glyph\">-</div> \
					<div class=\"terminal-shine\"></div> \
					<div class=\"terminal-glow\"></div> \
				</div> \
				<div class=\"terminal-light terminal-green\"> \
					<div class=\"terminal-glyph\">+</div> \
					<div class=\"terminal-shine\"></div> \
					<div class=\"terminal-glow\"></div> \
				</div> \
			</div> \
			<div id=\"terminal-title\"> \
				Terminal - ~: root@localhost: ~ \
			</div> \
			<div id=\"terminal-bubble\"> \
				<div class=\"terminal-shine\"></div> \
				<div class=\"terminal-glow\"></div> \
			</div> \
		</div> \
	</div> \
	<div id=\"terminal-body\"><p> \
";


	var termBot = "</p> \
		<div class=\"terminal-cursor\"></div> \
	</div> \
</div> \
";

	$(".terminal").each(function(){
	var myContent = $(this).text();
	var arrayContent = myContent.split('\n');
	var newString = "";
	jQuery.each(arrayContent, function() {
		// make sure there's text to avoid blank spaces
		if (this.length != 0 ) {
			// is string a root command
			if (this.charAt(0) == "#") {
				newString += this.replace(rstr, rprompt).concat("<br>\n");
			// is string a comment (don't forget to close that div)
			} else if (this.charAt(0) == "!") {
				newString += "</p>" + this.replace(cstr, comment).concat("</div>\n<p>");
			// must be stdout
			} else {
				newString += stdout + this + "<br>\n";
			}
		}
	});
	$(this).replaceWith( termTop + newString + termBot);
	});
});
2011
03.29
Recap: I got a brand new Pioneer head unit at the end of 2005, and quickly became frustrated by the interface for it’s many options. The controls for accessing the ipod and sirius were beyond ridiculous: you had to go into a function menu, f1-f4 to access things like “repeat” or “scroll title” or “pause”. Ignore the fact that the unit has both a pause button and a display scroll button RIGHT ON THE FRONT OF THE DECK!@#$!@% I was so mad that when I was at CES in vegas the following January, I went over to the pioneer booth to ask them why they would put out a product like that, and when I could expect a firmware update to fix it. He explained that that wasn’t gonna happen, and that I should “ebay that one, and buy this years model”. I retorted by asking why I should continue to be a lifetime pioneer customer instead of going to buy from Alpine, to which he explained I would suffer the same problems. After giving it some more thought, I realized that he was right and that the entire industry was built upon the need to limit the options and force you to upgrade since the hardware itself would last too long (for their liking).

So, I came home from vegas and promptly ripped the entire thing out of my truck deciding that I would no longer support that industry when I could come up with a perfectly fine solution myself. I first saw computers being placed in cars in 1999, so I figured that by 2006 it should be downright easy. I was mostly right. There is a pretty decent community for this, though admittedly it seems to have reduced a lot now that in-car mobile computing solutions are becoming an OEM option. But the opensource software is there, and there are plenty of hardware options so it’s not too hard. Normal learning curves apply.

As with any good homebrew project, it requires constant maintenance on my part. This is certainly a bit frustrating, and has led to me largely ignoring the unit for the past 2 years. I was faced with a buggy PSU that I needed to replace (which means pulling the seats out of my truck and futzing with the wiring) and I’d just purchased an iPhone.. so suddenly my new toy with earbuds made it less important to get the CarPC running again. This year I’ve finally decided to get back to work on it and make a robust solution that will (hopefully) solve the various minor bugs and allow for easy reinstallation should things go awry. I’ll be posting about that here I guess.

Here are 3 quick shots of the process to get an idea of how it turned out… If you want to see the entire build process (at least, as often as I could remember to grab the camera) you can visit the gallery.

It started off like this... (please ignore the gross soda drips, thx)

And for a while it looked like this...

Eventually becoming this



System Specs (as of 2007)

  • 10.2 inch Xenarc Touchscreen
  • Jetway Hybrid J7F2WE2G motherboard
    • VIA C7 2 GHz processor
    • Integrated VIA UniChrome Pro AGP graphics with MPEG-2 accelerator
    • VIA 1617A 6 channel AC’97 codec
    • Embedded TV encoder, SATA, USB, 1 PCI slot
    • 512mb DDR2 ram
  • 16gb RocketDisk Solid State Drive for OS
  • 100gb 2.5″ 5400rpm storage drive for music and video
  • Obnoxiously large Griffin Powermate knob for volume, etc (macro programmable)
  • 1 poorly glued usb connector cut into the dash
  • An amp and some speakers that I can’t recall the branding of atm…

Functionality (as of 2007)

  • Anything you can do on a 2ghz XP pc… but as for nice integrations..
  • RideRunner front-end provides a skinned environment for all needs
  • Winamp is the audio player of choice
  • iGuidance GPS ties nicely into riderunner
  • Windows Media Player classic is used for video due to it’s light weight and overall compatibility
  • Sirius Satellite Radio being pulled via swapped out controller board on an Alpine unit.  Delivers audio out into the line-in and is controlled via the serial port
  • Zyxel wireless box used to bridge to nearby access points (never worked great)
2011
02.10
I was recently faced with getting an installation of kaltura video server running on a fully up to date CentOS 5.5 server.  This sounded like a normal/easy LAMP install that I expected to have online with an hour or so, but it proved to be more difficult due to the requirements of the software.

When I ran the install script, I was told the following:
One or more prerequisites required to install Kaltura failed:PHP version should be >= (current version is 5.1.6) MySQL version should be >= 5.1.33 (current version is 5.0.77)
This was problematic as the main CentOS repo did not have those versions, and trying to do a manual upgrade of the MySQL rpm’s from their website resulted in package conflicts.

Luckily that changed when I googled up this page on using the remi repository.
! ## Remi Dependency on CentOS and Red Hat (RHEL) # rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-4.noarch.rpm # rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-5.rpm ! ## no longer needed in php 5.3, will cause dependency failures # yum remove php-mhash ! ## now you can actually install the packages you need # yum –enablerepo=remi,remi-test install mysql mysql-server memcached php-pecl-memcache
Now you should run
mysql_upgrade
to upgrade your tables for the latest 5.5 release and try to run the
php install.php
from within the kaltura installer again.

If you encounter an error when setting up the database, check the install log file in the install directory to see what the error is.

If it is similar to this:
09.02.2011 11:06:06 ERROR Executing command failed: ERROR 1064 (42000) at line 2: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘Type=MyISAM’ at line 26
Then you simply need to edit package/app/app/deployment/base/sql/02.schema_updates.sql and replace “Type=MyISAM” with “Engine=MyISAM” (the new standard in 5.5).