inicio mail me! sindicaci;ón

Archive for oldbrew

iPhone Magic

Dashcode

Recently i’ve been playing about with the iPhone SDK. I’m actually quite impressed at the great tools included to make development easier, whether you choose to develop native applications or web applications.

Since i wasn’t quite up to scratch with my Objective C, i thought i’d see how much better the in-built browser was. Using Dashcode, i was easily able to prototype some pretty neat touch-based interfaces.

Still, one of the major criticism’s i seem to find about developing web apps for the iPhone is a lack of an off-line option. If you aren’t connected to a network, you can’t make use of any web applications.

Well, that’s not strictly true. You can use the “data:/” URI hack, where you bookmark a URL containing the HTML of the application you want to use off-life. But this is not a very useful solution if you want to store persistent data your application can use after re-loading.

Which is why i was pleased to find out that the iPhone simulator in the SDK includes support for WebKit’s new Database storage API. In essence this means that you can persistently store pretty much anything you want on the client.

How is this useful on the iPhone? Well, it means we can now make very useful offline web applications with persistent data storage.

Here is the “proof of concept” i have cooked up.

http://www.cuppadev.co.uk/iphone/database-images/

If you visit the above URL in the iPhone simulator, you should see three items which you can click on. (Note that these are all data:/ URI’s)

  • The first creates a database (if it does not already exist) and stores the data for an image, which is then loaded back and shown on the page.
  • The second inserts a second image into the database. If you click on the first item again, there will now be two images shown on the page.
  • The third replaces the data of the first and the second image. If you click on the first item again, you might get a little shock.

There are of course limitations to this Database API. Access to databases is restricted on a per-domain basis (although in Webkit “data:/” URL’s are treated as a single domain), and on the iPhone simulator you only get up to 5mb of storage.

Still, it works and i can see it being a very useful feature for future web applications on the iPhone.

This actually works in Safari 3.1 too, so you don’t need to download the huge iPhone SDK to try this out. It technically should work in Firefox 3 too, though as of yet i haven’t managed to get it to allow access to the database.

SCUMM in JavaScript

Soon after bumping into haXe and Doomed Online, they got me thinking. “Would it be possible to run SCUMM games in flash?”. The answer to that of course is yes, as was demonstrated by my SCUMM Interpreter written in haXe. Though as with anything, you really need to spend the time to implement everything, and justify it somewhat.

(Not to mention that Flash 10 is supposedly going to be able to compile C code, thus making my complete port more or less redundant)

Now i would have stopped there, if i hadn’t noticed that haXe targets multiple platforms, including every web developer’s best friend, JavaScript. Thus i thought, “Would it be possible to run SCUMM games in Javascript?”. For the answer… well, take a look!

OpenQuest in a browser

Yes, that is an image of OpenQuest running in a web browser, specifically Firefox. It can run in other browsers too, though to date i have only tested Firefox and Safari, the latter of which mysteriously crashes.

And if you want, you can try it yourself by clicking here. A word of warning though, it is highly recommended that you use Firefox to run it. Otherwise you might get a nasty crash, or a big disappointment.

As previously, just about enough is implemented to get the first room of OpenQuest loaded. Actors, verbs, objects, and sounds are not implemented, though it would certainly be possible. However the engine runs much slower than in Flash, so i doubt anything that could be considered to be “playable” could be implemented with it.

Still, i feel I’ve now accomplished what i set out to do when writing this interpreter – that is to push haXe, Flash, and JavaScript to the limit and see what i can get out of them. And of course, learn a bit more about SCUMM too.

Again, i would like to congratulate the ScummVM team for their SCUMM interpreter and Alban Bedel for his scummc compiler. Without their efforts, i wouldn’t have had any code or references from which to base my haXe-based SCUMM interpreter.

Edit: Source code available from github.

Edit: No longer crashes in Safari provided you are using Safari 3.1.2 or later.

Yet another RailsCollab demo

Recently i have had another go at tweaking RailsCollab, the pet project of mine (which i have mentioned previously).

After moving the source repository from Subversion to Git, i decided to add in a long standing missing feature – the web-based configuration editor.

Configuration Editor

Originally i pretty much stayed away from implementing this as Ruby on Rails was a real pain in the ass when it came to deployment, so i couldn’t implement a configuration loader that i knew would work in 90% of deployment cases.

That was, until recently when Phusion Passenger was released.

Phusion Logo

For those of you that don’t know, Passenger is an Apache module which allows you to simply drop in your Rails application and run it with practically zero configuration. It pretty much falls under the “it just works” category. I have no doubt that anyone using RailsCollab will prefer using Passenger to deploy. Consequently, i have been able to implement a rather nice configuration loader based on this assumption.

Which brings me to the demo. A short while back, my web host, DreamHost added Phusion Passenger support to their web servers. Factor everything together, and you have… the RailsCollab demo!

Link to the demo

“But wait!” you ask, “how do i login?”. Well, using OpenID of course. As with my previous demo, you should be able to select the “Use OpenID” checkbox and type in your OpenID to login.

OpenID Logo

This will automagically register you with the system, adding you to the “OpenID” company and the “RailsCollab” project. Afterwards if you want, you can reset your password so you can login using a regular username & password, though personally i think typing in your OpenID is a better idea.

Note that your OpenID provider needs to support handing over identity fields in order for RailsCollab to correctly register you. MyOpenID is an example of a provider that supports this. Also note that if there is a user with a duplicate username or email in the system, registration will fail.

One more thing

The RailsCollab demo also supports the Basecamp API. This means that you can take any existing widget, program, or service that integrates with Basecamp and use it with RailsCollab. e.g. Avalanche, Freshbooks, or Cashboard

So what are you waiting for? Try the demo already!: :)

Buzzing Off

Many months ago, i was invited to join the social networking site cre8Buzz. I accepted mainly out of interest, as i have always tended to stray away from these sort of services.

cre8Buzz Logo

Now i’m buzzing off.

Why you ask? Well, after looking objectively at what i was getting out of the site, i concluded that there was simply nothing. Actually, that’s not quite fair so i shall elaborate.

In fact, i’m not quite sure what i’m meant to be getting out of it. Perhaps i’m looking at it the wrong way; instead should i be thinking “what are other people meant to be getting out of it?”.

So if we look at the “Top 8 Communities” list for example, we find:

  1. Moms
  2. Women
  3. Photography
  4. Real Estate
  5. Entrepreneurs
  6. Dads
  7. Fiction
  8. Social

The first two, Moms and Women. Yikes! Not exactly my forte. Looking further, here’s the “Top Ranked Blogs” list:

  1. Bliss in Bloom Women
  2. Oh, The Joys Moms
  3. Looking Beyond the Cracked Window Fiction
  4. Twas Brillig Women
  5. Momo Fall’s Moms
  6. Joeprah – My Life as a Stay at Home Dad Dads
  7. The Busy Dad Blog Dads
  8. Mimz-photography Photography

Which pretty much sums up what cre8Buzz is about. Moms & Dads! I’ve inadvertently been fooled into joining a parenting community!

Now this in itself wouldn’t have been a bad thing… if i was a parent. But considering i’m not, i just don’t see what i can possibly get out of networking on cre8Buzz.

I should also factor into this the rather obvious lack of activity on my profile. When i joined, i chose to participate in the “Entrepreneurs” community, which sounded like a great idea at the time. In total i managed to get 5 people to join my friends list. I even posted on the forum.

But then… nothing.

It seemed that there was negligible activity within the “community”. Updates were sporadic, if there were any at all. It wasn’t really worth my time bothering to try and participate.

Which pretty much sums up my view on cre8Buzz. I’m sure it probably is a great social networking site, but it just doesn’t work for me. but My mouse is now hovering over the “Destroy Account” button…

Going… Going… Gone!

An Overview of Bungee Connect

A while ago, i was contacted by Ted Haeger of Bungee Labs in response to my blog entry on Heroku. He invited me to check out Bungee Connect, their fully featured web-based IDE. So i did.

Keep in mind that the following overview is of the Beta version, which is still under development and so is still subject to change. Also remember that this is in no way an in-depth review.

For those who don’t know, Bungee Connect is an all-inclusive web development environment. It covers development, testing, and publishing of web applications. In addition, a collaborative element is introduced with support for multiple users.

Development

Bungee Connect IDE

So here’s the development environment, which has a striking resemblance to a certain Intergrated Development Environment from another company.

Naturally, the first thing anyone would want to do is make a simple “Hello World” application, which sounds very simple at first – right? Wrong!

Sadly there is quite a big learning curve getting to grips with Bungee’s terminology and workflow.

As you’ll note by looking at the screen shot, the hierarchy for my “Hello World” application looks like this:

  • Yo_World
    • MyAppProject
      • NewPage
    • MyTypeLib
      • Yo_World
        • Object

Which to me, seems a bit overcomplicated.

Bungee Connect is not the sort of development environment where you can just pick it up and churn out a working application without first reading the documentation.

Still, with a lot of head bashing you could probably think of the above as an example of MVC (Model, View, Controller). i.e. “MyAppProject” is where the views go, and “MyTypeLib” is where all of the controllers go.

For the actual code, it seems primarily based on Java or CSharp. Though i couldn’t find this explicitly stated anywhere, so i am not sure.

One of the key features which sets this solution apart from other web-based development environments is the GUI designer. It can be very much likened to Visual Studio – there’s a control palette on the left, object inspector on the bottom, and you can move about controls in a WYSIWG-style canvas.

Another thing of note is that you can bind values of controls to counterparts in control objects. This means that you can easily build up complex interfaces without writing tonnes of glue code, which can save a lot of time. If you have ever used Interface Builder on a mac, you’ll probably know what i mean.

Hello World! Example

Staging & Deployment

Assuming you made it through the development process, it’s likely you’ll want to subject your application to rigourous testing and eventually publish it to Bungee Connect’s servers for public consumption.

Bungee Connect Licenses

That is, after you accept no more than 3 long and wordy license agreements, which to say the least was a big legal commitment for such a service. I might not have been bothered if there were only 2, but 3? Also factor in the additional Terms of Use and Privacy Policy. That makes 5. Crazy!

It should also be noted that you are locked into deploying your application on Bungee Connect’s servers.

Conclusion

Enough rambling. So is Bungee Connect any good? Well at the moment, not really. I say this because it just seems like an overly complicated solution for a rather simple problem. While I want to “Build the app, not the crap”, it would be nice if i could “Not deal with the crap”.

The “Crap” i refer to includes:

  • Complicated licensing
  • Steep learning curve (terminology, process, quirks)
  • Buggy interface (e.g. drag & drop didn’t work at all in Safari!)

Bungee’s statement, “Build the app, not the crap” got me thinking. When was the last time i really thought i was building the app, not the crap?

Delphi Box

Yes, Delphi. Hello World? Just stick a label on the default project’s form, type “Hello World”, and press run. It couldn’t be any simpler.

Compare and contrast with Bungee Connect: I have to make a “TypeLib”, a controller, then a form. Then if i am lucky i might figure out which item in which list is the form, drag over a label, type “Hello World”, and then stick it all on the page in my other project.

I really do wonder, why can’t modern web-based web application development be simple and fun?

An Analogue Clock using Safari Transforms

Recently Safari 3.1 has been released for Mac and Windows, boasting a whole load of useful new features. One of these is support for CSS transforms – i.e. you can translate, scale, and rotate HTML elements in a web page.

CSS transforms can come in quite handy for making complex dynamic objects, without the need for 3rd party plugins or applets. For example i was able to make the following BBC-esque analogue clock, using only DIV’s and JavaScript :

(Note that currently this only works in Safari 3.1)

Yes, DIV’s and JavaScript. No Canvas, no Flash, no SilverLight, no Java Applets, no Plugins.

It makes me wonder, considering that browsers seem to be getting so powerful nowadays, should one really bother using Flash & co anymore?

What not to write in haXe, Part II

I decided to have another go at writing some awe-inspiring haXe code again. This time, i picked up from where i left off – that was trying to get my infamous SCUMM interpreter working on additional platforms which haXe supports.

For reference, i concentrated on getting it to work on the neko platform.

To start off with, i took notice of a suggestion to simplify the import statements which littered the top of the source code. So instead of this:


#if flash9
import flash.display.Bitmap;
...
#else neko
import noflash.Bitmap;
...
#end

I consolidated everything into a single file which looked like this:


#if flash9
typedef Bitmap = flash.display.Bitmap;
...
#else neko
typedef ByteArray = noflash.ByteArray;
...
#end

So when i used “import hiscumm.Common”, i could now access all of the classes listed with little fuss!

Another change i made was to re-factor the way resources were loaded. Before, i just used flash 9’s ByteArray. However as there is no direct equivalent of this on the neko platform, i had to implement my own.

Thinking more, i determined that only a relatively small portion of my code actually needed to use all of the features of ByteArray, so instead i changed all of the IO code to use the neko api’s Input & Output classes.

Finally i made all 32bit integers Int32’s. Consequently, i had to re-implement the Int32 class for the flash platform, but all things considered it was the best solution.

Problems

As before, i ran into a fair share of problems. Most were minor, and others were solved when i upgraded from haXe 1.17 to 1.18. Here are some of the more notable ones i came across.

“No arrays larger than 115 elements”

I ended up finding a rather obvious solution to this problem which worked transparently with the other platforms. All one has to do is split up the troublesome array into several smaller arrays and then concatenate them together. e.g.


var longarray = [1,2,3].concat([4,5,6]).concat(7,8,9); // works

Problem solved.

“Beware of classes extending Int”

In an earlier implementation of my Int32 class, i had it extending Int. This turned out to be a fatal mistake, as when i tested out the code absolutely nothing worked.

The solution of course was just to not extend from Int.

“haxe.Timer does not have a constructor”

I kept getting a rather odd compile error. It seemed that no constructor was defined for the Timer class, which i used to run the game loop. This was very odd, as the API documentation didn’t state anything unusual about the Timer class on the neko platform.

However after checking out the code to the Timer, i soon came to realise the horrifying truth: the Timer class wasn’t implemented for the neko platform. Arrrgh! I got this far and now i’m stopped by something as simple as this?

Thankfully i figured out a rather obvious workaround. Instead of using the timer, i merely made a typical run-of-the-mill game loop. Problem solved.


while (true)
{
onTime();
neko.Sys.sleep(0.01);
}

The result

As the output below shows, the interpreter now actually runs on neko. Unfortunately there appears to be a rather nasty bug when decoding the room image. But then again i’ve not implemented any video code for the neko platform yet, so the usefulness of this is questionable to say the least.


$ neko test.n
NekoTest.hx:42: Engine init
SCUMM.hx:486: boot state
SPUTMResource.hx:308: Loading resource 1 from file 1, room 2 (SCRIPT)
SCUMM.hx:488: Started
SCUMM6.hx:1249: ARRAY = ""
SCUMM6.hx:1249: ARRAY = "ScummC Paused !"
SCUMM6.hx:1249: ARRAY = "Are you sure you want to quit ? (Y/N)Y"
SCUMM6.hx:1249: ARRAY = "Are you sure you want to restart ? (Y/N)Y"
SCUMM6.hx:1249: ARRAY = "Save it"
SCUMM6.hx:1249: ARRAY = "Load it"
SCUMM6.hx:1249: ARRAY = "Continue"
SCUMM6.hx:1249: ARRAY = "Cancel"
SCUMM6.hx:1249: ARRAY = "Quit"
SCUMM6.hx:1249: ARRAY = "Ok"
SCUMM6.hx:1249: ARRAY = "Saveing '%s'"
SCUMM6.hx:1249: ARRAY = "Loading '%s'"
SCUMM6.hx:1249: ARRAY = "ScummC test Menu"
SCUMM6.hx:1249: ARRAY = "Save game"
SCUMM6.hx:1249: ARRAY = "Load game"
SCUMM6.hx:1249: ARRAY = "Game NOT saved"
SCUMM6.hx:1249: ARRAY = "Game NOT loaded"
SCUMM6.hx:1249: ARRAY = "Insert disk %c"
SCUMM6.hx:1249: ARRAY = "You must enter a name"
SCUMM6.hx:1249: ARRAY = "Insert your save disk"
SCUMM6.hx:1249: ARRAY = "Failed to open %s (%c%d)"
SCUMM6.hx:1249: ARRAY = "Read error on disk %c (%c%d)"
SCUMM6.hx:788: 103, 645
SPUTMResource.hx:308: Loading resource 2 from file 1, room 2 (ROOM)
SPUTMRoom.hx:173: RMIM == RMIM
SPUTMImage.hx:109: smap size == 8
SPUTM.hx:1096: Internal exception, aborting! (state=SPUTM_RUNNING)
SPUTM.hx:1097: >>

As before, the hiscumm code is available for reference. Unlike last time however, the code is now hosted in a git repository so you can now see all the nitty gritty changes i have made to it. Great!

Click here to check it out!

What not to write in haXe

You might have notice that during the past few months i’ve written a few articles about haXe, a language and compiler which pits itself as a “toolbox for the web developer”.

Recently i decided to test out haXe’s platform support. I did this by taking my SCUMM interpreter code – which i had previously written for flash 9 – and tried to get it to work on the other two major platforms haXe supports, javascript and neko.

To start off with, i had to remove its dependency on flash. This was achieved by making replacement classes and switching between the two using the conditional pre-processor. i.e.:


#if flash9
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.utils.ByteArray;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.Timer;
import flash.events.TimerEvent;
#else neko
import noflash.ByteArray;
import noflash.Bitmap;
import noflash.BitmapData;
import noflash.Point;
import noflash.Rectangle;
import noflash.Timer;
import noflash.TimerEvent;
#end

Most of the modifications to the code looked like this, with liberal sprinklings of ”#if flash9 … #end” round the flash specific code.

Eventually i got to the point where things started to look like they were going to compile, or so i thought

Problems

“Array too big”

The first problem i encountered was that it wouldn’t compile.


hiscumm/SCUMM6.hx:1870: lines 1870-2127 : This array declaration is too big, try to split it

Array declaration too big? What on earth was it going on about?


| TArrayDecl el ->
if List.length el > 115 then error "This array declaration is too big, try to split it" e.epos;
call p (field p (ident p "Array") "new1") [array p (List.map (gen_expr ctx) el); int p (List.length el)]

Oh, right. Seems i cannot have arrays declared with more than 115 elements. A seemingly arbitrary limitation that is not referenced anywhere in the documentation – great!

Not needing the opcode table for my little experiment, i commented most of it out. Problem solved.

“32bit? no, 31bit!”

Now the first time i got the interpreter to compile for neko, i thought “Wow, great! Looks like this is going to work.” Unfortunately though, it didn’t. Instead, i got a rather odd exception when reading out of my replacement ByteArray:


Uncaught exception - Overflow

Turns out the problem was with this code here, in neko.Input:


public function readInt32() {
var ch1 = readChar();
var ch2 = readChar();
var ch3 = readChar();
var ch4 = readChar();
if( (ch4 & 128) != 0 ) {
if( ch4 & 64 == 0 ) throw Error.Overflow;
return ch1 | (ch2 << 8) | (ch3 << 16) | ((ch4 & 127) << 24);
} else {
if( ch4 & 64 != 0 ) throw Error.Overflow;
return ch1 | (ch2 << 8) | (ch3 << 16) | (ch4 << 24);
}
}

So basically the reader was trying to stuff the whole 32 bit value into a neko Integer, which is actually 31 bits. Oddly enough though, the value being read was identical to a value i specified in the code.

But haXe never bothered to complain about an overflow!

This can be demonstrated by the following code, which prints “-766623411” instead of the expected “1380860237”.


trace(1380860237);

Thankfully, a solution exists. There is an “Int32” type which properly handles 32bit integers. However there is a really big snag with it – it’s a class.

That means you cannot use any fancy inbuilt operators with it – you have to use a set of functions instead.


import neko.Int32;

var result: Int = 1 + 2; // simple
var result32: Int32 = Int32.add(Int32.ofInt(1), Int32.ofInt(2)); // aaaarrrghh!!!

result += 1; // simple
result32 += 1; // don't even think about it, it won't work

And to top it all off, this “Int32” class only exists for the neko platform, you cannot use it with flash or javascript. Unless you write it yourself, but that is besides the point. It should at least have been there to fill in the gap.

Conclusion

If you are looking at writing code in haXe and want it to work across all 3 of its supported platforms (flash*, neko and javascript), then beware if you are reading, writing, or otherwise processing 32bit integers.

In addition watch out for mysterious arbitrary limitations such as the 115 item limit for declared arrays.

A Wiki written in haXe

A while ago now, i writ a piece about haXe, a language and compiler which pits itself as a “toolbox for the web developer”.

Now i thought haXe was a great idea, with a great potential for consolidating the mess that is web development. But at the time, i couldn’t find any examples of its full use out in the field.

That was until today, when i discovered MyMiniCity!

I have heard that MyMiniCity is the first example of a web based game completely written using haXe. The back-end appears to run on mod_neko, while the front-end uses a mix of JavaScript and Flash, both compiled using haXe (from what i can tell at least).

Getting to the point…

Now i shall get to the point. I was so impressed with MyMiniCity that i decided to have a go at writing a Wiki in haXe. This pretty much took me most of the day as i had to make heads and tails of haXe’s library’s.

In any case, ended up with something which kind of works. For the code, see overleaf.

<!-more->

The code

Beware! this code ain’t pretty. But it works for the most part. Note that you might also have to make a dummy file called “macros.mtt”.

index.hxml


-cp /usr/lib/haxe/lib/mtwin/1,2,6
-neko Index.n
-main Index

Index.hx



// Main web application class.

import mtwin.web.Handler;

class Page extends neko.db.Object {
public var id : Int;
public var name : String;
public var content : String;

public var last_edited : Date;

public function toHTML() : String
{
return mtwin.text.Text2Xhtml.transform(content);
}

public static var manager = new neko.db.Manager<Page>(Page);
}

class Index {
// mtwin.web.Request represents the current http request with url, parameters, etc...
static var request : mtwin.web.Request;
// for this example we will use mtwin.templo XHTML template engine
static public var template : mtwin.templo.Loader;
// this is some dynamic template context for templo
static public var context : Dynamic;

// Instance vars
static var cnx : neko.db.Connection;

public static function main(){
mtwin.templo.Loader.BASE_DIR = "/Users/jamesu/Projects/Experiments/haxe/web/";
mtwin.templo.Loader.TMP_DIR = "/tmp/";
context = Reflect.empty();
template = null;

request = new mtwin.web.Request();

// connect to database
cnx = neko.db.Mysql.connect({
host : "localhost",
port : 3306,
database : "HaxeWiki",
user : "root",
pass : "",
socket : null
});

neko.db.Manager.cnx = cnx;
neko.db.Manager.initialize();

// creates the main application handler
var handler = new WikiHandler();

// little check to avoid index.n in path
var level = if (request.getPathInfoPart(0) == "index.n") 1 else 0;

// start processing the request starting from specified path info part
handler.execute(request, level);

// if the templo template is defined, we execute it
if (template != null){
neko.Web.setHeader("Context-Type", "text/html; charset=UTF-8");
neko.Lib.print(template.execute(context));
}

// close database connection
neko.db.Manager.cleanup();
cnx.close();
}
}

class WikiHandler extends Handler<String> {

public function new(){
super();

// Edit page
free("edit", "editpage.mtt", doEditWikiPage);
}

// Overide execute so we can process wiki pages
override public function execute( request:mtwin.web.Request, ?pathLevel:Int ){
if (pathLevel == null)
pathLevel = 0;

var part = request.getPathInfoPart(pathLevel);

this.request = request;
this.level = pathLevel;

if (part == "")
part = "default";

part = part.toLowerCase();
initialize();

// Check for special wiki pages
if (actions.exists(part)){
actions.get(part)();
return;
}

doWikiPage(part);
}

function doWikiPage(title: String){
var context = Index.context;

// Search for wiki page in database
var wikipages = Page.manager.search({name : title}, true);
var wikipage : Page = wikipages.isEmpty() ? null : wikipages.first();

if (wikipage == null)
{
context.wikipage = new Page();
context.wikipage.name = title;
context.wikipage.content = '';
context.wikipage_new = true;
prepareTemplate("editpage.mtt");
}
else
{
context.wikipage = wikipage;
prepareTemplate("viewpage.mtt");
}
}

function doEditWikiPage(){
var context = Index.context;

var realtitle = request.get('name').toLowerCase();
var wikipages = Page.manager.search({name : realtitle}, true);
var wikipage : Page = wikipages.isEmpty() ? null : wikipages.first();

if (wikipage == null)
{
context.wikipage_new = true;
wikipage = new Page();
wikipage.name = realtitle;
}
else
{
context.wikipage_new = false;
}
context.wikipage = wikipage;

if (request.get('content') != null)
wikipage.content = request.get('content');

// Skip rest if not POST'ing
if (neko.Web.getPostData() == null)
return;

if (context.wikipage_new)
{
// Make page
wikipage.last_edited = Date.now();

wikipage.insert();
neko.Web.redirect("/" + wikipage.name);
}
else
{
// Edit page
wikipage.last_edited = Date.now();

wikipage.update();
neko.Web.redirect("/" + wikipage.name);
}
}

// same as above
override function prepareTemplate( t:String ){
Index.template = new mtwin.templo.Loader(t);
}
}


database.sql

MySQL schema.

CREATE TABLE Page (
id int(10) unsigned NOT NULL auto_increment,
name varchar(40) NOT NULL,
content TEXT NOT NULL DEFAULT '',
last_edited datetime default NULL,
PRIMARY KEY (id)
);

viewpage.mtt



<html>
<head>
<title>Viewing page ::wikipage.name::</title>
</head>

<body>
<h1>::wikipage.name::</h1>
<div id="content">
::raw wikipage.toHTML()::
</div>
<p><a href="/edit?name=::wikipage.name::">Edit page</a> (Last edited : ::wikipage.last_edited::)</p>
</body>
</html>

editpage.mtt


<html>
<head>
::if (!wikipage_newl)::
<title>Editing page ::wikipage.name::</title>
::else::
<title>New page</title>
::end::
</head>

<body>
<h1>Edit page</h1>
<form method="post" action="/edit">
<input type="hidden" name="name" value="::wikipage.name::"/>
<textarea name="content" rows="10" cols="50">::wikipage.content::</textarea>
::if !wikipage_new::
<input type="submit" value="Edit"/>
::else::
<input type="submit" value="Save"/>
::end::
</form>
</body>
</html>

Instructions

Assuming you have got haXe installed, but never got the web stuff working you might want to do the following:

  1. sudo haxelib install mtwin
  2. cd /usr/lib/haxe/lib/mtwin/1,2,6/mtwin/templo
  3. sudo haxe temploc.hxml
  4. sudo cp temploc /usr/bin/

Then something like this should suffice to get the wiki code running:

  1. mysql -u root HaxeWiki < database.sql
  2. haxe index.hxml
  3. nekotools server -rewrite

And you can make wiki

Accounting with Luca

A while ago now, i stumbled across a web based double entry accounting solution called Luca (not to be confused with the Mac Application).

Unfortunately though, the documentation was a bit sparse. However with a bit of persistence, i have just about managed to figure out how to use it.

Starting out

(note that for this little walkthrough i am using Luca 1.02, so don’t be surprised if you are using a later version and things look that bit different)

Assuming you have managed to download and install Luca, as well as log in, you’ll be presented with this rather interesting interface:

Luca main menu

Whoah! Lots of options to choose from, but which of those do we need to start off with?

First things first, you’ll need to create a chart of accounts, so select the “Charts of accounts” option. You’ll be presented with a list of charts, which should be empty. Click on “Add new chart”, and your screen will look something like this:

Luca new chart

The only 2 values which are of interest are “Description” and “Format mask”, the former of which can be anything you like. The latter is a bit more tricky, and it took me a while to figure out. It seems that the “Format mask” is basically a sequence of 9’s using dots as separators. The more dots you use, the more you can nest your accounts.

For reference, i put the following values in this form:

  • Description: LucaCorp
  • Format Mask: 9999.99 (i.e. 2 levels one using four digits, the other using two)

You should now have a chart you can use. But to be of any use, it needs to be assigned to an Organization. To do this, go back to the main menu, and select “Organizations”. Then select “Add new Organization”. Your screen should now look something like this:

Luca new organization

Give your Organization a name, a remark if you like, and of course a chart of accounts. The values i used are as follows:

  • Name: LucaCorp
  • Remarks: blank
  • Chart of Accounts: LucaCorp

Note that you will also need to give yourself (and anyone else you trust with a user account) permission to use the Organization when entering transactions. This can be done in the “Users X Organizations” screen.

Creating accounts

Now would be a good idea to actually make some accounts. To do this, go back to the main menu and select “Accounts of the chart”. Then for the “Parent chart being edited:” field, select your chart of accounts. Your screen should now look something like this:

Luca add account

For each account you want to create, click on “Add Account” and fill in the form, which should look something like this:

Luca add account

The “Class” is the type of account to be created. You can make Accounts for Assets, Liabilities, Equity, Revenue, and Expenses (note that this list can be altered by playing about with the “Account classes”).

The “Std. journal” corresponds to an id of a “Standard Journal Description” which you can make in “Standard Journal Descriptions”. From what i can tell this allows you to save on typing repetitive descriptions when entering transactions, though i have not really found a use for it yet.

“Code” is the identifier of this account. It needs to correspond to the “Format Mask” you created earlier, e.g. in my case, “1234” and “1234.01” would both be acceptable.

“Parent account” is the code of the account you wish to be the parent. You can use this to create complex hierarchies of accounts, something which i assume Accountants love to do.

The rest of the fields are pretty obvious, apart from “Mobile clients” which i can only assume allows people using Luca’s bluetooth functionality to enter transactions on the account (note though that i have not tried this out).

So now you can create accounts at will. As for which accounts to create, it’s really up to you. However if you are a bit stuck, below is a table of values you can enter to reproduce a set of accounts from of one of my favourite tutorials on Double Entry Accounting written by Joseph Mack.

RocketScience LLC Accounts

Class Code Parent Description Small description
Asset 1234 cash cash
Asset 1234.01 1234 Joseph Mack, withdrawing jm_withdrawing
Asset 1234.02 1234 check account check_account
Asset 1234.03 1234 petty cash petty_cash
Liabilities 1235 liabilities liabilities
Liabilities 1235.01 1235 Joseph Mac, capital jm_capital
Equity 1236 equity equity
Equity 1236.01 1236 accumulated profit and loss acc_profit_loss
Equity 1236.02 1236 [clo]profit and loss profit_loss
Revenue 1237 revenue revenue
Revenue 1237.01 1237 fees earned fees_earned
Expenses 1238 expenses expenses
Expenses 1238.01 1238 advertising advertising
Expenses 1238.02 1238 food,entertainment food_entertainment
Expenses 1238.03 1238 office supplies office_supplies

Entering transactions

To enter transactions in Luca, you’ll need to first create a Batch. To do this, from the main menu select “Batches”. Then on the next screen, select your Organization and click on “Add new batch”. Your screen should look something like this:

Luca add batch

As you might have noticed, there is not much to a batch. The only thing to look out for is the dates you enter, which need to be in the format “yyyy/mm/dd”, and need to lie within the organization’s active period (the default being 1970/01/01 -> 1970/01/01).

If you ever want to change the date range of the active period, all you need to do is select “Active Period” from the main menu, then click on “Edit” next to the relevant accounting period for your organization. Your screen should look something like this:

Luca edit accounting period

Then all you need to do is enter an initial and final date. It’s as simple as that!

For my first batch, i used the following:

  • Description: First batch!
  • Initial date: 1970/01/01
  • Final date: 1970/01/01
  • Checksum: 0
  • Status: Open
  • Type: Normal batch

Now you can start entering your transactions, which in Luca are referred to as Journals. To do this, from the main menu select “Journals”. Then on the next screen, select your Organization and Batch, then click on “Add new journal”. Your screen should look something like this:

Luca add journal

So to sum this up…

“DB account” and “CR account” mean “Account to debit” and “Account to credit” respectively. I’m going to assume you know enough about double entry accounting to figure out which accounts you credit and which you debit.

“Std. journal” i already mentioned when creating accounts.

“Cost center” i have yet to figure out, best to leave this as 1 unless you really need it set.

“Date”, “Description”, “Value”, and “Status” are all pretty obvious.

You can enter as many journals as you like in a batch. It is also interesting to note that you don’t have to enter both a credit and debit for an entry – you can quite easily add multiple debit or credits in a row.

Profit and Loss

At the end of the accounting year, you’ll probably want to determine profit and loss, which usually involves folding revenue and expense accounts into a single profit and loss account. This is otherwise known as “closing out the accounts”.

So how does one do this in Luca? Quite simply in fact. Select “Balance closing” from the main menu, and your screen should look something like this:

Luca closing balance

So basically all you need to do is select your organization, enter in start and end dates, then click “Prepare to close balance”.

However you’ll probably bump into a few issues first time, as three conditions need to be satisfied:

  1. You need an account which contains “[clo]” somewhere in its description to store the closing values.
  2. The period you specify needs to be within the current active period.
  3. All batches in the specified period need to be set to “Closed”

The first condition is rather easy to satisfy. All you need to do is make an equity account named something like “[clo]Profit and Loss”.

The last two conditions we more or less went over when talking about batches.

Assuming you got the balance to close, your “Profit and Loss” equity account should now look something like this:

Luca profit and loss ledger

To sum it all up

Luca is a pretty promising accounting solution. It does accounting, reports, and also includes a bit of multiuser management too. In contrast to other solutions, it doesn’t try to do everything – which i believe is one of its strengths. It’s a relief not having to wade through a swamp of CRM to do something as simple as sorting out the accounts.

Sadly though Luca doesn’t appear to have a very active community, and from what i can tell Elvis Pfützenreuter puts most of the work into it.

Still from what i have been able to gather Luca is still under development so with any luck it’ll gain more useful features in the future such as multiple currency support.

Next entries »
Close
Powered by ShareThis