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.

Tuesday, October 20, 2015

archlinux pacman - an introduction

Packages in arch repositories are constantly upgraded. When a package is upgraded, its old version is removed from the repository. There are no major arch releases. Each package is upgraded as new versions become available from upstream sources. The repository is always coherent. (The packages in the repository always have compatible versions.) This type of repository is called a rolling repository. Before packages are upgraded in the core, extra and community repositories, they are tested in the testing repository, to ensure that the distribution is stable.

pacman saves to disk a list of packages available in the repository. This list is not automatically updated (refreshed). (The list is a.k.a. repository databases and the update of the list is a.k.a. synchronizing those databases.) The list can be refreshed using pacman -Sy. pacman -Syy refreshes the list even if it appears to be up to date. I don't know the effect of pacman -Syy when the pacman list is newer than that of the mirror, for example as a result of falling back to a different not yet updated mirror.

When the list is outdated it is possible that packages to be installed with pacman -S package are not available.

When pacman installs one package with pacman -S package it takes care that all its correct version dependencies are installed but it does not verify that dependencies of other packages are not broken by such updates. If the list has been updated but packages not, then this command could make the system unusable. That is why the list should only be updated together with all packages in the system with pacman -Syu and you should never run pacman -Sy or pacman -Sy package.