Saturday, January 11, 2014
Chromecast as WiFi Extender
Monday, January 6, 2014
Chromecast Auto Tune Doesn't Work
The only problem is that even though our TV has multiple HDMI inputs, our TV doesn't support something called HDMI-CEC, which is required in order for Chromecast to automatically tune the TV to the HDMI port Chromecast is connected to. Meaning we would still have to find the TV remote or walk to the TV to use Chromecast.
Luckily I found a solution, the Kinivo 501BN HDMI Switcher
It's kind of funny really, now when someone in the house says "Where's the remote?" I can answer with "Call it" without being a smart ass.
Monday, November 18, 2013
Arduino Powered Vertical Garden
Here's a couple of photos of the system at the moment. I originally went with foggers and a 12 port drip irrigation manifold, but there was not enough pressure in my house spigot to push the foggers. I experimented with some sprayers I had and they're wasting a lot of water because the spray pattern is too large. I have one basket mister on the system and it looks like the way to go. I'm thinking a 6 port manifold and 6 of those misters will work fine.
Now, the title does say "Arduino Powered" vertical garden, so I suppose I should get to the Arduino part. I haven't actually started on that part yet, though here are my plans with it. I'm going to hook at solar cell scavanged from a solar powered deck light to the analog input of the Arduino for use as a sun meter. The more voltage I see on that analog input, the brighter it is outside. I live in Florida, so it's always humid... The brighter it is, the more water I need to hit the plants with.
I was originally going to use a simple garden hose timer to water everything, but given I have the yard sprinklers on another Arduino Mega in the house anyways, I might as well hook this up as well.
Anyways, I'm having a tough time finding local suppliers of 3 3/4" net pots to fit in my 3 1/2" holes. So I'll have to order them online and wait for a bit. On the bright side, my Home Depot had Dig brand drip irrigation supplies on sale for about 80% off! 50ft rolls of 1/4" microtube for $0.99 instead of $4.99, score!
Sunday, November 17, 2013
RHT03 / DHT-22 Temperature / Humidity Sensor Housing
throughout the house for monitoring temp/humidity with an Arduino Mega. They're kind of awkward to place though. I discovered with a couple of snips with an exacto knife however, the DHT-22 fits quite nicely in a one port single gang wall plate, which in turn can be mounted to a single gang cut in box in the wall to protect connections.
Here's some photos of how it turned out.

Saturday, November 16, 2013
Arduino Solar Sensor
What to do with the voltage, albeit tiny current, generated from the solar cell though? I could charge a backup battery for the house's Arduino Mega.
Sunday, January 20, 2013
auth.log Service Restart
Rather than reboot the whole server, I wanted to restart the service that writes to auth.log. I found a reference to rsyslog, but I was a couple of versions of Ubuntu later than the 10.04 mentioned in that conversation. (Ubuntu 12.04 LTS) so I ended up getting "rsyslog: unrecognized service" when I tried that.
I ran "service --status-all" to get a list of services on the machine and "sysklogd" looked promising so I tried restarting it.
user@server:~# service sysklogd restart
* Restarting system log daemon... [ OK ]Then I exited SSH and logged back in, to find that my auth.log file was getting written to again.
Saturday, January 19, 2013
regex capture $1 refers to no regex
To
awk '{print \$1\"/\"\$2\"/\"\$3}'
From
awk '{print $1\"/\"$2\"/\"$3}'
Wednesday, January 26, 2011
Simple URL Shortening Script
If you read the documentation for mod_asis, the fundamentals of how this all works may be immediately obvious. If not, basically mod_asis lets you have a sort of static response cache. A lot like having a static HTML cache, but with HTTP headers.
Assuming you have your URL shortening domain setup and you have a nice empty DocumentRoot for your new URL shortening service, the first thing you need to do is create a directory named "stubs". If you want to setup some sort of UI to create new shortened URLs with setup your permissions on stubs so that PHP can write to stubs, but nobody else can.
Within the stubs directory create an htaccess file (ideally you'd use Directory or Location containers in your VirtualHost, but for example sake I'm using htaccess).
Within that htaccess file, add the fillowing line.
SetHandler send-as-isWhat that line does, is force every requested file to pass through mod_asis, which if you've read the documentation for mod_asis you know that other than adding a Date and Server header to the response, mod_asis just sends the file to the visitor as-is.
So, if I put a file in that directory named "abc123" with the following contents, I'll basically be given a 302 redirect from the server pointing me to google.com
NOTE: There are two newlines after the Location line to signal the end of HTTP headers. This is important
Status: 302
Location: http://www.google.com/
So basically, at this point I could distribule the shortened URL "http://domain/stubs/abc123" and it would redirect visitors to google.com; This isn't all that nice though, as I have "stubs" in the URL and that sort of defeats the purpose of a shortened URL.
That's why in the parent directory of stubs, AKA the DocumentRoot, I add the following to the htaccess file.
RewriteEngine on
RewriteBase /
RewriteRule ([a-f\d]{1,8})$ stubs/$1 [L]
Now I can distribute my shortened URL as "http://domain/abc123" and it will redirect to google.com; I could still distribute the URL with stubs in it if I wanted and it would still work for both shortened URLs.
At this point I have a small, simple, and efficient URL shortener. I have to manually go into my stubs directory and add a new file every time I want to shorten a URL though.
For that, I have the following simple PHP script with a bulk shortened URL capable UI.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>My URL Shortener</title>
</head>
<body>
<div id="container">
<header>
<h1>My URL Shortener</h1>
<p>Enter as many URLs as you want, one per line.</p>
</header>
<div id="main">
<?php
/*
Contains backwards compatibility code;
If you comment this include() out and don't get any errors, it's safe to leave it out.
*/
include('./lib.php');
if( ! empty($_POST['u']))
{
$url_list = '<ul>';
foreach(preg_split('#[\r\n\f]+#', $_POST['u'], -1, PREG_SPLIT_NO_EMPTY) as $_url)
{
$url = parse_url($_url);
if($url && http_build_url('', $url) == $_url)
{
$crc = sprintf('%x', crc32($_url));
if( ! file_exists("./stubs/{$crc}"))
{
file_put_contents("./stubs/{$crc}", "Status: 302\nLocation: {$_url}\n\n\n");
}
printf('<li><a href="http://%1$s%2$s%3$s">http://%1$s%2$s%3$s</a> » %4$s</li>',
$_SERVER['HTTP_HOST'],
str_replace('//', '/', dirname($_SERVER['REQUEST_URI']) . '/'),
$crc,
$_url
);
}
}
if(strlen($url_list) > 4)
{
echo $url_list, '</ul>';
}
}
?>
<form action="index.php" method="post">
<fieldset>
<legend>URL</legend>
<textarea name="u" id="u" rows="10" style="width:400px;"></textarea>
<p><input type="submit" name="s" id="s" value="Shorten!"/></p>
</fieldset>
</form>
</div>
<footer>© Me; 2011</footer>
</div>
</body>
</html>Also, because the PHP function "http_build_url" is a PECL function, I have the following code I include in "lib.php".
<?php
if (!function_exists('http_build_url'))
{
define('HTTP_URL_REPLACE', 1); // Replace every part of the first URL when there's one of the second URL
define('HTTP_URL_JOIN_PATH', 2); // Join relative paths
define('HTTP_URL_JOIN_QUERY', 4); // Join query strings
define('HTTP_URL_STRIP_USER', 8); // Strip any user authentication information
define('HTTP_URL_STRIP_PASS', 16); // Strip any password authentication information
define('HTTP_URL_STRIP_AUTH', 32); // Strip any authentication information
define('HTTP_URL_STRIP_PORT', 64); // Strip explicit port numbers
define('HTTP_URL_STRIP_PATH', 128); // Strip complete path
define('HTTP_URL_STRIP_QUERY', 256); // Strip query string
define('HTTP_URL_STRIP_FRAGMENT', 512); // Strip any fragments (#identifier)
define('HTTP_URL_STRIP_ALL', 1024); // Strip anything but scheme and host
// Build an URL
// The parts of the second URL will be merged into the first according to the flags argument.
//
// @param mixed (Part(s) of) an URL in form of a string or associative array like parse_url() returns
// @param mixed Same as the first argument
// @param int A bitmask of binary or'ed HTTP_URL constants (Optional)HTTP_URL_REPLACE is the default
// @param array If set, it will be filled with the parts of the composed url like parse_url() would return
function http_build_url($url, $parts=array(), $flags=HTTP_URL_REPLACE, &$new_url=false)
{
$keys = array('user','pass','port','path','query','fragment');
// HTTP_URL_STRIP_ALL becomes all the HTTP_URL_STRIP_Xs
if ($flags & HTTP_URL_STRIP_ALL)
{
$flags |= HTTP_URL_STRIP_USER;
$flags |= HTTP_URL_STRIP_PASS;
$flags |= HTTP_URL_STRIP_PORT;
$flags |= HTTP_URL_STRIP_PATH;
$flags |= HTTP_URL_STRIP_QUERY;
$flags |= HTTP_URL_STRIP_FRAGMENT;
}
// HTTP_URL_STRIP_AUTH becomes HTTP_URL_STRIP_USER and HTTP_URL_STRIP_PASS
else if ($flags & HTTP_URL_STRIP_AUTH)
{
$flags |= HTTP_URL_STRIP_USER;
$flags |= HTTP_URL_STRIP_PASS;
}
// Parse the original URL
$parse_url = parse_url($url);
// Scheme and Host are always replaced
if (isset($parts['scheme']))
$parse_url['scheme'] = $parts['scheme'];
if (isset($parts['host']))
$parse_url['host'] = $parts['host'];
// (If applicable) Replace the original URL with it's new parts
if ($flags & HTTP_URL_REPLACE)
{
foreach ($keys as $key)
{
if (isset($parts[$key]))
$parse_url[$key] = $parts[$key];
}
}
else
{
// Join the original URL path with the new path
if (isset($parts['path']) && ($flags & HTTP_URL_JOIN_PATH))
{
if (isset($parse_url['path']))
$parse_url['path'] = rtrim(str_replace(basename($parse_url['path']), '', $parse_url['path']), '/') . '/' . ltrim($parts['path'], '/');
else
$parse_url['path'] = $parts['path'];
}
// Join the original query string with the new query string
if (isset($parts['query']) && ($flags & HTTP_URL_JOIN_QUERY))
{
if (isset($parse_url['query']))
$parse_url['query'] .= '&' . $parts['query'];
else
$parse_url['query'] = $parts['query'];
}
}
// Strips all the applicable sections of the URL
// Note: Scheme and Host are never stripped
foreach ($keys as $key)
{
if ($flags & (int)constant('HTTP_URL_STRIP_' . strtoupper($key)))
unset($parse_url[$key]);
}
$new_url = $parse_url;
return
((isset($parse_url['scheme'])) ? $parse_url['scheme'] . '://' : '')
.((isset($parse_url['user'])) ? $parse_url['user'] . ((isset($parse_url['pass'])) ? ':' . $parse_url['pass'] : '') .'@' : '')
.((isset($parse_url['host'])) ? $parse_url['host'] : '')
.((isset($parse_url['port'])) ? ':' . $parse_url['port'] : '')
.((isset($parse_url['path'])) ? $parse_url['path'] : '')
.((isset($parse_url['query'])) ? '?' . $parse_url['query'] : '')
.((isset($parse_url['fragment'])) ? '#' . $parse_url['fragment'] : '')
;
}
}
?>That just gives me a simple textarea that I can enter a list of URLs into, and automatically have stubs for short URLs written to the stubs directory and get a list of shortened URLs back.
Monday, January 24, 2011
Google Safe Browsing Wordpress Dashboard Module
The project is named wp-google-safe-browsing-dashboard and the plug-in is available for download at Google Code. It's a nice simple plugin, just upload the zip file using your Wordpress plug-ins manager, activate it, and you're good to go!
Please, no applause, just throw money.
Saturday, January 22, 2011
$18.50 Average Adsense Page RPM
Basically, it's a 500-600 word article centered on the page with some navigation links on top, a descriptive heading, a paragraph of introduction text, a 728x90 advertisement, the entire article text, then some links to other articles and websites on the bottom.
There are no layout graphics at all in this layout, only an occasional article-relevant graphic within the article text from time to time. No sidebars, navigation is kept above the heading, and down in the footer. I haven't been adding any links within the article text to relevant articles.
There are 3 sizes of black text, normal, h1, and h2 sizes. The background is solid white and the links are the default blue. The main heading is centered, the rest of the text is left-aligned within the centered 800 pixel column.
The websites use almost no bandwidth, CPU to generate the pages is minimal.
It will be interesting to see if this layout survives, it really does give new meaning to "content is king".
Sunday, January 9, 2011
Text Ads or Image Ads
Sometimes a layout will dictate whether you can use text ads or rich media ads. There are certain scenarios where using text ads would break the Adsense TOS whereas using image ads wouldn't.
Another thing to consider is which one would fit better with the placement. Sometimes using one type or the other just doesn't make any sense because it sticks out like a sore thumb rather than a piece of jewelry.
In any event, I've gone ahead and gathered my statistics for the entire year of 2010 and listed each of the Adsense ad types in order of best performing to worst performing for each of the categories Adsense tracks.
Page Views
- Image Ads
- Text Ads
- Flash Ads
- Animated Image Ads
- Rich Media Ads
CTR
- Animated Image Ads
- Text Ads
- Image Ads
- Flash Ads
- Rich Media Ads
CPC
- Rich Media Ads
- Flash Ads
- Image Ads
- Animated Image Ads
- Text Ads
Page RPM
- Rich Media Ads
- Image Ads
- Animated Image Ads
- Text Ads
- Flash Ads
Estimated Earnings
- Image Ads
- Rich Media Ads
- Text Ads
- Animated Image Ads
- Flash Ads
Thursday, January 6, 2011
Blocking Low Paying Adsense Categories
Sensitive Categories has things like dating, politics, religion, etc. Whereas General Categories has everything else.
Both of these sections show a list of possible Adsense categories along with what percentage of the ads you've displayed came from each category, and how much of your Adsense revenue came from each category. Most of the categories also break down into multiple sub-categories.
As soon as I found it I immediately realized I had a couple of categories with bad impression/revenue relationships. For instance I had one category that was accounting for 13% of impressions, however it only accounted for 3.8% of revenue. In comparison there are other categories that account for 6.9% of revenue on 3.3% of impressions and 4.5% on revenue on 2.5% of impressions.
So, I went ahead and blocked the categories with horrible impression to revenue relationships. I figure that having more ads from more profitable categories being displayed will translate into more money. Since Adsense has much improved reporting in V3 it will be easy to see just how well my changes do in the future.
There is a 50 category limit on the number of Adsense categories that can be blocked.
Saturday, November 13, 2010
client denied by server configuration: .htaccess
It turns out, that the problem had to do with mod_autoindex. The directory in question is setup to use mod_autoindex and list a bunch of changelogs in the directory. For whatever reason, mod_autoindex wants to access .htaccess while it's building a list of files and since .htaccess files are disallowed for all in the normal Apache configuration, it's getting that permission error.
I've found that adding .htaccess to the IndexIgnore directive will stop this error from happening. Since I also have mod_autoindex ignore the link to a parent directory, my IndexIgnore directive looks like this.
IndexIgnore .. .htaccess
Sunday, November 7, 2010
Select Odd Rows in MySQL
SELECT * FROM mytable WHERE id & 1;If you're unfamiliar with a bitwise AND, basically what it says is return true of the left operand has the same bits set as the right operand. The number 1 only has one bit set, and conveniently enough that one bit is the same bit that will only be present in odd numbers.
Wednesday, November 3, 2010
Blogger Double Post Bug
In any event, I'd been putting this off for awhile because when I went to use the blogger template designer, I was getting a double post bug where my posts would show on the page twice whether I was on the index or just a single post page.
I couldn't seem to find an easy way to remove the extra posts widget so I just said screw it. Today though I got tired of putting it off, and decided to dig into the HTML of the template and hunt down the obviously present second posts widget.
From the looks of things, it just wasn't recognizing my posts template when it reverted to the default templates. It was looking at my posts widget as if it were a HTML widget or something other than posts, so it was adding a new posts widget. Though, the editor for my widget was still that of a posts widget, so there was no remove this widget button.
So, I singled out my own posts widget, the one with an id of "blog2", and removed the entire widget wrapper and all of the includables. Worked like a charm.
Tuesday, October 19, 2010
RSS Feed for SVN Changelog
So far I have the feed and an archive of the revisions being automatically generated and uploaded to the remote server daily.
Having an RSS feed for the SVN commit history presented an interesting problem where I couldn't really update the script_version field in the scripts schema.sql file without clogging up my revision history with worthless updates about the version number being updated.
So, I wrote a small script that exports a copy of the script, retrieves the SVN revision number from the repo, then updates schema.sql with the correct version number before finally packaging script for me.
In case anyone's curious, here's the code for that. This little script lives in my working copy on my workstation, not under version control.
#!/bin/bash
echo "Exporting HEAD revision..."
svn -q export http://192.168.1.102/svn/wallpaper-script
echo "Updating working copy..."
svn -q update
php -r '
$properties = `svn info -r HEAD`;
if(preg_match("#^revision:\s*(\d+)\s*$#im", $properties, $revision))
{
echo "Updating script version in schema.sql to 2.{$revision[1]}...", PHP_EOL;
$schema = file_get_contents("wallpaper-script/install/schema.sql");
$schema = str_replace("script_version'\'', '\''2.0'\'')", "script_version'\'', '\''2.{$revision[1]}'\'')", $schema);
file_put_contents("wallpaper-script/install/schema.sql", $schema);
echo "Compressing package...", PHP_EOL;
shell_exec("tar zcf wallpaper-site-script_2.{$revision[1]}.tar.gz wallpaper-script");
}
'
echo "Cleaning Up..."
rm -rf wallpaper-script
echo "Done."
Saturday, February 6, 2010
gedit Loads Slow
The way I fixed this issue was to disable the file browser pane plugin from Edit -> Preferences -> Plugins. Once I disabled the file browser pane plugin I was able to get gedit to startup faster, immediately even.
Thursday, November 26, 2009
Suppress rm No such file or directory
rm: cannot remove `*.html': No such file or directoryIf you have a cron job that deletes files daily or on another schedule you probably don't want to get the email that tells you something like that. There's always the option of redirecting the output to
/dev/null but then you're screwed if there's any other errors that you actually want to know about.Instead, use the
-f or --force flag of the rm program. That flag literally means ignore nonexistent files, never prompt. So instead of getting that cannot remove error, it will just go about business as usual.Instead of the following to delete two types of files,
rm /path/to/*.html; rm /path/to/*.html.gzUse the following to delete them and not have to worry if one type doesn't exist.
rm -f /path/to/*.html; rm -f /path/to/*.html.gz
Monday, November 2, 2009
svnserve.conf: Option expected
For instance, the following error is given if I remove the hash from the beginning of the passwd line and leave the whitespace there between the beginning of the line and the start of the option.
svnserve.conf:20: Option expected
Saturday, October 31, 2009
X-Pad: avoid browser bug
X-Pad: avoid browser bug" header you should feel lucky. The X-Pad header is a work around Apache uses for a bug in really old versions of Netscape and it only shows up if there's a chance the 256th or 257th byte of a response is a newline.It's a junk header, all it does is prevent the 256th and 257th byte of the response from being a newline. If Apache didn't do this, old versions of Netscape would hang.
It's a wonder why this is still part of Apache, we're talking really old versions of Netscape here.
Subscribe to:
Posts (Atom)

