Wednesday, October 17, 2012

Installing Multi-Byte PHP Functions

I received this error today:

Fatal error: Call to undefined function mb_strlen()

And it would look the same, no matter what multi-byte PHP function I might be using: mb_strpos(), mb_substr(), etc. And it is beginning to be important to have this extensions installed if you are working with international, multi-byte character sets like UTF-8.

The fix is super easy. All you need to do is install the PHP multi-byte extension with yum (if you're on CentOS or RHEL). Do the following from the command line:

yum install php-mbstring
service httpd restart

That installs the extension and restarts Apache. Then you're good to go!

Thursday, September 20, 2012

MacBook Pro Retina & Linksys Routers

I have two Linksys wireless routers (WRT160N and E1200). One at an office, the other at home. I bought a MacBook Pro Retina a couple days ago (OS v10.8.1). I've now found that my new MBP doesn't play nice with Linksys.

Typically what happens is that, while still connected (according to the status bar), the connection chokes for about 30 seconds -- nothing flows through the pipes. What is even crazier is that it does the same for everyone else on the network (Macs and PCs).

This doesn't happen at Starbucks or the Apple store (which I am pretty sure don't use Linksys routers).

I can't find anything online about this so I'm asking the question: Has any one else had any issues with the MBP or rMBP on Linksys routers?

PS. The routers do have the latest firmware.

Saturday, June 16, 2012

Installing Memcached on CentOS

I have a web server running CentOS and wanted to get some good caching going for PHP use. This is how I installed memcached, from the command line:

  • Install memcached
    • yum install memcached
  • Install Pecl (if you don't yet have it, installing pear installs pecl)
    • yum install php-pear
  • Install Pecl's Memcached package (for PHP)
    • Install dependencies, as needed
      • yum install php-devel
      • yum install gcc
      • yum install zlib-devel
    • pecl install memcache
    • Use a text editor to add "extension=memcache.so" to php.ini (may be in the /etc folder)
  • Restart the service
    • service memcached start 
    • service httpd restart
And when you want some raw stats, you can get them via telnet:
  • telnet localhost 11211
And type "stats" to see hits, misses and more!

Here are some examples of memcached use in PHP.

Tuesday, April 10, 2012

iPad POS List

I did some research a while back and compiled a list of Point of Sale (POS) systems that function on the iPad (and some on the iPhone, too). It is strangely harder than you'd think to find a complete list, like this. So, here they are, in no particular order:

Wednesday, April 4, 2012

Filezilla Password File

Have an FTP password in Filezilla and need to get it? I often do, for some strange reason.

If you run Windows 7, go to C:\Users\YOUR_USERNAME\AppData\Roaming\FileZilla

You'll see a series of .xml files and sitemanager.xml stores all the goods (yes, in plain text... they let the OS/file-system handle security). Get what you need.

Wednesday, March 28, 2012

Floating Section Scrolls with Page (HTML & JS)

I had the need yesterday to make a section or block of HTML scroll with the page. I wanted it to stay in a spot on the page, relative to all else, until the visitor scrolled the page down. Then I wanted it to stay at the top of the page, never scrolling off the page. It was to be a section (eg, a navigation bar or image) that essentially had an initial "parked" position in the design, but should always be visible, even when the user scrolls down. Check out the illustration to the right and an example of the code in use.

I've seen different implementations of this. The most popular solution is a "chaser" where the element's absolute position is updated dynamically after each page scroll event. You have probably seen sites like this. They are a bit annoying and clunky - the element is constantly hiding and showing after every scroll.

After no luck finding a solution that I liked, I created one. It is below for your enjoyment. It uses jQuery to make things easier (ie, this framework is required). Take, use and be merry.

AND, the javascript:

$(function() {
 
 window.floater = {};
 
 /* Settings */
 window.floater.element = $('#float'); // Element to float
 window.floater.topMargin = 20; // Margin from top of window
 
 /* Global Vars & Initial Position */
 window.floater.captured = false;
 window.floater.posi = window.floater.element.offset();
 window.floater.marginLeft = parseInt(window.floater.element.css('margin-left').replace('px', ''), 10);
 
 $(window).scroll(function() {
  var curScroll = {
   top: $(window).scrollTop(),
   left: $(window).scrollLeft()
  };
  
  if (curScroll.top >= (window.floater.posi.top - window.floater.topMargin)) {
   
   if (!window.floater.captured) {
    window.floater.captured = true;
    var scrollAtTrigger = curScroll.top;
    if ((window.floater.posi.top - scrollAtTrigger) < window.floater.topMargin) scrollAtTrigger = window.floater.posi.top - window.floater.topMargin;
   }
   
   window.floater.element
    .css({
     position: 'fixed',
     top: (window.floater.posi.top - scrollAtTrigger)+'px',
     left: (window.floater.posi.left - window.floater.marginLeft - curScroll.left)+'px'
    });
    
  } else {
   
   window.floater.captured = false;
   window.floater.element.css({ position: 'static' });
   
  }
 });
 
 $(window).resize(function() {
  var posiFix = window.floater.element.css({position: 'static'}).offset();
  window.floater.element.css({position: 'fixed'});
  window.floater.posi.left = posiFix.left;
  $(window).scroll();
 });
 
});

The nuts and bolts: Put the float wherever you'd like it to be on the page initially. Then, when the document is loaded, the JavaScript goes to work. It sets up two events: one page-scroll event and one page-resize event. This is where the hard work is done. Once the page scrolls past a certain point, the position of the floater is set to fixed which means it remains a certain position relative to the window or viewport. There is no flickering or chasing using this method. It is clean and smooth.

Note: The floater's initial CSS position must be set as 'static' (which is a CSS default if it is undeclared). If you need to set it to 'relative' or 'absolute', use a wrapper to position it.

Note 2: I've noticed on Firefox 6.0 that there is a weird bug (?) that causes iframes to refresh if their positioning switches from 'static' to 'fixed'. So, if you plan on playing a YouTube video in your floater, beware: it my refresh and reset your video on scroll.

Tuesday, March 27, 2012

Lyrics - Beautifully Displayed

A friend and I decided the world needed a lyric site that looked good and didn't bombard you with ads. We put together Lyric Garden for this purpose. We're only starting with a few songs to see how things go. Check it out.

Thursday, March 22, 2012

Turn your iPod Touch into a Phone

This was kind of a fun little project, so I thought I'd share. Just a heads up, before you get too far along, this is not free. I know Google is in the habit of giving away things like free phone calls, but this stuff (like making real phone calls) generally costs money.

First, you'll need an app for that. I downloaded the Bria VoIP SIP phone app. (It is also available for the iPad.) This handy little app turns your iPod touch (or iPad) into a VoIP phone -- in other words, you can make phone calls over WiFi or a data connection.

Next, you'll need a phone number (also called a DID). There are a lot of service providers out there but I've used Flowroute, a company with servers in the southeast, for my interconnect. They charge about 1 cent per minute for calls to anywhere in the US plus $1.40 a month for the number. Needless to say, you can make a lot of long distance calls on the cheap.

Lastly, you'll need to configure your Bria app to work with Flowroute. To do this, log into Flowroute and click on the "interconnection" tab. There you'll find the info you'll need. Then start the Bria app on your iPod and go to "settings" and click the plus sign to add a new account.

Bria SettingFlowroute Setting
"Display as"Your phone number (eg, "15551230000")
"Username"Your phone number (eg, "15551230000")
"Password""Password"
"Domain""SIP Registrar / Proxy"
"Out. Proxy""SIP Registrar / Proxy"
"Auth Name""Username & Auth Username"

And that is it. Easy peasy. Click "Register" and your portable Apple device is a VoIP phone and you can make reliable, clear phone calls on the cheap. (Note: You'll need a pair of headphones that have a mic built in, like the headphones that come with the newer iPods.)

Sunday, February 26, 2012

Google and Privacy - Freakin' me out

I love Google and their innovative (and FREE) products and services. But lately, they're starting to freak me out.

For one, I noticed that all the display ads on the sites I visited started to look the same. That's right, Google knew what sites I had visited in the past and were showing ads for these sites. It was mildly disturbing. I guess I should have known that they had all that data on me, but when you start fixing my ads it is a little creepy. And how do you stop this? You can't unless you install an extension on your browser. That's right, there is actually no natural, install-free way to stop it. Google's extension for doing this is called IBA Opt-out (stands for Interest Based Ads).

(Aside: Does anyone else think that the weird random combination of lower-case letters in the Chrome Web Store URLs make it look like a spam site?)

Google web search has added a new feature lately that is creepin' me out, too. There is a new integration with your social contacts. I don't have a Google+ account yet I keep seeing what friends of mine recommend when I search for something on the web. I don't care what they recommend! I am searching Google not asking my friend Bill what he thinks. I could care less. And showing pictures of my friends at the top after I search is not as endearing as you'd think. It is like I having a friend whisper his answer in my ear every time I ask someone else a question.

If you go to Google websites even occasionally, it is hard to miss that they have a new privacy policy that starts March 1st. I applaud the simplicity of the policy. However, I suspect that it isn't as innocent as it appears. Google now wants the ability to share your information across all of their products. That's right, you could have a Google Docs account and a Gmail account and now Google wants to be able to use that information to shape your ads on Google Search. And even better, they can use your Google+ demographic data for their ads! (See 3/23/12 Update.)

To rant a bit longer, what about the strange Google Chrome login that has started to appear in my browser? I don't even remember asking it to sync EVERYTHING between my two computers and their browsers. But it assumed I did. How nice (that's sarcasm, by the way).

This all is starting to make me want to diversify. Microsoft, for instance, appears to have a nice replacement for Google Docs. Maybe it also time to switch to WordPress for my blog. One thing  is for sure, I certainly wont be using Google+ anytime soon. That's all I need, to give Google more personal information about me.

This is affecting how I see Google new products, now. I saw an article today about a new Google tablet. If this had come out last year, I would be excited to check it out. Now, well ... not so much. Why would I buy something from the company that has an over-zealous approach to taking my information and spreading it across all of their services and sites with or without my permission? No thanks.

Update 3/2/12: After reading this I started migrating my personal Blogger blogs to a self-hosted multi-site WordPress install. This one blog (firelitdesign) is going to stay here for the time being. The rest were migrated.

Update 3/23/12: An ex-Googler apparently also had concerns and started a project to help block Google, Facebook and Twitter from tracking your movements around the web.

Friday, February 24, 2012

Forming a Michigan LLC

When I was living in California a few years back I used LegalZoom to form an LLC. After that I moved to Washington and now I live in Michigan. In each of these last two states I formed an LLC without the help of a 3rd party. I was surprised how easy it was. So I am writing this post to help residents of Michigan. There is no reason to pay LegalZoom to do these things for you... save your money, it's easy!

Quick disclaimer: I'm not a lawyer and I don't want to be one. So take this all with a grain of salt. I may be wrong on some detail and if you really want to make sure you did everything correctly, you should contact a lawyer.

Michigan LLC
Step 1 is to make sure you can actually use the name you picked out -- someone may have beaten you to it. I'd recommend doing a quick Michigan search and USPTO trademark search for your business name. (Michigan has some more business naming guidelines that may be helpful.)

Step 2 is to form the LLC. Click here to download the required form (BCS/CD-700). Now, the instructions are on page 2 and it is pretty clear, but I thought I'd summerize if you aren't into reading instructions.

Article I: This will be the name of your company. Don't forget to add "LLC" to the end of the name. It is required.
Article II: You can just say that you're generally in compliance or list what your LLC will be doing for business.
Article III: Leave blank if the LLC has no end or dissolution date.
Article IV: This is where you put your name and address.
Article V: This is where you would tell Michigan that your LLC is managed by a manager (someone besides the LLC members). But for most, like freelancers and small home-businesses, you will be member-managed and will leave this field blank.

Have it signed by each member and send it in. It will take about 2 or 3 weeks to hear back (unless you expedite).

Lastly, after you form your Michigan LLC (and get back confirmation) you can apply for a DBA name (if you'll be operating under another name besides your new LLC) and get a FEIN (a kind of social security number for a business).

It is all quite easy. Save yourself some money and do it yourself.

Wednesday, January 25, 2012

jQuery UI & Disabling Text Selection on Click

Part of making a wonderfully interactive website with jQuery is the process of making certain elements clickable. Sometimes that means making a portion of text interactive without using the regular means of a hyperlink. One problem comes up when doing this, however. When a person clicks rapidly the browser usually interprets this to mean you want to highlight a word or paragraph. How do you stop this? Call .disableSelection() on the element with jQuery. This will disable text selection. For example:
$('#elementId').disableSelection();
It actually binds an event on the object which prevents the default behavior. It is an undocumented feature but it is awfully handy. Remember: it requires jQuery and jQuery UI as it is part of the jQuery UI core.

Friday, January 13, 2012

Synchronous AJAX with JQuery

Yes, you read that right. I just didn't think anyone would understand SJAX.

AJAX, if you don't know, stands for Asynchronous JavaScript and XML and is the term widely applied to sending HTTP POST and GET requests from client-side javascript. In JQuery, that would be $.ajax() or $.getJSON() or any one of the other similar variations.

The question that I had, to continue with the topic of this post, was, How do I do preform a synchronous AJAX call? That is, how would I treat an AJAX call as if it were inline javascript. The JQuery functions I mention above have a parameter where you would specify the call-back function that would run after the requested document is fully retrieved by the client, hence the response and call back are run asynchronously, or whenever the response has been received from the server. Then, how do I make this synchronous so that the code after the call does not execute until the javascript GET or POST is complete.

Well, it is pretty darn easy, I've found. There is a single parameter, "async," that you set to false. That's it. I've written this whole blog post and the answer is a one-word parameter: async.

$.ajax(ajaxurl, {
     async: false
});

So, now you know how to do SJAX. ;)