|
This · is · Not · a · Brain · Surgery
random thoughts on technology
 |
|
My 9 y.o kid is using Internet. I see nothing wrong with that. Internet is no longer an optional part of this world and he needs to be friendly with it. He reads Wikipedia, visits LEGO-related sites, etc. I have enabled parental controls on his Mac, so hopefully some inappropriate web sites are blocked. The only problem I have is amount of time he spends on YouTube. YouTube could be an amazing educational resource but at the same time it could be an amazing time waster. I decided to limit amount of time he spends on YouTube, like many parents limit amount of time their kids spend in front on TV. I found no easy way to do this short of blocking his complete access to computer according to pre-defined schedule. But I wanted to block only YouTube and let him use everything else. Below I will share my solution to the problem. It is a bit involved, and requires you to have Linux box on your home network, but this is the only working solution I found so far. The trick is to use HTTP proxy (Squid) with squidguard plugin. On RHEL you can install and activate required packages using following commands: yum install squid squidguard squidguard-blacklists chkconfig squid onLet us start with default config file: cd /etc/squid cp squidguard-blacklists.conf squidguard.confNow edit squidguard.conf, adding following lines at the bottom: time playhours { weekly * 19:00-20:00 }
src all { ip 10.0.81.0/24 }
### ACL definition acl { all within playhours { pass good !bad !adult !aggressive !hacking !warez any redirect 302:http://localhost/access-denied.html?url=%u } else { pass good !bad !adult !aggressive !audio-video !hacking !warez any redirect 302:http://localhost/access-denied.html?url=%u }
default { pass none redirect http://localhost/block.html } }My home network is 10.0.81.0/24. This config allows to access video web sites (which include YouTube) only during 1 hour: from 7pm to 8pm every day. You can devise more complex schedule if you want to. In addition to blocking YouTube this config blocks various adult and hacking web sites at all times, as extra level of protection. To test your config you can use this handy command: echo "http://www.youtube.com 10.0.81.1/ - - GET" | sudo -u squid squidGuard -c /etc/squid/squidguard.conf -dTo activate it, edit squid.conf adding the following line: url_rewrite_program /usr/bin/squidGuard -c /etc/squid/squidguard.confNow all you need to set up your child computer to use HTTP proxy, pointing to IP of squid computer and default port 3128. Unfortunately due to the bug in MacOS versions up to Lion you need to disable parental controls on the account to make proxy settings work. As an extra measure of protection, you can use OpenDNS free parental controls. Here is how my OpenDNS dashboard looks like:  After setting up OpenDNS account all you need to do is to add the following line to squid.conf: dns_nameservers 208.67.220.220 208.67.222.222Hint: if you have dynamic IP, you can use ddclient to update it at OpenDNS site using this config. And here is what is shown if YouTube is accessed during not permitted time slot:  |
 |
|
Designing mobile user interface is not very complex. Just use common sense, think about user, and keep an eye on limited screen estate. But, some people just do not get it. For example, Foursquare Android App, which I am using daily, is driving me nuts. Take a look at the first screen I see when it is started:  It opens in "Friends" tab, which supposed to show me where my friends are. OK. Makes sense. What do I see: 1. It shows me where I am. Doh! I know where I am. No need to remind me. I want to see my friends, and given limited screen space it does not make sense to waste it on reminding me where I am now. 2. It shows me same information again, this time under "Last 3 hours" section. This is just plain stupid. At this point, 1/3 of screen space which could have been used to show my friend’s locations have been wasted just to remind me that I am Starbucks where I have checked in just 2 minutes ago. Taking into account additional space used by three levels of toolbars on top, just enough useful screen space left to shows me the locations for only two of my friends. |
 |
|
There is a lot of buzz about BitCoin in the news recently. Most people are exited about distributed, untraceable, and unregulated nature of this new currency. However, there is another overlooked aspect of it, related to the practice of " bitcoin mining." Anybody now can buy some hardware and start minting his own bitcoins. Initial investment in hardware aside, all you need now is to spend some electricity to produce money (bitcoins). Depending on your electricity costs and bitcoin exchange rates you can make small but steady monthly income. An interesting aspect of this electricity-to-money conversion is that electricity does not need to be transferred far and could be consumed very close to a generator producing it. For example, you can have a module with solar battery on top and bitcoin-generating computer inside which you can put anywhere to get free money literally growing under a sun! For example, the picture below shows 1000w Solar Photovoltic System. It generates enough electricity to power a PC with 2-4 powerful GPU cards, capable of producing very decent bitcoin mining performance.  |
 |
|
My daughter is a UCSC student. Recently, her MacBook was stolen from her dorm room. She has filed a burglary report with campus police, but recovery chances are slim. Not to slander character of UC students, but I think there is a good chance the laptop will resurface somewhere on campus someday. Once it connects to the campus network it could be identified by MAC address. From there, hopefully, the identity of thief could be tracked down. I was able to find MAC address of stolen laptop, and my daughter gave it to campus IT. However, I am not sure if they would take the task of tracking stolen laptops seriously. This made me think that there might be a crowd sourced solution to this problem. Imagine a site, where one can report stolen computer along with its MAC address. Now, the volunteers would run a small daemon on their laptops. The daemon will be constantly monitoring the ARP table and check if any of nearby MAC addresses are in the list belonging to stolen machines. If match is detected a report along with spotting time and the location is sent to the owner. If enough people participate miscreants could be spotted on campuses, in hotels, at offices, cafes. This should work for all WiFi or ethernet equipped devices: computers, laptops, tables, mobile phones, game consoles, etc. Obviously, there are some privacy issues. Sending somewhere MAC addresses of nearby computers could be viewed by some people as a privacy violation. This could be addressed by using one-way hashes and sending them instead of MAC addresses. Second concern is what if somebody puts into the system a MAC address of somebody else laptop with purpose to track this person. This issue is more difficult to address. Maybe the site should require submitters to provide their real identity (verified by credit card of by other reliable means) or accept new records only if police report has been filed and a copy has been enclosed. |
 |
|
I have recently moved one of my web servers containing mostly static pages to GoDaddy hosting. Before it was hosted at Linux machine and I was backing it up using weekly cron sript using rsync. With new hosting I had to set up a new backup procedure. The problem us that although GoDaddy gives you SSH access they do not provide rsync on their machines. I was toying with idea of cross-compiling it elsewhere and bringing a binary with me, but I found a simpler solution using sshfs. Here are step by step instruciton: Definitions:www.yourhost.com - your go daddy web host (assuming it has ssh access) username - your login name for ssh access to go daddy host backuphost- a Linux machine with root access, at which you will be backing up your web site. on backup host:1. As root, generate new ssh key without passphrase using ssh-keygen command. Call it backup.dsa. (normally stored in /root/.ssh/backup.dsa) 2. Add the following lines to your /root/.ssh/configHost www.yourhost.com User username IdentityFile ~/.ssh/backup.dsa
3. Make sure you have empty mount point ( mkdir /mnt) on www.yourhost.com:1. Add contant of the file backup.dsa.pub (one you generated on backup host) to ~/.ssh/authorized_keysNow we are all set. Let us try it:First just try to see if your ssh works. As root issue the command: ssh www.yourhost.comIt should let you in without password. If this does not work add -v flag to ssh command and proceed with regular troubleshooting of ssh public key authentication. Most likely you will need to fix permissions on ~/.ssh directory and its contents on the remote host. Once this worked, you can mount remote filesytem: sshfs www.yourhost.com: /mntAnd back it up: rsync -az -qq /mnt/html/ ~/backups/www.yourhost.comDo not forget to unmount when you done: umount /mntThis is a quick and dirty solution. Most likely fusefs options could be tweaked to get even better performance. You can add these commands to script file in /etc/cron.weekly/ on backup host to implement automatic weekly backups. |
 |
|
Switching between Nexus One and iPhone I could not help noticing that my typing error rate is significantly lower with iPhone. Both devices have about the same screen size and similar keyboard layout. That made me wondering what makes iPhone keyboard superior. Is it the layout, for example spacing between the keys? Smarter algorithms? With help from Quora I have been able to disover that one of the key differences is an algorithm used by iPhone to adjust target area based on next key prediction: "Although the size of the keys displayed on an iPhone/iPod Touch keyboard does not change during typing, the iPhone's predictive algorithm will subtly increase the "target area" of what it thinks your next keystroke will be. This helps reduce mistypes." Alternative Android keyboard called TickButtons using similar idea, except it does change visual size of the keys:  Luckly there are many alternative keyboards available for Android. I was looking for a conventional keyboard, so I have exluded ones like Swype. After trying several of them I was able to find one which allows me to type much more accurately on Android. Not only it supports target area resizing as iPhone does, it also have a calibration mode where you train it to the way you are pressing the keys. I am now happy user of Smart Keyboard. |
 |
|
Here is the situation: you are driving a car, perhaps using your GPS device for navigation and want to stop for a quick bite or a cup of coffee. You would probably first think about using list of nearby restaurants offered by your GPS device, or perhaps an application like Yelp to see what are the good places to eat nearby. The problem is that location search offered by most applications is not particularly optimized for such simple and common situation. The gist of the problem is that it is assuming that you are static and does not use information about your route and roads into account. For example it would show you all restaurants in, say, 5 mile vicinity from whenever you are. But most likely you will not be interested in the restaurants which are located behind you. You would rather not spend time turning around and going back. So in simple case your search area should be shaped not like a circle with radius of 5 miles with you in the center, but rather as a rectangle extending along your route with some reasonable distance on both sides. This would make your search aware of your route. In more general case I wish my navigation system to be clever enough to search in a “detour” mode, assuming than whatever I am searching for is just a stop on my path and I would want to continue to my ultimate destination afterwards. In this case it could use different distance metric to filter and order search results. Now it orders them just by distance from my location. What I really care is how much detour to given place will extend my route. For example, let us call my current position A and my final destination Z. There are two potential restaurants, say, B and C which fit my search criteria (Indian food most likely, in my case). Instead of using distance AB and AC it should build a route A-B-Z and A-C-Z and compare overall time from A to Z over each of these routes. It would be especially nice if it would use traffic information, if available. |
 |
|
In my last post I have described OWI-007 Robotic Arm parallel port protocol. They have a newer, more advanced model called Robotic Arm Edge:  You can use USB interface module to connect it to PC. Unfortunately official software works only under Windows and do not provide API. I have been able to reverse engineer their USB protocol and write sample code which allows to control the arm from Mac and Linux. This is USB device with vendor id 0x1267 and product id 0. The device is controlled by 3 byte commands sent via USB control transfers. Command format is byte0, byte1, byte2. Each byte controls a group of arm features. All motors could be controlled independently. Most commands start action which is continued until next action is signalled. Byte '00' universally used as stop action. Bit numbering in byte:
| 7 (most significant) | 6 | 5 | 4 | 3 | 2 | 1 | 0 (least significant)
| Meaning of bits in each byte: Byte 0First byte controls grip, shoulder and wrist. Bits are assigned as following:
| Bit numbers | Controls | Bit combinations
| | 0,1 | Grip | 00-do not move, 01-close, 10-open
| | 2,3 | Wrist | 00-do not move, 01-move up, 10-move down
| | 4,5 | Elbow | 00-do not move, 01-move up, 10-move down
| | 6,7 | Shoulder | 00-do not move, 01-move up, 10-move down
| Sample commands, activating single motor:
| Byte 0 | Command
| | 00 | stop grip, wrist, elbow and shoulder movement
| | 01 | grip close
| | 02 | grip open
| | 04 | wrist up
| | 08 | wrist down
| | 10 | elbow up
| | 20 | elbow down
| | 40 | shoulder up
| | 80 | shoulder down
| Sample commands activating 2 motors simultaneously:
| Byte 0 | Command
| | 11 | grip close and elbow up
| | 82 | grip open and shoulder down
| Byte1Second byte controls base. Bits are assigned as following:
| Bit numbers | Controls | Bit combinations
| | 0,1 | Base | 00-do not move, 01-rotate clockwise, 10-rotate counter-clocwise
| Sample commands:
| Byte 1 | Command
| | 00 | stop base rotation
| | 01 | rotate base clockwise
| | 02 | rotate base counter-clocwise
| Byte 2Third byte controls LED light inside the grip. Bits are assigned as following:
| Bit numbers | Controls | Bit combinations
| | 0 | LED | 0-off, 1-on
| Sample commands:
| Byte 2 | Command
| | 00 | LED off
| | 01 | LED on
| Sample source code using libusb:
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <libusb-1.0/libusb.h>
#define EP_INTR (1 | LIBUSB_ENDPOINT_IN)
#define ARM_VENDOR 0x1267
#define ARM_PRODUCT 0
#define CMD_DATALEN 3
libusb_device * find_arm(libusb_device **devs)
{
libusb_device *dev;
int i = 0;
while ((dev = devs[i++]) != NULL) {
struct libusb_device_descriptor desc;
int r = libusb_get_device_descriptor(dev, &desc);
if (r < 0) {
fprintf(stderr, "failed to get device descriptor");
return NULL;
}
if(desc.idVendor == ARM_VENDOR &&
desc.idProduct == ARM_PRODUCT)
{
return dev;
}
}
return NULL;
}
int main(int ac, char **av)
{
if(ac!=4)
{
fprintf(stderr,"Usage: armedgetest CMD0 CMD1 CMD2\n");
return 1;
}
unsigned char cmd[3];
cmd[0]=(unsigned char)strtol(av[1],NULL,16);
cmd[1]=(unsigned char)strtol(av[2],NULL,16);
cmd[2]=(unsigned char)strtol(av[3],NULL,16);
libusb_device **devs;
libusb_device *dev;
struct libusb_device_handle *devh = NULL;
int r;
ssize_t cnt;
r = libusb_init(NULL);
if (r < 0)
{
fprintf(stderr, "failed to initialize libusb\n");
return r;
}
libusb_set_debug(NULL,2);
cnt = libusb_get_device_list(NULL, &devs);
if (cnt < 0)
return (int) cnt;
dev=find_arm(devs);
if(!dev)
{
fprintf(stderr, "Robot Arm not found\n");
return -1;
}
r = libusb_open(dev,&devh);
if(r!=0)
{
fprintf(stderr, "Error opening device\n");
libusb_free_device_list(devs, 1);
libusb_exit(NULL);
return -1;
}
fprintf(stderr, "Sending %02X %02X %02X\n",
(int)cmd[0],
(int)cmd[1],
(int)cmd[2]
);
int actual_length=-1;
r = libusb_control_transfer(devh,
0x40, //uint8_t bmRequestType,
6, //uint8_t bRequest,
0x100, //uint16_t wValue,
0,//uint16_t wIndex,
cmd,
CMD_DATALEN,
0
);
if(!(r == 0 && actual_length >= CMD_DATALEN))
{
fprintf(stderr, "Write err %d. len=%d\n",r,actual_length);
}
libusb_close(devh);
libusb_free_device_list(devs, 1);
libusb_exit(NULL);
fprintf(stderr, "Done\n");
return 0;
}
Sample usage:
./armedgetest 00 00 01
sleep 3
./armedgetest 00 00 00
will turn the light on for 3 seconds and then would turn it off. It have been tested on MacOS X, but should work on Linux as well. |
 |
|
One of my projects involes controlling a robot arm. We were using Robotic Arm Trainer OWI-007 from OWI. It is cheap (under $100). We were using their parallel port interface. OWI does not offer official API, but it was easy to figure out command sequences. Here are bytes one need to send to the parallel port, to control the arm: stop_arm = 0x05, grip_open = 0x0D, grip_close = 0x00, elbow_up = 0x15, elbow_down = 0x01, wrist_cw = 0x04, wrist_ccw = 0x81, shoulder_up = 0x03, shoulder_down = 0x45, base_ccw = 0x02, base_cw = 0x26Sending one of these commands will make an arm perform specified motion until STOP (0x05) or other command is sent. Only one motor at a time could be engaged. There is no speed control, but we have been able to implement a limited speed control using Pulse With Modulation approach. Now we are looking at their newer model, Robotic Arm Edge which only comes with USB interface. OWI "don't offer any support for 3rd party programming for the USB interface", but I hope we can figure out their USB protocol on our own. |
 |
|
My company has recently switched to Google Apps (paid edition). It is not cheap: $50 per user annually, but we decided it is worth it, comparing to cost of supporting our own email infrastructure. Google was kind enough to assign as a support engineer to help us with migration. We did migration on our own, and just needed help with few small issues. Before boring you with details let me go straight to conclusions, in case you do not want to read the rest: 1. Core functionality of Google Apps works pretty well - we are happy 2. Do not expect much support. My impression is that Google is doing whatever they think they should be doing, and do not care about you or your money. Just be grateful to be able to use their stuff and shut up. [This is similar to Apple's attitude, except Apple cares about your money] 3. Knowing all this, would I still switch to Google Apps? Emphatically YES. Sample issues: Problem: There is no way to browse global address book, although you can search in it. Suggested Solution: 1. Export CVS and email to all your employees. Ask them to import to their private address books. 2. Use API (they actually offered to send me a link to API docs!) [I guess the assumption is that I should write my own interface to their address book] Problem: There is no way to change owner of documents on Google Docs from @gmail.com address to google apps user (it complains about different domains) Suggested Solution: Export all documents in Ms Word/Excel formats and re-import them, losing history, sharing settings, etc. Problem: Some problems with IMAP mailbox migration (Feature of apps control panel) Suggested Solution: 1. Although it is offered via Control panel it is deprecated and should not be used. It is not supported. 2. Although I am not using Microsoft Exchange, I should install "Google Apps Migration for Microsoft Outlook". It will import IMAP as well. It requires Outlook to be installed. I will need Windows machine for this. Then it will proceed to download 4Gb of my mailboxes via IMAP and will re-upload them to Google Apps. Problem: There was typo in name of one of users which we fixed. In the list of accounts it shows correctly, but in auto-completion in email and elsewhere it still shows mistyped one, one week after it was fixed. Suggested Solution: Usually changes to user real names take 24 hours propagate. [When I pressed on saying that a week have passed, they said that this is known issue which will be fixed, eventually. No ETA, no workaround) Problem: You can create calendar, and in sharing options make it shared with all people in the company. But co-workers have no way to find it - search does not show it. Suggested Solution: You need to get cryptic calendar ID from sharing settings (it looks like email address) and email it to all your employees, and as them to add to their calendars using this ID. |

|
|