######## SYNTAX ######## links: [[wikipage]], btw: [[use-dashes-instead-of-camel-case]] [[wikipage|text to show]] quoted text: "<`" text "`>" executable lua code (it will be run in place): "<?" code "?>" titles: use ascii art tables: use ascii art diagrams: use ascii art enumerations: use plain text list items: use plain text definition lists: use plain text quotations: use ascii art or plain text text color: use green text italics, bold text, underlining, variable width fonts: don't use them Example: link to this page (example code being run here) (execution finished) Output: 2 Only basic "safe" functions are allowed to the interpreter, please don't abuse the precious cputime or memory. Btw, only executable code from authenticated users is run. ######## IMAGE LIBRARY ######## There are only 16 available colors (proudly choosen by me): 0.. 3: white, yellow, orange, red 4.. 7: magenta, blue, teal, sky blue 8..11: green, dark green, brown, tan 12..15: light gray, gray, dark gray, black img = image(w, h) Returns a newly created image of size w*h (min 8x8, max 320x200). img:color(c) Sets the current foreground (pen) color. Must be an integer between 0 and 15. Returns this same image img. img:get(x, y, w, h) Returns a string made of lines where each caracter corresponds to the hex representation of the respective pixel of the image in the given range. For instance a black 16x8 image with a red point at (3, 1), will serialize to the following text: ffffffffffffffff fff3ffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffff img:line(x1, y1, x2, y2) Draws a line between (x1, y1) and (x2, y2). Both source and destination points will be drawn. Returns this same image img. Example: img:plot(x, y) Sets the point at x, y to the current foreground color, modifying the image. For the x,y outside their boundaries this function does nothing. Returns this same image img. img:put(x, y, w, h, data) This method being the opposite of get, allows to load an image from dumped data. Chars not in [0-9a-f] will be ignored, but the amount of valid pixels in the dumped data must be equal to w*h. Returns this same image img. img:rect(x, y, w, h) Draws a w*h size filled rectangle, returning the same image img. img:render() Returns the image as a safe string that you may concatenate to other text (for inline display) or just return it. img:text(x, y, text) Puts text into the image at position x, y (in pixels from top left corner, as usual). Text will be rendered with the traditional atari 8-bit font using the current color for foreground and transparent background, inverse video is not supported (you could however draw a rectangle behind the text and then change the color). The parameter text must be encoded in utf-8 with only the following chars supported (equivalent to those of the 7 bit ATASCII), any other will be replaced to '●': '♥','├','▕','┘','┤','┐','╱','╲','◢','▗','◣','▝','▘', '▔','▂','▖', '♣','┌','─','┼','●','▄','▎','┬','┴','▌','└','␛','↑', '↓','←','→', ' ','!','"','#','$','%','&',"'",'(',')','*','+',',', '-','.','/', '0','1','2','3','4','5','6','7','8','9',':',';','<', '=','>','?', '@','A','B','C','D','E','F','G','H','I','J','K','L', 'M','N','O', 'P','Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_', '♦','a','b','c','d','e','f','g','h','i','j','k','l', 'm','n','o', 'p','q','r','s','t','u','v','w','x','y','z','♠','|', '↰','◀','▶' Example: CONVERTING IMAGES After saving the desired image (whose size must not be bigger than 320x200) in PNM color ascii format (identified by having the text P3 in the first line), you may use the following command to convert it to the same format used by get/put: cat image.pnm | luajit -e 'P={[0]={255,255,255},{255,255,0},{255,102,0}, {221,0,0},{255,0,153},{34,0,153},{49,112,140},{44,152,225},{0,170,0}, {0,102,0},a={102,51,0},b={153,102,51},c={187,187,187},d={136,136,136}, e={68,68,68},f={0,0,0}} g=io.read"*a":gsub("#[^\n]*",""):gmatch"%S+"; assert(g()=="P3","make sure the image is in pnm ascii color format (P3)"); w,h=tonumber(g()),tonumber(g());g(); assert(0<w and w<=320 and 0<h and h<=200,"invalid size"); rgb,i,buff={},1,{};for v in g do rgb[i],i=tonumber(v),i%3+1 if i==1 then md=1e9 for c,p in pairs(P)do d=(p[1]-rgb[1])^2+(p[2]-rgb[2])^2+(p[3]-rgb[3])^2 if d<md then md,mc=d,c end end buff[#buff+1]=mc if #buff==w then print(table.concat(buff));buff={}end end end' ######## PERFORMANCE ######## It's pretty obvious that running mod_lua with luajit makes a huge performance improvement. However debian apache2's mod_lua comes with lua-5.2 by default. So in order to fix that, I've recompiled the mod_lua.so library with the following commands or other ones (I'm not sure though). # apt-get source apache2 <- this is the first obvious one, # dpkg-buildpackage <- to compile it. * build/special.mk loads the config parameters from build/config_vars.mk, in the latter you may change MOD_LUA_LDADD = -lluajit-5.1 * The remaining variables can be set in modules/lua/modules.mk: MOD_CPPFLAGS = -DAP_ENABLE_LUAJIT MOD_INCLUDES = -I/usr/include/luajit-2.0 * The next step is to, in modules/lua/lua_vmprep.c comment the lines with calls to luaopen_jit and loadjitmodule, sort of "fixing" this bug: http://mail-archives.apache.org/mod_mbox//httpd-bugs/201111.mbox/%3Cbug-52252-7868@https.issues.apache.org/bugzilla/%3E * Under modules/lua run: make mod_lua.so * Then you'll find in modules/lua/.libs/mod_lua.so the so desired library, with that in place (/usr/lib/apache2/modules/), after a restart, you'll finally be able to enjoy the speed boost. ######## DATABASE ######## CREATE TABLE pages(name text not null, version int not null, content text, rendered text, private boolean, created_on int not null, primary key(name, version)); -- name: name of the page, for instance 'lua/wiki'. -- version: an integer starting with 1 incremented each time the page is saved. -- content: the content of the page before rendering. -- rendered: the html result of rendering content, if null it's updated once -- someone requests the page. -- private: if not null then this page will only be shown if the user has edit -- access as well. -- created_on: seconds from epoch when the version was created. CREATE TABLE passwords(pattern text primary key, password_hash text, salt text); -- on page save the wiki will only store the changes if there's at least one -- row such that: -- page_name:match(pattern), and -- sha1(salt..':'..password) == password_hash. -- This design allows different passwords for access to different page subsets. ######## REST API ######## In the current installation at fideo, <basePath> is "/wiki.lua/!rest/v0". As for the <pageName> it referers the name of the wiki page without the initial slash, ie: "/wiki.lua/foo/bar" will have <pageName> "foo/bar". GET <basePath>/pages/<pageName>[?params] params: format=(plain|html), version=<integer> Fetches a wiki page. Returning an error if the page doesn't exist. If the format is not specified, both html and plain text are returned. If the version is not specified, the last one is returned. If the page was "deleted", then empty bodies will be returned. If the page was never created or the requested version does not exist, a 404 error will be returned. response body schema: { "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { "body": { "type": "object", "properties": { "plain": { "type": "string", "description": "The source code of the requested page." }, "plain": { "type": "string", "description": "The requested page rendered into html." }, }, "description": "The body of the wiki page in at least one format.", "minProperties": 1 }, "version": { "type": "integer", "description": "Requested or last version number." } }, "required": [ "body", "version" ] } POST <basePath>/pages/<pageName> Creates or updates a wiki page. To "delete" the page just update it with an empty body. request body schema: { "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { "previousVersion": { "type": "integer", "description": "This request will fail if the page doesn't exist and this is defined, or if it exist and its value is not equal to the last version in the database.", }, "body": { "type": "string", "description": "Content of wiki page." }, "password": { "type": "string", "description": "Password used for access control." } }, "required": [ "body" ] } response body schema: { "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { "version": { "type": "integer", "description": "Version of the page just created or updated." } }, "required": [ "version" ] }