2012-04-13

Emacs Lisp vs Perl: Validate Local File Links

This page shows 2 scripts to validate html local file links (i.e. check file existence of local links). One written in perl, one in elisp.

The 2 script's algorithms are not artificially made to be the same, but follow the natural style/idiom for each lang. They do the same job for my need.

lots code. See here instead: http://xahlee.org/emacs/elisp_vs_perl_validate_links.html

Ruby Creator Matz on How Emacs Changed My Life

Perm URL with updates: http://xahlee.org/emacs/Matz_Ruby_how_emacs_changed_my_life.html

Matz Ruby how emacs changed my life
Yukihiro Matsumoto (aka Matz), creator of Ruby, giving a talk: “How Emacs changed my life”. Slide at www.slideshare.net. (photo by Corey Goldberg, used with permission.)

This is at LibrePlanet 2012 conference at the University of Massachusetts, Boston, around 2012-03-26. Also, Matz is given FSF's “Award for the Advancement of Free Software” for 2011.

Matz and rms 2012-03
Matz and RMS. 1893×2430 Source www.fsf.org

emacs lisp: Getting User Input with Completion and Input History

Perm URL with updates: http://xahlee.org/emacs/elisp_idioms.html

Some commands provide input history, so that user can use key to enter previous input. (e.g. shell-commandAlt+!】) Also, some commands provide name completion (e.g. “dired” 【Ctrl+x d】)

The most useful are: read-string, read-file-name, read-regexp. Examples:

(defun test-fun (arg)
  "Prompt user to enter a string, with input history support."
  (interactive (list (read-string "Your name is:")) )
  (message "String is 「%s」." arg) )

(defun test-fun (arg)
  "Prompt user to enter a file path, with file name completion and input history support."
  (interactive (list (read-file-name "Open directory:")) )
  (message "Path is 「%s」." arg) )

(defun test-fun (arg)
  "Prompt user to enter a elisp regex and input history support."
  (interactive (list (read-regexp "Type a regex:")) )
  (message "Regex is 「%s」." arg) )

The most general command is read-from-minibuffer. All the above are implemented on top of it.

(info "(elisp) Minibuffers")

2012-04-12

The Bug-Reporting Attitude

Windows XP send report prompt Windows XP error report files
In 2005, Microsoft Windows XP will pop-up a dialogue box when a program crashed, and will ask the user about whether she wants to report to Microsoft, with detail about data collection policy. More screenshots at Microsoft XP Bug Report Panels
Adium crash screenshot
Bug-reporting solicitation panel from Adium, a multi-protocol chat client (on OS X). (screenshot captured 2006-06)

for ten more, see http://xahlee.org/UnixResource_dir/writ/bug_report_attitude.html

Google Search Now Requires Javascript?

Perm URL with updates: http://xahlee.org/w/Google_search_requires_javascript.html

Google search no longer works if you have Javascript off.

Google search w javascript off Error 404 2012-04-12-2
Google Search result when Javascript is turned off, 2012-04-12. (on Windows 7, Firefox 11.0)

Because i do Google search with javascript off everyday, so this probably means today (2012-04-12) is the day they made this change.

2012-04-13 Update: it does works now without javascript. Strange. Few hours ago, i tested with both Firefox and Opera and Chrome on Windows, with and without Javascript.

2012-04-11

idiomatic find/replace script in python

Bjoern Paschen wrote a improved, idiomatic, version of python multi find/replace code we did before.

# -*- coding: utf-8 -*-
# Python

# find & replace strings in a dir
# by Bjoern Paschen, 2012-04-08

import os, re

# if this this is not empty, then only these files will be processed
my_files = []

input_dir = "c:/Users/h3/web/xahlee_org/"

min_level = 4 # files and dirs inside input_dir are level 1
max_level = 4 # inclusive

find_replace_list = [
    (u'<iframe style="width:100%;border:none" src="http://xahlee.org/footer.html"></iframe>', 
     u'<iframe style="width:100%;border:none" src="http://xahlee.org/footer.html"></iframe>',
     ),
    (u'testing',
     u'done',
     ),
    (u'utf8-test',
     u'ƿƺ'
     ),
    ]

def replace_string_in_file(f):
    content = u''
    temp = u''
    writeout = False
    
    with open(os.path.normpath(f), 'rb') as data:
        content = unicode(data.read(), 'utf8')

    for rep in find_replace_list:
        temp = re.sub(rep[0], rep[1], content, re.M)
        if temp != content:
            content = temp
            writeout = True

    if writeout:
        with open(os.path.normpath(f), 'w+b') as data:
            data.write(content.encode('utf8'))

def calc_level(input_dir, actual_dir):
    def depth(d):
        # strings are sequences, so we can use filter()
        # calculates the length of the sequence containing only teh seperators
        return len(filter(lambda x: x == os.sep, os.path.abspath(d)))
    
    # relative depth, starts at 1, not at 0
    return depth(actual_dir) - depth(input_dir) + 1

def process_dir(root, dirs, files):
    # calculate depth level
    level = calc_level(input_dir, root)

    if min_level <= level <= max_level:
        [replace_string_in_file(os.path.join(root, f)) for f in files if (os.path.splitext(f)[1] == '.html' and os.path.isfile(os.path.join(root, f)))]

# main routine
if __name__ == "__main__":
    if my_files:
        [replace_string_in_file(x) for x in my_files]
    else:
        [process_dir(root, dirs, files) for root, dirs, files in os.walk(input_dir)]

for original discussion, see: Fuck Python: String Methods, Functions, Slashes and Backslashes.

for basics on how to write find/replace script in python, see:

Google's New Ad: “Google+: There's more to explore”

Google+: There's more to explore

It's all women! What do we men do?

Human Operated Twitter Spam: Beg a Question to Make Real Interaction

Perm URL with updates: http://xahlee.org/w/twitter_spam_ask_nice_questions.html

got a twitter spam.

@xah_lee Can you tell me why the symmetry groups are labelled p1, p4m, p31m, p3m1 etc? I just can not work it out Thank you in advance

from “@delahunty91”

i actually answered quickly. Then, went to check his tweets, several «I made $350 today ‹cryptic link›».

check out this article! I made $350 today! ow.ly/5LwT9?voru

check out this article! I made $370 today! goo.gl/7Zu1F?gijor

check out this article! I made $350 today! ow.ly/5Lypm?syhi

Clearly spam. Went to one of the site with Firefox javascript off and got a spam/malware site warning.

this is a human operated scam. The guy's question came from reading this page Wallpaper groups: The 17 Wallpaper Groups.

He may not be a professional spammer. Might signed up with one of the spam programs to make a few bucks. See: Where Do Spammers Came From? (A Xah Story of Human Animals).

Why's he asking me question? Of course, ask in a nice way, most people are eager to answer. Then, he's got real interaction with real people. Then, spam detectors get confused.

Twitter Humor: Chrome vs Emacs, Version Numbering Pressure

Got this tweet today:

bamanzi: «Emacs压力好大 RT @riku: 我擦, Chrome 的版本都已经到 20 了。»

Translation:

riku: «OMG! Chrome's version reached 20.»

bamanzi: «pressure is on Emacs»

2012-04-10

ErgoEmacs Keybinding is now in MELPA

ErgoEmacs Keybinding is now in the MELPA repository. (thanks to Steve Purcell for adding it)

I've also added instructions for check out using svn. For how to use melpa/svn to install, see: ErgoEmacs Keybinding

2012-04-09

Large Scale Software Development with Elisp

Scheme Lisp is Coming to Emacs!

(meeting - Tue Apr 10 19:00 - Rocky Bernstein: Large Scale Software Development with Elisp)

He lives in relative obscurity yet his software is used daily by millions. Rocky Bernstein, former IBM Researcher, Chaitin co-author and 30 year developer walks us through a mosaic of development techniques focusing on personal software scalability.

The long time Free Software developer is best known for his decade of debugger development using Emacs Grand Unified Debugger as a front-end for his other works:

  • Ruby Debugger (ruby-debug)
  • Python Debugger (pydb)
  • Perl Debugger
  • POSIX Shell Debuggers for bash, Korn Shell, zsh and GNU Make

Additionally, Rocky is the author of libcdio: the GNU CD I/O and ControlLibrary. Allowing multimedia assessing of CD-images (includingISO-9660) in an OS and device-independent way, it is used in FreeBSD, NetBSD and nearly every Linux distribution.

Location:
Meetup HQ, 9th Floor (maps.google.com)
632 Broadway

Official announcement: www.lispnyc.org

Slashdot news: Guile Scheme Emacs-Lisp Compatibility Matures @ Source news.slashdot.org

2012-04-08

Fuck Python: Strings Methods, Functions, Slashes and Backslashes

Perm URL with updates: http://xahlee.org/comp/fuck_python.html

fuck Python.

just fucking spend 2 hours and still going.

here's the short story.

so recently i switched to a Windows version of python. Now, Windows version takes path using win backslash, instead of cygwin slash. This fucking broke my find/replace scripts that takes a dir level as input. Because i was counting slashes.

Ok no problem. My sloppiness. After all, my implementation wasn't portable. So, let's fix it. After a while, discovered there's the os.sep. Ok, replace "/" to os.sep, done. Then, bang, all hell went lose. Because, the backslash is used as escape in string, so any regex that manipulate path got fucked majorly. So, now you need to find a quoting mechanism. Then, fuck python doc incomprehensible scattered comp-sci-r-us BNF shit. Then, fuck python for “os.path” and “os” modules then string object and string functions inconsistent ball. And FUCK Guido who wants to fuck change python for his idiotic OOP concept of “elegance” so that some of these are deprecated.

So after several exploration of “repr()”, “format()”, “‹str›.count()”, “os.path.normpath()”, “re.split()”, “len(re.search().group())” etc, after a long time, let's use “re.escape()”. 2 hours has passed. Also, discovered that “os.path.walk” is now deprecated, and one is supposed to use the sparkling “os.walk”. In the process of refreshing my python, the “os.path.walk” semantics is really one fucked up fuck. Meanwhile, the “os.walk” went into incomprehensible OOP object and iterators fuck.

now, it's close to 3 hours. This fix is supposed to be done in 10 min. I'd have done it in elisp in just 10 minutes if not for my waywardness.

This is Before

def process_file(dummy, current_dir, file_list):
   current_dir_level = len(re.split("/", current_dir)) - len(re.split("/", input_dir))
   cur_file_level = current_dir_level+1
   if min_level <= cur_file_level <= max_level:
      for a_file in file_list:
         if re.search(r"\.html$", a_file, re.U) and os.path.isfile(current_dir + "/" + a_file):
            replace_string_in_file(current_dir + "/" + a_file)

This is After

def process_file(dummy, current_dir, file_list):
   current_dir = os.path.normpath(current_dir)
   cur_dir_level = re.sub( "^" + re.escape(input_dir), "", current_dir).count( os.sep)
   cur_file_level = cur_dir_level + 1
   if min_level <= cur_file_level <= max_level:
      for a_file in file_list:
         if re.search(r"\.html$", a_file, re.U) and os.path.isfile(current_dir + re.escape(os.sep) + a_file):
            replace_string_in_file(current_dir + os.sep + a_file)
            # print "%d %s" % (cur_file_level, (current_dir + os.sep + a_file))

Complete File

# -*- coding: utf-8 -*-
# Python

# find & replace strings in a dir

import os, sys, shutil, re

# if this this is not empty, then only these files will be processed
my_files  = []

input_dir = "c:/Users/h3/web/xahlee_org/lojban/hrefgram2/"
input_dir = "/cygdrive/c/Users/h3/web/zz"
input_dir = "c:/Users/h3/web/xahlee_org/"

min_level = 2; # files and dirs inside input_dir are level 1.
max_level = 2; # inclusive

print_no_change = False

find_replace_list = [

(
u"""<iframe style="width:100%;border:none" src="http://xahlee.org/footer.html"></iframe>""", 
u"""<iframe style="width:100%;border:none" src="http://xahlee.org/footer.html"></iframe>""", 
),

]

def replace_string_in_file(file_path):
   "Replaces all findStr by repStr in file file_path"
   temp_fname = file_path + "~lc~"
   backup_fname = file_path + "~bk~"

   # print "reading:", file_path
   input_file = open(file_path, "rb")
   file_content = unicode(input_file.read(), "utf-8")
   input_file.close()

   num_replaced = 0
   for a_pair in find_replace_list:
      num_replaced += file_content.count(a_pair[0])
      output_text = file_content.replace(a_pair[0], a_pair[1])
      file_content = output_text

   if num_replaced > 0:
      print "◆ ", num_replaced, " ", file_path.replace("\\", "/")
      shutil.copy2(file_path, backup_fname)
      output_file = open(file_path, "r+b")
      output_file.read() # we do this way instead of “os.rename” to preserve file creation date
      output_file.seek(0)
      output_file.write(output_text.encode("utf-8"))
      output_file.truncate()
      output_file.close()
   else:
      if print_no_change == True:
         print "no change:", file_path

#      os.remove(file_path)
#      os.rename(temp_fname, file_path)

def process_file(dummy, current_dir, file_list):
   current_dir = os.path.normpath(current_dir)
   cur_dir_level = re.sub( "^" + re.escape(input_dir), "", current_dir).count( os.sep)
   cur_file_level = cur_dir_level + 1
   if min_level <= cur_file_level <= max_level:
      for a_file in file_list:
         if re.search(r"\.html$", a_file, re.U) and os.path.isfile(current_dir + re.escape(os.sep) + a_file):
            replace_string_in_file(current_dir + os.sep + a_file)
            # print "%d %s" % (cur_file_level, (current_dir + os.sep + a_file))

input_dir = os.path.normpath(input_dir)

if (len(my_files) != 0):
   for my_file in my_files: replace_string_in_file(os.path.normpath(my_file) )
else:
   os.path.walk(input_dir, process_file, "dummy")

print "Done."