pwlk blog Journaling since 2007

29Jan/122

Smart Player Piano

Intro

Two years ago (Spring 2010) I was working on my Senior Design Project for the Tech Expo at Duke Energy Convention Center.  My project was titled, "Smart Player Piano".  The whole project and experience was very rewarding a lot of fun.  It wasn't until a couple days ago when I received an email from someone at the University of Cincinnati saying they saw a copy of my poster hanging up, that I realized I never really 'released' my project to the public.  So, here it is, the story of my project, Smart Player Piano.

I won't go into too many details about the project because it is all been said before and will be supplied later.  The quick and dirty of what Smart Player Piano does is that it takes an image, dots on a page, and converts them into notes like a player piano does. What makes this different is the "Smart" part.  Throwing a bunch of dots on a page wouldn't sound good, so using some basic music theory chord progression, the pixels are modified to sound better.  Some of the features of the project were:

  1. Import/Export images
  2. Import/Export midis
  3. Drawing abilities
  4. Adjust tempo
  5. Max smart adjustments intervals
To see all the details, check the end of the post for power point/design doc/poster/handout and the project available for download.

Pictures

Smart Player Piano at 2010 Tech Expo

Standing by my booth at the 2010 Tech Expo at the Duke Energy Convention Center. Ready to show the world ... or at least the engineers of Cincinnati ... Smart Player Piano

Smart Player Piano with Advisor Dr. Anca Ralescu

Standing with my advisor Dr. Anca Ralescu in front of my booth at the 2010 Tech Expo

Kids enjoying Smart Player Piano

One of the most rewarding aspects of presenting the Smart Player Piano was the reaction it received from all the kids that came to the Expo. I was honored to receive the "Young People's Choice" award out of all the projects at the expo.

Kids enjoying Smart Player Piano

The kids loved getting their pictures taken and seeing what it looked like once it was imported into Smart Player Piano. Then they could hear what their picture "sounds" like before and after it was "autofixed". More than once I had a chaperone come by saying that they were nearly to the bus to head back to school and the kids would still be talking about Smart Player Piano enough that the chaperone would come back to see what all the talk was about.

Presenting to IEEE Cincinnati

In addition to the Young People's Choice award, I was honored that Smart Player Piano was selected as "Best in Computer Science" at the Tech Expo. With this award I was invited to an IEEE Cincinnati meeting to present my project to some of the engineering professionals around Cincinnati.

Docs

Here are a few docs that I put together for Smart Player Piano

Application

Annnnnnd here's the actual project.  As with most coding projects that you haven't looked at in more than ... a few weeks, I'm a little fuzzy on how everything is laid out.  What I've done, which I think will work, is zipped up all the project files along with my demo directory that contains some fun midis and images and have a README in the root.  The README should cover how everything is organized.

Closing

And that's about it.  Hopefully you enjoy Smart Player Piano.  Feel free to leave comments below for questions/comments/concerns.  I had a lot of fun with this project and hope you all do the same.

29Nov/110

The Value of $0.99 – Frustrations from a Developer

One of the many ways Apple changed the world was by giving a single dollar, real monetary value.

The App Store opened up a whole new and exciting world for software developers to flex their digital muscles and see where the wind could carry them.  I have only recently begun my trek into the world of app development, but in these few months, my eyes have truly been opened to the monetary value of digital media.  Now I am careful to say "monetary" value, because many things can have value, but only certain things have monetary value.  And by value, I mean what someone would be willing to trade for the product or service, monetary value ... obviously, money.

The Internet brought out the pirate in all of us.  Moving songs from one computer to another ... it really didn't feel like stealing ... it was just like moving the files of a group project from a classmates computer to yours, simple.  Record labels fought it, lawsuits against individuals (sorry I don't have the references right now, I may fill them in later).  But iTunes saw the problem and countered with a solution instead of a push back.  Offer individual songs for an affordable price!  Amazing...

Years pass and the iPhone/iPod Touch/iPad come to life and the App Store is born.  Apps on sale for $9.99 and selling well.  Competition drives the price down.  Apps sell for $4.99 and sell well.  Competition drives the price down.  Apps sell for $0.99 and sell well.  No where to go but free...

An interesting thing happened.  For the price of an impulse purchase candy bar at the grocery check out counter, one could purchase an app of any sorts that would keep them entertained and fixated for hours.  But where one would not think twice about that impulse purchase that gave them pleasure for the car ride home, they would spend an hour looking for reviews and YouTube videos on whether or not this piece of appware was worth their $0.99 (+ tax).  And of course I include myself in this audience.

Why do people feel the need to be so stringent on their $0.99 app purchases while a candy bar is so much easier?  Is it for the mere fact that an app is not (well sorta) tangible?  Is it that there are too many choices on the App Store to really make an impulse purchase?  Is it the presentation of the App Store?  Is it that you are only making a $0.99 purchase while the candy bar is just a percent of a fraction of the groceries in your cart?  Should we be selling app specific gift cards at the checkout counter?

I'm no marketing genius.  I wish I were.  I wish I had the answers to these questions, but I don't.  I think the answer is probably a little bit of 'yes' to most if not all of them, though.

But from the other side, now I am a developer of apps.  I see the thousands that enjoy and endlessly praise my apps while they are free but refuse to touch them as if they were a plague when they cost $0.99.  I see the negative reviews people leave complaining that they have to pay for additional functionality in an already fully functional FREE game.  I see the faceless users belittle my hours and days of late nights and weekends by saying, not worth four quarters.  I know ... I'm whining.  But it fascinates and frustrates me to no end because I don't understand why the dollar holds such a high value in the App Store.  The consumer has every right to do all the things I have mentioned in this paragraph.  I as the app developer, work for them.

What it really comes down to is this though ... whoever can take the app store aisle of a grocery store and turn it into an impulse purchase at the register type of experience ... those will be shoes worth walking in.

23Jul/112

Issues with upgrading to OS X Lion

Upgrading to OS X Lion has been an awful experience.  So many things have gone against the phrase I have always used in reference to Apple, "It just works!"

I wanted to put together a quick post of issues I have had with the update and the way the issues have been fixed in case anyone else is getting the same headaches that I've been getting.

First, I do believe it is relevant to give some details on my MacBook because it is getting up there in age ... I guess.  Things are starting to slow down.  No comparison to the days of having to reformat Windows at least once a year, but things are starting to slow down.

My MacBook Specs

13-inch Late 2007 Processor 2.2 GHz Intel Core 2 Duo Memory 2 GB 667 MHz DDR2 SDRAM Graphics Intel GMA X3100 144 MB Software Mac OS X Lion 10.7 (11A511)

 

Desktop Freezes after logging in

I downloaded Lion from the app store just fine, ran the installer  just fine, it took about an hour for the full install.  Upon reboot, I log in at the fancy new login screen and my Desktop shows just fine.  But that's it... I quickly realize the seconds on my clock are no longer ticking and I can't click on anything.  The cursor still moves around, but nothing is responsive.  Strange... I rebooted.  Same issue.  I do some searches online and come up with nothing.  It is about 11pm so calling Apple support is not an option at this point in the evening.  Finally I decide why not and reboot again.  Magic of all magic it works!  I know this isn't the fix you were hoping to hear ... but I have rebooted a few times since and I have not had the issue with the frozen Desktop since.

Installing Xcode

This really rubbed me the wrong way.  They released Xcode 4 for Snow Leopard and charge $5 for it.  Then when Lion comes out they just open it up for anyone to download for free?  What?!?!  I'm all for free, but what the heck, Apple?  Why charge $5 if you are just going to open it up for free a few months later?  Ugh...

Anyways... So I try and run Xcode as one of the first things after installing Lion and get that message about needing to update Xcode because my current version is not compatible with Lion.  Ok, fine ... where is the update?  Maybe it should have been intuitive that the new Xcode was a new app in the App Store, but since I already bought Xcode from the App Store I would have thought that it would have updated in app or at least been in the updated apps section of the App Store.  But neither was the case.  I did find it in the App Store as a brand new app and started the download.  I then kicked off the installation and got the "To continue installation please quit: iTunes".  I had seen this issue in the ratings of Xcode and wasn't too surprised when I saw it popped up.  So I went into Activity monitor and killed the iTunes Helper process.  Nothing changed.  I had left the install to work overnight so who knows how many hours it had been sitting on the quit iTunes prompt, so I decided to kill the installer and reboot.  I re-kicked the Xcode installation again (#2) and went about my business.  I made it all the way to "waiting for other installations to complete" and got stuck again...

Well, thanks to an article on TUAW, I deleted the lock file and rebooted:

First, hop into Terminal and change directories over to /private/var/db/mds/system. Then remove the mds.install.lock file (you'll need to sudo rm, so be prepared to authenticate as root). Finally, reboot your system (sudo reboot).

(via TUAW)

I thought that the install had completed and tried to launch Xcode but was greeted with this popup:

Xcode error

When will it stop?!?!?!

 

Ok, fine.  I re-kicked of the Xcode installation again (#3).  Keep in mind that this installation is not a short process... it keeps dying at the end.

This time around I have made it all the way to the Updating Files... screen and it has been sitting there the entire time I've been writing this post.  I was hoping it would complete so I could finish off this post with a happy ending, but it doesn't look like it is going to be the case.

I'm very frustrated with this entire process.  I haven't spent much time in Lion yet, but I am yet to see anything on the surface that is a real big improvement over Snow Leopard.  If anything, the computer is slower and choppier.  Maybe I'm just in a bad Apple mood right now, but I don't see why so many issues have come to light.  If it has to do with my late 2007 MacBook ... well that is a shame and rather unnacceptable.  Ok, I'll give my end rant tag </rant> and get back to work at trying to figure out what the heck is happening to my computer.

Best of luck in your upgrade to "the world's most advanced desktop operating system" ... eh

*Update: Xcode problem solved

I did a big no no in the world of problem solving.  I consciously changed more than just one variable and then repeated the test, so I really am not completely sure which was the cause, but they might even be related.

There is a pdf /Developer/About Xcode.pdf that I opened up and started reading to see if any helpful hints could be found.  It mentioned that the entire /Developer directory was created with an Xcode install.  So I decided to rename the current /Developer directory and give it another go, hopefully starting from fresh.

But I also...

I also decided to look more into the previously mentioned TUAW tip and tried it again.  I removed the lock, but this time after rebooting the OS, I checked to make sure that the lock file was still gone.  To my surprise it was not!  mds.install.lock had been retouched at a timestamp of when the computer was restarted.  I don't know exactly what mds does, and someone please correct me if I'm wrong, but I believe it deals with indexing in Spotlight.  And I did notice that spotlight was still indexing (pulsing dot in the magnifying glass or click the magnifying glass to see the status).  I decided to wait until Spotlight was done indexing before kicking off the Xcode installation once again.  I didn't have to way all too long.  When the indexing was complete I checked for the .lock and it was still there.  I did a quick remove but this time did not reboot.  I went straight into Xcode installation (#4).

Slow slow slow ... but eventually, I heard the nice tone that for some reason Apple decided to double as installation complete and iPhone message tone.  Installation complete!

What I took away from this process was that Xcode installation is finicky.  And the best way to go about it is with a clean slate.  Reboot your machine right before attempting to install.  Make sure no other applications are running while you try and install.  And if something does go wrong... try and wipe everything (sudo mv /Developer /Developer-old).  Thankfully, that seemed to work for me.  Yay for getting back to code!

16Feb/110

Dice Game Simulation

The other day I played a dice game with the in-laws. Here's the basics:
You start with five dice. Give a roll and see what you have. If you have any 5's or 2's you take out the dice that have the 5's or 2's and roll again (you get a zero for that round). If you roll and do not have any 5's or 2's, you add up all the dice and roll again. Your points accumulate through the rounds until you have no dice left.

So here is an example:
: You roll a 5, 4, 3, 2, and a 4
Since you rolled a 5 and a 2, you take those two dice out and roll again (still with zero points)
: You roll a 2, 1, and a 1
Since you rolled a 2, you take that die out and roll again (still with zero points)
: You roll a 3 and 4
No 5's or 2's, so you add up the dice and that is the start to your running total: 7
: You roll a 4 and 4
No 5's or 2's, so you add up the dice and add to your running total: 7 + 8 = 15
: You roll a 2 and 2
Bummer, all your dice were 5's or 2's, so you are out of dice with a final score of 15

Pretty simple, right? I quickly realized that there was no actual thought process to the game it was really just the luck of the dice that gave you a score. So naturally I wanted to write a simulation to see what a normal score looks like on a large scale.

I put together a little bit of code and came up with the following results:

Rolls Distribution for 10000 games
Rolls: ##Graph## Percent% (Count)
01: # 0.37% (37)
02: ##### 4.53% (453)
03: ############ 11.61% (1161)
04: ################# 16.83% (1683)
05: ################ 15.73% (1573)
06: ############### 14.11% (1411)
07: ############ 11.3% (1130)
08: ######## 7.78% (778)
09: ###### 5.53% (553)
10: #### 3.89% (389)
11: ### 2.73% (273)
12: ## 1.64% (164)
13: ## 1.31% (131)
14: # 0.74% (74)
15: # 0.77% (77)
16: # 0.41% (41)
17: # 0.26% (26)
18: # 0.16% (16)
19: # 0.08% (8)
20: # 0.08% (8)
21: # 0.03% (3)
22: # 0.04% (4)
23: # 0.03% (3)
24: # 0.01% (1)
25: # 0.02% (2)
27: # 0.01% (1)

Score Distribution for 10000 games
Score: ##Graph## Percent% (Count)
000: ##################### 20.54% (2054)
001: ## 2% (200)
002: # 0.66% (66)
003: ### 2.56% (256)
004: #### 3.85% (385)
005: ## 1.91% (191)
006: #### 3.45% (345)
007: #### 3.27% (327)
008: ### 2.13% (213)
009: ### 2.31% (231)
010: #### 3.35% (335)
011: ### 2.29% (229)
012: ### 2.76% (276)
013: ### 2.44% (244)
014: ### 2.54% (254)
015: ### 2.16% (216)
016: ### 2.12% (212)
017: ### 2.42% (242)
018: ## 1.88% (188)
019: ### 2.04% (204)
020: ### 2.06% (206)
021: ## 1.81% (181)
022: ## 1.92% (192)
023: ## 1.73% (173)
024: ## 1.61% (161)
025: ## 1.44% (144)
026: ## 1.33% (133)
027: ## 1.25% (125)
028: ## 1.27% (127)
029: ## 1.25% (125)
030: ## 1.03% (103)
031: ## 1.09% (109)
032: # 0.95% (95)
033: # 0.77% (77)
034: # 0.96% (96)
035: # 0.74% (74)
036: # 0.82% (82)
037: # 0.76% (76)
038: # 0.63% (63)
039: # 0.53% (53)
040: # 0.7% (70)
041: # 0.7% (70)
042: # 0.66% (66)
043: # 0.55% (55)
044: # 0.49% (49)
045: # 0.52% (52)
046: # 0.43% (43)
047: # 0.42% (42)
048: # 0.4% (40)
049: # 0.28% (28)
050: # 0.32% (32)
051: # 0.33% (33)
052: # 0.18% (18)
053: # 0.18% (18)
054: # 0.17% (17)
055: # 0.29% (29)
056: # 0.2% (20)
057: # 0.18% (18)
058: # 0.18% (18)
059: # 0.12% (12)
060: # 0.17% (17)
061: # 0.11% (11)
062: # 0.1% (10)
063: # 0.16% (16)
064: # 0.14% (14)
065: # 0.1% (10)
066: # 0.08% (8)
067: # 0.08% (8)
068: # 0.1% (10)
069: # 0.07% (7)
070: # 0.05% (5)
071: # 0.07% (7)
072: # 0.07% (7)
073: # 0.07% (7)
074: # 0.05% (5)
075: # 0.07% (7)
076: # 0.05% (5)
077: # 0.05% (5)
078: # 0.01% (1)
079: # 0.04% (4)
080: # 0.04% (4)
081: # 0.05% (5)
082: # 0.02% (2)
083: # 0.05% (5)
084: # 0.02% (2)
085: # 0.05% (5)
087: # 0.02% (2)
088: # 0.03% (3)
090: # 0.01% (1)
091: # 0.01% (1)
092: # 0.02% (2)
094: # 0.01% (1)
095: # 0.02% (2)
096: # 0.01% (1)
098: # 0.01% (1)
099: # 0.01% (1)
100: # 0.02% (2)
107: # 0.02% (2)
116: # 0.01% (1)

Average rolls: 6
Average score: 16

So apparently the average score is 16 and the average number of rolls is 6. The average score was lower than I expected and the average number of rolls was higher than expected. But hey, I'd love to get a round that scores 116, that'd be pretty awesome.

Anyway, I'll paste the code below. The program takes one parameter, an integer of the number of games you want to simulate. It also prints out the results of each game as such:

Game 1
2, 6, 6, 5, 2
2, 5
game total: 0

Game 2
3, 6, 4, 1, 2
4, 1, 4, 1
6, 4, 4, 2
4, 1, 2
5, 5
game total: 10

(...)

Game 9999
6, 6, 3, 1, 1
4, 4, 4, 1, 1
6, 5, 3, 6, 2
6, 4, 3
1, 3, 1
4, 1, 3
5, 5, 5
game total: 57

Game 10000
3, 1, 6, 4, 2
4, 4, 1, 4
1, 4, 5, 3
5, 1, 2
2
game total: 13

Pretty interesting to just look through. So here's the code:
Tough to read without tabs, so you can alsodownload the file here

#include <iostream>
#include <cstdlib>
#include <time.h>
#include <map>

using namespace std;

int main (int argc, char * const argv[]) {
// Start with 5 dice
// Roll dice
// if any of the dice are of value 2 or 5
// remove dice that are of value 2 or 5 and roll again
// else
// add up dice and add to total score then roll again
// if there are no dice left, game over

srand(time(NULL)); // initialize random

int numberOfDice, valueOfDice[5], rollSum, totalScore, tmpNumberOfDice;
int numberOfRolls, totalGamesRolls=0, averageRolls=0;
int numberOfGames, totalGamesScores=0, averageScore=0;
bool goodRoll;
map<int, int> games;
map<int, int> numRolls;
int i,j;

numberOfGames = atoi(argv[1]);

for (j = 0 ; j < numberOfGames ; j++) {
// New game
totalScore = 0;
numberOfDice = 5;
numberOfRolls = 0;
cout << "Game " << j+1 << endl;
while (numberOfDice > 0) {
// New round
rollSum = 0;
goodRoll = true;
numberOfRolls++;
tmpNumberOfDice = numberOfDice;
for (i = 0; i < tmpNumberOfDice ; i++) {
// New roll
valueOfDice[i] = rand() % 6 + 1;
cout << valueOfDice[i];
if (i < (tmpNumberOfDice-1)) cout << ", ";
else cout << "\n";
if (valueOfDice[i] == 2 || valueOfDice[i] == 5) {
goodRoll = false;
numberOfDice--;
}
rollSum += valueOfDice[i];
}
if (goodRoll)
totalScore += rollSum;
}
cout << "game total: " << totalScore << "\n\n";
numRolls[numberOfRolls]++;
totalGamesRolls += numberOfRolls;
games[totalScore]++;
totalGamesScores += totalScore;
}

// Display rolls distribution
map<int, int>::iterator it;
float percent;

cout << "\nRolls Distribution for " << numberOfGames << " games" << endl;
cout << "Rolls: ##Graph## Percent% (Count)" << endl;
for (it = numRolls.begin() ; it != numRolls.end() ; ++it) {
percent = (float)((it->second)*100) / (float)numberOfGames;
if (it->first < 10) cout << "0";
cout << it->first << ": ";
for (i = 0 ; i < percent ; i++)
cout << "#";
cout << " " << percent << "%" << " (" << it->second << ")" << endl;
}

// Display score distribution
cout << "\nScore Distribution for " << numberOfGames << " games" << endl;
cout << "Score: ##Graph## Percent% (Count)" << endl;
for (it = games.begin() ; it != games.end() ; ++it) {
percent = (float)((it->second)*100) / (float)numberOfGames;
if (it->first < 10) cout << "0";
if (it->first < 100) cout << "0";
cout << it->first << ": ";
for (i = 0 ; i < percent ; i++)
cout << "#";
cout << " " << percent << "%" << " (" << it->second << ")" << endl;
}

averageRolls = totalGamesRolls / numberOfGames;
cout << "\nAverage rolls: " << averageRolls << endl;

averageScore = totalGamesScores / numberOfGames;
cout << "Average score: " << averageScore << endl;

return 0;
}

8Dec/100

Toshimote – iPhone remote for Linux media server

Welcome to Toshimote! Toshimote is a web application that I developed for use with an Ubuntu media server I have hooked up to my television. I was tired of using VNC to do something as simple as pause a video and Toshimote is the result.

If you would like to make visit my static apps page on Toshimote, head over to: http://www.pwlk.net/apps/toshimote

AND click here to view a hands on (non-working) demo of the site (best viewed from iPhone).

Resources

Overview

There are really two main parts to this project, (1) web applilcation and (2) server applications. All the website is doing is sending commands to the server to be executed with the TV as the display. Immediately below is a video demonstration I put together showing how this all works. It might be a good idea to give it a quick view so you have a mental image of what's going on when I go through the sections below.

Server

The very first item that needs to be mentioned is how you redirect output to the physical monitor attached to the server, in my case, the television. The global variable DISPLAY stores what display is being used. Typically the change to DISPLAY is so that you can execute X11 programs from the server on your local machine. But this time we want to redirect a little differently.

export DISPLAY=":0.0"

I believe this value is typically consistent, but you can double check on your server by seeing what the value of $DISPLAY is.

echo $DISPLAY

The server apps are extremely simple thanks to xte. Xte is an application that reads arguments to execute key strokes and mouse movements. All I did was write a shell script for each individual command I wanted to execute and stored the script in /usr/local/bin. Here are a few examples of some scripts I use.

#Ubuntu menu

#!/bin/bash

xte 'keydown Alt_L';
xte 'key F1';
xte 'keyup Alt_L'

#Move mouse to the left

#!/bin/bash

touch /home/jason/flags/mousemove.flag;
while [ -f /home/jason/flags/mousemove.flag ];do
xte 'mousermove -2 0'
done

#Stop mouse movement

#!/bin/bash

if [ -f /home/jason/flags/mousemove.flag ];then
rm -f /home/jason/flags/mousemove.flag
fi

Keep in mind that this is where lots of modification would need to be done. I opened up the keyboard shortcuts application in Ubuntu and used that as my resource for writing all the scripts.

The last thing that I'd like to mention about the server is in the Apache setup. I couldn't in a short amount of time get the web user (www-data) to either execute commands or change the DISPLAY value (I can't remember anymore). To solve this I took a step that will make most everyone cringe. I modified /etc/apache2/envvars and changed the login to the one and only real user of the box, 'jason'. You probably noticed that I had my flag for mouse movements hard coded to /home/jason. I know that ~ does not work but I never checked ${HOME}. As I am only developing this application for myself, I took the easy/lazy way out and rounded a few corners. As for security, I basically tossed it out the window. It doesn't take a genius to realize that they could do some serious damage to my files with this web app, but the site is hosted locally on the server that is behind the router. And if someone were to spend the time ... it is just my media server, nothing important is kept on that box.

Web App

The GUI is simple. A three column and infinite number of rows table. Oh yes I did. Tables are still alive and well in my world. Honestly this is the most perfect use of an HTML table that I've ever used. There really is nothing complex about the GUI.

AJAX is our friend in this app. We don't want the remote to reload every time we click a button. Especially when we use the mouse and have to click twice (once to start the movement of the mouse and once to stop the movement). When a button on the remote is clicked, the name of the script is sent through to a PHP script that executes that command. Yes, I know, as I said above, security nightmare. But that's really all there is to the web app side. Here are a few code snippets:

runScript.php

$com = $_REQUEST['com'];
$run_command='export DISPLAY=":0.0";'.${com};
exec($run_command);

Javascript function

function doCommand(command)
{
if (command=="xte_mouse_left_go" || command=="xte_mouse_right_go" || command=="xte_mouse_up_go" || command=="xte_mouse_down_go") {
// show the full screen banner that user clicks to stop mouse
document.getElementById("banner").style.visibility="visible";
document.getElementById("controls").style.visibility="collapse";
document.getElementById("banner").innerHTML="[less than]a href=\"#\" onClick=\"doCommand('xte_mouse_stop');\">Click to stop mouse[less than]/a>"
} else {
// hide the full screen banner that user clicks to stop mouse and show buttons
document.getElementById("banner").style.visibility="hidden";
document.getElementById("controls").style.visibility="visible";
}
xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("GET","runScript.php?com="+command,true);
xmlhttp.send();
}

Where next?

Realistically what I plan to do with Toshimote is to just add more buttons whenever the need arises. I will zip up all my code and post it on the site here as a resource to any that want to set up something similar. But for further development towards a public easy to use release, eh...

What should happen if I were to continue this project is mainly secure it up. I would make one single script that is the middle man between the web app and the actual commands being run on the server. It would take arguments and execute the proper script based on the arguments. That way, commands that aren't xte scripts couldn't be executed.

I would also put more effort into getting the default www-data user up and running and/or do a little more research on how things are suppose to be run on the server from the outside world.

Those are really the two main things that come to mind right off the bat. I'm sure I'll come up with many more things that I want the remote to be able to do while laying in bed trying to fall asleep, though. If you have anything that you'd like to see on the Toshimote, either contact me or leave a comment here.