This is a simple Greasemonkey script that adds "Record a Play" links to the played games lists. This is useful when browsing your friends Recent Plays list as it allows you to directly add a play from the page without having to first open the game. It also sets the play date to that of the original item so if you both played the same game its a simple two click to copy their play to your own account.
A picture is worth a thousand words:
Installation Instructions:
Install the Greasemonkey plug-in for your web browser. Or use this version for Safari(Click NinjaKit for Safari.)
Restart your web browser as necessary.
Install the Greased MooTools and Extra Log Plays Links scripts into Greasemonkey.
This is my personal blog and mainly contains technical solutions, open source code, and other projects I have worked on. Much of the technical solutions are very niche so your milage may vary.
Wednesday, April 21, 2010
Friday, April 16, 2010
PHP MySQL database abstraction class
I wrote a very elegant database interaction class for PHP some time ago. The class is a simple layer between a PHP application and its database and provides a very clean and efficient interface to the database. It does not generate the SQL code for you, but rather it makes a cleaner method of calling your SQL code. It allows you to generate repeatable queries as objects, provides parameter substitution in queries, and allows reading a record via class accessors. Some samples of these features are shown below.
I have not posted the source code itself as I feel this is one of my more exquisite projects and I don't want to see it taken without credit. I may be willing to provide the code on request though.
Examples: A simple reader query. (Select)
A simple non-reader query. (Insert, Update, Delete)
The same update only using parameters instead of string substitution. There are two ways to do this and both generate identical SQL code.
All three of the above update calls will generate the following statement. Notice how the second two statements automatically quote string and escape any special characters in strings.
You can also use parameters in reader queries exactly the same way as above. Also you can prepare the query and then set parameters/execute the query as a seperate step. Again the folloing are identical.
To read the results there are a few other options as well.
Also there are a few other calls that may be useful. You can get the number or records and raw SQL statement like so.
I have not posted the source code itself as I feel this is one of my more exquisite projects and I don't want to see it taken without credit. I may be willing to provide the code on request though.
Examples: A simple reader query. (Select)
$users = new query("SELECT userID, username, lastAccess, enabled FROM users;"); if(!$users->is_valid()) return false; while($users->fetch()) { echo $users->usersID; }
A simple non-reader query. (Insert, Update, Delete)
if(!query::run("UPDATE users SET session = '$userSessionID', lastAccess = NOW() WHERE userID = $userID;")) throw new Exception("Database update failed.");
The same update only using parameters instead of string substitution. There are two ways to do this and both generate identical SQL code.
return query::run("UPDATE users SET session = @1, lastAccess = NOW() WHERE userID = @2;", $userSessionID, $userID); return query::run("UPDATE users SET session = @sessionID, lastAccess = NOW() WHERE userID = @usersID;", array(sessionID => $userSessionID, usersID => $userID));
All three of the above update calls will generate the following statement. Notice how the second two statements automatically quote string and escape any special characters in strings.
UPDATE users SET session = 'SESSION', lastAccess = NOW() WHERE userID = UID;
You can also use parameters in reader queries exactly the same way as above. Also you can prepare the query and then set parameters/execute the query as a seperate step. Again the folloing are identical.
$users = new query("SELECT userID, username, lastAccess, enabled FROM users WHERE username = @username;", false); $users->username = $username; $users->execute(); $users = new query("SELECT userID, username, lastAccess, enabled FROM users WHERE username = @1;", false); $users->execute(true, $username); $users = new query("SELECT userID, username, lastAccess, enabled FROM users WHERE username = @username;", false); $users->execute(true, array(username => $username);
To read the results there are a few other options as well.
$users = new query("SELECT userID, username, lastAccess FROM users WHERE username = @username;", false); foreach($users as $user) { $users->username = $user; if(!$users->execute()) continus; echo $users->usersID; // Get a coulmn value. print_r($users->get_row()); // Print the entire row. echo $users->get_md5(); // Time dependent hash. echo $users->get_md5('userID', 'username'); // UserID/Username dependent hash. echo $users->get_columns(); // Get a list of loaded columns. }
Also there are a few other calls that may be useful. You can get the number or records and raw SQL statement like so.
$users = new query("SELECT userID, username, lastAccess, enabled FROM users;"); echo $users->get_length(); echo $users->get_last_sql(); query::run("UPDATE users SET groupName = @1, lastEdit = NOW() WHERE groupName = @2;", $newGroupName, $groupName); echo query::length(); echo query::last_sql();
Backup your FreeBSD system configuration.
I set up a simple script to create a configuration backups of my FreeBSD box and I thought I would share it. Note that this script will only back up the /etc and /usr/local/etc directories and weighs in at just under 1MB per backup.
First create a backup script as we can't execute our complex command directly in cron. You may want to customize the exclude options to your licking, the two listed exclusions are the rather large gconf defaults, witch is not needed, and the working files for transmission.
Now make it executable.
Now add the job to cron and set it to run weekly as root.
First create a backup script as we can't execute our complex command directly in cron. You may want to customize the exclude options to your licking, the two listed exclusions are the rather large gconf defaults, witch is not needed, and the working files for transmission.
sudo vim /usr/local/sbin/backup-config bash -c 'tar -czf /root/freebsd-cfg-`date "+%Y-%m-%d"`.tgz --exclude={etc/gconf,usr/local/etc/transmission/home/{resume,torrents,Downloads,blocklists}} /etc/ /usr/local/etc/'
Now make it executable.
chmod +x /usr/local/sbin/backup-config
Now add the job to cron and set it to run weekly as root.
sudo vim /etc/crontab# Backup the entire server configuration once a week. 0 1 * * 0 root backup-config 2>/dev/null
Thursday, April 15, 2010
Patch for VIrtualbox not working on Freebsd after updating graphics/png port.
I have had a very frustrating time over the last few days. After doing a full portupgrade I found that virtualbox-ose would no longer work properly. The GUI portion was working and I could run vm's but I was unable to manage any machines from the console with VBoxManage. Trying to do any operations would just die with the following error.
The only changes where Virtualbox being bumped from 3.1.4 to 3.1.6 and a new version of the dependent graphics/png package. After much testing I determined that the problem was with the png update change but I couldn't figure out how to resolve it. I finally found a patch out and about that fixed this problem so I am posting more details here. The patch listed in that page is actually not a patch at all but rather a replacement makefile so i created a patch and posted instructions below.
Build the pached version
Patch, build, and install.
ERROR: failed to create a session object! ERROR: code NS_ERROR_FACTORY_NOT_REGISTERED (0x80040154) - Class not registered (extended info not available) Most likely, the VirtualBox COM server is not running or failed to start.
The only changes where Virtualbox being bumped from 3.1.4 to 3.1.6 and a new version of the dependent graphics/png package. After much testing I determined that the problem was with the png update change but I couldn't figure out how to resolve it. I finally found a patch out and about that fixed this problem so I am posting more details here. The patch listed in that page is actually not a patch at all but rather a replacement makefile so i created a patch and posted instructions below.
Build the pached version
Patch, build, and install.
cd /usr/ports/emulators/virtualbox-ose sudo wget http://pynej.dnsalias.com/Shared/virtualbox-ose-3.1.6_2-1.patch sudo patch -p0 < virtualbox-ose-3.1.6_2-1.patch sudo portupgrade -f virtualbox-ose
Thursday, April 8, 2010
Updatting c# applicationSettings in a ASP.NET Web Application
I have a few .NET web applications, using MVC, that make use of applicationSettings in their configuration. These settings are semi-constant but do need to be updated from time to time. I was trying to make an edit screen in the web application for developers so they could edit the applicationSettings without having to get on the server and manually edit the Web.config file. As expected the applicationSettings are read only when accesses directly in the application and can not be updated. Also it's not possible to configure the settings as userSettings when running as a web application. Though we could do this by manualy reading and writing the file I was looking for a simpler way to do it.
After some tinkering I found a fairly simple way of doing this. Basically we can use a custom ConfigurationManager instance to read the Web.config independently of the application and update this instance of the configuration. Then we just call the save method and the edited data is saved out. Here is the code for a simple update call.
Note that this code is tailored for MVC and is looping tough the FormCollection values. You could also explicitly read the post variables as parameters of the post action, or use this outside of MVC entirely. Just keep in mind that however you do it you can't loop by clientSection.Settings as the requirement to remove/re-add each updated value prevents this.
After some tinkering I found a fairly simple way of doing this. Basically we can use a custom ConfigurationManager instance to read the Web.config independently of the application and update this instance of the configuration. Then we just call the save method and the edited data is saved out. Here is the code for a simple update call.
Note that this code is tailored for MVC and is looping tough the FormCollection values. You could also explicitly read the post variables as parameters of the post action, or use this outside of MVC entirely. Just keep in mind that however you do it you can't loop by clientSection.Settings as the requirement to remove/re-add each updated value prevents this.
using System.Configuration; [AcceptVerbs(HttpVerbs.Post), Authorize(Roles = "Admin")] public ActionResult SaveSettings(FormCollection collection) { /* This section of code uses a custom configuration manager to edit the Web.config application settings. * These settings are normally read only but web apps don't support user scoped settings. * This set of variables is used for system features, not runtime tracking so it it only updated when an * administrator logs in to reconfigure the system. * * Author: Jeremy Pyne* Licence: CC:BY/NC/SA http://creativecommons.org/licenses/by-nc-sa/3.0/ */ // Load the Web.config file for editing. A custom mapping to the file is needed as the default to to match the application's exe filename witch we don't have. System.Configuration.Configuration config = ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap() {ExeConfigFilename = HttpContext.Server.MapPath("..\\Web.config") }, ConfigurationUserLevel.None); // Find the applicationSettings group. ConfigurationSectionGroup group = config.SectionGroups["applicationSettings"]; if (group == null) throw new AjaxException("Could not find application settings."); // Find this applications section. Note: APP needs to be replaced with the namespace of your project. ClientSettingsSection clientSection = group.Sections["APP.Properties.Settings"] as ClientSettingsSection; if (clientSection == null) throw new AjaxException("Could not find Hines settings."); // Loop through each value we are trying to update. foreach (string key in collection.AllKeys) { // Look for a setting in the config that has the same name as the current variable. SettingElement settingElement = clientSection.Settings.Get(key); // Only update values that are present in the config file. if (settingElement != null) { string value = collection[key]; // Is this is an xml value then we need to do some conversion instead. This currently only supports the StringCollection class. if (settingElement.SerializeAs == SettingsSerializeAs.Xml) { // Convert the form post (bob,apple,sam) to a StringCollection object. System.Collections.Specialized.StringCollection sc = new System.Collections.Specialized.StringCollection(); sc.AddRange(value.Split(new char[] { ',' })); // Make an XML Serilization of the new StringCollection System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(System.Collections.Specialized.StringCollection)); System.IO.StringWriter writer = new System.IO.StringWriter(); ser.Serialize(writer, sc); // Get the xml code and trim the xml definition line from the top. value = writer.ToString().Replace("<?xml version=\"1.0\" encoding=\"utf-16\"?>", ""); } // This is a custom override for MVC checkboxes. They post as 'false' when unchecked and 'true,false' when selected. if(value == "true,false") value = "True"; if(value == "false") value = "False"; // Replace the settings with a updated settings. It is necessary to do it this way instead of // updating it in place so that the configuration manager recognize that the setting has changed. // Also we can't just look through clientSection.Settings and update that way because then we wouldn't // to do this exact thing. clientSection.Settings.Remove(settingElement); settingElement.Value.ValueXml.InnerXml = value; clientSection.Settings.Add(settingElement); } } // Save any changes to the configuration file. Don't set forceSaveAll or other parts of the Web.config will get overwritten and break. config.Save(ConfigurationSaveMode.Full); }
Subscribe to:
Posts (Atom)
Project Licenses
These works by Jeremy Pyne are licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License