Friday, July 25, 2014

How to associate a file name extension with a darwin /linux/unix command-line executable on osx/macintosh.

One of the things one can do with self-serving (a multi-platform command-line executable for making simple tools that employ the user's browser as the UI and javascript for the logic), is to bundle a bunch of resources into a file with the ".slfsrv" extension; for example "morningMenu.slfsrv".  On my macintosh I could execute this from the command line "self-serving morningMenu.slfsrv" or on the Windows command line with "self-serving.exe morningMenu.slfsrv".

I wanted to associate the ".slfsrv" extension with the executable, so that one could run a .slfsrv program simply by double-clicking on the file in OSX's Finder or Windows' explorer. This was very easy in Windows but on the Mac it took me quite a while to figure out. It turns out you can't associate a file extension with a simple executable, it has to be a  Mac App.

How to mac a Mac App from a darwin executable

To make a Mac App from a darwin executable

  1. Launch the Automator application
  2. Click "New Document"
  3. For document type select Application
  4. From the Actions library on the left select select "Run Shell Script" and drag that to the workplace on the right
  5. Change the "Pass input" option to "as arguments"
  6. Edit the shell script for what to be something like one of these:

    /path/to/my/exec/myexecutable "$@"

    or

    for f in "$@"
    do
        /path/to/my/exec/myexecutable "$f"
    done
  7. Select File/Save and create a name and location for your ".app" file. In my case I called this "SelfServing.app" and put it in my "~/bin" folder

You next want to associate a file extension with the .app you just created, as follows:

  1. In the finder open a folder containing a file of that type. In my case I opened the folder containing the file morninMenu.slfsrv
  2. Right click on the file and select "Get Info"
  3. Under "Open With" select "Other..." and locate the .app file you created from Automator (you probably want to have all files with that extension opened with your app).
Using it

That's it. Now you can run the command-line program on all files with that executable simply by double clicking that type of file in Finder, or from the command-line typing "open myfile.myextension"

Thursday, June 12, 2014

Sharing picasa photos, albums, and tags between Windows and Macintosh OSX computers

So, you have all your pictures on your computer, you view and tag them with Picasa, and your Windows-using spouse wants to have the same photos and tags and albums and such on her Windows machine. What do you do?

First you share your picture folders between machines using BitTorrent Sync. That works great. Oh Joy!

Next, after you've spent hours on your Macintosh tagging people in all the photos, you want your spouse to see all those same tags on her Windows machine. So you play around with sharing the Picasa "contacts" folder, and you try sharing the "db3" folder, and you try the "store name tags in photo" Picasa options, and the experimental "write faces to XMP" and various combinations of the above.  No matter what you try, at best it doesn't share data between machines, and at worst it corrupts your data.

So you stop syncing everything except the photo folders themselves. And you restore your "contacts" and "db3" folders (you did remember to back those up, didn't you), and you give up on you and your spouse ever having the benefit of being able to share your tagged people faces.

Sigh.

Tuesday, May 27, 2014

How I use Google AdSense and Google Analytics with Meteor websites

Here is how I managed to get Google AdSense and Google Analytics into my Meteor websites: airbnbconfessions and NoMorePasswordsJustEmail.

Google Analytics is easy

It's not difficult getting Google Analytics into your Meteor web app. Simply take the Google Analytics startup code and put it in client-side of your Meteor source.

Here, for example, is a file I have within the /client directory of my Meteor airbnbconfessions source code.

Meteor.startup(function() {
    $(document).ready(function() {
        // show google analytics if running on the live web site
        if ( -1 != document.URL.indexOf("www.airbnbconfessions.com") )
        {
            (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
            (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
            m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
            })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

            ga('create', 'UA-YOUR-CODE-HERE', 'airbnbconfessions.com');
            ga('send', 'pageview');
        }
    });
});

Note that I rely on jQuery and $(document).ready() but I assume Meteor.startup() probably would work as well.

Google Adsense is trickier

Two problems: 1) Meteor really wants to be in controls of rendering all your HTML, and 2) Google really wants the page to exists as some raw HTML before rendering the ads.

For (1), Meteor provides the /public directory. Anything in /public bypassed the Meteor rendering system and is just available to the web client like any other raw internet file.

For (2), the ads will be loaded within iframes, refereing to those /public files, from the main page.

Bringing Google Adsense and Meteor together

In NoMorePasswordsJustEmail, I want the ads to appear in the right for web browsers, but on the bottom for mobile browsers. So in my primary index.html file uses bootstrap classes in this code:

<div id="list-stuff">
      <div class="row">

        <div class="span9">

          ...page stuff...

        </div>

        <div class="span3 hidden-phone" style="text-align:center;">
          <center>
            {{> adsRight}}
          </center>
        </div>
      </div>

      <div class="row visible-phone" style="margin-left:-20px;margin-right:-20px;">{{! style makes up for 20 pixels added to body }}
        <div class="span10" style="text-align:center;">
          <center>
            {{> adsBottom}}
          </center>
        </div>
      </div>

    </div>

Those adsright and adsbottom templates render iframes that will load the files that were in  /public and look like this client/ads.html file.

<!-- google ads stuff -->
<!-- http://stackoverflow.com/questions/14389766/meteor-js-use-external-script -->
  <template name="adsRight">
    <div id="adsRight">
      <iframe src="/adright.html?v={{{unique}}}" seamless width="160" height="600" scrolling="no"
       frameborder="0" marginheight="0" marginwidth="0"
       style="margin:0;padding:0;border:none;width:160px;height:600px"></iframe>
    </div>
  </template>
  <template name="adsBottom">
    <div id="adsBottom">
      <hr/>
      <iframe src="/adbottom.html?v={{{unique}}}" seamless width="336" height="280" scrolling="no"
       frameborder="0" marginheight="0" marginwidth="0"
       style="margin:0;padding:0;border:none;width:336px;height:280px"></iframe>
    </div>
  </template>

That code refers to unique, just force Google to take a moment to check the text on the page each time, and provide a fresh ad as the text of the page changes with new reloads. client/ads.js provides that:

Template.adsRight.unique = function() {
    return (new Date()).valueOf();
};

Template.adsBottom.unique = function() {
    return (new Date()).valueOf();
};

Finally, the two files that like to the ads themselves.

public/adbottom.html:

<html>
<head>
<style type="text/css">
* {
    margin: 0;
    padding: 0;
}
</style>
</head>
<body>
<div>

<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- nmpjebottom -->
<ins class="adsbygoogle"
     style="display:inline-block;width:336px;height:280px"
     data-ad-client="ca-pub-YOUR-GOOGLE-CODE"
     data-ad-slot="YOUR-GOOGLE-ADSLOT"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>

</div>
</body>
</html>

public/adright.html:

<html>
<head>
<style type="text/css">
* {
    margin: 0;
    padding: 0;
}
</style>
</head>
<body>
<div>

<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- nmpjeright -->
<ins class="adsbygoogle"
     style="display:inline-block;width:160px;height:600px"
     data-ad-client="ca-pub-YOUR-GOOGLE-CODE"
     data-ad-slot="YOUR-GOOGLE-ADSLOT"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>

</div>
</body>
</html>

That's all.

Good luck. My fingers are crossed for you.