Today, M. Aurélien Croc, the author of Splix, informed me that a new version of Splix, 0.0.2, is now usable in 64-bit.
Of course I am happy because now I am no longer limited to submitting 4294967296 documents to the spooler; now I can submit 18446744073709551616 documents at a time. I mean why else would you even bother running a spooler in a 64-bit environment? (I kid).
Packages needed:
libcupsys2-dev
libcupsimage2-dev
/tmp/splix-0.0.2 $ make
make[1]: Entering directory `/tmp/splix-0.0.2/src'
g++ -O2 `cups-config --cflags` -I../include -c -o rastertospl2.o rastertospl2.cpp
g++ -O2 `cups-config --cflags` -I../include -c -o raster.o raster.cpp
g++ `cups-config --ldflags` -lcups -lcupsimage -o rastertospl2 spl2.o printer.o band.o compress.o rastertospl2.o raster.o
make[1]: Leaving directory `/tmp/splix-0.0.2/src'
make[1]: Entering directory `/tmp/splix-0.0.2/ppd'
make[1]: Nothing to be done for `all'.
make[1]: Leaving directory `/tmp/splix-0.0.2/ppd'
/tmp/splix-0.0.2 $ sudo make install
make[1]: Entering directory `/tmp/splix-0.0.2/src'
install -m 755 -s rastertospl2 `cups-config --serverbin`/filter
make[1]: Leaving directory `/tmp/splix-0.0.2/src'
make[1]: Entering directory `/tmp/splix-0.0.2/ppd'
install -d -m 755 `cups-config --datadir`/model/samsung
for filename in ml1510 ml1520 ml1610 ml1710 ml1740 ml1750 ml2010 ml2150 ml2250 ml2550; do \
install -m 644 $filename.ppd `cups-config --datadir`/model/samsung;\
for lang in fr it de; do \
install -m 644 $filename$lang.ppd `cups-config --datadir`/model/samsung;\
done; \
done \
make[1]: Leaving directory `/tmp/splix-0.0.2/ppd'
--- Everything is done! Have fun ---
The files installed are:
/usr/lib/cups/filter/rastertospl2
/usr/share/cups/model/samsung/*.ppd (among them is ml1740.ppd)
We can add the printer from cups's web interface (typically found at http://localhost:631). When prompted for printer model, just provide the ppd (in my case it is /usr/share/cups/model/samsung/ml1740.ppd).
(originally from http://microjet.ath.cx/WebWiki/2006.11.17_DebianAMD64_and_SamsungML1740_Part2.html)
2006-11-05
Continuation support in ruby
I heard today that Ruby 2.0 is going to abandon support for continuation, at least initially until things have stabilised a bit. It is no longer a news, it is just that I have not been active in Ruby community for a while.
My initial reaction upon hearing that was "What a pity". On second thought, I realised that dropping continuation initially makes sense. The support for continuation in Ruby 1.x is missing an ensure procedure that is continuation-friendly; meaning one that is called only once one a given path is no longer accessible.
A proper ensure mechanism that supports explicit continuation formation system, like Ruby 1.8, would have produced:
Notice how "ensure" is supposed to be called only once. I have a sample implementation of such continuation-observant ensure mechanism in system-managed-unwind-protect-in-sisc for SISC, a scheme implementation.
"But, but, what if I really want something like ensure that is called each time a code section is called?", you asked. In other words, you want something like Ruby 1.8's multiple-shot ensure in this new world of single-shot ensure.
That is not a problem and don't think that you are being unreasonable for asking this feature. It is useful to be able to guarantee execution of some code upon exiting a dynamic environment.
A dynamic environment is the environment that your program can access at any given time. The environment can change with each instruction executed by the machine.
But such one-sided guarantee does not really do anything interesting. How about a guarantee that some code is also executed upon entering a dynamic environment, thus having a symmetric aspect.
Scheme has dynamic-wind that does the above:
The utility in having a in/excursion guard can't be understated. In SRFI-34, dynamic-wind is used to install a custom exception handler. Yes, a custom exception handler; this is probably a strange concept for some people. Why would one have different exception handlers on the same piece of code? The first reason is "why not?". A dynamic language restricted to having a static exception handler feels incomplete. The second reason is more practical. Since you can in/ex-curse from/to any context (via calling a provided continuation object), how an exception is handled in a given context is not necessarily the same as in other different contexts.
Thus, a complete example of how multiple-shot and single-shot ensure example co-existing (sorry, in scheme as there is no Ruby implementation with single-shot ensure yet):
Notice how "ensure" is called just once even though there are two incursion into the protected code block.
The last deficiency in Ruby 1.x is the restriction that a continuation has to be resumed from the same thread that reifies it.
(originally from http://microjet.ath.cx/WebWiki/2006.11.05_Continuation_Support_in_Ruby.html)
The Problem with Continuation Support in Ruby 1.x
My initial reaction upon hearing that was "What a pity". On second thought, I realised that dropping continuation initially makes sense. The support for continuation in Ruby 1.x is missing an ensure procedure that is continuation-friendly; meaning one that is called only once one a given path is no longer accessible.
$create_cont_k=nil def do_something(k) puts "Do something called" $create_cont_k = k end def do_something_else return unless $create_cont_k puts "Do something else called" k = $create_cont_k $create_cont_k = nil k.call end def create_cont callcc{|create_cont_k| do_something(create_cont_k)} ensure puts "Ensure called" end create_cont do_something_else # /tmp $ ruby1.8 /tmp/ensure-run-multiply.rb # Do something called # Ensure called # Do something else called # Ensure called
A proper ensure mechanism that supports explicit continuation formation system, like Ruby 1.8, would have produced:
# /tmp $ ruby1.8 /tmp/ensure-run-multiply.rb # Do something called # Do something else called # Ensure called
Notice how "ensure" is supposed to be called only once. I have a sample implementation of such continuation-observant ensure mechanism in system-managed-unwind-protect-in-sisc for SISC, a scheme implementation.
"But, but, what if I really want something like ensure that is called each time a code section is called?", you asked. In other words, you want something like Ruby 1.8's multiple-shot ensure in this new world of single-shot ensure.
That is not a problem and don't think that you are being unreasonable for asking this feature. It is useful to be able to guarantee execution of some code upon exiting a dynamic environment.
A dynamic environment is the environment that your program can access at any given time. The environment can change with each instruction executed by the machine.
But such one-sided guarantee does not really do anything interesting. How about a guarantee that some code is also executed upon entering a dynamic environment, thus having a symmetric aspect.
Scheme has dynamic-wind that does the above:
(define *CREATE-CONT-K* #f) (define (do-something k) (display "Do something called\n") (set! *CREATE-CONT-K* k)) (define (do-something-else) (when *CREATE-CONT-K* (display "Do something else called\n") (let ((k *CREATE-CONT-K*)) (set! *CREATE-CONT-K* #f) (k)))) (define (create-cont) (dynamic-wind (lambda () (display "Entering...\n")) (lambda () (call/cc (lambda (create-cont-k) (do-something create-cont-k)))) (lambda () (display "Exiting...\n")))) (create-cont) (do-something-else) ;; /tmp $ sisc -x /tmp/dynwind.scm ;; Entering... ;; Do something called ;; Exiting... ;; Do something else called ;; Entering... ;; Exiting...
The utility in having a in/excursion guard can't be understated. In SRFI-34, dynamic-wind is used to install a custom exception handler. Yes, a custom exception handler; this is probably a strange concept for some people. Why would one have different exception handlers on the same piece of code? The first reason is "why not?". A dynamic language restricted to having a static exception handler feels incomplete. The second reason is more practical. Since you can in/ex-curse from/to any context (via calling a provided continuation object), how an exception is handled in a given context is not necessarily the same as in other different contexts.
Thus, a complete example of how multiple-shot and single-shot ensure example co-existing (sorry, in scheme as there is no Ruby implementation with single-shot ensure yet):
(class-path-extension-append! (list "file:/home/ysantoso/share/project/scheme/unwind-protect/")) (require-library 'unwind-protect) (import unwind-protect) (import s2j) (define (do-gc) ((generic-java-method '|gc|) (java-null (java-class '|java.lang.System|)))) ;; do-something and do-something-else functions are elided for brevity (define (create-cont) (dynamic-wind (lambda () (display "Entering...\n")) (lambda () (unwind-protect (call/cc (lambda (create-cont-k) (do-something create-cont-k))) (display "Ensure\n"))) (lambda () (display "Exiting...\n")))) (create-cont) (do-gc) (do-something-else) (do-gc) ;; /tmp $ sisc -x /tmp/dynwind.scm ;; Entering... ;; Do something called ;; Exiting... ;; Do something else called ;; Entering... ;; Exiting... ;; Ensure
Notice how "ensure" is called just once even though there are two incursion into the protected code block.
The last deficiency in Ruby 1.x is the restriction that a continuation has to be resumed from the same thread that reifies it.
def do_something_else return unless $create_cont_k puts "Do something else called" k = $create_cont_k $create_cont_k = nil t=Thread.new { k.call} t.join end # /tmp $ ruby1.8 ensure-run-multiply.rb # Do something called # Ensure called # Do something else called # ensure-run-multiply.rb:13:in `call': continuation called across threads (RuntimeError) # from ensure-run-multiply.rb:14:in `join' # from ensure-run-multiply.rb:14:in `do_something_else' # from ensure-run-multiply.rb:25
(originally from http://microjet.ath.cx/WebWiki/2006.11.05_Continuation_Support_in_Ruby.html)
2006-10-24
System-managed UNWIND-PROTECT in SISC
Authentication
Login with:
Scheme's
call/cc
provides a flexible way to control execution flow. Its flexibility allows for different approaches to implementing unwind-protect
. Dorai Sitaram's "Unwind-Protect in Portable Scheme" shows a portable implementation of
unwind-protect
. It does so by constricting the flexibility of call/cc
. User would have to specify when to call the unwindforms
part of unwind-protect
. In certain situations, it is desirable to have this level of control. In others, it would be akin to having to manually manage memory allocation. The other approach is having an automatically executed
unwindforms
such as the one described by Taylor R. Campbell, "2006-05-01 On control brackets and resource release". Having the system manages the execution of unwindforms
is more in line to traditional implementations of unwind-protect
in other languages. It is this approach that interests me. By associating a
protector cell
to the bodyform
, we can rely on the GC mechanism cleaning up the protector cell once =bodyform='s continuation is no longer reachable. If it is no longer reachable, then it is safe to execute the unwindforms
. He also describes an optimisation of a common case where =bodyform='s continuation is never reified. Without it, there is only one =bodyform='s continuation and once the execution passes through the end of
bodyform
, it is safe to continue to unwindforms
. In his 'blog', he provides a sample implementation for MIT-Scheme. The implementation would have to be platform-specific since it hooks into the GC. However, it is easy to port that to other platform.
An Implementation in SISC
As a user of SISC, and as someone who has seen many applications (including SISCWeb) usingdynamic-wind
as a poor-man's unwind-protect
, having a system-managed unwind-protect
in SISC is a good idea. As I was not aware of any existing implementation, I proceeded to create one using Taylor Campbell's example as the starting point. To hook into Java's GC finalisation process, I used
GCHook.java. Then unwind-protect.scm implements the rest.
unwind-protect-in-sisc
(originally from http://microjet.ath.cx/WebWiki/2006.10.24_UnwindProtectInSISC.html and http://microjet.ath.cx/WebWiki/2006.10.27_UnwindProtectInSISCPart2.html)
Labels:
continuation,
scheme,
sisc,
unwind-protect
2006-09-04
Debian Sarge (3.1), LVM2, and Linux >= 2.6.16
I upgraded Linux kernel from 2.6.15 to 2.6.17 and found out that the weekly backup process appeared to hung the whole machine. I narrowed the problem to when the snapshot volume was being removed:
lvremove /path/to/snapshot/volume
I found this email that describes a workaround, but the more proper workaround is to upgrade sarge's lvm2 package made available by Juergen Kreileder.
(originally from http://microjet.ath.cx/WebWiki/2006.09.04_DebianSarge_LVM2_Linux2.6.16.html)
lvremove /path/to/snapshot/volume
I found this email that describes a workaround, but the more proper workaround is to upgrade sarge's lvm2 package made available by Juergen Kreileder.
(originally from http://microjet.ath.cx/WebWiki/2006.09.04_DebianSarge_LVM2_Linux2.6.16.html)
2006-08-07
perl-like lock for ruby
Authentication
Login with:
lock(an_obj) { ..... }
similar to the lock library in perl.
"That won't not that hard to build", I thought. I did the first version in about 5 minutes. Then thought that it would be nice to make it robust to object_id wrap-around and also to discard unnecessary records associate to an_obj when an_obj has been garbage collected.
require 'thread' require 'weakref' class Lock Record = Struct.new("Record", :weakref, :mutex) def initialize(auto_cleanup_per_record = 1000) @mutex = Mutex.new @obj_records = {} @create_count = 0 @auto_cleanup_per_record = auto_cleanup_per_record end def lock(what, &block) record = acquire_obj_record(what) record.mutex.synchronize { if block_given? block.call end } end private def cleanup_proc lambda {|id| @mutex.synchronize { to_delete = [] @obj_records.each_pair{|k,v| if not v.weakref.weakref_alive? to_delete << k end } to_delete.each{|id| @obj_records.delete(id) } #puts "Cleanup id: #{to_delete.join(",")}. Size: #{@obj_records.size}: #{@obj_records.keys.join(",")}" } } end def acquire_obj_record(what) @mutex.synchronize { if record = @obj_records[what.object_id] and record.weakref.weakref_alive? record else ObjectSpace.define_finalizer(what, cleanup_proc) @obj_records[what.object_id] = Record.new(WeakRef.new(what), Mutex.new) end } end public @instance = Lock.new def self.lock(what, &block) @instance.lock(what, &block) end def self.cleanup(verbose=false) @instance.cleanup(verbose) end end if $0 == __FILE__ module Test def self.test1(finalizer_block) puts "Test1" s="str"*1024*1024 ObjectSpace.define_finalizer(s, finalizer_block) puts s.object_id t1 = Thread.new { Lock.lock(s) { 4.times { puts "Thread1" sleep(0.25) } } } t2 = Thread.new { puts "Thread2 started" Lock.lock(s) { 4.times { puts "Thread2" sleep(0.25) } } } t1.join t2.join end def self.test2(finalizer_block) puts "Test2" s="noo"*1024*1024 puts s.object_id ObjectSpace.define_finalizer(s, finalizer_block) Lock.lock(s) end def self.test3(finalizer_block) puts "Test3" 10.times { s="noo"*1024*1024 puts s.object_id ObjectSpace.define_finalizer(s, finalizer_block) Lock.lock(s) } end end Test.test1(lambda {|id| puts "Finalized: #{id}"}) GC.start puts "GC invoked" Test.test2(lambda {|id| puts "Finalized: #{id}"}) GC.start puts "GC invoked" Test.test3(lambda {|id| puts "Finalized: #{id}"}) GC.start puts "GC invoked" end =begin /mnt/vg0.home/ysantoso/tmp/ruby-postgres/tests $ ruby /tmp/lock.rb Test1 -604990708 Thread1 Thread2 started Thread1 Thread1 Thread1 Thread2 Thread2 Thread2 Thread2 GC invoked Test2 -610787788 GC invoked Test3 -610788148 -610953348 -615730956 -615809476 -615887996 Finalized: -615730956 Finalized: -610953348 -615902566 -615981086 -615697446 Finalized: -615809476 Finalized: -615887996 Finalized: -615902566 -614121002 -614199522 Finalized: -614121002 Cleanup id: -615809476,-615730956,-610953348,-615902566,-615887996. Size: 7: -614199522,-615697446,-615981086,-610787788,-614121002,-610788148,-604990708 Finalized: -614199522 Cleanup id: -614121002. Size: 6: -614199522,-615697446,-615981086,-610787788,-610788148,-604990708 Finalized: -615697446 Cleanup id: -614199522. Size: 5: -615697446,-615981086,-610787788,-610788148,-604990708 Finalized: -615981086 Cleanup id: -615697446. Size: 4: -615981086,-610787788,-610788148,-604990708 Finalized: -610787788 Cleanup id: -615981086. Size: 3: -610787788,-610788148,-604990708 Finalized: -610788148 Cleanup id: -610787788. Size: 2: -610788148,-604990708 GC invoked Finalized: -604990708 =end
(originally from http://microjet.ath.cx/WebWiki/2006.08.07_LockLibraryForRuby.html)
2006-07-30
Producing divx-device compatible files with xvid
Found this little gem:
http://forum.doom9.org/showthread.php?p=855604
Safe params:
Params that helps:
http://forums.afterdawn.com/thread_view.cfm/165637
(originally from http://microjet.ath.cx/WebWiki/2006.07.30_ConstrainingXVIDToPlayInDIVXDevices.html)
http://forum.doom9.org/showthread.php?p=855604
Safe params:
- Home theatre profile (max bitrate 4854 instead of 8000 for AS@L5 )
- No custom matrix (use MPEG or H263)
- NO QP, AQ, Trellis, GMC NO PACKED bitstream
Params that helps:
- MAX consecutive B-VOPS set to 1.00
- CBR audio
- No openDML
- Recommended max resolution 640*xx
http://forums.afterdawn.com/thread_view.cfm/165637
(originally from http://microjet.ath.cx/WebWiki/2006.07.30_ConstrainingXVIDToPlayInDIVXDevices.html)
2006-05-20
Christmas in May, Muvo FM TX, PATA to USB adapter
I went nuts. I decided to have an early Christmas.
I have been wanting a portable MP3 player for a long time to replace my broken Rio (first-gen MP3 player). Nothing caught my eyes in terms of price-feature ratio until I happened upon an ad for Creative MuVo FM TX 1GB for $57.50. That's a great buy as other stores were still selling it for about $100+. I bought it.
I also bought a USB-PATA adapter. It is this small adapter you attached to the back of an IDE drive. On the other side of the plug is a wire with a USB connector.
I wanted to move the DVDRW drive out from secondary IDE which was shared with another hard drive. The hard drive contained my /usr volume. Burning a DVD would cause frequent jerkiness in interactive session. The cheap solution to that is to either buy a PATA to SATA adapter or PATA to USB adapter.
I tried the PATA to SATA adapter first primarily because my motherboard had two SATA ports and they had never been used. I bought the adapter from EBay. It arrived a month later from China. Opening the package, I found that adapter wrapped in a non-anti-static plastic bag. Uh oh.
I detached all my disks and use an old 3GB hard drive for experimentation with this PATA-SATA adapter. Based on my reading the hard drive must be set to master. When I turned on the computer, the light on the adapter shone green. Since this was going to be my first SATA device, I tried booting with Knoppix 4.2 which boasted a large number of drivers. It was not recognised. The SATA controller, SiS964, was recognised, but not the attached device. Not being familiar with SATA handling in Linux, and not having a real SATA device to verify against, I chose not to pursue this path any further, at least until I have a real SATA device.
So, I bought a non-brand-name USB-PATA adapter. Supposedly it presents the hard disk as a USB Mass Storage device, which Linux has been supporting since last century.
There was no problem. I burned a DVD without having The adapter worked and it could pump data from and to the DVDRW at 20MBps without me noticing any jerkiness in interactive session.
I'm enjoying this early Christmas.
(originally from http://microjet.ath.cx/WebWiki/2006.05.20_ChristmasInMay.html)
I have been wanting a portable MP3 player for a long time to replace my broken Rio (first-gen MP3 player). Nothing caught my eyes in terms of price-feature ratio until I happened upon an ad for Creative MuVo FM TX 1GB for $57.50. That's a great buy as other stores were still selling it for about $100+. I bought it.
I also bought a USB-PATA adapter. It is this small adapter you attached to the back of an IDE drive. On the other side of the plug is a wire with a USB connector.
I wanted to move the DVDRW drive out from secondary IDE which was shared with another hard drive. The hard drive contained my /usr volume. Burning a DVD would cause frequent jerkiness in interactive session. The cheap solution to that is to either buy a PATA to SATA adapter or PATA to USB adapter.
I tried the PATA to SATA adapter first primarily because my motherboard had two SATA ports and they had never been used. I bought the adapter from EBay. It arrived a month later from China. Opening the package, I found that adapter wrapped in a non-anti-static plastic bag. Uh oh.
I detached all my disks and use an old 3GB hard drive for experimentation with this PATA-SATA adapter. Based on my reading the hard drive must be set to master. When I turned on the computer, the light on the adapter shone green. Since this was going to be my first SATA device, I tried booting with Knoppix 4.2 which boasted a large number of drivers. It was not recognised. The SATA controller, SiS964, was recognised, but not the attached device. Not being familiar with SATA handling in Linux, and not having a real SATA device to verify against, I chose not to pursue this path any further, at least until I have a real SATA device.
So, I bought a non-brand-name USB-PATA adapter. Supposedly it presents the hard disk as a USB Mass Storage device, which Linux has been supporting since last century.
There was no problem. I burned a DVD without having The adapter worked and it could pump data from and to the DVDRW at 20MBps without me noticing any jerkiness in interactive session.
I'm enjoying this early Christmas.
(originally from http://microjet.ath.cx/WebWiki/2006.05.20_ChristmasInMay.html)
2006-05-03
Linksys WRT54GX2
After I returned WRE54G, I bought WRT54GX2.I don't know if it really increases my range, but I noticed that all the deadspots in the house that I know of have disappeared. In the past, interactive session was not very pleasant as the connection frequently became laggy. It is not occurring that frequently anymore; there are still some occurrences, typically in the morning (06:00 or so).
The bad thing about WRT54GX2 was the wired ethernet port could not reliably auto-negotiate 100baseT protocol. Googling for it lead me to http://www.dslreports.com/forum/remark,14714795. The firmware on my device was 1.01.06. So, I downloaded the new firmware (1.01.14 as of now) and tried to upgrade the device.
But I was unable to update the firmware. None of the suggestions in that URL did the trick. Experimenting for one hour with various settings didn't yield anything either.
Just when I was close to giving up, I had this crazy notion of trying to do the upgrade using Internet Explorer. Behold! It worked.
I find it hard to believe that a device manufactured in 2005 by a company using GPL code would still require a particular browser. But believe I had to.
Anyway, don't bother to backup your configuration by Administration -> Config Management -> Backup. It's worthless as the configuration file is version-specific. Pen and paper would work better.
(originally from http://microjet.ath.cx/WebWiki/2006.05.03_Linksys_WRT54GX2.html)
2006-04-15
Ruby's hash implementation
Authentication
Login with:
It is not meant for high-volume usage.
/tmp $ ruby testspeed.rb Rehearsal ---------------------------------------------------------------------------------------------- reading with while, name=1million 1.240000 0.030000 1.270000 ( 1.272282) reading with readline, name=1million 0.980000 0.210000 1.190000 ( 1.215839) reading with while and inserting into hash, name=1million 5.330000 0.200000 5.530000 ( 5.715192) reading with while and inserting into array, name=1million 5.640000 0.210000 5.850000 ( 5.975710) ------------------------------------------------------------------------------------ total: 13.840000sec user system total real reading with while, name=1million 1.750000 0.020000 1.770000 ( 1.785138) reading with readline, name=1million 1.440000 0.010000 1.450000 ( 1.454656) reading with while and inserting into hash, name=1million 4.050000 0.020000 4.070000 ( 4.102691) reading with while and inserting into array, name=1million 2.290000 0.020000 2.310000 ( 2.320377)
def create_file(name, size) File.open("/tmp/largefile_#{name}", "w") {|f| size.times {|i|f.puts "foo#{i}"; } } end # do these once # create_file("1million", 1*1000*1000) # create_file("5million", 5*1000*1000) def read_with_while(name) File.open("/tmp/largefile_#{name}") {|fh| while line = fh.gets line.chomp! end } end def read_with_readlines(name) File.readlines("/tmp/largefile_#{name}") end def read_into_hash(name) hash={}; array=[]; File.open("/tmp/largefile_#{name}"){ |fh| while line = fh.gets; line.chomp!; hash[line] = 1; end} end def read_into_array(name) array=[]; File.open("/tmp/largefile_#{name}"){ |fh| while line = fh.gets; line.chomp!; array << line end} end require 'benchmark' Benchmark.bmbm {|r| ["1million"].each{|name| GC.start r.report("reading with while, name=#{name}") {read_with_while(name)} GC.start r.report("reading with readline, name=#{name}") {read_with_readlines(name)} GC.start r.report("reading with while and inserting into hash, name=#{name}") { read_into_hash(name)} GC.start r.report("reading with while and inserting into array, name=#{name}") { read_into_array(name)} } }
(originally from http://microjet.ath.cx/WebWiki/2006.04.15_Ruby%27sHash.html)
2006-03-26
Linksys WRE54G version 2.0 (repeater/extender)
Authentication
Login with:
Toms Hardware reviewed this device sometimes ago. They were not really impressed by the product and the setup was painful. They were reviewing version 1.0.
True enough, things have changed in version 2.0. The device now includes a RJ-45 port for wired setup. This makes the setup easier somehow.
Setup was not difficult, except for the following:
- The SSID must be the same as the router's SSID. This is an annoyance since that means I can't choose which device to connect to for comparison purposes.
- The router has been setup to use 64bit WEP. But the expander's WEP implementation seems to not be compatible as it couldn't connect to the router. Fortunately, its WPA Personal implementation is compatible with the router's.
With the expander activated, I now can go beyond the previous range. However, interactive session sucked real bad. It seems the device is buffering data, which is bad for interactive session.
I returned it after several days because I work with interactive session most of the time.
(originally from http://microjet.ath.cx/WebWiki/2006.03.25_Linksys_WRE54G_v2.html)
2006-02-15
Hexifier and XML entities escaper
Happy belated Valentine's day.
I have a present for Emacser out there: a hexifier and XML Entities
escapers.
The function
constructing a docstring with a lot of backslashes.
(originally from http://microjet.ath.cx/WebWiki/2006.02.15_Hexifier_and_XML_Entities_Escaper.html)
I have a present for Emacser out there: a hexifier and XML Entities
escapers.
ys-hex306.el
(require 'hexl) (defun ys/escape (string to-escape-char &optional escape-char) ;; Escapes all instances of to-escape-char in the given string by prefixing each instance with escape-char (default to backslash ``\``). ;; ;; (let ((str "/ \\/ \\\\/ \\n")) ;; (insert (concat "\n" str "\n" (ys/escape str ?/)))) ;; / \/ \\/ \n ;; \/ \\\/ \\\\\/ \\n " Escapes all instances of to-escape-char in the given string by prefixing each instance with escape-char (default to backslash ``\\``). (let ((str \"/ \\\\/ \\\\\\\\/ \\\\n\")) (insert (concat \"\\n\" str \"\\n\" (ys/escape str ?/)))) / \\/ \\\\/ \\n \\/ \\\\\\/ \\\\\\\\\\/ \\\\n " (if (eq escape-char nil) (setq escape-char ?\\)) (with-temp-buffer (insert string) (goto-char (point-min)) (save-match-data (let ((regexp (concat (regexp-quote (char-to-string to-escape-char)) "\\|" (regexp-quote (char-to-string escape-char))))) (while (re-search-forward regexp (point-max) t) (replace-match (concat (char-to-string escape-char) (match-string 0)) t t)))) (buffer-substring (point-min) (point-max)))) (defun ys/unescape (string &optional escape-char) ;; Converts ``\/ \n \\\/`` to ``/ n \/``. Basically converts ``\x`` to ``x`` where x is any single character and \ is the escape-char." ;; (let ((str "/ \\/ \\\\/ \\n")) ;; (insert (concat "\n" str ;; "\n" (ys/escape str ?/) ;; "\n" (ys/unescape (ys/escape str ?/))))) ;; / \/ \\/ \n ;; \/ \\\/ \\\\\/ \\n ;; / \/ \\/ \n " Converts ``\\/ \\n \\\\\\/`` to ``/ n \\/``. Basically converts ``\\x`` to ``x`` where x is any single character and \\ is the escape-char.\" (let ((str \"/ \\\\/ \\\\\\\\/ \\\\n\")) (insert (concat \"\\n\" str \"\\n\" (ys/escape str ?/) \"\\n\" (ys/unescape (ys/escape str ?/))))) / \\/ \\\\/ \\n \\/ \\\\\\/ \\\\\\\\\\/ \\\\n / \\/ \\\\/ \\n " (if (eq escape-char nil) (setq escape-char ?\\)) (with-temp-buffer (insert string) (goto-char (point-min)) (save-match-data (let ((regexp (concat (regexp-quote (char-to-string escape-char)) "\\(.\\)"))) (while (re-search-forward regexp (point-max) t) (replace-match (match-string 1) t t)))) (buffer-substring (point-min) (point-max)))) (defun ys/hexstring-to-charstring (hexstring) ;(insert (concat "\n" (ys/hexstring-to-charstring "039900000000000000000000000046"))) ; ™������������F "(insert (concat \"\\n\" (ys/hexstring-to-charstring \"039900000000000000000000000046\"))) \231������������F " (let ((expected-length (/ (length hexstring) 2))) (save-excursion (let ((result (with-temp-buffer (insert hexstring) (goto-char (point-min)) (save-match-data (while (and (not (eobp)) (looking-at "\\([0-9A-Fa-f]\\)\\([0-9A-Fa-f]\\)")) (replace-match (char-to-string (hexl-htoi (string-to-char (match-string 1)) (string-to-char (match-string 2)))) t t))) (buffer-substring (point-min) (point-max))))) ;; check if the conversion is valid (let ((result-length (length result))) (if (/= result-length expected-length) (error "Expected a charstring of length %d, but instead the length is %d" expected-length result-length))) result)))) (defun ys/charstring-to-hexstring (charstring) ;(insert (concat "\n" (ys/charstring-to-hexstring " ™������������F"))) ;039900000000000000000000000046 "(insert (concat \"\\n\" (ys/charstring-to-hexstring \" \231������������F\"))) 039900000000000000000000000046 " (mapconcat #'(lambda (char) (format "%02x" char)) charstring "")) (defun ys/hex306string-to-char306string (hex306string) ;(insert (concat "\n" (ys/hex306string-to-char306string "303132332f636f6e7665727420746869732f2062757420/don't convert this/2066696e616c6c79202f636f6e7665727420746869732f"))) ;0123\/convert this\/ but /don't convert this/ finally \/convert this\/ "(insert (concat \"\\n\" (ys/hex306string-to-char306string \"303132332f636f6e7665727420746869732f2062757420/don't convert this/2066696e616c6c79202f636f6e7665727420746869732f\"))) 0123\\/convert this\\/ but /don't convert this/ finally \\/convert this\\/ " (save-excursion (with-temp-buffer (insert hex306string) (goto-char (point-min)) (save-match-data (while (and (not (eobp)) ;; needed because the regexp below won't fail due to * (re-search-forward "\\([0-9A-Fa-f]*\\)" (point-max) t)) ;(message (match-string 0)) (let* ((hexstring (match-string 0)) (charstring (ys/hexstring-to-charstring (match-string 0))) (escapedcharstring (ys/escape charstring ?/))) ;(message (format "hexstring:%s\ncharstring:%s\nescaped:%s" hexstring charstring escapedcharstring)) (replace-match escapedcharstring t t)) ;(message (format "reminder:%s" (buffer-substring (point) (point-max)))) (if (looking-at "/.*?/") (goto-char (match-end 0)) (if (< (point) (point-max)) (error "Invalid hex306 string. Encountered a non-hexchar char but also not surrounded with //"))))) (buffer-substring (point-min) (point-max))))) (defun ys/char306string-to-hex306string (char306string) ;(insert (concat "\n" (ys/char306string-to-hex306string "\n0123\\/convert this\\/ but /don't convert this/ finally \\/convert this\\/"))) ;0a303132332f636f6e7665727420746869732f2062757420/don't convert this/2066696e616c6c79202f636f6e7665727420746869732f "(insert (concat \"\\n\" (ys/char306string-to-hex306string \"\\n0123\\\\/convert this\\\\/ but /don't convert this/ finally \\\\/convert this\\\\/\"))) 0a303132332f636f6e7665727420746869732f2062757420/don't convert this/2066696e616c6c79202f636f6e7665727420746869732f " (save-excursion (with-temp-buffer (insert char306string) (goto-char (point-min)) (save-match-data (let ((charstring-begin (point-min))) (while (not (eobp)) (cond ((looking-at "\\\\.") ; skip over escaped char. we must consume escaped char first so when we scan for a don't-convert-region, we won't get a false positive ) ((looking-at "/\\(.*?\\)/") ; leave the don't-convert-this-region alone, but convert previous characters to hex (let ((charstring (buffer-substring charstring-begin (match-beginning 0)))) (re-search-backward (regexp-quote charstring)) (replace-match (ys/charstring-to-hexstring (ys/unescape charstring))) ;(message (format "remaining:%s" (buffer-substring (point) (point-max)))) ; the match-data info would have changed (because the length of charstring changed) , so we re-run the search (if (looking-at "/\\(.*?\\)/") (setq charstring-begin (match-end 0)) (error "Lost pointer to the don't-convert-region")))) ((looking-at ".\\|\n") ; skip over other char ) (t (error "Shouldn't have happened"))) ;(message (format "going to %d/%d, remaining:%s" (match-end 0) (point-max) (buffer-substring (match-end 0) (point-max)))) (goto-char (match-end 0))) (let ((charstring (buffer-substring charstring-begin (match-end 0)))) (re-search-backward (regexp-quote charstring)) (replace-match (ys/charstring-to-hexstring (ys/unescape charstring)))))) ;(message (format "End-state:%s" (buffer-substring (point-min) (point-max)))) (buffer-substring (point-min) (point-max))))) ;; ys/charstring-to-hexstring-region and ys/hexstring-to-charstring-region converts between these two forms: ;; 0123\/convert this\/ but /don't convert this/ finally \/convert this\/ ;; 303132335c2f636f6e7665727420746869735c2f20627574202f646f6e277420636f6e7665727420746869732f2066696e616c6c79205c2f636f6e7665727420746869735c2f (defun ys/hexstring-to-charstring-region (region-begin region-end) "Converts ``039900000000000000000000000046`` to `` ™������������F``" (interactive "r") (save-excursion (let ((charstring (ys/hexstring-to-charstring (buffer-substring region-begin region-end)))) (delete-region region-begin region-end) (goto-char region-begin) (insert charstring)))) (defun ys/charstring-to-hexstring-region (region-begin region-end) "Converts `` ™������������F`` to ``039900000000000000000000000046``" (interactive "r") (save-excursion (let* ((charstring (buffer-substring region-begin region-end)) (hexstring (ys/charstring-to-hexstring charstring))) (delete-region region-begin region-end) (goto-char region-begin) (insert hexstring)))) ;; ys/char306string-to-hex306string-region and ys/hex306string-to-char306string-region converts between these two forms: ;; 0123\/convert this\/ but /don't convert this/ finally \/convert this\/ ;; 303132332f636f6e7665727420746869732f2062757420/don't convert this/2066696e616c6c79202f636f6e7665727420746869732f (defun ys/char306string-to-hex306string-region (region-begin region-end) "Converts ``0123\/convert this\/ but /don't convert this/ finally \/convert this\/`` to ``303132332f636f6e7665727420746869732f2062757420/don't convert this/2066696e616c6c79202f636f6e7665727420746869732f``" (interactive "r") (save-excursion (let* ((char306string (buffer-substring region-begin region-end)) (hex306string (ys/char306string-to-hex306string char306string))) (delete-region region-begin region-end) (goto-char region-begin) (insert hex306string)))) (defun ys/hex306string-to-char306string-region (region-begin region-end) "Converts ``303132332f636f6e7665727420746869732f2062757420/don't convert this/2066696e616c6c79202f636f6e7665727420746869732f`` to ``0123\/convert this\/ but /don't convert this/ finally \/convert this\/``" (interactive "r") (save-excursion (let ((char306string (ys/hex306string-to-char306string (buffer-substring region-begin region-end)))) (delete-region region-begin region-end) (goto-char region-begin) (insert char306string)))) (provide 'ys-hex306)
ys-xml-escape.el
(require 'cl) (defun ys/xml-escape-entities-and-non-printable-ascii (string) "Escapes XML entities and any non-ascii characters and also ascii characters that are not ``printable`` ( 32 < x < 126 )." (mapconcat #'(lambda (char) (case char (?< "<") (?> ">") (?& "&") (?' "'") (?\" """) (t (if (and (<= 32 char) (<= char 126)) (char-to-string char) (format "&#%02d;" char))))) string "")) ;(insert (concat "\n" (ys/xml-escape-entities-and-non-printable-ascii "<goo&ten, \"'night\", he said>�"))) ;<goo&ten, "'night", he said>� (defun ys/xml-unescape-entities (string) "Unescapes XML entities" (save-excursion (with-temp-buffer (insert string) (goto-char (point-min)) (while (not (eobp)) (cond ((looking-at "&#\\([[:digit:]]+?\\);") (let ((char (string-to-number (match-string 1) 16))) (replace-match (char-to-string char)) (goto-char (match-end 0)))) ((looking-at "&\\(.+?\\);") (let ((entity (match-string 1))) (replace-match (case (intern entity) ('lt "<") ('gt ">") ('amp "&") ('apos "'") ('quot "\"") (t (error "Unknown XML entity: %s" entity)))))) (t (goto-char (+ 1 (point)))))) (buffer-substring (point-min) (point-max))))) ;(insert (concat "\n" (ys/xml-unescape-entities "<goo&ten, "'night", he said>�"))) ;<goo&ten, "'night", he said>� (eql (intern "lt") 'lt) (defun ys/xml-escape-entities-and-non-printable-ascii-region (region-begin region-end) "Escapes XML entities and any non-ascii characters and also ascii characters that are not ``printable``." (interactive "r") (save-excursion (let ((escaped (ys/xml-escape-entities-and-non-printable-ascii (buffer-substring region-begin region-end)))) (delete-region region-begin region-end) (goto-char region-begin) (insert escaped)))) (defun ys/xml-unescape-entities-region (region-begin region-end) "Unescapes XML entities" (interactive "r") (save-excursion (let ((unescaped (ys/xml-unescape-entities (buffer-substring region-begin region-end)))) (delete-region region-begin region-end) (goto-char region-begin) (insert unescaped)))) (provide 'ys-xml-escape)
What I put into my .emacs for these two utils:
(require 'ys-hex306) (global-set-key "\C-chc" 'ys/hex306string-to-char306string-region) (global-set-key "\C-chh" 'ys/char306string-to-hex306string-region) (require 'ys-xml-escape) (global-set-key "\C-cxe" 'ys/xml-escape-entities-and-non-printable-ascii-region) (global-set-key "\C-cxu" 'ys/xml-unescape-entities-region) (defun ys/quote-for-docstring (region-begin region-end) (interactive "r") (save-excursion (let* ((original-mode-name mode-name) (commented (buffer-substring-no-properties region-begin region-end)) (uncommented (with-temp-buffer (funcall (symbol-function (intern (format "%s-mode" (downcase original-mode-name))))) (insert commented) (uncomment-region (point-min) (point-max)) (buffer-substring-no-properties (point-min) (point-max)))) (quoted (with-output-to-string (print uncommented)))) (insert quoted))))
The function
ys/quote-for-docstring
= is especially handy forconstructing a docstring with a lot of backslashes.
(originally from http://microjet.ath.cx/WebWiki/2006.02.15_Hexifier_and_XML_Entities_Escaper.html)
2006-01-12
RSS and VSZ are not an accurate measure of memory usage
Yesterday I had the honour to chat with Bosko Milekic, a FreeBSD developer, regarding his concern of the outrageous VSS and RSS (virtual memory size and resident size, respectively) of a ruby app. I remembered that I had some code showing that VSS and RSS do not accurately measure an app's memory usage.
Since this was Bosko Milekic I was talking with, he was able to use the code to further investigate the problem matter. The best part is, he wrote a write-up (Ruby on Rails and Application Memory Consumption Patterns) of what he has learnt including what his further investigation revealed. As a result, now I know more than yesterday.
Isn't collaboration simply wonderful?
Updated 2007-04-20: updated linked URI.
(originally from http://microjet.ath.cx/WebWiki/2006.01.12_RSS_and_VSZ_AreNotAccurateMeasureOfMemoryUse.html)
Since this was Bosko Milekic I was talking with, he was able to use the code to further investigate the problem matter. The best part is, he wrote a write-up (Ruby on Rails and Application Memory Consumption Patterns) of what he has learnt including what his further investigation revealed. As a result, now I know more than yesterday.
Isn't collaboration simply wonderful?
Updated 2007-04-20: updated linked URI.
(originally from http://microjet.ath.cx/WebWiki/2006.01.12_RSS_and_VSZ_AreNotAccurateMeasureOfMemoryUse.html)
Subscribe to:
Posts (Atom)