Showing posts with label dev. Show all posts
Showing posts with label dev. Show all posts

Tuesday, April 1, 2014

One Book Away, for Android

After nearly seven months (7 months!) since my final project for my Android program was completed, I have released it onto the app store. Introducing (formally)... One Book Away!

Go install it now at the Google Play store:
https://play.google.com/store/apps/details?id=com.mabon.onebook

If you like it, please leave a glowing review!

Now for some questions that no one is asking...


Where did this idea come from?
The idea for this app came to me a few years ago when I was trying to organize things I was waiting for at the library.  After placing holds on a few popular books or movies, I found they seemed to come all at the same time!  So I came up with a way to estimate how long I would have to wait for books and movies.

Originally, I thought it would be a greasemonkey script.  The only reason I decided to use Android was that I needed a project for my Android class and I couldn't think of anything else.  The first app was just a manual-entry calculator, but as I learned about the platform it grew into a full-blown useful app.

Some past iterations of the app:

Why did it take 7 months?
One of my instructors gave the advice to build something that you would find useful, then after building it decide if it would be useful to others.  At the very least you get something you find useful for the work you put in.  However, I ran into the problem of the app working well enough for me, so I wasn't as motivated to finish polishing it.  On top of that, I was only putting in about 1 day a week, and if a major issue arose it might take me 2 weeks to find a good solution.

What's your status?
I'm a full-time contractor, so I was looking for something to do on the side for fun.  I don't do any advertising for my apps, and I feel if I was ever going to look to do this more seriously it would be beneficial to me to keep publishing apps.

What got you into Android development?
I did some robotics development a few years ago that I very much liked.  The same bug that might render a web page incorrectly might cause your robot to turn left and run off the table.  Android development reminded me of that past, so I wanted to explore it further.

What do you think of Android development?
I've been on a c++ project for a few years, so getting back into Java was a little strange.  I don't like development that gets in my way, and I want it to be straight forward and just work.  Some parts are very nice, especially the xml files for the layout and strings.  Other parts I'm not so hot on, like the amount of code it takes to do what appears to be a simple task.

It took a while to get used to Eclipse coming from the easy debugging style of Visual Studio.  I switched to Android Studio as soon as I could, but in hindsight I think I should have waited until it was more stable.  In a lot of ways Android Studio held me up the most.

What's next?
Believe it or not, I have 2-3 more ideas I'm eager to start on.  I'd also like to work with someone fun to help keep the project moving, and keep it from being such a lonely process.





Thursday, October 24, 2013

Bookmarklet Reporting with dotProject

I’ve been using dotProject for keeping track of my hours on certain projects. It’s a bit of overkill for my needs, but it was easy to get started without worrying about trying to find the perfect tool. Over time I’ve found that going my own route has given me some perspective of what I want.

dotProject's interface is rather ancient by web standards, and it’s feature-set is a bit daunting. Some features seem overly complicated and others seem rather sparse. However, the simple html design lends itself to being very flexible to get what I need out of the system.

One particular report that is my bread and butter is the “Task Log”. All my projects have tasks, and I log hours to those tasks. At the end of the month I just want a list of all the logged hours for the month in a nice list.

However, the big issue I have is the default begin/end dates are useless to me. They load on a 2 week cycle, so the default end-date will be the current date, with the begin date set to 2 weeks ago. Changing them should be simple, but the date textboxes are read-only, and the only way to change them is with a popup widget that is cumbersome to deal with.

One day I had some inspiration and thought, if the dates are being sent as query parameters, why not just formulate those parameters myself? After a little bit of experimentation I ended up building 2 JavaScript bookmarklets: One runs the report for the current month, and the other opens a dialog asking for the month before running the report.

A bookmarklet is just a bookmark, but instead of a URL to a webpage, it contains JavaScript that instructs the browser to do something. In this case I'm instructing it to open the URL of the report using the dates that I want.


I’m going to show the main logic I used, followed by compacted versions. I'm not a huge fan of compacted code, but I was afraid that there might be a size limit for bookmark's URL. At the end I’ll show some examples in screenshots.


Full disclosure: this is my test code, some or all of it may not work correctly, you may need to make some tweaks.


Main code logic
Don’t forget to use your URL instead of the fake one used in this example 

//This is the URL before you add the date parameters
var BASE_URL = "http://dotproject.example.com/index.php?m=projects&a=reports&project_id=0&report_type=tasklogs&log_userfilter=0&do_report=submit";

//first day of current month
var begin_date = new Date();
begin_date.setDate(1);    

//last day of current month
var end_date = new Date(begin_date.getFullYear(), begin_date.getMonth() + 1, 0);

//open the URL, with the formatted dates
open( buildURL( formatDate(begin_date), formatDate(end_date)));

//format YYYYMMDD
function formatDate(dtDate) 
{
    var sDate = "";
    sDate += dtDate.getFullYear();
    sDate += pad2(dtDate.getMonth()+1);
    sDate += pad2(dtDate.getDate());    
    return sDate;
}

//pad 0 (zero) to single-digit date parts (i.e. 3/9/2013 = 03/09/2013)
function pad2(n) 
{
 var str = String(n);
 if(str.length < 2) { 
  str = "0" + str; 
 }
 return str;
}

//return the full URL (BASE_URL + THE date parameters)
function buildURL(sBegin, sEnd) {
    var str = "";
    str = BASE_URL+"&log_start_date="+sBegin+"&log_end_date="+sEnd;
    return str;
}



Task Log: Current Month (compacted)
Don’t forget to use your URL instead of the fake one used in this example
//open report for the current month:
javascript:(function(){
 var BASE_URL = "http://dotproject.example.com/index.php?m=projects&a=reports&project_id=0&report_type=tasklogs&log_userfilter=0&do_report=submit";
 function fd(d) {var s="";s=d.getFullYear();s+=pd(d.getMonth()+1);s+=pd(d.getDate());return s;}
 function pd(a){a=String(a);a.length<2 a="" amp="" br="" return=""> var m1 = new Date();m1.setDate(1);
 var m2 = new Date(m1.getFullYear(),m1.getMonth()+1,0);
 location.href=BASE_URL+"&log_start_date="+fd(m1)+"&log_end_date="+fd(m2);
 })(); 

Task Log: Ask for Month
Don’t forget to use your URL instead of the fake one used in this example
//ask for month (number), then open the report:
javascript:(function(){
 var BASE_URL = "http://dotproject.example.com/index.php?m=projects&a=reports&project_id=0&report_type=tasklogs&log_userfilter=0&do_report=submit";
 function fd(d) {var s="";s=d.getFullYear();s+=pd(d.getMonth()+1);s+=pd(d.getDate());return s;}
 function pd(a){a=String(a);a.length<2 a="" amp="" br="" return=""> var m1 = new Date();m1.setDate(1);
 var m = prompt("Enter Month: ", m1.getMonth()+1);
 m1.setMonth(m-1);
 var m2 = new Date(m1.getFullYear(),m1.getMonth()+1,0);
 location.href=BASE_URL+"&log_start_date="+fd(m1)+"&log_end_date="+fd(m2); 
 })();


Adding bookmarklets in pictures

Default report parameters, those dates won't help me
Start with a new bookmark, and paste the JavaScript into the Location field
Here's the result, the dates load correctly!
Creating a separate bookmark to ask for the month
Here is the bookmarklet asking for the month
The report showing the correct dates!


Wednesday, October 16, 2013

Download Adobe Connect Presentations

Download your own copy of an Adobe Connect 8 Presentation




The following are some methods I used to download offline copies of presentations given at a class I took at the University of Washington.  Adobe Connect 8 was the web meeting software used, and it should be noted that Adobe provides documentation on how to provide offline copies, but for various reasons our instructors weren't able to figure it out.

If you search the Adobe Connect user forums, you’ll notice it’s filled with people posting questions on how to export their presentation. I found some good information in the forums and other places, and this post simply lists the methods I used to achieve the goal.


The Easy Way Out: Throw money at the problem
Without a doubt, the easiest solution is to use a screen recording utility.  You may already have a favorite tool, but I payed for one called Screencast-O-Matic.  For what it’s worth, it did a great job for the price.  In hindsight, I would have just recorded the presentations as they became available.
http://www.screencast-o-matic.com



The Do It Yourself Method
Disclaimers:
  • You must be comfortable with the basics of editing and and video (I do you no favors)
  • Fail Early! If it’s not working out, don’t blame yourself and go the easy route

Software: FLV Editor Lite

I found a good free Flash editor called FLV Editor.  It’s free lite version will work fine if you stay under 4 input files, and honestly if you need more you shouldn’t use this method.  If you find the software useful, I’d encourage you to support the developer and buy the software.

The publisher also has a player called FLV Player, which is a pretty robust player despite its ugly interface.  It plays FLV files better than the VLC Player.

Download the presentation

You will have to download the presentation directly from the web software using these steps:  
1. View the Adobe Connect video on your browser like you normally would
2. Remove the extra parameters from the URL, and add this on the end: /output/filename.zip?download=zip
3. Reload page, wait for a download dialog to display and save the file


What is in that Zip file anyway?

The zip file you receive consists of several Flash (FLV) files that make up different parts of the presentation (audio/video/chat/etc); together they form the entire presentation.  The way I understand it, there is one file that controls all the others, called mainstream.

In the best case scenario, the presenter gives the presentation without stopping the recording. However, if they paused any part of the presentation at any time, a new file is created.  This is where the mainstream file steps in, it keeps track of which files should be “played” when, like a music conductor in an orchestra.  This file will not help us, but it’s important to understand how it works.

Extract Audio/Video

I only wanted the audio and the screen share.  Unfortunately the audio and screen shares are stored in separate files.  In the best case scenario:
  • The audio is stored in a file similar to: cameraVoip_****.flv
  • The screen share video is stored in a file similar to: screenshare_****.flv


Video can also be stored on the voip file (usually a web cam of the instructor), so we will need to separate the audio from the video in that file.  Then we will merge the audio to the video from the screenshare file.


Here are the steps to follow this best-case scenario:
  1. Open the FLV Editor
  2. Add the cameraVoip file  
    1. Drag the file into the editor section
    2. Choose the option to un-link the audio & video
    3. Delete just the video part, leaving the audio behind (this can be tricky)
  3. Add the screenshare file
    1. Drag the file into the editor section
    2. It should only have a video part, no sound
  4. Make sure the audio and video line up,and export to Flash
    1. There is an option to export to other formats with the pay version


If you have more than one of either the audio or video

The instructions are similar to the best-case scenario, except you have to get a little creative.  If you can watch the original presentation on the website, you may be able to figure out where the presenter paused.  You can then try to match up all the files in the editor appropriately.



Are there other options?
I originally tried an awesome command-line utility called ffmpeg:  
  • It can work with flv files, but isn’t so good with converting them, so stick to flv
  • If you have more than one of either the audio or video files, prepare for a difficult time
  • Sometimes the audio/video would be out of sync, usually because one of the files was ~5 seconds longer than the other.  
  • There are plenty of examples on the web on how to use this tool.
  • http://www.ffmpeg.org

My method was to extract the audio, then combine it with the video using a script.
Here are the 2 commands that were the heart of my script:

ffmpeg -i cameraVoip*.flv -vn -acodec mp3 output_audio.mp3
ffmpeg -i output_audio.mp3 -i screenshare*.flv -acodec copy -vcodec copy output_video.flv


If you can follow what’s going on in those 2 commands, you can try ffmpeg.  I found it a fun exercise to remind myself that I still have some command-line skills, and that was good enough to move on to something else that would get the task finished faster.


Conclusion
This are the methods I used to download copies of the presentations: I tried to piece the presentation together by myself, but if I ran into any issues I immedately went to the screen recorder.

Your presentation can vary wildly, so you might have to do some investigation with the various files in the zip archive to determine the best course of action.  Hopefully I have at least given you some inspiration.

Tuesday, August 27, 2013

Android Project: One Book Away

One Book Away
The Library App revisited

I have officially come to the end of my Android classes at the University of Washington!  The program consisted of 3 classes, each with their own project.  If you look back in my blog you’ll find the other 2 projects, which were: 
1st class: "Library Hold Wait", a sort of calculator for items waiting at the library  
2nd class: "One Step Further", a child developmental milestone quiz 

I’ll take a moment to mention that "One Step Further" is in the Google Play store.  It’s much more streamlined and polished than the one I presented in class.  You should check it out, and if you like it please give it a good rating!

My 3rd app took the same idea of the library hold calculator and extended it to make it much more useful.  Instead of manually entering your hold information in a calculator-style format, the app reads data directly from the Seattle Library and does all the calculations for you.

I am happy with the results, and I think it leaves the door open to add more features to eventually get the app into the Play store in the coming months.  I could even port this app to work with other libraries that use the Horizon system.


I've been working so hard over the past few months, that I let loose a little bit for the presentation.  You'll have to excuse the weird color combinations, HUGE cheesy images, and lots of in-page transitions. 




screenshots

Main Page

Loading Hold Data

Detail Page

Preferences

Update Checkout Periods




Tuesday, June 11, 2013

One Step Further, for Android


I've been taking a series of classes on Android development at the University of Washington.  You may have seen a previous post from my first project (Library Hold-Wait).

Compared to the last project, I spend much more time developing this project than the last.  It's a day after my presentation, and I'm completely exhausted.  Luckily I have a couple weeks before I start taking the 3rd and final course of the series.

I've included the video of the presentation, and some additional screenshots and slides below.  The app was developed for class, but I hope to get a variant of it up on the Google Play store at some point.  At the very least it can be a good resume-builder.



Notes:
  • The app has some features that were required for class: an RSS reader, links to other services, both a Map in a webview and a Map using Google Maps APIv2
  • I have had a version of this idea for a few years now; so it wasn't too much of a stretch to adjust it further to fit with the requirements of the class

Screenshots:


Landing Activity
Fairly standard screen

Assessment section
Choose which behaviors your child is displaying

Results of the Assessment
Always consider talking to a doctor

More Information Section
Extra information


Slides:















Monday, March 25, 2013

Notepad++ Time-Stamp

Kudos

I’ve been keeping some form of a work journal for years; I’d highly recommend it.  I recently got annoyed with creating timestamps in Notepad++, and ran across a helpful post in a forum.  It was so helpful that I thought I’d do my best to try to give it some additional street cred.

Here is the original link:
http://sourceforge.net/p/notepad-plus/discussion/331753/thread/3458d1da#62f2

What day of the week was 4/22/2006 anyway?

Before I start, if you have the TextFX plugin already setup in Notepad++, it provides 2 static methods of inserting a datetime stamp:
Menu: TextFX > TextFX Insert > I:Date & Time: short format: 3:56 PM 3/22/2013
Menu: TextFX > TextFX Insert > I:Date & Time: long format:  3:56 PM Friday, March 22, 2013
If these look good enough to you, you can skip to the section on how to map a keyboard shortcut to these.  However, in addition to the time and date, I also wanted the day of the week, like this:
03:36 PM 03/22/2013 (Friday)


Steps

It turns out this can easily be done with a simple Python script.  I don’t even know Python that well and I was able to do it.

1. Install the python plugin:
  • The plugin’s name is: Python Script
  • It’s recommend you do this via the NP++ Plugin Manger (Menu: Plugins > Plugin Manger)
  • Here’s a link to the project page:  http://npppythonscript.sourceforge.net/
  • The script includes some basic Python libraries, so you shouldn’t need to install Python or other 3rd party libraries

2. Setup script in Notepad++:
  • Menu:  Plugins > Python Script > New Python Script
  • It will ask you for a new file name, I choose: npp_timedate_stamp.py
  • A new tab will appear in NP++ for you to enter the script.
  • This is the script I used:
    
    # Add date/time stamp in Notepad++ 03:28 PM 03-22-2013 (Friday)
    import time
    editor.addText( time.strftime( '%I:%M %p %m/%d/%Y (%A) ' ) )
    
    
  • Here is a link to the Python documentation which shows what all the format string characters: http://docs.python.org/2/library/time.html
  • Save your script

3. Configure Notepad++ to use the script:
  • Menu: Plugins > Python Script > Configuration
  • You should see your script under the User Scripts section
  • Add it to Toolbar and/or Menu
  • I put it in both, but I only managed to find it under menu
  • It shows up as its own entry under Menu: Plugins > Python Script > npp_timedate_stamp

4. Create a keyboard shortcut (my preferred method):
  • Menu: Settings > Shortcut Mapper
  • Switch to Plugin
  • Scroll down until you see your script name (i.e. npp_timedate_stamp)
  • Click on it, choose Modify, and choose a key.  I used: CTRL + ;

Furthermore

This was exciting to me in more ways than one, because in the past I’ve looked for ways of modifying Notepad++, and plugins can be a daunting undertaking.  Apparently the Python plugin is mapped to all the Notepad++ features, so I might utilize it more in the future.

Thursday, March 21, 2013

Entry-Level Android Application

I've been taking a series of classes on Android development in my spare time via UW.  The final project for my 1st class was to build a simple 2-screen application and present it in front of the class.

Lucky for me the presentation was recorded.  Un-lucky for me it was recorded using Adobe Connect, which makes downloading and editing the video extremely annoying.  I figured a way around all the hurdles and you can watch the video below.  I've also posted the slides below with some notes.



Some quick notes:
  • Originally I was going to made a tip calculator, but was talked into this idea instead
  • The idea for this app came from an idea I had for a Greasemonkey script

The slides from the presentation:



Slide 1
  • The presentation was meant to be mostly verbal with just a few points made on the slides themselves.  However, I did modify a couple for this blog post.



Slide 2
  • A simple feature allows me to explore the entire end-to-end process



Slide 3
  • The first example is simple to allow the audience to quickly follow the gist of the calculation
  • The second example shows how the result can be useful: with a 5 month wait, I can plan to read something else while I'm waiting



Slide 4
  • The better looking app usually wins
  • I found this image of an old-style library checkout card to use as a guide (my apologies if this is your image)




Slide 5
  • For the actual presentation, I switched to using a separate overhead projector that displayed my phone on the wall.  I just inserted a screenshot for this version.



Slide 6
  • Process button wasn't needed, but works as a visual cue to the user
  • I used View elements in the XML layout, with a height/width of 1dip to make the lines
  • I repeated those lines at the bottom to complete the look I was trying to achieve
  • If I had to do this again, I would calculate the device's resolution and repeat those lines as many times as I needed.  It didn't matter for this project.




Slide 7
  • Changing Preferences wasn't supposed to overwrite the current values the user had entered, but upon testing this just confused the user.  I had to change it to just have the preferences always over-write the current values.
  • I originally had the result displayed in a TextView (read only), but decided to change it to a EditView so the user could select and copy the result
  • The font and background with smudges made a HUGE difference. Smudges were just in the background image I created in GIMP, the aspect ratio didn't matter.
  • I don't think anyone noticed, but I used that same background image in the app for this slide. I wanted to show that the image could be re-sized to fit just about anything and still look realistic.




Slide 8
  • If you didn't watch the video, the audience had a couple questions and comments about how I did a couple things
  • The comment that I remember most was when someone commented on the background image - he said at first he thought the screen on my phone was dirty! 

Wednesday, June 9, 2010

End Of Day(s) Function

Some of our reports were not showing items marked with a date and time when using the BETWEEN operator. This was because BETWEEN only considers values that are equal to one of the values, or falls in-between the range defined by them. When you use dates with with no time, the operator assumes the time is 0.

i.e.: BETWEEN '1/1/2010' and '1/2/2010' would mean '1/2/2010' would be treated as '1/2/2010 00:00:00.000'.

I created a date function to return a given day as the last second of the day. So '1/2/2010' will be returned as '1/2/2010 23:59:59.997. The milliseconds weren't really needed in my case, but I felt like doing it anyway.


Here is the function I created. I use a [DATE] schema for my date-related functions on our server.


/*
[DATE].[EndOfDay]
6/3/2010 JMJ

Returns a datetime set to the Last possible (milli) second of the day.
i.e. [DATE].[EndOfDay]('12/8/2008') would return '12/31/2008 23:59:59.997'
*/
CREATE FUNCTION [DATE].[EndOfDay] (
@InputDate DATETIME
)

RETURNS DATETIME
BEGIN
--Get Next day (with no time)
declare @dtNextDay datetime;
set @dtNextDay = DATEADD(d, 1, DATEADD(d, DATEDIFF(d, 0, @InputDate), 0));

-- remove -2 milliseconds (that's as close as you can get)
-- which puts you into the last second of the original given day
return DATEADD(ms, -2, @dtNextDay);
END

----
Here is some example code using the function:

declare @dates table (
entrydate datetime
);

insert into @dates
select '1/1/2010 00:00:00.000'
union all
select '1/1/2010 10:00:00.000'
union all
select '1/2/2010 00:00:00.000'
union all
select '1/2/2010 12:00:00.000'
union all
select '1/2/2010 23:00:00.000'
;


select * from @dates
where entrydate between '1/1/2010' and '1/2/2010'
;


-- returns:
-- 2010-01-01 00:00:00.000
-- 2010-01-01 10:00:00.000
-- 2010-01-02 00:00:00.000


select * from @dates
where entrydate between '1/1/2010' and DATE.EndOfDay('1/2/2010')
;

-- returns:
-- 2010-01-01 00:00:00.000
-- 2010-01-01 10:00:00.000
-- 2010-01-02 00:00:00.000
-- 2010-01-02 12:00:00.000
-- 2010-01-02 23:00:00.000

Wednesday, February 11, 2009

IIS 7 ASP scripts (vbscript) fail to send email (web.com)

I recently had a horrible experience with web.com. They "upgraded" our web server that broke all my client's email functionality for his ASP scripts. These scripts ran flawlessly for years without issue, then all of the sudden none of them worked, and the web host seemed unwilling to help us.

After doing some research, I discovered that they upgraded their servers to MS IIS 7, which no longer directly supports sending emails from an ASP page using "CDO.Message" or "CDONTS". I'm hoping that other web.com users might come across this article in a google search and could save some themselves some time. There might also be other people who have another web host with similar problems.

From what I understand, according to all articles I have found around the web, IIS7 no longer supports sending emails from an ASP page using "CDO.Message" directly.

Here is my old code, which no longer works:

Sub SendMail(Subject,Body,EmailTo,EmailFrom)
Set Newmail = CreateObject("CDO.Message")
newmail.TextBody = Body
newmail.Subject = Subject
newmail.To = EmailTo
newmail.From = EmailFrom
newmail.Send
set newmail = nothing
end Sub


There are a few solutions out there, but the one that worked for me (as a web.com user) is to use CDOSYS. I found this through a series of searches, and my solution I present is just my flavor of the method recommended:

Regarding the Fields used for "CDO.Configuration", I had to play around to find the ones that my webhost seemed to care about. For instance, I have commented out cdoSendUsingPort and replaced it with a 2 (the actual value of cdoSendUsingPort). Most people online seem to be recommending putting the address of your SMTP server for the "smtpserver" setting, but I found that web.com only worked with "localhost".



Function SendEmail(Subject,Body,EmailTo,EmailFrom)
' SendEmail(Subject,Body,EmailTo,EmailFrom)
' 2/10/2009 JMJ: Uses CDOSYS method of sending email
'

Set cdoMessage = CreateObject("CDO.Message")
Set cdoConfig = CreateObject("CDO.Configuration")

Set Flds = cdoConfig.Fields

With Flds
.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2 'cdoSendUsingPort
.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "localhost"
.Item("http://schemas.microsoft.com/cdo/configuration/smtpconnectiontimeout") = 60
.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
.Update
End With

With cdoMessage
Set .Configuration = cdoConfig
.To = EmailTo
.From = EmailFrom
.Subject = Subject
.TextBody = Body
.Send
End With

Set cdoMessage = Nothing
Set cdoConfig = Nothing
Set Flds = Nothing

SendEmail = true

End Function 'SendEmail()


Coincidentally, there are a couple more solutions out there. One is to copy a couple dll’s onto the new server to provide support for legacy ASP scripts; another is to just send emails using the database. I’ve provided some links below that were helpful to me.

Tips for Classic ASP developers on IIS7

IIS7 - Classic ASP Forum

How to send e-mail with CDO

ASP Sending e-mail with CDOSYS