Tuesday, March 1, 2016

Implementing Ionic ion-slides in place of the deprecated ion-slide-box

I have been working with Ionic 1.7.14 lately and ran into issues with <ion-slide-box>. It turns out <ion-slide-box> is deprecated and replaced by <ion-slides>. Unfortunately, the documentation is poor. The silver lining is that it is worth the switch as ion-slides is built on iDangerous' Swiper which is probably the best slider/slidebox out there.

For those Ionic loyalists who live by the documentation, good luck making much of anything great based on the documentation at http://ionicframework.com/docs/v2/api/components/slides/Slides/ and http://ionicframework.com/docs/v2/components/#slides.

The reason I say this is because the documentation doesn't show how to expose all the functions of the Swiper plugin via javascript which are seemingly endless (http://idangero.us/swiper/api/). This is also the main reason to even use the new <ion-slides> directive. While you can specify options like loop and pagination (see below) via the Ionic directive's "option" directive, these aren't even explained in the docs except as when used as directives themselves (i.e. pager and loop). Further, it is especially unclear how the entire Swiper API can be leveraged using <ion-slides>.

Here is a solution, specifically note the onInit which captures the Swiper plugin (in original form) to the $scope. Now you can leverage the Swiper API (as referenced in link above) against this $scope.swiper object. The $scope.sliderOptions will be used by the <ion-slides> via the "options" directive as mentioned previously.

// CONTROLLER
// Setup swiper
$scope.sliderOptions = {
    loop: true,
    pagination: false,
    onInit: function(swiper){
        $scope.swiper = swiper;
    },
    onSlideChangeStart: function(swiper){
        //
    }
};

// TEMPLATE
<ion-slides options="sliderOptions">
    <ion-slide-page ng-repeat="slidesin slides">
        // iDangerous Swiper Slide in Ionic
    </ion-slide>
</ion-slides>

Tuesday, February 16, 2016

Installing Cisco VPN Client and SonicWall Global VPN Client on Windows 10 Upgrade

So you've upgraded to Windows 10 and been promised everything will keep working just as before... but one of the most important apps you have is now broken! This is what happened to me when upgrading to Windows 10. Both my Cisco VPN Client and SonicWall Global VPN Client stopped working. Fortunately, there is a fix... and it is surprisingly pretty.

In comes TechyGeeksHome to the rescue! They have put together a great utility to help rectify these issues (specifically for Cisco VPN, but works for SonicWall Global VPN too).


  1. Uninstall your VPN(s).
  2. Go to http://blog.techygeekshome.info/2016/01/cisco-vpn-client-how-to-make-it-work-with-windows-10.
  3. Download the Windows 10 fix package.
  4. Run the included WinFix.exe (by Citrix)
  5. Run the included DNE Update (by Citrix)
  6. Install the Cisco VPN MSI (the exe will not work) (msi for x64 can be found here according to Google search)
  7. Run the included CiscoVPNClientFixx (by TechyGeeksHome)
  8. If you also want to use SonicWall Global VPN, you can now install it as well
These steps solved my issues and I am back up and running on Windows 10 + VPN thanks to TechyGeeksHome.

Sunday, January 31, 2016

Android Intent App Options Now Include Apps from Play Store That Are Not Installed On Device

I was using my android recently and noticed something quite surprising. I was opening an .XLSX file and the typical intent/app selection popover came up on screen. I had Google Sheets and Quickoffice apps as options as always (they are installed on my device), but I now also had an "Excel" option with the text "Free" to the right. At this point I'm not sure what goes into getting a "yet-to-be-installed" app to appear in the list of intent/app options, but this is a pretty big move for Android to take. What do you think?

Here is a screenshot for your enjoyment:

Sunday, December 13, 2015

Fixing iOS 9 (9.1,9.2) Blank uiWebView Page in a Corona App

As expected, an update has come along that breaks something in your Corona app... this particular issue has to do with changes in iOS 9 uiWebView security. If you are not connecting your webview via (valid) https, you will now get a blank  page in your webview. This can be resolved by customizing App Transport Security settings in info.plist (for native apps). This file won't exist in your Corona project, but it is supported via the build.settings file. There is a Corona forum post on how to update build.settings to generate the necessary info.plist settings in your build here. Even better, there is a Corona blog entry with more insight here. Finally, if you want to truly understand your settings, reference the Apple docs on this here.

In the end, your build.settings will need an exception added like so:

settings = { iphone = { plist = { NSAppTransportSecurity = { NSExceptionDomains = { ["example.com"] = { NSIncludesSubdomains = true, NSThirdPartyExceptionAllowsInsecureHTTPLoads = true }, }, }, }, }, }


If you control the domain, you should use NSExceptionAllowsInsecureHTTPLoads rather than NSThirdPartyExceptionAllowsInsecureHTTPLoads. Only use NSIncludesSubdomains if you need to allow multiple subdomains.

Of course, the ideal solution is to ensure any webview is connecting via a valid https connection... but that is not always possible.

Wednesday, November 25, 2015

Ebates First 30 Days Review

Of course I had heard of Ebates, but I had never actually tried Ebates until 30 days ago as per the recommendation of a friend. This is my 30 day review.

The main reason I had never tried Ebates before is because the idea of coupon sites, comparison sites, and deal sites has become quite lackluster to me over the years. I thought Ebates was the same as the rest. I thought I could just assume Ebates was another comparison engine, posting coupons and deals just like the rest. Boy was I wrong...

My first experience with Ebates was great. I signed up, saw a promo for a $10 gift card after first $25 purchase and proceeded to order a laptop battery from Newegg. I would have ordered the battery from Newegg anyway, but now I was getting cashback and a $10 WalMart gift card just for clicking through from Ebates first. Sure enough, the cashback showed up in my account and my gift card was processed... not immediately of course, but ultimately it happened without any strings attached and without any intervention required. I have a $10 WalMart gift card on the way to me right now.

The first Ebates experience was good enough that I installed their chrome extension. Since then, I have made a couple more online purchases and received cashback. My cashback balance reached $5.33 in the first 30 days. I thought there was surely some strict threshold required before they would cut me a check, but I have a $5.33 check on the way as of today. Again, no strings attached and no intervention required.

Now that I've had a successful first month and Ebates has proven to be non-disruptive and practically automatic, I will certainly continue to use them. I have actually started looking for coupons again since Ebates makes that super easy as well. Further, I am considering some larger purchases I would have not otherwise considered due to 6% cashback and readily-available coupons via Ebates.

I highly recommend getting on board with Ebates. It is free and supports Facebook and Google login to make it even easier. Login and in 1-2 clicks you'll be on your favorite ecommerce store as always, but this time you'll be earning no-strings-attached cashback via Ebates.

If you're ready to sign up for Ebates now, click here to get started.

Tuesday, July 28, 2015

API for Retrieving Website Favicon with Fallback

I have worked on a number of projects where pulling in favicons from external websites needed to be done. This would typically be approached by checking for existence of a /favicon.ico in the root of the website or something along those lines. This isn't fool proof by any means though since the favicon can be named differently or located in a different path. It also takes a lot of unnecessary overhead to check for existence of a favicon before serving up a fallback.

Fortunately, there is a "hidden" Google API of sorts that handles this for you. It is used to pull in favicons for websites attached to your Google+ profile page. It works as follows:

http://s2.googleusercontent.com/s2/favicons?domain=mrrobwad.blogspot.com&alt=p

It turns out the fallback can be one of a few things. So far, I've discovered that setting the 'alt' parameter to 's' yields a blank page icon and 'p' yields a page template icon when no favicon is available. Setting to any other single letter yields a browser/world icon. There could be more, but I have only checked for single letters so far.

Enjoy!

Friday, July 3, 2015

How To: Minify JS and CSS with ColdFusion

If you're reading this post, I can assume two things.
  1. You're running ColdFusion and need to minify JS and/or CSS files.
  2. You've researched other solutions such as complex regex routines or CFCs and are not satisfied with those solutions.
Regarding #2, modern minification is complex and tedious. If you've tried writing your own routines, you know what I mean. Not to mention, effective minification consists of more than just code formatting. So what's the answer? Well, there is already a clear and proven minification winner: YUI Compressor. This utility is widely used, reliable, and efficient. It also includes useful options to give you some level of control as well as insight.

Now that we've picked our minification engine, how do we make it work with ColdFusion?

First you need to get YUI Compressor installed on your server and YUI Compressor relies on Rhino, so we need to get that installed as well. All of this relies on you having Java installed, but since you are running ColdFusion I am assuming you do!


DOWNLOAD RHINO (recommended release at time of this post is 1.7R5)
  • Install to directory of choice, i.e. C:\apps\rhino\rhino1_7R5
  • Add to Windows CLASSPATH
    • System Properties > Advanced > Environment Variables > System Variables > CLASSPATH
      • If CLASSPATH system variable doesn't already exist, add it with value of "c:\apps\rhino\rhino1_7R5" or your chosen install directory.
      • If CLASSPATH system variable already exists, edit it by adding ";c:\apps\rhino\rhino1_7R5" or ";" followed by your chosen install directory.

DOWNLOAD YUI COMPRESSOR (recommend release at time of this post is 2.4.8)
  • Install to directory of choice, i.e. c:\apps\yuicompressor\yuicompressor-2.4.8.jar

Verify you can run YUI Compressor from command line
  • Open a command prompt in a test directory with a non-minified JS file present, i.e. test.js
  • Run command $ java -jar c:\apps\yuicompressor\yuicompressor-2.4.8.jar -v c:\test\test.js -o test.min.js
  • The "-v" argument causes output to include analysis of the JS with tips for improvements. Don't include this option if you are minifying CSS.
  • You should see test.min.js created in the current/test directory.

Run minification from within ColdFusion:
  • Use <cfexecute> to run YUI Compressor against file in need of minification.
  • minifyResult will contain the command prompt output.
  • minifyError will contain error information.
<cfexecute name="java" arguments="-jar c:\apps\yuicompressor\yuicompressor-2.4.8.jar c:\test\test.js -o test.min.js" variable="minifyResult" errorVariable="minifyError" timeout="10"/>

  • ColdFusion runs cfexecute from the ColdFusion bin, so this is where the minified file will be generated, so we need to move the generated file from the CF bin to the desired target directory.
  • The cf_bin_path variable value will likely be different for your install, so you need to update this variable to point to your actual CF bin directory.
<cfset cf_bin_path = "c:\ColdFusion\runtime\bin">
<cffile action = "move"
source = "#cf_bin_path#\test.min.js"
destination = "c:\target-directory\test.min.js">