• 201507.26

    Squeezebox setup without the remote/controller

    My dad recently gave me a Squeezebox for a present after he’d upgraded his home audio system. I was grateful but ultimately stumped on how to set it up. I read a bunch online about setting it up with the remote it comes with. Oh wait. Mine doesn’t have a remote.

    Let the fun begin.

    Connecting to the Squeezebox

    This is harder than it sounds. Initially, I tried wiring it into my router and seeing if it could see it. It could not. This was a WRT54G with Tomato firmware. Maybe the setups just weren’t compatible or something ridiculous like that.

    So I tried another way I found after poking around a lot: the Squeezebox has a build in wireless SSID that you can connect to in ad-hoc mode (after holding the only button for > 6 seconds and it enters reset/config mode).

    However, doing this is finicky and had me tearing my hair out. Ultimately, I got my Windows machine connected to it. When it connects, it gives your machine an IP in the 192.168.1.100-254 range. If it gives you a 169.xxx.xxx.xxx address, it’s game over. Try restarting your machine. Try resetting the Squeezebox. Try a rain dance while wearing a tribal loincloth. You just might get that IP.

    I recently bought a new router (Buffalo, w/ DD-WRT) and plugged the reset-mode Squeezebox into it (via LAN) and was able to connect to it instantly, so try that first and only go the ad-hoc wireless route if you absolutely have to.

    Talking to the Squeezebox

    The Net-UDAP software is amazing and wonderful. I don’t know what it does under the hood, but it lets you talk to your Squeezebox should you finally get connected to it in some capacity.

    Unless you’re on Windows. Yes, I know, it supposedly works on Windows but just didn’t find the Squeezebox with running discover.

    My only solution was to spin up a linux VM with a bridged network adapter and run Net-UDAP there instead. Worked flawlessly. Hopefully you have a linux box laying around, or maybe it will just work for you in Windows. Try the Windows perl binary instead of cygwin’s perl.

    Anyway, once you’ve got everything connected, you run the Net-UDAP like so:

    cd /path/to/net-udap
    ./scripts/udap_shell.pl -a 192.168.0.106
    

    Note that the 192.168.0.106 is the address for the machine you’re running the shell on, not the Squeezebox itself.

    You should get a prompt:

    UDAP> 
    

    Now run the discover command:

    UDAP> discover
    info: *** Broadcasting adv_discovery message to MAC address 00:00:00:00:00:00 on 255.255.255.255
    info:   adv_discovery response received from 69:69:69:69:69:69
    info: *** Broadcasting get_ip message to MAC address 69:69:69:69:69:69 on 255.255.255.255
    info:   get_ip response received from 69:69:69:69:69:69
    info: *** Broadcasting get_data message to MAC address 69:69:69:69:69:69 on 255.255.255.255
    info:   get_data response received from 69:69:69:69:69:69
    

    Hopefully you get output like that. If you get empty output, see “Connecting to the Squeezebox” =[.

    Setup

    Once that finicky little bastard is discovered, run list:

    UDAP> list  
     #    MAC Address    Type       Status
    == ================= ========== ===============
     1 69:69:69:69:69:69 squeezebox init
    

    You can see it has an ID of 1 so we do:

    UDAP> conf 1
    

    Your prompt will now change, and you’re in config mode:

    UDAP [1] (squeezebox 696969)>
    

    Now you can connect it to your network via wireless by setting values into its config. This will differ network to network, but here are the commands I run to get things working on a network with WPA2-PSK TKIP+AES:

    set hostname=jammy interface=0 lan_gateway=192.168.0.1 lan_ip_mode=1 primary_dns=192.168.0.1
    set wireless_SSID='my network SSID' wireless_wpa_mode=2 wireless_wpa_cipher=3 wireless_keylen=0 wireless_mode=0 wireless_region_id=4 wireless_wpa_on=1 wireless_wpa_psk='WPA passwordddd' wireless_channel=9
    set server_address=192.168.0.113
    

    For a list of the fields and what they mean, type fields:

    UDAP [1] (squeezebox 696969)> fields
                 bridging: Use device as a wireless bridge (not sure about this)
                 hostname: Device hostname (is this set automatically?)
                interface: 0 - wireless, 1 - wired (is set to 128 after factory reset)
              lan_gateway: IP address of default network gateway, (e.g. 192.168.1.1)
              lan_ip_mode: 0 - Use static IP details, 1 - use DHCP to discover IP details
      lan_network_address: IP address of device, (e.g. 192.168.1.10)
          lan_subnet_mask: Subnet mask of local network, (e.g. 255.255.255.0)
              primary_dns: IP address of primary DNS server
            secondary_dns: IP address of secondary DNS server
           server_address: IP address of currently active server (either Squeezenetwork or local server
    squeezecenter_address: IP address of local Squeezecenter server
       squeezecenter_name: Name of local Squeezecenter server (???)
            wireless_SSID: Wireless network name
         wireless_channel: Wireless channel (used by AdHoc mode???)
          wireless_keylen: Length of wireless key, (0 - 64-bit, 1 - 128-bit)
            wireless_mode: 0 - Infrastructure, 1 - Ad Hoc
       wireless_region_id: 4 - US, 6 - CA, 7 - AU, 13 - FR, 14 - EU, 16 - JP, 21 - TW, 23 - CH
       wireless_wep_key_0: WEP Key 0 - enter in hex
       wireless_wep_key_1: WEP Key 1 - enter in hex
       wireless_wep_key_2: WEP Key 2 - enter in hex
       wireless_wep_key_3: WEP Key 3 - enter in hex
          wireless_wep_on: 0 - WEP Off, 1 - WEP On
      wireless_wpa_cipher: 1 - TKIP, 2 - AES, 3 - TKIP & AES
        wireless_wpa_mode: 1 - WPA, 2 - WPA2
          wireless_wpa_on: 0 - WPA Off, 1 - WPA On
         wireless_wpa_psk: WPA Public Shared Key
    

    To see the values already set, run list when in config mode.

    Great, so you’ve set up all your network values and are confident that you’ve done it all right the first time. Good for you. Now you can run save_data:

    UDAP [1] (squeezebox 696969)> save_data
    info: *** Broadcasting set_data message to MAC address 69:69:69:69:69:69 on 255.255.255.255
    ucp_method set_data callback not implemented yet at /path/to/udap/../src/Net-UDAP/lib/Net/UDAP.pm line 292.
    Raw msg:
              00 01 02 03 04 05 06 07 - 08 09 0A 0B 0C 0D 0E 0F  0123456789ABCDEF
    
    00000000  00 02 00 00 00 00 00 00 - 00 01 00 04 20 16 5A 05  ............ .Z.
    00000010  00 01 C0 01 00 00 01 00 - 01 00 06 00 1A           .............
    info:   set_data response received from 69:69:69:69:69:69
    

    Make sure save_data returns a response similar to this. If it doesn’t, run it again. In fact, run it again anyway. Run it again…and again…and again.

    Great, now run reset to finalize everything:

    UDAP [1] (squeezebox 696969)> reset
    info: *** Broadcasting reset message to MAC address 69:69:69:69:69:69 on 255.255.255.255
    ucp_method reset callback not implemented yet at /path/to/udap/../src/Net-UDAP/lib/Net/UDAP.pm line 292.
    Raw msg:
              00 01 02 03 04 05 06 07 - 08 09 0A 0B 0C 0D 0E 0F  0123456789ABCDEF
    
    00000000  00 02 00 00 00 00 00 00 - 00 01 00 04 20 16 5A 05  ............ .Z.
    00000010  00 01 C0 01 00 00 01 00 - 01 00 04                 ...........
    info:   reset response received from 69:69:69:69:69:69
    

    All done. Now don’t ever change your network setup ever again or you’ll have to deal with this shit again. Or just get a fucking remote…

    Comments
  • 201401.22

    Debugging javascript in the default Android browser

    Note that this may or may not work on your device. If you're running into an app that works in a real browser but on in your Android's stock browser, do this:

    1. Navigate to your app in the browser.
    2. In the same tab go to about:debug
    3. Reload (it may reload for you).
    4. Profit.

    This will show you errors that even window.onerror doesn't catch, which should help you narrow down your problem(s).

    Source: This stackoverflow answer.

    Comments
  • 201011.21

    Vim: Cursor at beginning of tab in normal mode

    One thing that annoys me in Vim is that in normal mode, the cursor defaults to being at the end of a tab character. When I hit "Home" I expect the cursor to go all the way to the left, but instead it hovers 4 spaces to the right of where I expect it to. I stumbled across the answer after reading a mailing list thread for vim.

    set list lcs=tab:\ \ 
    " Note the extra space after the second \

    You can put this in your .vimrc to automatically set this behavior. Very useful.

    Comments
  • 200912.01

    SSH Agent on Cygwin

    There are probably a billion guides for this already, but whatever. If you DON'T have a ~/.bash_profile (a file that gets executed every time you start cyg):

    touch ~/.bash_profile
    chmod a+x ~/.bash_profile
    

    Now that you have the file, add this to it:

    SSHAGENT=/usr/bin/ssh-agent
    SSHAGENTARGS="-s"
    if [ -z "$SSH_AUTH_SOCK" -a -x "$SSHAGENT" ]; then
    	eval `$SSHAGENT $SSHAGENTARGS`
    	trap "kill $SSH_AGENT_PID" 0
    fi
    

    This will start up ssh-agent for each Cygwin shell you have open. Close your Cygwin shell (if one is open) and open a new one. Now type:

    ssh-add ~/.ssh/id_rsa
    [enter your password]
    

    Voila! No more typing your stupid password every time you need to ssh somewhere. Note that if you close the Cygwin window, you'll have to ssh-add your key again! This is good security...you can close the window when you're done and someone who happens on your computer sitting there won't have password-less access to any of your secure logins.

    Comments
  • 200912.01

    A simple (but long-winded) guide to REST web services

    After all my research on what it means for a service to be RESTful, I think I've finally got a very good understanding. Once you understand a critical mass of information on the subject, something clicks and the first thing that comes in to your head is "Oh yeah! That makes sense!"

    It's important to think of a REST web service as a web site. How does a website work?

    • A website works using HTTP. If you need to fetch something on a website, you use the HTTP verb "GET." If you need to change something, you use "POST." A RESTful web service uses other HTTP verbs as well, namely PUT and DELETE, and can also implement OPTIONS to show which methods are appropriate for a resource.
    • A website has resources. A resource can be information, images, flash, etc. These resources can have different representations: HTML, a jpeg, an embedded video. REST is the same way. It is resource-centric. Want a list of users? GET /users. Want an event? GET /events/5. Want to edit that event? PUT /events/5. Every resource has a unique URL to identify it!
    • Resources are not dealt with directly. Instead, representations of resources are used. This can be a bit hard to grasp. What is a user? It's a nebulous object somewhere that I cannot interact with. It is an idea, an entity. A representation is a form of the user resource I can interact with. A representation can be a comma delimited list, JSON, XML...anything the client and server both understand. How do we know what we're interacting with? Media types:
    • As a website will tell you what kind of image you're requesting, a REST service tells you what kind of resource representation you are receiving. This is done using media types. For instance, if I do a GET /events/7, the Content-Type may be "application/vnd.beeets.event+json" which tells us this is a vendor specific media (the "vnd") and it's an event in JSON format. You can pass these media types in your Accept headers to specify what type of representation you would like. These media types are documented somewhere so that client will know exactly what to expect when consuming them.
    • If you request a page that doesn't exist or you aren't authorized to view, a website will tell you. This is done using headers. A good REST service will utilize HTTP status headers to do the same. 200 Ok, 404 Not Found, 500 Internal Server Error, etc. These have already been defined and refined over many, many years by people who have been doing this a lot longer than you (probably)...use them.
    • A website will have links from one page to another. This is one of the main points of a REST service, and is also widely forgotten or misunderstood (it took me a while to figure it out even doing intense research). Resources in a REST service link to eachother, letting a client know what resources can be found where, and how they relate to eachother. An HTML page has links to it. So does a REST resource. Links can be structured however you like, but some good things to include are the URI of the linked resource, the relationship it has with the current resource, and the media type. This creates what's known as a "loose coupling" between client and server. A client can crawl the server and figure out, only knowing a pre-defined set of media types, what resources are where and how to find them. This principal is known as HATEOAS (or "Hypermedia as the Engine of Application State").
    • REST is stateless. This means that the server does not track any sort of client state. There are no session tokens the client uses to identify itself. There are no cookies set. Every request to the REST service must contain all information needed to make that request. Need to access a restricted resource? Send your authentication info for each request. It's that simple. Isn't it easier to track session? Not really. Maybe it's easier on a small level, but once you start needing to scale, you will wish you'd gone stateless. Using a combination of HTTP basic authentication and API/Secret request signing, you don't have to send over plain text passwords at all. Hell, even throw in a timestamp with each request to minimize replay attacks. You can get as crazy as you'd like with security. Or for those who prefer security over performance, use SSL.

    Now for some examples. Because I'm currently working on an event application, we'll use that for most of the examples.

    Let's get a list of events from our server:

    GET /events
    Host: api.beeets.com
    Accept: application/vnd.beeets.events+json
    {"page":1,"per_page":10}
    -----------------------------------------
    HTTP/1.1 200 OK
    Date: Tue, 01 Dec 2009 04:12:48 GMT
    Content-Length: 1430
    Content-Type: application/vnd.beeets.events+json
    {
    	"total":81,
    	"events":
    	[
    		{
    			"links":
    			[
    				{
    					"uri":"/events/6",
    					"rel":"/rel/event self edit",
    					"type":"application/vnd.beeets.event"
    				},
    				{
    					"uri":"/locations/121",
    					"rel":"/rel/location",
    					"type":"application/vnd.beeets.location"
    				}
    			],
    			"id":6,
    			"title":"Paris Hilton naked onstage",
    			...
    		},
    		...
    	]
    }

    What do we have? A list of events, with links to the resource representations of those events. Notice we also have links to another resource: the location. We can leave that for now, but let's pull up an event:

    GET /events/6
    Host: api.beeets.com
    Accept: application/vnd.beeets.event+json
    -----------------------------------------
    HTTP/1.1 200 OK
    Date: Tue, 01 Dec 2009 04:12:48 GMT
    Content-Length: 666
    Content-Type: application/vnd.beeets.event+json
    {
    	"links":
    	[
    		{
    			"uri":"/events/6",
    			"rel":"/rel/event self edit",
    			"type":"application/vnd.beeets.event"
    		},
    		{
    			"uri":"/locations/121",
    			"rel":"/rel/location",
    			"type":"application/vnd.beeets.location"
    		}
    	],
    	"id":6,
    	"title":"Paris Hilton naked onstage",
    	"date":"2009-12-05T04:00:00Z"
    }

    Using the link provided in the event listing, we managed to pull up an individual event, which we know how to parse because we know the media type...but wait, what's this? OMG, someone is trying to smear Paris!! She's on at 8:30!!! NOT 8!!! Let's edit...if we do a PUT with new information, we'll be able to save Paris' good name:

    PUT /events/6
    Host: api.beeets.com
    Accept: application/vnd.beeets.event+json
    Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
    {"title":"Paris Hilton naked onstage (yuck)","date":"2009-12-05T04:30:00Z"}
    -----------------------------------------
    HTTP/1.1 200 OK
    Date: Tue, 01 Dec 2009 04:12:48 GMT
    Content-Length: 666
    Content-Type: application/vnd.beeets.event+json
    {
    	"links":
    	[
    		{
    			"uri":"/events/6",
    			"rel":"/rel/event self edit",
    			"type":"application/vnd.beeets.event"
    		},
    		{
    			"uri":"/locations/121",
    			"rel":"/rel/location",
    			"type":"application/vnd.beeets.location"
    		}
    	],
    	"id":6,
    	"title":"Paris Hilton naked onstage (yuck)",
    	"date":"2009-12-05T04:30:00Z"
    }

    What have we learned? Given one URL (/events), we have discovered two more (/locations/[id] and /events/[id]). We've also seen the media types in the responses that allow the client to know what kind of resource it's dealing with and how to consume it.

    Hopefully this pounds two really important points in: media types and HATEOAS. Without them, it's not REST. You can't just pass application/xml or application/json for every response. Sure, maybe the client can decode it, but they don't know what it is, and without linking to other resources, they don't know how to find anything...unless you want to document everything and never change your service.

    Some other tips/points:

    • Give yourself a few initial entry points to your REST service. You should be able to discover all of the resources in it just by crawling. If you can't, you haven't done HATEOAS correctly. This is a lot harder than it sounds, but it's more than useful later on. Think of your REST service like a website with good navigation.
    • Remember to implement the OPTIONS verb for your resources. It will tell the client what verbs can be used on what resources. With some decent routing built into your application, this should be a cakewalk.
    • As mentioned, you can use HTTP basic authentication for your requests. If the client is anything but a web browser, you won't have to serve up an ugly popup login box, you can just do all that shit transparently. If you don't want to send a cleartext password (please don't!) you can salt the password on the client side and send it over. Hash the password again with the client's secret for added security. Crackers will be amazed at your 1337 computer hacking skillz. You can then verify the hashed salted value on the server side. Add client-secret request signing with a timestamp for uber security.
    • Read a lot more info on REST. It seems that SO many "RESTful" services out there are half-baked and made by people who researched the topic for half a day. Some good ones to take points from are the Sun Cloud API and the Netflix API. Notice the documentation of media types and LACK of documentation on every single URL you can request. This is that loose-coupling stuff I was talking about.

    That's it for now! I wrote this as a culmination of knowledge for the last week or so of research I've done...please let me know if any information is missing or incorrect and I can make updates. Hope it was helpful!

    Comments
  • 200911.03

    How to convert HTML named entities to numbered entities in PHP

    I recently (read: today) had an obnoxious problem: I'm writing some code for creating an ATOM feed, and kept getting errors about entity-escaped values. Namely, things like ’, •, etc. Even written as entities, Opera and IE7 did not recognize them. I read somewhere that it was necessary to convert the named entities to numbered entities. Great.

    Well, PHP doesn't have a native function for this. Why, I do not know...there seems to be functions for many other things, and adding an argument to htmlentities that returns numbered entities would seem easy enough. Either way, I wrote a quick function that takes the htmlentities translation table, adds any missing values that are not in the translation table, and runs the conversion to numbered entities. Check it:

    function htmlentities_numbered($string)
    {
    	$table	=	get_html_translation_table(HTML_ENTITIES);
    	$trans	=	array();
    	foreach($table as $char => $ent)
    	{
    		$trans[$ent]	=	'&#'. ord($char) .';';
    	}
    	$trans['€']	=	'€';
    	$trans['‚']	=	'‚';
    	$trans['ƒ']	=	'ƒ';
    	$trans['„']	=	'„';
    	$trans['…']	=	'…';
    	$trans['†']	=	'†';
    	$trans['‡']	=	'‡';
    	$trans['ˆ']	=	'ˆ';
    	$trans['‰']	=	'‰';
    	$trans['Š']	=	'Š';
    	$trans['‹']	=	'‹';
    	$trans['Œ']	=	'Œ';
    	$trans['‘']	=	'‘';
    	$trans['’']	=	'’';
    	$trans['“']	=	'“';
    	$trans['”']	=	'”';
    	$trans['•']	=	'•';
    	$trans['–']	=	'–';
    	$trans['—']	=	'—';
    	$trans['˜']	=	'˜';
    	$trans['™']	=	'™';
    	$trans['š']	=	'š';
    	$trans['›']	=	'›';
    	$trans['œ']	=	'œ';
    	$trans['Ÿ']	=	'Ÿ';
    	$string	=	strtr($string, $trans);
    	return $string;
    }
    

    Hope it's helpful.

    UPDATE - apparently, even the numbered entities are not valid XML. Fair enough, I've converted them all to unicode (0x80 - 0x9F). All my ATOM feeds validate now (through feedvalidator.org).

    Comments
  • 200910.26

    VirtualBox: how to "clone" your VMs

    Notice the "clone" in quotes. Why? You can't actually clone a VM technically. We can work around that, though. Keep in mind, this guide is for VirtualBox <= 3.0.8 (later versions may have a clone button or something).

    One thing you CAN do is export to OVF and re-import, but I've found that OVF loses many settings (like video ram, network settings, whether you use SATA or not, etc). I prefer not to even bother with this method.

    The next thing you can do is just clone your VM's hard disk(s):

    1. Go into the ~/.VirtualBox/HardDisks/ folder. Copy and paste (windows) or cp (linux/unix) from db_master1.vdi to db_master2.vdi. If you try to import this into the Virtual Media Manager, it will piss and moan about the UUID being duplicate or some shit.
    2. VBoxManage internalcommands setvdiuuid db_master2.vdi - this is the magic command that allows you to import that new HD.
    3. Create a new VM, and set db_master2.vdi as the primary drive.
    4. Configure your new VM to have the same settings. (this is a pain, but there really aren't that many settings).

    There are a few things you'll have to dick with once you have your VM cloned. If you're into networking/cluster/HA crap like me, you'll probably have a static IP. This obviously needs to be changed. It's different for every distro, but it's in /etc/rc.d/rc.inet1.conf for Slackware, and /etc/networking/interfaces for Debian (any other distro can go to hell).

    Your old network interfaces, eth[0...n] will now be eth[(n+1)...(n*2)]: eg, if you had eth0 and eth1 before, they will now be eth2 and eth3. To reset this, (in Slackware):

    1. Open/etc/udev/rules.d/75-network-devices.rules in your favorite editor
    2. Remove all the entries.
    3. Restart. (note - someone please correct me if you don't need a restart... perhaps /sbin/udevtrigger will fix this?)
    4. You will now have eth0 and eth1 again. Hoo-fucking-ray.

    The process is the same for Debian, but the 75-network-devices.rules will most likely have a different name.

    Good luck.

    Comments
  • 200909.07

    How to reduce your carbon emissions

    Here I will outline some wonderful techniques I've developed for saving the planet. A lot of these may come off as common sense but, as we all know, most people don't have it so I'll go over them anyway.

    1. Driving. This is the obvious and hard one. Although I realize you can't stop driving altogether, there are ways to drive the same distance without using as much gas.
      • Accellerate slowly. You are driving a 2 ton object. Although it feels slow, generating the amount of power to get that object from 0 to 30 is enormous, and a lot of fuel is used to get started. I can't stress how important this is going uphill...take it slow.
      • Don't stop for anything. Once you stop, you have to accelerate again. If you are coming up on a red light, decrease your speed a few hundred feet before you reach it. Then, you'll be traveling a constant slow(er) speed and by the time you get there, the light will be green. If you get good at timing, you'll be able to keep up a good speed and never have to stop for a red. Don't mind the asshole tailgating you, they'd have to wait at the light anyway. With stop signs, obey the "no cop, no stop" philosophy.
      • Keep your tires filled and your car in tune.
      • Get a better car. If you actually go offroad a lot, you constantly haul stuff around, or have to deal with 3 feet of snow, you can skip this step. If you live in California like me, you can ditch your stupid SUV and get a real car. Remember, the size of your dick is inversely proportional to the size of your car. The bigger your car, the tinier your penis.
      • Get off your fat McDonalds ass and walk or ride your bike once in a while.
    2. Lights. Get compact fluorescents. The initial cost is worth the eventual energy savings. They last forever and are much brighter than incandescents. Also, with any type of light, it's better to leave it on for a few minutes than to incessantly turn it on and off. Note - with compact fluorescents, they are not disposable...they need to be properly recycled!
    3. Heating/cooling. Heating a house or apartment is a big deal, so do it only when you need to. Wear a coat or put on some shorts and open the windows. Yes, you may be uncomfortable, but don't be such a fuckin' wuss. Some people are cold all the time and have no food. Bein uncomfortable builds character. Get over yourself, asswipe.
    4. Food. I'm not going to shove the organic thing down your throat. It is better, however, to buy foods from your area. If you live in Siberia, skip this step. If not, supporting foods that haven't been trucked across the globe saves energy because they haven't been trucked across the globe.
    5. If it's yellow let it mellow, if it's brow... You get it. Flushing doesn't waste water. Water just goes back into the water cycle. Flashing wastes electricity. Huh? Toilets don't use electricity, stupid! Oh yes they do. In order for the water to come out your sink or toilet, it has to be pressurized. This takes a lot of energy. Imagine, if you will, trying to pressurize an entire city with a hand pump. A lot of work, right? Right. Well, pumps use electricity, and a lot of it. The less water you use, the less electricity used to pressurize the water system.
    6. Don't die. As your body decomposes, it releases harmful carbon into the atmosphere.

    I hope you've enjoyed my energy-saving tips. Be sure to stay tuned for more in the future.

    Comments