Warning: Declaration of P_Photocrati_NextGen::define() should be compatible with C_Base_Product::define($id = 'pope-produ...', $name = 'Pope Produ...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/product.photocrati_nextgen.php on line 0

Warning: Declaration of M_Fs::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/fs/module.fs.php on line 0

Warning: Declaration of M_Router::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/router/module.router.php on line 0

Warning: Declaration of M_I18N::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/i18n/module.i18n.php on line 0

Warning: Declaration of M_Validation::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/validation/module.validation.php on line 0

Warning: Declaration of M_WordPress_Routing::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/wordpress_routing/module.wordpress_routing.php on line 0

Warning: Declaration of M_Security::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/security/module.security.php on line 0

Warning: Declaration of M_Lzw::define($context = false) should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/lzw/module.lzw.php on line 0

Warning: Declaration of M_NextGen_Settings::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/nextgen_settings/module.nextgen_settings.php on line 0

Warning: Declaration of M_MVC::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/mvc/module.mvc.php on line 0

Warning: Declaration of M_Ajax::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/ajax/module.ajax.php on line 0

Warning: Declaration of M_Dynamic_Stylesheet::define($context = false) should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/dynamic_stylesheet/module.dynamic_stylesheet.php on line 0

Warning: Declaration of M_Frame_Communication::define($context = false) should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/frame_communication/module.frame_communication.php on line 0

Warning: Declaration of M_DataMapper::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/datamapper/module.datamapper.php on line 0

Warning: Declaration of M_NggLegacy::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/ngglegacy/module.ngglegacy.php on line 0

Warning: Declaration of M_NextGen_Data::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/nextgen_data/module.nextgen_data.php on line 0

Warning: Declaration of M_Dynamic_Thumbnails::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/dynamic_thumbnails/module.dynamic_thumbnails.php on line 0

Warning: Declaration of M_NextGen_Admin::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/nextgen_admin/module.nextgen_admin.php on line 0

Warning: Declaration of M_NextGen_AddGallery_Page::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/nextgen_addgallery_page/module.nextgen_addgallery_page.php on line 0

Warning: Declaration of M_NextGen_Pagination::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/nextgen_pagination/module.nextgen_pagination.php on line 0

Warning: Declaration of M_Gallery_Display::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/nextgen_gallery_display/module.nextgen_gallery_display.php on line 0

Warning: Declaration of M_Attach_To_Post::define($context = false) should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/attach_to_post/module.attach_to_post.php on line 0

Warning: Declaration of M_NextGen_Other_Options::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/nextgen_other_options/module.nextgen_other_options.php on line 0

Warning: Declaration of M_NextGen_Pro_Upgrade::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/nextgen_pro_upgrade/module.nextgen_pro_upgrade.php on line 0

Warning: Declaration of M_MediaRss::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/mediarss/module.mediarss.php on line 0

Warning: Declaration of M_Cache::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/cache/module.cache.php on line 0

Warning: Declaration of M_Lightbox::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/lightbox/module.lightbox.php on line 0

Warning: Declaration of M_NextGen_Basic_Album::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/nextgen_basic_album/module.nextgen_basic_album.php on line 0

Warning: Declaration of C_NextGen_Basic_Album_Installer::install() should be compatible with C_Gallery_Display_Installer::install($reset = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/nextgen_basic_album/class.nextgen_basic_album_installer.php on line 0

Warning: Declaration of M_NextGen_Basic_Templates::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/nextgen_basic_templates/module.nextgen_basic_templates.php on line 0

Warning: Declaration of M_NextGen_Basic_Gallery::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/nextgen_basic_gallery/module.nextgen_basic_gallery.php on line 0

Warning: Declaration of C_NextGen_Basic_Gallery_Installer::install() should be compatible with C_Gallery_Display_Installer::install($reset = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/nextgen_basic_gallery/class.nextgen_basic_gallery_installer.php on line 0

Warning: Declaration of M_NextGen_Basic_ImageBrowser::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/nextgen_basic_imagebrowser/module.nextgen_basic_imagebrowser.php on line 0

Warning: Declaration of C_NextGen_Basic_ImageBrowser_Installer::install() should be compatible with C_Gallery_Display_Installer::install($reset = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/nextgen_basic_imagebrowser/class.nextgen_basic_imagebrowser_installer.php on line 0

Warning: Declaration of M_NextGen_Basic_Singlepic::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/nextgen_basic_singlepic/module.nextgen_basic_singlepic.php on line 0

Warning: Declaration of C_NextGen_Basic_SinglePic_Installer::install() should be compatible with C_Gallery_Display_Installer::install($reset = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/nextgen_basic_singlepic/class.nextgen_basic_singlepic_installer.php on line 0

Warning: Declaration of M_NextGen_Basic_Tagcloud::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/nextgen_basic_tagcloud/module.nextgen_basic_tagcloud.php on line 0

Warning: Declaration of C_NextGen_Basic_Tagcloud_Installer::install() should be compatible with C_Gallery_Display_Installer::install($reset = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/nextgen_basic_tagcloud/class.nextgen_basic_tagcloud_installer.php on line 0

Warning: Declaration of M_Widget::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/widget/module.widget.php on line 0

Warning: Declaration of M_Third_Party_Compat::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/third_party_compat/module.third_party_compat.php on line 0

Warning: Declaration of M_NextGen_XmlRpc::define() should be compatible with C_Base_Module::define($id = 'pope-modul...', $name = 'Pope Modul...', $description = '', $version = '', $uri = '', $author = '', $author_uri = '', $context = false) in /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/nextgen_xmlrpc/module.nextgen_xmlrpc.php on line 0

Warning: session_start(): Cannot send session cookie - headers already sent by (output started at /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/product.photocrati_nextgen.php:0) in /home/sidesul6/public_html/wp-content/plugins/one-time-password/wp-otp-class.php on line 78

Warning: session_start(): Cannot send session cache limiter - headers already sent (output started at /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/product.photocrati_nextgen.php:0) in /home/sidesul6/public_html/wp-content/plugins/one-time-password/wp-otp-class.php on line 78

Warning: Declaration of Walker_PostExpirator_Category_Checklist::start_lvl(&$output, $depth, $args) should be compatible with Walker::start_lvl(&$output, $depth = 0, $args = Array) in /home/sidesul6/public_html/wp-content/plugins/post-expirator/post-expirator.php on line 0

Warning: Declaration of Walker_PostExpirator_Category_Checklist::end_lvl(&$output, $depth, $args) should be compatible with Walker::end_lvl(&$output, $depth = 0, $args = Array) in /home/sidesul6/public_html/wp-content/plugins/post-expirator/post-expirator.php on line 0

Warning: Declaration of Walker_PostExpirator_Category_Checklist::start_el(&$output, $category, $depth, $args) should be compatible with Walker::start_el(&$output, $object, $depth = 0, $args = Array, $current_object_id = 0) in /home/sidesul6/public_html/wp-content/plugins/post-expirator/post-expirator.php on line 0

Warning: Declaration of Walker_PostExpirator_Category_Checklist::end_el(&$output, $category, $depth, $args) should be compatible with Walker::end_el(&$output, $object, $depth = 0, $args = Array) in /home/sidesul6/public_html/wp-content/plugins/post-expirator/post-expirator.php on line 0

Warning: Cannot modify header information - headers already sent by (output started at /home/sidesul6/public_html/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/product.photocrati_nextgen.php:0) in /home/sidesul6/public_html/wp-includes/feed-rss2.php on line 8
SideApps http://sideapps.com Tue, 20 Jan 2015 15:28:24 +0000 en-US hourly 1 http://wordpress.org/?v=4.3.5 DreamRight Wherefore Art Thou http://sideapps.com/iphoneipod-touch-apps/dreamright-wherefore-art-thou/ http://sideapps.com/iphoneipod-touch-apps/dreamright-wherefore-art-thou/#comments Tue, 20 Jan 2015 15:28:24 +0000 http://sideapps.com/?p=377 I introduced DreamRight in my aptly named post Introducing DreamRight. Since then I’ve graduated from RPI, moved to Schenectady, adopted a dog and started work as a mobile developer at Transfinder. Excuses, I know.

Anyway, you’ll be absolutely devastated to hear the development on DreamRight has been temporarily suspended. My reasons are threefold (and will sound an awful lot like excuses).

  1. I had garnered all the knowledge I could regarding custom drawing routines and UIView Animations
  2. I moved onto another app that you’ll soon be hearing about
  3. I was busy!

That’s not to say I didn’t make any progress… I managed to get my custom dream log display working jusstttt right – check it out:

]]>
http://sideapps.com/iphoneipod-touch-apps/dreamright-wherefore-art-thou/feed/ 0
Introducing DreamRight http://sideapps.com/iphoneipod-touch-apps/introducing-dreamright/ http://sideapps.com/iphoneipod-touch-apps/introducing-dreamright/#comments Sun, 09 Nov 2014 07:04:31 +0000 http://sideapps.com/?p=372 I’ve been interested in lucid dreaming and sleep science for quite a while… One of the best ways to improve lucid dreaming skills is to keep a dream diary. I’ve tried this in the past and simply cannot bring myself to wake up and immediately type out or write down my dream as it quickly starts to fade from memory. I’ve had more success using the voice recording app but I had no easy way to organize these snippets or do anything useful without exporting them. Additionally, it quickly became too much trouble for me even start/stop/save a clip when all I want to do is close my eyes again.

DreamRight is an idea I’ve been tossing around in my head for some time. I’m focusing my personal programming projects on UI/UX where my skills are most lacking and decided this project would be a great candidate. Here’s a standard use case for the app:

  • Enter sleeping mode
  • Have a dream
  • Tap anywhere on the phone to activate voice recording
  • Tap again to stop or wait for the configurable silence timeout
  • Rinse and repeat until morning
  • Tap and hold to leave sleep mode and save your dreams
  • Add notes, transcribe recording to text, share dreams, etc

In essence this is a pretty simple app. However, like most of my projects, I can think of countless ways to expand functionality. In my other large scale iOS project, Rise, I started with the utility and am leaving most of the design until later. With DreamRight I’ve decided to take the opposite approach – placing design first and only moving on to a feature when I’m absolutely satisfied with the design.

So far all I’ve done is create the intro screen along with a little helper I built to design the star animations. I’m working on the dream log view and then will move on to the actual sleep mode. If anyone with an iPhone is interested in testing I’d be happy to add you as a tester – all I need is an email address. Take a look!

 

]]>
http://sideapps.com/iphoneipod-touch-apps/introducing-dreamright/feed/ 0
Quiz App for Transfinder http://sideapps.com/iphoneipod-touch-apps/quiz-app-for-transfinder/ http://sideapps.com/iphoneipod-touch-apps/quiz-app-for-transfinder/#comments Tue, 07 Oct 2014 18:59:28 +0000 http://sideapps.com/?p=359 I’m graduating soon and have been busy the past few weeks applying and interviewing for a handful of positions. One of these positions is with a fairly small company, Transfinder. Transfinder provides tools for school districts and parents to enhance safety and track a variety of factors for report generation. After a successful phone interview I was given a programming project for the next stage of the interview process. Transfinder gave me access to their API for three days and I was tasked with developing a program utilizing the API in some way.

The assignment was very open ended – there were no requirements on a programming language or specific functions. In the past year or so my personal projects have shifted mainly to iOS and Objective-C so an iPhone app was the clear choice. I developed an app that pulls data on students and schools from Transfinder’s API. The user is then presented with a simple quiz on students’ association with schools. This is a fairly simple description but the project also involved multithreading and custom draw routines. I’m very happy with the end result and it landed me a second, in-person interview. Check it out!

]]>
http://sideapps.com/iphoneipod-touch-apps/quiz-app-for-transfinder/feed/ 0
Campus Key for Foothill College http://sideapps.com/iphoneipod-touch-apps/campus-key-for-foothill-college/ http://sideapps.com/iphoneipod-touch-apps/campus-key-for-foothill-college/#comments Thu, 25 Sep 2014 20:35:00 +0000 http://sideapps.com/?p=352 I took an iOS development class at Foothill College a little over a year ago and ended up developing a small app for them. It’s a system to generate “key request forms” – a form that faculty and staff have to fill out for each and every office/building they need access to. I learned some neat tricks making it and am pretty happy with how it turned out.

 

]]>
http://sideapps.com/iphoneipod-touch-apps/campus-key-for-foothill-college/feed/ 0
Batch Download iOS App Icons http://sideapps.com/miscellaneous/batch-download-ios-app-icons/ http://sideapps.com/miscellaneous/batch-download-ios-app-icons/#comments Fri, 29 Aug 2014 15:24:55 +0000 http://sideapps.com/?p=338 This site has been in serious need of a redesign for years and a graphic designer friend of mine had the idea of spelling my domain using app icons! I loved this idea but I had a slight lack of letter based app icons to play around with (read: none).

It turns out Apple provides an iTunes Search API which I could use to programmatically access search results for any terms/categories/etc. The major limitation of this API is that it will only return 200 results for a single search term and has no way to specify pagination (so I can’t, for example, get results 200-400 in my request). The only way around this would be to download and parse the entire Enterprise Partner Feed which contains all metadata in the iTunes store. Regrettably, I am not an enterprise partner (yet) so I don’t have access to that data.

The JSON search results specify locations for both 60×60 and 512×512 app icon images. The script I’ve written prompts the user for a comma separated string containing a list of search results. The script will then query the Search API for each of the terms and download the 200 results into a subfolder named by the associated search term. There’s no support for searching in specific categories only or searching the top charts but that functionality would be trivial to add using the API documentation as reference.

Here is a link to all of the “letter icons” I’ve accumulated: letterIcons.zip (sorry, I only cared about SIDEAP)

I’ve also included the first draft of the new site logo (currently using the 2nd draft as of 8/29/14). If anyone wants to try their hand at another design I’ll give them two million dollars. Don’t forget to grab the source below as well! My apologies for the lack of comments in the code… I’m better than that.

Website Header Prototype A

import urllib2
import json
import os
import shutil
import thread

downloadCount = 0
totalDownloads = 0

# Download a single file
def downloadFile(url, destination):
	global downloadCount
	
	f = open(destination, 'wb')
	f.write(urllib2.urlopen(url).read())
	f.close()

	downloadMessage = 'Completed download ' + str(totalDownloads - downloadCount + 1) + '/' + str(totalDownloads)

	downloadCount -= 1

	print(downloadMessage)

# Icon downloading (multithreaded implementation)
def downloadIcons(searchTerm, results, verbosity):
	global downloadCount

	if verbosity > 0:
		print('Beginning download of ' + str(results) + ' results for search term "' + searchTerm + '"')

	if verbosity > 1:
		print('Sending HTTP request')

	requestString = 'https://itunes.apple.com/search?term=' + searchTerm + '&country=us&entity=software&media=software&limit=' + str(results)
	response = urllib2.urlopen(requestString).read()

	if verbosity > 1:
		print('Received HTTP response')
		print('Parsing into JSON')

	responseJSON = json.loads(response)
	resultCount = responseJSON['resultCount']

	if verbosity > 1:
		print('Received ' + str(resultCount) + ' results')

	for i in range(resultCount):
		appDict = responseJSON['results'][i]
		appName = appDict['trackName']
		appIcon60 = appDict['artworkUrl60']
		appIcon512 = appDict['artworkUrl512']
		appIcon60Ext = appIcon60[appIcon60.rindex('.'):]
		appIcon512Ext = appIcon512[appIcon512.rindex('.'):]

		appName = appName.replace('/', ' ')

		if verbosity > 0:
			print('Downloading App "' + searchTerm + '" ' + str(i + 1) + '/' + str(resultCount))

		if verbosity > 1:
			print('\tName: ' + appName)
			print('\tIcon 512x512: ' + appIcon512[appIcon512.rindex('/') + 1:])

		targetDir = 'Icons/' + searchTerm + '/'

		downloadCount += 1

		thread.start_new_thread(downloadFile, ((appIcon512, targetDir + appName + '512x512' + appIcon512Ext)))

		if verbosity > 1:
			print ('\t\tDownloaded!\n')

# Main function
if __name__ == '__main__':
	if not os.path.isdir('Icons'):
		os.mkdir('Icons')

	while (True):
		searchTerm = raw_input('Please enter the search terms seperated by commas (! to exit): ')
		if searchTerm == '!':
			break

		searchTermList = searchTerm.split(',')

		threadedTerms = []

		for term in searchTermList:
			targetDir = 'Icons/' + term

			if os.path.isdir(targetDir):
				userResponse = raw_input('Icons for search term "' + term + '" have already been downloaded... Redownload (y/n)? ')
				if userResponse == 'n':
					continue

				shutil.rmtree(targetDir)

			threadedTerms.append(term)

			os.mkdir(targetDir)

		for term in threadedTerms:
			totalDownloads += 200
			thread.start_new_thread(downloadIcons, (term, 200, 0))

		wait = raw_input()

 

]]>
http://sideapps.com/miscellaneous/batch-download-ios-app-icons/feed/ 0
Introducing Rise http://sideapps.com/iphoneipod-touch-apps/introducing-rise/ http://sideapps.com/iphoneipod-touch-apps/introducing-rise/#comments Thu, 14 Aug 2014 04:23:52 +0000 http://sideapps.com/?p=318

I’m an avid biker currently living on the slope of what could be considered a plateau. Downtown elevation is ~5-10 meters, I live at ~60 meters and the top of my campus is ~100-120 meters. Suffice to say, I’ve been doing some hill training. I’ve used MapMyRide to track my workouts in the past but I’d like a workout tracker centered around elevation. Now entering the ring: Rise.

Rise aspires to be a simple, straightforward application geared entirely around elevation data (leaving the possibility for almost endless expansion). So far, response has been mixed – many people don’t see a need for this app and it’s been brought to my attention that Strava provides similar elevation graphing options. However, I believe by focusing mainly on elevation that my app will be able to match my high standards of simplistic UX and beautiful UI. Also I want it so I’m doing it.

I’ve been developing Rise in my free time for a little over a month and I’m very pleased at the progress I’ve made. I’m still in the experimental stages and have put no thought or time into UI or UX. I’m confident I’ll be able to get the elevation graph to display just the way I want it but I need some guidance/assistance in coming up with a “workflow” for the app. I haven’t reached the point where I’m ready to dedicate my own focus toward UX design and it would be wonderful to find someone interested in working on this with me.

Here are the features I’ve got working:

  • Local GPS lat/long/elevation logging
  • Google elevation API queries using lat/long from the GPS
  • Data upload functionality for data to aid with a best-fit algorithm for the elevation chart
  • Local viewing of uploaded data in CSV or TXT with the ability to export the data
  • Graph support – about halfway to where I’d like it to be but fully functional in its current state
    • Zoom and pan within proper bounds
    • Logic implemented for gradients under slopes of varying strength
    • Dynamic axes that update automatically upon pan or zoom

Here’s what I’ve got on the docket before an initial release:

  • Theming support
  • Ability to select slopes of the plot in order to view additional data like min/max/average speed
  • More chart data animations
  • Chart export options
  • Data unification algorithm
  • UI + UX

Well, that about does it for this introductory post… here are a few links for you guys and a look at the current graph:

Rise on Github
Uploaded Data


Rise App

]]>
http://sideapps.com/iphoneipod-touch-apps/introducing-rise/feed/ 1
CatSpam: An Innovative Approach to Spam http://sideapps.com/news/catspam-an-innovative-approach-to-spam/ http://sideapps.com/news/catspam-an-innovative-approach-to-spam/#comments Thu, 24 Jul 2014 20:24:00 +0000 http://sideapps.com/?p=315 I often come up with programming ideas as I’m trying to fall asleep and, more often than not, this forces me out of bed to start some silly work. About a year ago I had an idea: Would it be possible to create a script to text friends, family and/or strangers with some form of spam. For some reason I landed on the innocuous topic of feline facts and got right to work.

My first idea was to use the email system that has been in place for some time now to send the text messages. However, this requires me to know what network the phone is on and that’s a problem I wasn’t interested in dealing with. Then I remembered Google Voice… For the uninitiated, anyone with a Google account can now get an additional phone number, free of charge. You can configure Google Voice to forward your calls to whichever phones you chose while keeping your primary phone number concealed.

Python, being one of my favorite languages was the clear choice for this task. It turns out that Google has no public API for their Google Voice service. Thankfully, some pro programmers have created Google Voice libraries for a handful of languages, including Python. I used pygooglevoice which ended up being a pleasure to work with. The program prompts the user for their Google login (which is securely handed off to Google for verification) and then asks the user for the phone number they would like to send spam to. Also configurable is a time interval in which the texts will be sent. The cat facts are read from a file located in the same directory and, in theory, could be replaced with any text file in the same format.

Enough about the program – here it is:

import getpass
import pygvoicelib
import time
import random
import sys

def readCatFacts():
    inFile = open('catfacts.txt','r')
    
    catFacts = []
    
    for line in inFile:
        line = line.strip('\n')
        catFacts.append(line)
    

catFacts = readCatFacts()

user = raw_input('Please enter your Google username: ')
passwd = getpass.getpass('Please enter your     return catFacts
Google password: ')

gvoice = pygvoicelib.GoogleVoice(user, passwd)

try:
    phoneList = gvoice.get_numbers()
except pygvoicelib.LoginError, e:
    print 'Failed to login. Reason: %s' % (e.reason)
    print 'Reasons Legend:'
    print '  failed -> Invalid credentails'
    print '  captcha -> Account is captcha locked'
    print '  error -> Unknown/Other errors'
    quit()

fromNum = -1;

for num in phoneList:
    if num.isdigit() and phoneList[num]['verified']:
        fromNum = num

print 'Login successful.'

if (fromNum == -1):
    print 'Unable to find a validated phone to test a call with - goodbye!'
    quit()

callNumber = input('Please enter the phone number to provide with cat facts: ')
callFrequencyMin = int(input("What's the minimum time between cat facts (minutes): "))
callFrequencyMax = int(input("What's the maximum time between cat facts (minutes): "))
e) + ' minutes'
	for i in range(sleepTime*60, -1, -1):
		print '\r' + str(i) + ' seconds remaining            ',
		sys.stdout.flush()
while True:
	sleepTime = random.randint(callFrequencyMin, callFrequencyMax)
	catFactNum = random.randint(0,len(catFacts)-1)
	successVar = repr(gvoice.send(callNumber, catFacts[catFactNum]))
	print 'Attempting to send cat fact... Success -> ' + successVar
	print 'Sleeping for ' + str(sleepTim
		time.sleep(1)
	print '\r',

If you’re interested in the actual catfacts.txt file you can check it out here: catfacts.txt

Here are packaged executables for Windows and OSX – make sure you have a catfacts.txt file in the same directory as the executable or the app will crash!

]]>
http://sideapps.com/news/catspam-an-innovative-approach-to-spam/feed/ 3
Add Markers to Google Map from CSV http://sideapps.com/code-tips-and-tricks/add-markers-to-google-map-from-csv/ http://sideapps.com/code-tips-and-tricks/add-markers-to-google-map-from-csv/#comments Thu, 17 Jul 2014 03:31:49 +0000 http://sideapps.com/?p=308 I was recently asked to create an HTML page that would access a CSV file containing a list of latitude/longitude values and generate a map with markers for each location. This project was a proof-of-concept challenge for me so I’ve really just made a barebones implementation. That said, it should be very easy to expand using only Google’s API documentation for reference. Google Maps were the clear choice as they’ve become a bit of a de facto standard. Enough – let’s dig into the code!

This block of Javascript converts a local CSV file to a multidimensional array that can be easily accessed and manipulated within memory:

// This will parse a delimited string into an array of
// arrays. The default delimiter is the comma, but this
// can be overriden in the second argument.
function CSVToArray( strData, strDelimiter ){
	// Check to see if the delimiter is defined. If not,
	// then default to comma.
	strDelimiter = (strDelimiter || ",");

	// Create a regular expression to parse the CSV values.
	var objPattern = new RegExp(
		(
			// Delimiters.
			"(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +

			// Quoted fields.
			"(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +

			// Standard fields.
			"([^\"\\" + strDelimiter + "\\r\\n]*))"
		), "gi");

	// Create an array to hold our data. Give the array
	// a default empty first row.
	var arrData = [[]];

	// Create an array to hold our individual pattern
	// matching groups.
	var arrMatches = null;

	// Keep looping over the regular expression matches
	// until we can no longer find a match.
	while (arrMatches = objPattern.exec( strData ))
	{
		// Get the delimiter that was found.
		var strMatchedDelimiter = arrMatches[ 1 ];

		// Check to see if the given delimiter has a length
		// (is not the start of string) and if it matches
		// field delimiter. If id does not, then we know
		// that this delimiter is a row delimiter.
		if (strMatchedDelimiter.length && (strMatchedDelimiter != strDelimiter))
		{
			// Since we have reached a new row of data,
			// add an empty row to our data array.
			arrData.push( [] );

		}

		// Now that we have our delimiter out of the way,
		// let's check to see which kind of value we
		// captured (quoted or unquoted).
		if (arrMatches[ 2 ]){
			// We found a quoted value. When we capture
			// this value, unescape any double quotes.
			var strMatchedValue = arrMatches[ 2 ].replace(
				new RegExp( "\"\"", "g" ),
				"\""
				);

		} else 
		{
			// We found a non-quoted value.
			var strMatchedValue = arrMatches[ 3 ];
		}

		// Now that we have our value string, let's add
		// it to the data array.
		arrData[ arrData.length - 1 ].push( strMatchedValue );
	}

	// Return the parsed data.
	return( arrData );
}

This initialization function is all it takes to generate a Google Map and add all of our markers:

function initialize() 
{	
	// Set lat/long to center on the USA
	var lat = 39.8282;
	var lng = -98.5795;
	var zm = 5;

	// Configure the starting variables for the map
	var mapOptions = {
		center: new google.maps.LatLng(lat, lng),
		zoom: zm,
		mapTypeId: google.maps.MapTypeId.ROADMAP
	};

	// Generate the actual map
	var map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);

	var returnValue = "";
	var request = new XMLHttpRequest();

	// Read the lat/long info for markers
	request.open("GET", "zip-lat-long.csv", false);
	request.send(null);
	returnValue = request.responseText;

	// Convert our data from the CVS file to a usable array
	var data = CSVToArray(returnValue);

	for (var i = 0; i < data.length; i++) 
	{
		// Create a lat/long object readable by Google
		var myLatlng = new google.maps.LatLng(parseFloat(data[i][1]), parseFloat(data[i][2]));

		// Generate a marker from the lat/long object and add it to the map
		var marker = new google.maps.Marker({
			position: myLatlng,
			map: map,
			title:data[i][0]
		});
	}	
}

Using these two functions, all it takes to generate the actual map is a single line of code:

// Initialize the Google Map
google.maps.event.addDomListener(window, 'load', initialize);

You can see this code in action right here: http://sideapps.com/smart911/

If you’re interested in the CSV file it can be downloaded here: http://sideapps.com/smart911/zip-lat-long.csv

I must admit, I am a bit prejudiced toward web applications… However, I found Google’s API and the small amount of Javascript I had to learn very pleasant. I anticipated a much longer process and was very happy to be able to complete the task so logically and directly. Hopefully this helps someone out!

 

]]>
http://sideapps.com/code-tips-and-tricks/add-markers-to-google-map-from-csv/feed/ 0
FlowReader: A Revolutionary Way of Speed-Reading http://sideapps.com/miscellaneous/flowreader-a-revolutionary-way-of-speed-reading/ http://sideapps.com/miscellaneous/flowreader-a-revolutionary-way-of-speed-reading/#comments Tue, 10 Jun 2014 20:23:58 +0000 http://sideapps.com/?p=292 Boston-based tech company, Spritz, has recently introduced a new speed-reading method. This technology utilizes a previously existing presentation method, known as RSVP (Rapid Serial Visual Presentation). A single letter is highlighted to focus attention to a natural center of the word. The brain processes the rest of the word through your peripheral vision. By keeping the highlighted word in the same place, Spritz is able to eliminate minute eye movements that make up a large part of our natural reading process.

My friend Julia Hlavacik and I were discussing this new technology when we realized we might be onto something interesting. Not only does this kind of program have potential for everyday uses such as e-readers, mobile web pages, and all forms of articles; it also circumvents a lot of the problems faced by dyslexic readers.

Dyslexic readers generally have trouble scanning lines of text, finding the next line of text, staying focused on a word in a line, reading on certain colors of paper/background along with some impairment of spatial awareness. This isn’t an exhaustive list, but all of these issues are either alleviated or circumvented through RSVP. Although normal readers may not experience these problems to the same acute degree as most dyslexic readers, this speed-reading program can still significantly boost the average person’s reading. This is particularly useful on small, digital screens where text can be difficult to adjust.

The video below demonstrates a brief proof-of-concept. The text you see is being presented at 250 WPM; the reading speed of an average adult. To many of you, this text will likely appear somewhat sluggish – most readers can easily adapt to 500 WPM or more. I chose to use an open source API called OpenSpritz as the Spritz API has limited customization options and forces users to create an account and sign in. Two examples of customization that would be impossible with Spritz’s API are the color theme and the ability to adjust the WPM on the fly to account for longer words or punctuation.

]]>
http://sideapps.com/miscellaneous/flowreader-a-revolutionary-way-of-speed-reading/feed/ 0
How to Attach an Image to an Email Using PHP http://sideapps.com/code-tips-and-tricks/how-to-attach-an-image-to-an-email-using-php/ http://sideapps.com/code-tips-and-tricks/how-to-attach-an-image-to-an-email-using-php/#comments Fri, 06 Jun 2014 04:39:25 +0000 http://sideapps.com/?p=288 I recently wrote a small data acquisition system using PHP. I’m not a fan of web-based development and know very little but I had some financial incentive for this project and took it upon myself to learn along the way. By far the biggest headache I ran into was dealing with PHP’s mail() function. There’s obviously a reason so many third party libraries exist that tackle this issue but, being stubborn, I wanted to do it from scratch.

My goal was to generate and send an email consisting of an HTML body with an image attached. Embedding the image within the HTML turned out to be fairly trivial (in comparison) but an attachment was preferred. After MUCH ado I came up with the following function which does just that.

NOTE: This function doesn’t go to any extremes to validate itself and doesn’t make it past very many junk filters. This was fine for my use case as the email will be going to a single administrator who can easily whitelist the domain. However, if this is a concern I would highly recommend using one of the third party libraries as considerable configuration is required both in the PHP and on the delivering server itself.

# Send mail with an attachment
function mailAttachment($to, $subject, $body, $from, $photoPath, $photoName, $filetype)
{
	$bound_text = md5(uniqid(rand(), true));;
	$bound = "--" . $bound_text . "\r\n";
	$bound_last = "--" . $bound_text . "--\r\n";

	$headers = "From:" . $from . "\r\n"
	. "MIME-Version: 1.0\r\n"
	. "Content-Type: multipart/mixed; boundary=\"$bound_text\"";

	$message =	"Sorry, your client doesn't support MIME types.\r\n"
	. $bound;

	$message .=	"Content-Type: text/html; charset=\"iso-8859-1\"\r\n"
	. "Content-Transfer-Encoding: 7bit\r\n\r\n"
	. $body
	. $bound;

	$file =	file_get_contents($photoPath);

	$message .=	"Content-Type: $filetype; name=\"$photoName\"\r\n"
	. "Content-Transfer-Encoding: base64\r\n"
	. "Content-disposition: attachment; file=\"$photoName\"\r\n"
	. "\r\n"
	. chunk_split(base64_encode($file))
	. $bound_last;

	if(mail($to, $subject, $message, $headers)) 
	{
	     echo 'MAIL SENT!' . '<br>';
	     echo 'to: ' . $to . '<br>';
	     echo 'from: ' . $from . '<br>';
	     echo 'bodyText: ' . $body . '<br>';
	     echo 'photoPath: ' . $photoPath . '<br>';
	     echo 'photoName: ' . $photoName . '<br>';
	     echo 'filetype: ' . $filetype . '<br>';
	} 
	else 
	{ 
	     echo 'MAIL FAILED';
	}
}

mailAttachment('admin@sideapps.com', 'attachmentTest', 'SomeHTML', 'noreply@sideapps.com', 'uploads/testImage.png', 'testImage.png', 'image/png');

]]>
http://sideapps.com/code-tips-and-tricks/how-to-attach-an-image-to-an-email-using-php/feed/ 0

Warning: Parameter 1 to W3_Plugin_TotalCache::ob_callback() expected to be a reference, value given in /home/sidesul6/public_html/wp-includes/functions.php on line 3297