Lua function to remove JavaScript comments

Nov 28 2011

JavaScript is an interpreted language. Therefore when the code is put in a web page, the client can easily see how it works. Commenting the code is a good coding practice to improve readability but we don’t want to waste user bandwidth with comments. Before releasing JavaScript codes it’s good to remove the comments from them. Here is a little Lua script that does the job.

 

--- Gets a valid compilable javascript code and removes its comments
-- @note the javascript code should be ready to compile that is: there are no syntax
-- errors whatsoever. Otherwise the behavior of this function is unpredictable.
-- @param txt the compilable javascript code
-- @return a text string the semantically behaves the same as the txt that was passed
-- to the function but doesn't have comments
function removeCommentsJS(txt)
	txt=txt:gsub("/%*.-%*/","\n")   --remove all multi-line comments
	txt=txt:gsub("//.-\n","\n")     --remove all single-line comments
	txt=txt:gsub("\n[%s\n]*\n","\n")--remove all empty lines
	txt=txt:gsub("^\n","")          --remove first empty new line
	txt=txt:gsub("\n$","")          --remove last empty new line
	return txt
end

And here is a test script that will not print any error if finished successfully:

--removeCommentsJS() test
txt={
[[
code;
]],
[[code;
]],
[[code;]]
,
[[/**
comments
*/
code;
]],
[[//comments
code;
]],
[[code;//comments
]],
[[//comments
code;
//comments
]],
[[//comments

code;

//comments
//comments
//comments
]],
[[//comments

/*comments*/

/** comments */

/**
* comments
*/

/**
* comments
* comments
* comments
* comments
*/

code;

//comments
//comments
//comments
]]
}
for _,t in ipairs(txt) do
    local uncommentedJS=removeCommentsJS(t)
    if uncommentedJS~="code;" then
        print("Test failed for :\n'"..t.."'! Return value is:\n'"..uncommentedJS.."'")
    end
end

Comments are off for this post

Lua string sanitization

Oct 07 2011

I needed to write some string as Lua code. In this case, if double quote (“) appears in the string, it may end the string literal in the generated source code. Also all the escape characters like \n if are written as \\n in the string may cause trouble. I thought it’s better to create a sanitization function just like HTML sanitization function and here it is:

Update: apparently Lua takes care of multiline strings before writing to file! it adds “..\n at the end of each line (including the quote) and ” at the beginning of the next line.

---replaces quotation marks (") with (\") so that the string can be saved as a Lua string in code files
-- NOTE: str should not be nil
function luastrsanitize(str)
	str=str:gsub('\\','\\\\')  --replace \ with \\
	str=str:gsub('"','\\"')    --replace " with \"
	return '"'..str..'"'
end

--luastrsanitize() test
print(repquote(""))
print(repquote("hi\""))
print(repquote("hi\nhow are you?"))
print(repquote('he said: "hi"'))
print(repquote("one tab\\tdistance"))
print(repquote([=[hello "kitty"!]=]))
print(repquote('"'))

Comments are off for this post

REST tutorial

Oct 04 2011

This website has a great and simple tutorial about REST: http://rest.elkstein.org/

The main advantage of ROA is ease of implementation, agility of the design, and the lightweight approach to things. In a way, SOA and SOAP is for people in business suits; that’s what you’ll find used in the banking and finance industries. Conversely, somebody that needs something up-and-running quickly, with good performance and low overhead, is often better off using REST and ROA. (src)

Here are some more links about REST from this website.

Comments are off for this post

How to connect your Wifi iPad to internet through an Android phone

Sep 23 2011

Problem definition:

1. I have an iPad with Wifi (this instruction works for iPad2, iPod, XBox and anything with Wifi)

2. I have a data plan (mobile broadband)

3. I have an Android phone (HTC Hero)

4. I want to browse the internet on the big screen of iPad using the internet from the Android phone.

Epilogue:

As you might have researched, sharing internet from an Android device is called tethering and as you might already know Google has removed all the tethering applications from Google market and the few which remain there need “root access” in order to control your Wifi settings and make it usable as an access point. But that’s not possible on ordinary handsets, well not without a small trick that I’m going to share here (it’s an old trick which has been shared on the internet herehere and there. I haven’t invented it).

Solution:

1. Find a way to transfer Androot to your phone and install it (the simplest way is via USB and writing it to SD card and then using a file manager program to run the file). This will give the “root access” to the Wifi tethering program. Make sure “Unknown source” is checked at Settings, Applications. I installed UniversalAndroot-1.6.2-beta5:

  • http://theunlockr.com/down/UniversalAndroot-1.6.2-beta5.apk
  • http://www.addictivetips.com/?attachment_id=41115
  • http://www.megaupload.com/?d=FJA3L8YZ

2. Install a Wifi tethering program. I use Barnacle Wifi tether which is an open source program freely available on the Android market. Run the program and set the access point and if you want WEP password for security. Press the start button and when it’s ready press the big “Associate” key.

3. Use your iPad or other Wifi enabled devide to connect to the Android device. You may need to enter the WEB password here as well.

Tricks/Notes:

  • If after pressing “start” Barnacle Wifi Tether just hangs up and doesn’t do much, go to your phone’s Wifi setting and disable/enable Wifi once and come back to app and press start again. That should have it going.
  • There are other ways to root a device as well. “Universal Androot” seems to be one of the easiest ones which I learned from this great page.
  • Androot asks your permission every time a program wants to gain root access. Though it can remember your choices to be less annoying.

 

Comments are off for this post

Lua function to check if a table is an array

Sep 23 2011

This is the simplest and fastest code I could develop in an hour. All tests pass and it sounds promising:

---Checks if a table is used as an array. That is: the keys start with one and are sequential numbers
-- @param t table
-- @return nil,error string if t is not a table
-- @return true/false if t is an array/isn't an array
-- NOTE: it returns true for an empty table
function isArray(t)
	if type(t)~="table" then return nil,"Argument is not a table! It is: "..type(t) end
	--check if all the table keys are numerical and count their number
	local count=0
	for k,v in pairs(t) do
		if type(k)~="number" then return false else count=count+1 end
	end
	--all keys are numerical. now let's see if they are sequential and start with 1
	for i=1,count do
		--Hint: the VALUE might be "nil", in that case "not t[i]" isn't enough, that's why we check the type
		if not t[i] and type(t[i])~="nil" then return false end
	end
	return true
end

--tests
nontable=5
nontable2=nil
emptyTable={}
oneMember={1}
oneMember2={"1"}
withfunc={1,function()return "yo" end}
withnil={nil,2,3,4}
named={a=2,4,5}

assert(isArray(nontable)==nil)
assert(isArray(nontable2)==nil)
assert(isArray(emptyTable)==true)
assert(isArray(oneMember)==true)
assert(isArray(oneMember2)==true)
assert(isArray(withfunc)==true)
assert(isArray(withnil)==true)
assert(isArray(named)==false)

print("All tests passed successfully!")

Comments are off for this post

Lua hex dump function

Sep 21 2011

This one is really cool! :D

---Returns a string representation of a hex dump of a string (containing binary bytes even zero)
function hexdump(s)
	local manLine="" --human readable format of the current line
	local hexLine="" --hexadecimal representation of the current line
	local address=0     --the address where the current line starts
	local LINE_LENGTH=16 --how many characters per line?
	local ADDRESS_LENGTH=4 --how many characters for the address part?
	local ret=""
	if not hex then
		hex={}
		local digit={[0]="0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"}
		for i=0,15 do for j=0,15 do hex[i*16+j]=digit[i]..digit[j] end end
	end
	for i=1,s:len() do
		local ch=s:sub(i,i)
		if ch:find("%c") then ch="." end--if ch is a control character, assign some default value to it
		manLine=manLine..ch
		hexLine=hexLine..hex[s:byte(i)].." "
		if (i % LINE_LENGTH)==0 or i==s:len() then
			--print(string.format("%04u | %-48s | %s",address,hexLine,manLine))
			ret=ret..string.format("%0"..ADDRESS_LENGTH.."u | %-"..3*LINE_LENGTH.."s| %s\n",address,hexLine,manLine)
			manLine,hexLine="",""
			address=i
		end
	end
	return ret
end

--Test code
print(hexdump("hello! how are you?\tI didn't know you are here! Salutation!\n\n\nHahaha!:D"))

Output:

0000 | 68 65 6C 6C 6F 21 20 68 6F 77 20 61 72 65 20 79 | hello! how are y
0016 | 6F 75 3F 09 49 20 64 69 64 6E 27 74 20 6B 6E 6F | ou?.I didn't kno
0032 | 77 20 79 6F 75 20 61 72 65 20 68 65 72 65 21 20 | w you are here!
0048 | 53 61 6C 75 74 61 74 69 6F 6E 21 0A 0A 0A 48 61 | Salutation!...Ha
0064 | 68 61 68 61 21 3A 44                            | haha!:D

Comments are off for this post

Lua for variable scope

Sep 21 2011

Lua has a special scoping. All variables are global by default (even if defined inside a function). Local variables should  explicitly be defined are not accessible from outside their scope. I was wondering if the variable used in a for iteration is local or global because Lua doesn’t allow local keyword after for. So the following simple test was developed:

i=0
for i=1,2 do
  print("i="..i)
end
for j=1,2 do
  print("j="..j)
end
if i then print("i="..i) else print "i isn't global" end
if j then print("j="..j) else print "j isn't global" end

And the output is:

i=1
i=2
j=1
j=2
i=0
j isn't global

So the iteration variables in Lua are local by default except if defined as global outside the for loop.

Comments are off for this post

Lua logging with limited size

Sep 17 2011

I was working on an embedded log API for an ARM system in Lua. The problem definition required limiting the amount of data that’s being written on the disk and a log file was eating all of that space to an extent that the machine was unusable. This happens when you hire inexperienced consultants who don’t understand the basics of embedded system programming. Anyway, I had to replace his code with a log API that only holds the latest log messages and here it is: the result of 3 days of my work.

The code has a lot of inline documentation so it should be obvious how it works but basically it makes for example 5 log files and the latest one is always the one with a bigger number (log-5.log is newer than log-4.log). The log message itself is also interesting. It tries to find the source of the log message and date/time.

--There can be several files. Their names are like:
-- LOG_FILE_PREFIX..N..LOG_FILE_POSTFIX
-- N will be variable between 1 to LOG_FILE_MAX_NUM
-- When file size reaches LOG_MAX_SIZE, an older log
-- file is removed and a new one is created

--{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Options
--- LOG_FILE_PREFIX is the prefix that will be used to create the log file name.
--  it also indicates the absolute path for the value. Default="/tmp/log"
LOG_FILE_PREFIX ="./logfile-"
---Number of log files. The files will have a number in their name that range from [1-N] inclusive
LOG_FILE_MAX_NUM =5
---The postfix to the log file. Default=".log"
LOG_FILE_POSTFIX=".log"
---Maximum length of a log file before trying to make a new one
LOG_MAX_SIZE    =100*1024      --bytes
--}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}Options

require "lfs"

local currFile,n

local function writeToFile(str)
	local function fname(n) return LOG_FILE_PREFIX..n..LOG_FILE_POSTFIX end

	if not currFile then
		--trying to find the latest log file (from its number)
		for i=LOG_FILE_MAX_NUM,1,-1 do
			local fn=fname(i)
			local f=io.open(fn)
			if f then
				f:close()
				currFile,n=io.open(fn,"a+"),i
				break
			end
		end
		--if still couldn't find the latest file, make the file#1
		if not currFile then currFile,n=io.open(fname(1),"w+"),1 end
	end

	str=str or ""
	--if there's not enough space
	print("currsize="..currFile:seek("end")+str:len())
	if (currFile:seek("end")+str:len())>LOG_MAX_SIZE then
		currFile:close()
		currFile=nil
		--do we need to create a brand new file?
		for i=n+1,LOG_FILE_MAX_NUM do
			local fn=fname(i)
			local f=io.open(fn)
			if not f then
				currFile,n=io.open(fn,"a+"),i
				break
			end
			f:close()
		end
		--did the above loop succeed to find a new file?
		if currFile then
			--remove all the files with a bigger number
			for i=n+1,LOG_FILE_MAX_NUM do os.remove(fname(i)) end
		else
			--ok, then we need to use a currently existing file
			os.rename(fname(1),fname(LOG_FILE_MAX_NUM+1))
			--shift file names
			for i=1,LOG_FILE_MAX_NUM do os.rename(fname(i+1),fname(i)) end
			currFile,n=io.open(fname(LOG_FILE_MAX_NUM),"w+"),LOG_FILE_MAX_NUM
		end
	end

	currFile:write(str)
	currFile:write("\n")
	currFile:flush(str)
end

---Write something as a log to the screen (or maybe later to a file)
-- Note: this function adds the current date and time to the log report.
-- @msg the message to be logged
function log(msg)
	local debuginfo=debug.getinfo(2,"lSn")
	if debuginfo then
		if      debuginfo.what=="main" then sourcename="MAIN"
		elseif debuginfo.what=="C"    then sourcename="C "..debuginfo.name
		elseif debuginfo.what=="Lua"  then sourcename="function "..debuginfo.name.."()"
		end
		sourcefile=debuginfo.source:match("@?(.*)")
		linenumber=debuginfo.currentline
		datetime=os.date("%H:%M:%S %d/%m/%Y")
		return writeToFile(datetime.." "..sourcefile..":"..linenumber..":["..sourcename.."]: "..msg)
	else
		return writeToFile("--"..msg)
	end
end

for i=1,3000 do
	log("hi, this is a log "..i)
end

Comments are off for this post

Make the table row extend to the end of the page

Sep 09 2011

Note: the HTML TABLE cell-spacing attribute is similar to CSS border-spacing (ref).

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
html,body{
	height:100%;
	margin:0;
	padding:0;
	border:none;
}
table{
	height:100%;
	width:100%;
	border:none;
	margin:0;
	padding:0;
	border-spacing:0;
}
table td{
	margin:0;
	padding:0;
}
table tr{
	margin:0;
	padding:0;
}
table tr:first-child{
	height:50px;
	background-color:red;
}
table tr:last-child{
	height:auto;
	background-color:blue;
}
</style>
<title>Untitled Document</title>
</head>

<body>
<table>
  <tr> <td>Header</td></tr>
  <tr> <td>Body</td></tr>
</table>
</body>
</html>

Comments are off for this post

Ajax-style “loading” animation generator

Sep 09 2011

Ajaxload.info

This one is even better than the previous link. You can choose the animation from a dozen of options and choose forground and background colors (transparent background is supported)

Comments are off for this post

« Newer posts Older posts »