Sunday, December 1, 2024

Java Generic Wildcards

this text is best read in a fixed width terminal 


C++ compiles code for each required parameterized type
Java compiles only one instance of the parameterized type, using Object as the type

because generic types in java erase information on type
  and still the type must be verified by the compiler
  there are cases when the code should compile but it doesn't
  the solution was to relax type checks at compile time


the '?' wildcard can only appear on the left hand side of an assignment
    and only when the variable or parameter is defined
  it imposes constraints on the right hand side of the assignment

a variable of <? extends MyClass> type can only refer objects of types that inherit MyClass
    this sets an upper bound
  you can't write to it because
    the compiler can't ensure that what you write is a derivate of its current content
    and therefore it cannot enforce homogeneity (?!)
  you can read <? super MyClass>'s from it
  this variable is a producer

a variable of <? super MyClass> type can only refer objects of types that are inherited by MyClass
    this sets a lower bound
  you can write <? extends MyClass>'s to it
  you can only read in Object's from it because the compiler only knows that it is a derivate of Object
  this variable is a consumer

variables of <?> type can refer objects of any type
  you can not write to it because
    the compiler can't ensure that what you write is a derivate of its current content
    and therefore it cannot enforce homogeneity (?!)
  you can only read in Object's from it because the compiler only knows that it is a derivate of Object

these constraints are verified at compile time


class Wild {
  public static void main(String args[]) {

    /*
    all errors are compile time

    as long as the type of right hand side in the variable declaration
        is compatible with the variable type,
      its type does not influence future compatibilities of the variable
      because its type in the assigned variable is not known to the compiler at the compile time

    of course, anything can be done with explicit type casts
    */


    MyGen<? extends MyClass> ge = new MyGen<MyClass>(new MyClass(1, 2));
      // ge = MyGen, extends
    // ge.e cannot be written but it can be read
    //   ge.e cannot be written because it may hold any class equal to or below MyClass
    //   and they need to ensure ge.e's homogeneity (?!)
    // ge.e is a producer
    // ge.e = new MyBase(3);
      // ByBase cannot be converted to CAP#1
      //   CAP#1 extends MyClass from capture of ? extends MyClass
    // ge.e = new MyClass(4, 5);
      // MyClass cannot be converted to CAP#1
      //   CAP#1 extends MyClass from capture of ? extends MyClass
    // ge.e = new MyDeriv(6, 7, 8);
      // MyDeriv cannot be converted to CAP#1
      //   CAP#1 extends MyClass from capture of ? extends MyClass
    MyBase geb = ge.e;
    MyClass gec = ge.e;
    // MyDeriv ged = ge.e;
      // incompatible types, ge.e can have any type equal or below MyClass
    System.out.println("ge.e = " + ge.e + "\t\tge.e.i = " + ge.e.i + "\tge.e.j = " + ge.e.j);


    MyGen<? super MyClass> gs = new MyGen<MyClass>(new MyClass(1, 2));
      // gs = MyGen, super
    // gs.e can be written but it can be read only into an Object
    //   gs.e can be read only into an Object because it may hold any class equal or above MyClass
    // gs.e is a consumer
    // gs.e = new MyBase(3);
      // incompatible types, gs.e can have any type equal to or above MyClass
    gs.e = new MyClass(4, 5);
    gs.e = new MyDeriv(6, 7, 8);
    // MyBase gsb = gs.e;
      // CAP#1 cannot be converted to MyBase
      //   CAP#1 extends Object super: MyClass from capture of ? super MyClass
    // MyClass gsc = gs.e;
      // CAP#1 cannot be converted to MyClass
      //   CAP#1 extends Object super: MyClass from capture of ? super MyClass
    // MyDeriv gsd = gs.e;
      // CAP#1 cannot be converted to MyDeriv
      //   CAP#1 extends Object super: MyClass from capture of ? super MyClass
    Object gso = gs.e;
    // the type of gs.e is known at run time
    System.out.println("gs.e class is: " + gs.e.getClass().getName());
      // gs.e class is: MyDeriv
    // but not at compile time, when gs.e is only known to be of type Object
    // System.out.println("gs.e = " + gs.e + "\t\tgs.e.i = " + gs.e.i + "\tgs.e.j = " + gs.e.j +
    //                      "\tgs.e.k = " + gs.e.k);
      // cannot find symbols gs.e.i, gs.e.j and gs.e.k


    MyGen<?> g = new MyGen<MyClass>(new MyClass(1, 2));
    // g = MyGen
    // we know nothing about the type of g
    //   so the only allowed operation is to read it into an Object
    // g.e = new MyBase(3);
      // MyBase cannot be converted to CAP#1
      //   CAP#1 extends Object from capture of ?
    // g.e = new MyClass(4, 5);
      // MyClass cannot be converted to CAP#1
      //   CAP#1 extends Object from capture of ?
    // g.e = new MyDeriv(6, 7, 8);
      // MyDeriv cannot be converted to CAP#1
      //   CAP#1 extends Object from capture of ?
    // MyBase gb = g.e;
      // CAP#1 cannot be converted to MyBase
      //   CAP#1 extends Object from capture of ?
    // MyClass gc = g.e;
      // CAP#1 cannot be converted to MyClass
      //   CAP#1 extends Object from capture of ?
    // MyDeriv gd = g.e;
      // CAP#1 cannot be converted to MyDeriv
      //   CAP#1 extends Object from capture of ?
    Object go = g.e;
    // System.out.println("g.e = " + g.e + "\t\tg.e.i = " + g.e.i + "\tg.e.j = " + g.e.j);
      // cannot find symbols g.e.i and g.e.j
  }
}


// my generic class: it stores an object of a generic type
class MyGen<T> {
  T e;
  // element
  MyGen(T e) {
    this.e = e;
  }
}

class MyBase {
  int i;
  MyBase(int i) {
    this.i = i;
  }
}

class MyClass extends MyBase {
  int j;
  MyClass(int i, int j) {
    super(i);
    this.j = j;
  }
}

class MyDeriv extends MyClass {
  int k;
  MyDeriv(int i, int j, int k) {
    super(i, j);
    this.k = k;
  }
}

Saturday, February 24, 2024

Tcl socket example explained


# the source of the example code: https://www.tcl.tk/man/tcl8.5/tutorial/Tcl42.html

# paste it in a fixed width character terminal for better reading 


proc serverOpen {channel addr port} {
    puts "serverOpen: channel: $channel - from Address: $addr  Port: $port"
    puts "The default state for blocking is: [fconfigure $channel -blocking]"
    puts "The default buffer size is: [fconfigure $channel -buffersize ]"

    # Set this channel to be non-blocking.
    fconfigure $channel -blocking 0
    set bl [fconfigure $channel -blocking]
    puts "After fconfigure the state for blocking is: $bl"
 
    # Change the buffer size to be smaller
    fconfigure $channel -buffersize 12
    puts "After fconfigure buffer size is: [fconfigure $channel -buffersize ]\n"

    # When input is available, read it.
    # the script is executed at the (global level)
    #   in the interpreter in which the fileevent command was invoked
    #   the file event handler is deleted if it ever returns an error (man fileevent)
    # the event is triggered and the script is run only when the first data comes in
    # 'Server' is just a name, such that readLine can be used in other contexts, too
    fileevent $channel readable "readLine Server $channel"
}

proc readLine {who channel} {
    global didRead
    global blocked

    puts "readLine: There is input for $who on $channel"

    # on the first iteration of the while loop below there is no 'eol',
    #   the channel is in non-blocking mode, so the read fails and nothing is read, see 'man 3tcl gets'
    # on the second iteration of the 'while' loop below, this does succeed
    set len [gets $channel line]
    # the channel is non-blocking, but it may be "blocked", see 'man fblocked'
    # 1 if blocked, 0 if not blocked
    set blocked [fblocked $channel]
    puts "Characters Read: $len  Fblocked: $blocked"

    # -1 is not enough data, see 'man 3tcl gets'
    if {$len < 0} {
        if {$blocked} {
            # not enough to read
            puts "Input is blocked"
        } else {
            # the 'eof' case
            puts "The socket was closed - closing my end"
            # this closes the new channel created by 'socket -server' for the new connection
            #   the server itself is closed in the last line of the script
            close $channel;
        }
    } else {
        puts "Read $len characters:  $line"
        puts $channel "This is a return"
        flush $channel;
    }
    incr didRead;
    # puts "readLine: didRead = $didRead"
}

set server [socket -server serverOpen 33000]

# after 120 update;    # This kicks MS-Windows machines for this application

# no call for serverOpen here
# puts {before the first vwait}
# vwait didRead
# puts {after the first vwait}

# puts {before socket client}

# this sends a connection request to the server listening on port 33000
#   the server creates a (new channel) on a new port especially for this connection
#   and then it makes the client connect to this new channel
# also now the server triggers an event that will run serverOpen when processed
set sock [socket 127.0.0.1 33000]

# puts {after socket client}

# if the first vwait is commented, then serverOpen is called here
# puts {before the second vwait}
# vwait didRead
# puts {after the second vwait}

set bl [fconfigure $sock -blocking]
set bu [fconfigure $sock -buffersize]
puts "Original setting for sock: Sock blocking: $bl buffersize: $bu"

fconfigure $sock -blocking No
fconfigure $sock -buffersize 8;

set bl [fconfigure $sock -blocking]
set bu [fconfigure $sock -buffersize]
puts "Modified setting for sock: Sock blocking: $bl buffersize: $bu\n"

# Send a line to the server -- NOTE flush
set didRead 0
# this makes fileevent to trigger an event that calls lineRead when processed
puts -nonewline $sock "A Test Line"
flush $sock;

# if the first two vwait's are commented, then both serverOpen and readLine are called here
# puts {before the third vwait}
# vwait didRead
# puts {after the third vwait}

# this sends "NewLine\n" immediately after "Read 18 characters:  A Test Line"
# readLine is run only on 'wait didRead', which reads the fileevent event
#   so this iterates two times
while {$didRead < 2} {
    puts "while: didRead = $didRead"
    # Wait for didRead to be set
    vwait didRead
    if {$blocked} {
        puts $sock "Newline"
        flush $sock
        puts "SEND NEWLINE"
    }
}

# this reads the readLine "This is a return" message
set len [gets $sock line]
puts "Return line: $len -- $line"
# this closes the client socket
close $sock
# puts {before last vwait}
# this processes the last fileevent event that calls readLine for the last time
#   now readLine closes the new channel because it sees that it is closed on the client side
vwait didRead
# this closes the server, which is still listening on the 30000 port
catch {close $server}
# so 'socket' creates and manages the connection
#   similarly to a pipe or a fifo (see ~/linux/misc/bash/fifo.txt)

# 'man 3tcl gets' (three cases)
# the three non-blocking cases are:
#   successfully read
#   not enough data, returns -1 and it's blocked
#   'eof', returns -1 and it's not blocked


Friday, February 23, 2024

Tcl fileevent events explained

# paste it in a fixed width character terminal for better reading 

# do '$ touch test.txt' before you run it with '$ tclsh scriptname.tcl'

set f [open test.txt]
puts "f = $f"

set k 0
after 0 {puts "before: k = $k"}
# k is in the global space, the script is run in the global space
fileevent $f readable {incr k; puts "k = $k"}
after 500
# events are processed in the order in which they have been created
#   'vwait k' stops processing events when it finds the first k modification event
# one new fileevent event is created when fileevent is first called
#   and it is PERMANENTLY placed FIRST IN LINE in the event queue
#   this event probably creates a hook for vwait and update such that
#     two more fileevent events are created next time when
#       either the event loop is entered and there is no such a fileevent event first in the queue
#       or the queue is empty when the event loop is exited
#       these two fileevent events are placed normally last in line in the event queue
#     such a scenario is also suggested by
#       "To generate events in case of an empty queue
#       Tcl_DoOneEvent will first ask all registered event sources to setup themselves"
#       at https://tcl.sourceforge.net/c-api/notifier.html
#   error bug this is crazy and that's why it's not mentioned in man fileevent
for {set j 1} {$j<=6} {incr j} {
  puts {new for cycle}
  after 500
  after 0 {puts "before: k = $k"}
  after 500
  # update
  vwait k
  }

# update

close $f
puts "f = $f"


Sunday, January 21, 2024

Tcl 'oo::define self' explained



oo::class create c {

method a {} { puts "c a" }

self method b {} { puts "c b" }}




c create o




# this raises unknown method "a", because 'a' is a member of 'c' as a class, not as an object

# c a




# this works, because 'b' is a member of 'c' as an object, due to self, see man oo_define (^ *self)

c b




# this works, because 'a' is a member of the class 'c' that created o

o a




# this raises unknown method "b", because b is a member of c as an object, not as a class

# o b

Saturday, December 16, 2023

firefox places.sqlite tags select

copy it into a fixed width character terminal for better view 


firefox places.sqlite contains all bookmarks 


sqlite3 places.sqlite "select sql from sqlite_master 

    where tbl_name = 'moz_bookmarks' and type = 'table';" 



each bookmark has a base entry in moz_bookmarks 

    where it has the title and the fk that links to moz_places.id 

    and it has an entry with the same fk for each tag 


moz_places has an entry with id = moz_bookmarks.fk that holds the URL 

    and it has a title that usually is the same with that in moz_bookmarks 


moz_bookmarks.title is more about the page, moz_places.title is more about the site 


there is no id = 0 record in moz_bookmarks or moz_places 

    the id = 0 record is referred to signal the root of the reference chain 


in moz_bookmarks: 


a bookmark has: 

  one entry that contains its title and it's followed by 

  entries with the same fk 

      that link through their parent to one tag of that bookmark each 

      all those entries with the same fk have a null title, since this query returns no results: 

          select id, title from moz_bookmarks m where 

              (select parent from moz_bookmarks where id = m.parent) = 4 and 

                  -- this selects entries that refer tags 

                  --     because entries referred by their parent have parent = 4 

              title not null;

  type is 1 for bookmarks and their links to tags 

  position does not appear to be important, maybe it refers to the position in the displayed list 

  keyword_id is null 

  folder_type is null 

  fields after title are not relevant for the bookmarks -- tags relationship 


tags have: 

    title is the name of the tag 

    parent = 4, which is the id of the Tags folder 

    type = 2 

    fk = null 


a folder has: 

    title is the name of the folder 

    parent is the id of the parent folder 

        the root folder is the Bookmarks Menu with id = 2 

    type = 2 

    fk = null 

to select all tags of a bookmark: 

parent = 4 eliminates the folder referred in the bookmark entry that contains the title 

if there is more than one bookmark with that exact title then 

    fk = (select ...) only fits the first result 

but if you replace that '=' with 'in', then all tags of all those bookmarks are listed in one column 

  tags used more than once by different bookmarks will appear only once in the list 

sqlite> select title from moz_bookmarks where id in (select parent from moz_bookmarks where fk = (select fk from moz_bookmarks where title = 'David Icke – The Answer – full length interview. Direct no-email version – starts at 6.46 and please share with everyone you can to bypass censorship – David Icke')) and parent = 4; 

or: 

parent = 4 eliminates the folder referred in the bookmark entry that contains the title 

verified 

if there is more than one bookmark with that exact title then 

  all tags of all those bookmarks are listed in one column and 

  tags used more than once by different bookmarks will appear more than once in the list 

sqlite> select m1.title from moz_bookmarks as m1, moz_bookmarks as m2, moz_bookmarks as m3 where m3.title = 'David Icke – The Answer – full length interview. Direct no-email version – starts at 6.46 and please share with everyone you can to bypass censorship – David Icke' and m2.fk = m3.fk and m1.id = m2.parent and m1.parent = 4; 

the first version is ten times faster than the second version 

time sqlite3 places.sqlite "select title from moz_bookmarks where id in (select parent from moz_bookmarks where fk = (select fk from moz_bookmarks where title = 'David Icke – The Answer – full length interview. Direct no-email version – starts at 6.46 and please share with everyone you can to bypass censorship – David Icke')) and parent = 4;"

NWO

David Icke

politics

news

video

continue

1:00:00 continue


real 0m0.012s

user 0m0.011s

sys 0m0.001s

time sqlite3 places.sqlite "select m1.title from moz_bookmarks as m1, moz_bookmarks as m2, moz_bookmarks as m3 where m3.title = 'David Icke – The Answer – full length interview. Direct no-email version – starts at 6.46 and please share with everyone you can to bypass censorship – David Icke' and m2.fk = m3.fk and m1.id = m2.parent and m1.parent = 4;"

NWO

David Icke

politics

news

video

continue

1:00:00 continue


real 0m0.183s

user 0m0.077s

sys 0m0.105s


to select all bookmarks that have a specific tag: 

  title is not null only for the bookmark entry that contains the title. 

    we know this because this returns no lines: 

      the subquery selects the id's of all tags 

      the outer query selects all references to all tags that have not null titles 

      sqlite> select title from moz_bookmarks where 

                  parent in (select id from moz_bookmarks where parent = 4) and title is not null; 

sqlite> select id, title from moz_bookmarks where fk in (select fk from moz_bookmarks where parent = (select id from moz_bookmarks where parent = 4 and title = '1984')) and title is not null; 

sqlite> select m1.id, m1.title from moz_bookmarks m1, moz_bookmarks m2, moz_bookmarks m3 where m3.parent = 4 and m3.title = 'David Icke' and m3.id = m2.parent and m2.fk = m1.fk and m1.title not null;

select m1.id, m1.title, count(*) from moz_bookmarks m1, moz_bookmarks m2, moz_bookmarks m3 where m3.parent = 4 and m3.title = 'David Icke' and m3.id = m2.parent and m2.fk = m1.fk and m1.title not null; 

1776|What David Icke Said in 1991, Dr Michio Kaku Confirms in 2008 - YouTube|443

time sqlite3 places.sqlite "select id, title from moz_bookmarks where fk in (select fk from moz_bookmarks where parent = (select id from moz_bookmarks where parent = 4 and title = 'David Icke')) and title is not null;" 

real 0m0.011s

user 0m0.004s

sys 0m0.008s

time sqlite3 places.sqlite "select m1.id, m1.title from moz_bookmarks m1, moz_bookmarks m2, moz_bookmarks m3 where m3.parent = 4 and m3.title = 'David Icke' and m3.id = m2.parent and m2.fk = m1.fk and m1.title not null;" 

real 0m0.012s

user 0m0.008s

sys 0m0.004s


to update a tag in all bookmarks 

verified 

you can use Firefox > Library window 

  find oldtag in Search Bookmarks 

  select all found bookmarks 

  edit oldtag into newtag in Tags 

  press Enter 

or 

verified 

sqlite: 

  you need to update the parent of all entries that refer that bookmark: 

    the new tag must be already defined 

    there should be no entries that have both the old tag and the new tag at the same time 

      both these conditions can be easily configured in Firefox > Library window 

sqlite3> update moz_bookmarks set parent = (select id from moz_bookmarks where title = 'new tag' and parent = 4) where id in (select id from moz_bookmarks where parent = (select id from moz_bookmarks where title = 'old tag' and parent = 4)); 


Monday, November 7, 2022

Python Metaclasses

Copy it to a fixed width font terminal for a good reading. 

This is what I gathered and guessed about Python metaclasses from the following pages: 

https://mail.python.org/pipermail/python-3000/2006-December/005030.html

https://www.geeksforgeeks.org/python-metaclasses/

https://realpython.com/python-metaclasses/

https://www.geeksforgeeks.org/metaprogramming-metaclasses-python/

Python is a work in progress and so is my understanding of this programming language. 


dynamically create a new class: 

'name' = type('name', 'bases', 'dict') 

  differs from class 'name''bases' 

    by the fact that the name, bases and attributes of the newly created class are decided at runtime 

  'name' - the name of the new class, memorized in 'name'. __name__ 

  'bases' - a tuple of the base classes from which the class inherits, memorized in 'name'.__bases__ 

  'dict' - a namespace dictionary containing definitions for the class body, memorized in 'name'.__dict__


metaclasses configure classes when they are created 

    this is different from inheritance 

  all classes inherit the class 'object' or its subclasses 

  all classes are configured by the metaclass 'type' or a subclass of it 

    (maybe it has to be a direct subclass) 

  'myclass'.__bases__, 'myclass'.__base__ - show directly inherited classes 

  'myclass'.__class__, type('myclass') - show the metaclass that configured 'myclass' 

   >>> type.__bases__ 

   (<class 'object'>,)

   >>> type(type) 

   <class 'type'>

   >>> int.__bases__ 

   (<class 'object'>,)

   >>> type(int) 

   <class 'type'>

   >>> type(7) 

   <class 'int'>


objects have a __call__() method  

  which calls the __new__() and __init__() methods

  __new__() creates the new object and returns it

    'cls' in __new__() is the new object

  __init__() initializes the newly created object passed as a parameter

    'self' in __init__() is the new object

  these methods can be overridden to configure the newly created object

  help(type.__call__), help(object.__call__)

  help(type) has a __call__ method, but help(object) does not


metaclasses are a “solution in search of a problem” 


examples of metaclass usage 

$ cat meta.py 


# MyMeta  is an instance of type   and a subclass of type 

# MyClass is an instance of MyMeta and a subclass of object 


def prints(): 

  print('   type(MyMeta) =', type(MyMeta), '\n   type(MyClass) =', type(MyClass), '\n') 


class MyClass: 

  pass 


# dynamic creation (definition) of MyClass, parameters can be decided at runtime 

MyClass = type('MyClass', (object,), {}) 


class MyMeta(type): 

  def __new__(cls, cls_name, bases, attrib): 

    print('>> MyMeta.__new__()') 

    return super(MyMeta, cls).__new__(cls, cls_name, bases, attrib) 

#          super() arguments are not required 


print('\nMyMeta.__bases__ =', MyMeta.__bases__, '\nMyMeta.__class__ =', MyMeta.__class__, '\n') 


class MyClass(metaclass = MyMeta): 

  pass 


prints() 


MyClass = MyMeta('MyClass', (object, ), {}) 


prints() 


# MyClass = type('MyClass', (object, metaclass = MyMeta,), {}) 

#                             invalid syntax   ^ 

#   so type() cannot create a class of a MyMeta type 

# prints() 


# MyClass = MyMeta() 

#   new() missing 3 required positional arguments: 'cls_name', 'bases', and 'attrib' 

# prints() 


def new(cls, cls_name, bases, attrib): 

  print('>> new()') 

  return super(MyMeta, cls).__new__(cls, cls_name, bases, attrib) 

#        super() arguments are required 


MyMeta = type('MyMeta', (type,), {'__new__' : new}) 


class MyClass(metaclass = MyMeta): 

  pass 


prints() 


$ python meta.py 


MyMeta.__bases__ = (<class 'type'>,) 

MyMeta.__class__ = <class 'type'> 


>> MyMeta.__new__()

   type(MyMeta) = <class 'type'> 

   type(MyClass) = <class '__main__.MyMeta'> 


>> MyMeta.__new__()

   type(MyMeta) = <class 'type'> 

   type(MyClass) = <class '__main__.MyMeta'> 


>> new()

   type(MyMeta) = <class 'type'> 

   type(MyClass) = <class '__main__.MyMeta'> 


$ cat meta.py 

class Meta(type):

  def __new__(cls, name, bases, dict):

    x = super().__new__(cls, name, bases, dict)

    x.attr = 100

    return x

class Foo(metaclass=Meta):

  pass

print('Foo.attr =', Foo.attr)

$ python meta.py 

Foo.attr = 100


$ cat meta.py 

class Meta(type):

  def __init__(cls, name, bases, dict):

    cls.attr = 100

class X(metaclass=Meta):

  pass

print('X.attr =', X.attr)

$ python meta.py 

X.attr = 100


Friday, December 8, 2017

zoom pdf for printing

This may help to install pdfedit on Ubuntu 14.04 Trusty https://askubuntu.com/questions/538966/how-can-i-install-pdfedit-on-ubuntu-14-04 and this on Ubuntu 16.04 Xenial https://gist.github.com/bmaupin/a23161b50f27179e6e5b064d6066b034.

Start pdfedit.

If the pdf file is uneditable then Tools > Delinearize it.

Use Page > Set page transformation matrix to find the transformation you want. You need to check Page transformation matrix description > Select which transformations to use. This only changes one page.

The programming language used is the qt script language, ECMAScript, almost identical to JavaScript. The API functions are listed in Help > Help.

Save this https://sourceforge.net/p/pdfedit/mailman/pdfedit-support/thread/20080707173451.GG4157%40dhcp35.suse.cz/ inspired script in ./zoom.qs:
f = loadPdf("myfile.pdf");
pg = f.getFirstPage();
pg.setTransformMatrix([1.4,0,0,1.4,-130,-180]);
while (f.hasNextPage(pg)) {
pg = f.getNextPage(pg);
pg.setTransformMatrix([1.4,0,0,1.4,-130,-180]); }
f.save();
f.unloadPdf();


Modify the arguments of setTransformMatrix into your desired ones found using Page > Set page transformation matrix. Parameters 1 and 4 should not be 0, that would make the text invisible.

Copy your pdf file to be processed in ./myfile.pdf.

Issue:
$ pdfedit -s zoom.qs

You can print with:
$ lp -o media-size=a4,fit-to-page -P 1 myfile.pdf

It would be nice to calculate the transformation matrix using the printer acceptable minimal margins, but I don't know how to get the current margins of the document.