Awesometoast.com

The multipurpose website of Aaron W. Herd

Portal Test Chamber Poster (download)

One of my daughter’s friends came over, and upon seeing my home office said, “Whoa! Your dad has a secret lab!” Well, the name stuck. It’s a Secret Lab now. But I felt like it needed a sign. Few things say “secret lab” to me better than Aperture Science, and since a lot of my work involves testing, I put together a 24″x36″ Testing Chamber poster to frame outside the entrance.

Want one of your own? Here’s my PSD file you can download/customize.

Portal-Poster

Posted under: General Stuff | No Comments »

Getting CORS to work with Apache

Ok, if you’re reading this, I’m assuming you know what CORS means, so I won’t tell you that it stands for Cross Origin Resource Sharing. Oh. I just told you.

Well anyway, you want to enable it on your Apache server. Maybe, like me, you’re building an API-based web app. So you need some Javascript to be able to pull data from a different server. (Or even, like in my case, a different subdomain on the same physical server.) It’s easy in Node.js, so it shouldn’t be hard in Apache.

So you google “apache enable cors”. The first result is from enable-cors.org. Wow, how relevant! Sounds so legit! And it says all you have to do is throw this somewhere:

Header set Access-Control-Allow-Origin "*"

So you put it in your httpd.conf file or .htaccess and you’re done! Boom!

GOIN HOME EARLY TONIGHT!

Except then you try it. And Firebug is all like: Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://buckle.up.because.thisll.suck.org. This can be fixed by moving the resource to the same domain or enabling CORS.

Chrome says: XMLHttpRequest cannot load https://howdare.youthink.thiswouldbe.easy. No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘https://pain.and.suffering.org’ is therefore not allowed access.

But… you did it right. You did just what it said you should do. You even googled it a few more times and everyone says the same thing. Just that one line of code and you’re done. Chrome even says that the header is there, for crying out loud!

Screenshot from Chrome

 

Yeah, no.

Disappointed face
Turns out there’s a friggin metric crapton more to it than that. I won’t go into all the details here, but there’s a lot. What I will do is give you just the quick and dirty list of things to try.

Enable mod_headers

There’s a module that allows Apache to add things to the request/response headers, and you’ll need that. Near the top-ish of your httpd.conf file, look for…

#LoadModule headers_module modules/mod_headers.so

(Mine was on line 115 in my Apache 2.4 setup.)

If yours has that hash/number/octothorpe/# sign at the beginning, remove it. As with any change to httpd.conf, you’ll need to restart Apache for this to take effect.

“Always”

First, just putting that line in my .htaccess wasn’t working. I could see the header in Chrome (image above) but it was apparently being ignored for who the crap knows why. Adding “always” before “set” seemed to correct this. I also moved it from my .htaccess to httpd.conf, just above my virtual hosts section.

Header always set Access-Control-Allow-Origin "*"

You’ll also see different versions, some where it reads header set, and others where it adds header add. Both will work, but set is safer in this case because add can add multiple headers, which according to the CORS documentation is not allowed.

Depending on your situation, that might do it for you. But probably not. So…

Other headers

I also needed to add these three:

Header always set Access-Control-Max-Age "1000"
Header always set Access-Control-Allow-Headers "X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"

The 2nd one determines what headers your requesting server (the one trying to make the remote call) is allowed to send. You likely don’t need all of those, but I left in a bunch for the sake of example.

The 3rd one is super important. It determines what kind of RESTful calls your app is allowed to make. Again, you probably don’t need all of them. In fact, if you’re only doing GET requests, that’s the only one you need. But if you want to POST, then you need OPTIONS, too. More on that below.

GET works, but POST doesn’t: welcome to “preflights”

I won’t go into details here, but I will say that POSTs are different than GETs beyond the obvious ways. One is that your browser will likely do what I learned today is called a “preflight” check. Basically, it sends a request before your actual POST, checking to see if it’s allowed to do what it’s trying to.

This was very confusing at first, because my GET calls were working fine, but when I tried to log in as a user with a POST call, Chrome 1. showed it as an OPTIONS request and 2. returned Error 404. The heck?

So now you see why adding the OPTIONS method was important. But what about that stupid 400/404 we were getting?

Turnt out, that initial OPTIONS call was actually running code on my API subdomain. PHP code, in my case. The PHP scripts were expecting to get some POST data–but of course they weren’t because this was a preflight, not an actual call. So they would error. Great…

Making PHP return 200 OK for preflights

I had to make a script called blank.php, which contained nothing but some ranty comments. Then, over in .htaccess, I added this:

RewriteEngine On                  
RewriteCond %{REQUEST_METHOD} OPTIONS 
RewriteRule ^(.*)$ blank.php [QSA,L]

What’s happening there is, whenever an OPTIONS request comes in (line 2), redirect any and all of them to blank.php (line 3). Blank.php is, of course, blank, so it returns an HTTP status of 200 OK. The browser then takes this as a successful attempt to discover what its OPTIONS are, learns from the other headers (Allow-Origin, Allow-Headers, Allow-Methods) that it’s allowed to do a POST, and then finally sends the real, actual, honest POST that I’ve been trying to get it to do this entire freakin’ time.

Hope that helped

Depending on your environment/needs, that might not be the end for you. If so, you have my sympathy. Either way, I hope this at least got you a few steps closer.

Posted under: Fixing Stuff, Web Design | No Comments »

OS X Yosemite, Core Storage, and partition woes.

os-x-yosemite

So when a new version of any OS comes out, I like to do a clean install. On Macs, this has usually been fairly easy, since HFS+ partitions are pretty flexible — they’ll let you add/remove/resize without a lot of hassle.

Until Yosemite.

In the past, I’ve made a new partition on my drive, installed the new OS X (like Mavericks), copy all of my files from the old partition to the new one, then delete the old one.

But when I tried this with 10.10 Yosemite, I ran into a new problem. Partitions were no longer flexible. I couldn’t delete or resize any of them. I found this out after a full day of getting the Yosemite partition just right.

Some research found that Yosemite will change its partition from HFS+ to “Core Storage”. (According to Ars Technica, there’s not a clear reason why, either.) I’m not sure of all the technical details, but this apparently killed flexibility. Yosemite was stuck on a partition with only 10GB of free space, when it could have had 400 from the old Mavericks partition. It wouldn’t even let me delete the Mavericks partition. Everything was locked.

Fortunately, I found a solution. You can convert Yosemite’s Core Storage partition back to HFS+. Once I did that, Disk Utility worked fine again. Some notes:

  • This is not destructive. You won’t lose anything.
  • This only works if you have not encrypted the partition with FileVault.

Here’s how:

First, you have to get something called a lvUUID for the partition. (Don’t worry about the annoying acronym. This is all scarier than it looks.)

Open Terminal, and run this (you can copy/paste):

diskutil cs list

This will give you a list of partitions similar to this:

Results of diskutil cs list

Thanks to BrettApple at the MacRumors forum for this.

Okay. See how it says “Revertible: Yes”? That means we can convert it back. You’ll need that super-long string of letters/numbers. In the same Terminal window, type:

diskutil coreStorage revert [THAT LONG STRING OF STUFF]

So in this particular case, we would run:

diskutil coreStorage revert 47F9D6B1-F8F2-4E64-8AD4-9F2E2BD78E29

The results should be quick. This took only seconds for me. Once that was finished, I was able to delete the Mavericks partition and resize my new Yosemite partition to fill all available space.

Some final notes:

  • For more details, check out this forum thread on MacRumors. In particular, post #38.
  • The first terminal command, diskutil cs list will only work if you actually have a CoreStorage partition.
  • You can run this while booted into the Yosemite partition in question. No need to boot the recovery partition or anything.

 

Posted under: Fixing Stuff | 45 Comments »

Variables not setting in Windows batch file?

Windows batch files (.bat) can be scripted, which means you can do all sorts of things like setting variables. But if you’re having a hard time getting those variables to set, this might be why.

SET var=Holy crap, it sets the variable!

Will work fine, but…

SET var = Holy crap, the space screws it up!

… will not. If you’re used to putting spaces after equals signs like I am, you can make this mistake without even knowing it. If you do it wrong, it won’t throw any errors either. Just silently fails.

Posted under: Fixing Stuff | No Comments »

Localize an SQL date using Javascript

So you have a date from your database and it looks like this: 2014-01-31 01:02:03. It so happens that your server is on UTC time. You want to:

  1. Format the date into something prettier, and
  2. Offset the date so it’s adjusted for a user’s local time zone.

Ok, great. You only have to SUFFER THE PAIN OF A THOUSAND MIGRAINES AND oh wait it’s actually sort of easy. But man, this took a lot of pain and searching to find. The key is moment.js, a glorious gift to developer-kind.

So the way I’m doing this is to create an HTML5 <time> element, but it can certainly be done other ways. First, after running a DB query, I have PHP produce this:

<time datetime="2014-01-03 12:57:03">
    2014-01-03 12:57:03
</time>

Not very pleasant to look at. So then we do a little moment.js…

var date = $(time).attr('datetime');
var newformat = 'D MMM YYYY [at] h:mm A';
var nice = moment(date, 'YYYY-MM-DD HH:mm:ss').format(new_format);
$('time').html(nice);

There’s some jQuery in there, too, but it isn’t necessary.

What we just did, is we read the date from our <time> element’s datetime attribute, then told moment what format it was in, so it could then spit it back out how we want it to, using .format(), as the human-readable part of the <time> element.

The result looks like this: 3 Jan 2014 at 12:57 PM. Yay. It’s nicer. But that’s still UTC time, and no timezone data was saved in our DB. So we have to add it.

<time datetime="2014-01-03 12:57:03 +0000">
    2014-01-03 12:57:03 UTC
</time>

Note that the stuff added here didn’t come from the DB, I added them manually. The “+0000″, or an offset of 0 hours for UTC time, is what we’re giving to moment.js. The “UTC” is just there for humans to read, just in case something goes wrong or Javascript is disabled. With those added, we inform moment.js that there’s a timezone offset in there:

var nice = moment(date,'YYYY-MM-DD HH:mm:ss ZZ').format(newformat);

See the “ZZ” we added in the middle? Now moment.js knows we have a timezone and what it is. And just like that, it’s been adjusted: 2 Jan 2014 at 5:57 PM (adjusted for America/Denver, -7:00).

It was so easy, that after all the suffering gone through before this point, I’m almost mad. But not really. But just a little bit.

Posted under: General Stuff | 1 Comment »

Using Sandbox always fails with PayPal IPN (PHP)

Warning: This post assumes you’re already familiar with IPN, and you’re just having trouble, well, troubleshooting it.

Okay, let’s say you’re setting yourself up with PayPal IPN. You’ve set up a PHP listener not unlike this one. You’re all set, right? Ready to test it out with PayPay’s IPN Simulator! Yeah!

Except it fails. It always fails. Why?

To try and figure it out, I set up a file named paypal.txt and told my listener to write the results to that file. Like so:

// These two lines are just landmarks so you can see where I am:
while (!feof($fp)) {
   $response = fgets ($fp, 1024);

   // Here's the actual logging code:
   $file = 'paypal.txt';
   $current = file_get_contents($file);
   $current .= PHP_EOL."DAMN !fp";
   file_put_contents($file, $current);

Okay? And after hours of troubleshooting, this is the only thing I would get:

HTTP/1.0 400 Bad Request
Server: BigIP
Connection: close
Content-Length: 19

Invalid Host header

Nice, huh? Super helpful. Well, as it turns out, the problem is that the example code I linked to above, and variations of it I’ve found all over the webs only work for live IPN responses. Meaning anything from www.sandbox.paypal.com (like PayPal itself tells you to use) will fail. EVEN IF YOU CHANGED IT to use Sandbox like so: (This is line 15 of the above-linked example code)

$fp = fsockopen ('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);

The problem

As near as I can tell, the problem is that the IPN responses are being sent from paypal.com, even though you want</> to — have been told by PayPal itself — to work with sandbox.paypal.com while developing.

The fix

Here it is. See line 2.

$header = "POST /cgi-bin/webscr HTTP/1.0\r\n";
$header .= "Host: www.sandbox.paypal.com\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($postback) . "\r\n\r\n";

Done. Problem should be solved. To sum up, it’s not enough simply to set the fsockopen() to use sandbox.paypal.com, you also need to set the response header correctly, or there will be a mismatch and sad, sad failure.

Hope this helps!

Posted under: Fixing Stuff, Web Design | No Comments »

Access a mapped network drive from PHP (Windows)

So you want to do something on a mapped network drive using PHP, but it simply tells you it couldn’t find the drive? Worry not.

What’s going wrong?

The problem is that PHP runs under the SYSTEM account, and the SYSTEM account can’t access mapped drives.

The solution:

So, we need to map the drive from the SYSTEM account. You can do this from your PHP script, but if you need persistent access, we can do this:

1. Download the Windows Sysinternals Suite and unzip it somewhere you can easily get to from a command prompt.

2. Open an elevated command prompt. (Search for “cmd.exe” from the Start ball, and then right-click on it, and choose Run as Administrator.)

3. Using the command prompt, navigate to wherever you put Sysinternals.

4. Elevate yourself once again to supreme power by using:

psexec -i -s cmd.exe

A new command prompt window will open that is running as the SYSTEM account.

5. Map the network drive:

net use z: \\[IP ADDRESS HERE]\[FOLDER NAME HERE] /persistent:yes

And you’re done!

Warnings:

You can only remove this mapping the same way you created it, from the SYSTEM account. If you need to remove it, follow steps 1 -4 but change the command on step 5 to: net use z: /delete.

The newly created mapped drive will now appear for ALL users of this system but they will see it displayed as “Disconnected Network Drive (W:)”. Don’t worry though! It displays as disconnected, but will work for any user.

Posted under: Fixing Stuff, Web Design | 4 Comments »

Make MySQL’s UNIX_TIMESTAMP() work in PostgreSQL

iStock_000003225418XSmall

And FROM_UNIXTIME(), too!

Maybe you’re like me, and you’re migrating something from MySQL over to PostgreSQL. Maybe, like me, you’re swearing a great deal and experiencing high blood pressure, too.
(Or maybe not.)

I’ve seen numerous threads that just tell you how you can change all your code to use Postgres’s epoch_something_something_aint_nobody_got_time_fo_dat() function instead, but epic hero Janusz Slota has a better way. He shows you how to, rather easily, make it possible to run those functions in PG without having to change a thing.

Check out his solution right on over here.

(Just change LANGUAGE ‘SQL’ to LANGUAGE ‘sql’ if you’re using PG 9.2+)

Posted under: Fixing Stuff | No Comments »

iTunes 11 and 12: Enable track skipping with Repeat One turned on (OSX)

Skipping tracks with repeat on? Preposterous!In iTunes 10, you could skip to the next/previous track when Repeat One was turned on. In 11 & 12, they assume that by “skip ahead”, you somehow mean “rewind this track”.

This really bothers some people.
Do not judge us, we have our reasons!

And here’s one way to fix it.

It took some work, but I finally came up with some AppleScript to handle this. Basically, we’re checking to see if Repeat One is on. If it is, we quickly disable it, skip to the next (or previous) track, and then turn it back on. Apple borked the old way of doing this (same with shuffle), so we’re using menu bar items instead.

-- This script lets you skip songs in iTunes 11/12 even if repeat one is on

tell application "System Events"
	tell process "iTunes"

		-- Find out if repeat one is on
		-- This finds out if the menu item is checked
		set isRepeatOneOn to (value of attribute "AXMenuItemMarkChar" of menu item 3 of menu 1 of menu item "Repeat" of menu 1 of menu bar item "Controls" of menu bar 1 as string) ≠ ""

		if isRepeatOneOn is true then

			-- Set repeat to ALL
			click menu item 2 of menu 1 of menu item "Repeat" of menu 1 of menu bar item "Controls" of menu bar 1

			-- Skip to previous track...
			click menu item "Previous" of menu 1 of menu bar item "Controls" of menu bar 1

			-- Need this, or the next step happens too fast
			delay 0.1

			-- Reactivate Repeat One
			click menu item 3 of menu 1 of menu item "Repeat" of menu 1 of menu bar item "Controls" of menu bar 1

		else
			-- Just skip to previous track
			click menu item "Previous" of menu 1 of menu bar item "Controls" of menu bar 1
		end if

	end tell
end tell

You can copy/paste that, or you can just download the script files here.
There’s one script for skip ahead, and one for skip back.

Wait—how do I use these?

Valid question. They’re not all that useful, really—unless you assign them to hotkeys.

Head on over here to Mac OS X Tips for ways and examples to set hotkeys to run AppleScripts.

Personally, I used Quicksilver to control iTunes for years, but now I use Alfred 2 (with Powerpack.)

(Since it’s not super obvious, let me know in the comments if you’d like help setting up either of these scripts using Alfred 2.)

 

Posted under: Fixing Stuff | 3 Comments »

Ever met a chronic insomniac?

Ever met a chronic insomniac?

Posted under: General Stuff | No Comments »
Page 1 of 612345...Last »