blog.humaneguitarist.org

discoveries in digital audio, music notation, and information encoding

Archive for the ‘scripts’ Category

HammerFlix 3: Village of the DOMed

leave a comment

Update, November 27, 2011: If you're looking for a live list of Hammer Films streaming on Netflix you can see it here.

To read more about the HammerFlicks project, click here.

Grrr. Obsession is a good ally for creativity, but it's still annoying.

I woke up today and decided to have a decent breakfast and do some very light work on HammerFlix – a small project to use the Netflix API to discover which Hammer Films movies are available on Netflix's Watch Instantly.

Basically, I just added some buttons/Javascript that will allow one to filter out the non-matches, show only Hammer films that HammerFlix thinks are on Netflix, or show only the ones that are apparently available for streaming.

Sure, there's still some work to be done to improve the reliability of the results as I mentioned yesterday, but I'm not too worried about it for now.

If you're wondering why the search for "The House Across the Lake" from 1954 shows "Them!" as a streaming match it's because "The House Across the Lake" isn't on Netflix and "Them!" is the first match the API returns. In this case, both movies happen to share 1954 as the release year. Currently, if HammerFlix sees that the first API returned result matches the release year, it reports the movie as available on Netflix. So, I need to make it a little smarter than that, but not this weekend.

Anyway, you can see the latest results here.

Dorks can view the source files in this folder. The best thing in there is the MIT license generated by the Spiteful Open Source License Generator.

:P

No more coding this weekend … time for a long walk sans electronics.

Update: OK, so I lied. I couldn't resist. I just added a score for how reliable the match is.

Go here to see the HammerFlix results from about 10pm EST tonight. on September 26, 2011.

There's now a "match score" under each thing HammerFlix claims is on Netflix. This is done by comparing the title from the Wikipedia filmography against the "short" and "regular" titles from the Netflix API XML result (i.e. two scores). I used the PHP similar_text() function to get the score for each and then averaged them for the "match score".

There's occasionally a PHP "undefined offset" error for a couple of films. That's no big deal and I'll fix it later by just making sure I test for some stuff before printing to screen. But it seems to work pretty well. The "The House Across the Lake"  vs. "Them!" mismatch only gets a 20% rating, so that tells me it might not actually be the same movie.

And as a reward, I'm watching "To the Devil, a Daughter" now …

--------------

Related Content:

Written by nitin

September 25th, 2011 at 11:00 am

Posted in scripts

Tagged with ,

in the can: another HammerFlix update

leave a comment

Update, November 27, 2011: If you're looking for a live list of Hammer Films streaming on Netflix you can see it here.

To read more about the HammerFlicks project, click here.

Last night while streaming Star Trek: TOS on NetFlix or Qwikster or whatever, I finished up this Python file around 3am that makes this semicolon delimited file of Hammer Films and their production year if you throw it at a local copy of this Wikipedia/Hammer Films filmography page.

Had enough of "this"? Well, there's more where that, I mean this, came from.

So, I woke up at about 9am and worked on this PHP version on HammerFlix.

And finally, about 12 hours after going to bed, I've got this list of Hammer Films on Netflix and whether they stream or not.  I should mention that I tested with both the "UK" and "US" versions of the titles if both were present in Wikipedia, so there are a few duplicate items in the list.

Eventually, I'll make the PHP file clickable so anyone can run it and get a current report. But as of right now, I've used up all my Netflix API allowance for the day.

Now, as I mentioned in this post I was only testing to see if a movie title and its production year matched the Wikipedia filmography data in order to determine if the movie was available on Netflix and whether it streamed.

Testing that way isn't perfect. For example, the Wikipedia page lists 2011 as the year for "The Woman in Black" but IMDB and Netflix say it's 2012. So that movie isn't reported correctly by HammerFlix.

I'm noticing a few other things, too, but I'll work on it later. Seriously, I need to get on with my weekend …

Maybe I'll watch a Hammer film tonight!

--------------

Related Content:

Written by nitin

September 24th, 2011 at 3:24 pm

Posted in scripts

Tagged with , ,

a HammerFlix update

leave a comment

Update, November 27, 2011: If you're looking for a live list of Hammer Films streaming on Netflix you can see it here.

To read more about the HammerFlicks project, click here.

Principal photography has begun on HammerFlix – a small project to use the Netflix API to discover which Hammer Films movies are available on Netflix's Watch Instantly.

So far, I've got a PHP file that has two functions.

The first one, named Igor, takes two arguments: a movie title and its release year. Igor then sends this to the Netflix API and retrieves only the first result for searching against that given title. Then Igor sends the XML version of the API results to another function, Master.

Master, aka Dr. Frankenstein, then evaluates the result. If the Netflix release date for the movie returned by the API matches the year value sent to Igor, then Master will display the link to that movie on Netflix. If the movie is available via Watch Instantly, Master will also display the link to the streaming movie. If the year doesn't match, Master reports that no results were found.

Testing against just the first match and using release year as the only qualifier might not be the best, but I think it might work pretty decently. If not, I'll have Igor retrieve more results and then Master can evaluate more results and use more test criteria before assuming the movie isn't on Netflix.

The next step is to get all the Hammer titles from the Hammer Filmography on Wikipedia and send each title and release year to HammerFlix. There might be some open/linked data opportunities later down the road with dbPedia, but that's not important for now.

You can see this very basic test of HammerFlix 0.01 here.

Anyway, here's the code for the development version of 0.01.

<?php

//Igor does the hard work of hitting up the Netflix API for movies matching $title.
//The code is mainly from: http://developer.netflix.com/page/resources/sample_php
function Igor($title, $year) {

    include ('../authentication/myAPI.php'); //this includes my Netflix API key and shared secret as $apiKey and $sharedSecret.

    //build stuff to send to API.
    $arguments = Array(
        'term' => $title,
        'expand' => 'formats',
        'max_results' => '1',
        'output' => 'xml'
    );

    $path = "http://api.netflix.com/catalog/titles";
    $oauth = new OAuthSimple();
    $signed = $oauth->sign(Array('path' => $path,
                'parameters' => $arguments,
                'signatures' => Array('consumer_key' => $apiKey,
                    'shared_secret' => $sharedSecret
                    )));

    //hit up API via CURL.
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $signed['signed_url']);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    //curl_setopt($curl, CURLOPT_SETTIMEOUT, 2); //Nitin commented this out on 2/5/2011 to prevent a PHP error message.
    $buffer = curl_exec($curl);
    if (curl_errno($curl)) {
        die("An error occurred:" . curl_error());
    }

    Master($buffer, $title, $year); //send XML results to Master().
}

//Master (Dr. Frankenstein) parses/returns the Netflix XML results retrieved by Igor.
function Master($buffer, $title, $year) {

    $xml = simplexml_load_string($buffer);
    $movieInfo = ($xml->catalog_title);
    $short = "short";
    $movieTitle_short = ($movieInfo->title->attributes()->$short);
    $regular = "regular";
    $movieTitle_regular = ($movieInfo->title->attributes()->$regular);
    $movieLink = ($movieInfo->id);
    $movieId = str_replace("http://api.netflix.com/catalog/titles/movies/", "", $movieLink);
    $movieYear = ($movieInfo->release_year);

    //test if movie is available for Watch Instantly/streaming.
    $streaming = $xml->xpath('//availability/category/@label');
    foreach ($streaming as $instantTest) {
        if ($instantTest == 'instant') {
            $streams = '';
        }
    }

    //output findings.
    echo "<li><p>Testing:<em> " . $title . " </em>from the year:<em> " . $year . "</em><br />";
    if ($movieYear == $year) {
        echo "<a href='http://movies.netflix.com/WiMovie/" . $movieId . "'>" . $movieTitle_short . "</a>";

        //IT'S ALIVE!!!
        //aka: show user the Watch Instantly link if it exists.
        if (isset($streams)) {
            echo "<br /><strong><a href='http://movies.netflix.com/WiPlayer?movieid=" . $movieId . "'>Watch Instantly</a></strong>";
        }
    } else {
        echo "No match.";
    }
    echo "</p></li>";
}

//Create life!
//aka: start doing things.
include ('../authentication/OAuthSimple.php');

echo "<ul>"; //put results in unordered list; send arguments to Igor().
Igor("The Brides of Dracula", "1960");
Igor("The Brides of Dracula", "1961");
Igor("Dracula Has Risen from the Grave", "1968");
Igor("Vampire Circus", "1972");
echo "</ul>";
?>
--------------

Related Content:

Written by nitin

September 10th, 2011 at 1:16 pm

Posted in scripts

Tagged with ,

SAVS: a Simple Audio/Video Synchronizer

leave a comment

About a year ago I did some text to audio synchronization tests with HTML5 and Flash.

The tests were partially successful, but I think what really mattered is that I set four goals that I felt needed to be met before the word "synchronization" could truly be used:

  1. The user should be able to click on a line of text and hear the related media.
  2. The user should be able to "scrub" ahead on the media player and the text should follow.
  3. The page should report where in the document the user is.
  4. The page should automatically keep the media/text synchronized without user intervention.

Basically, I've seen a few people make it so that you could watch media while the transcript text was also on the page (scrollable as opposed to overlaid closed captions) and the user could click on a line and have the movie/audio skip ahead to that moment (goal #1). That's great and all, but that's not synchronization.

;)

Synchronization is a two way street and I've been working this past week during what I'm calling "4 days of madness" to come up with a really simple solution to real synchronization. I did run across this really cool RadioLab page that achieves goal #1, but as much as I like it I want more features with less flash (as in "flash and dash" not Adobe Flash!) and less code. No mistake: it looks fantastic and I also appreciate that they've got the text timed to clusters of a couple of words rather than by line but the only thing I've seen that gets it all "right" per my perspective was a subscription resource by Alexander St. Press. It achieved all the goals above using a Flash player and the rest appeared to by done with Javascript and some jQuery smooth scrolling. It was also timed by clusters of words and not just by line or by paragraph. Of course, conceptually it's the same whether one marks up their text – in the temporal sense – by line or by word, but it's a little more work to do it by word of course. Unfortunately, I've seen people do the opposite: they use a static unit of time like 60 seconds and only mark up the text every minute. That's taking the easy way out and also misses the point entirely since it makes the text subservient to an arbitrary unit of time. Would it be acceptable if closed captioning and subtitles on your foreign films only showed up in large chunks every minute? I would hope not, and in the case of the former it would violate the the spirit if not the letter of the "law" in regard to accessibility. If done right, you can use the same timed text file to both serve up captions in addition to showing the full text on the page. It's more time and cost efficient to re-purpose the same data for two needs.

Anyway, let's get back to Alexander St. Press. I loved what I saw when my boss (I work at NC Live) showed it to me. I got really excited and said something like, "This is what I've been waiting to see!". In addition to the great and true syncing, they also had a feature that would let the user make and share clips, much the way you can on sites like NBC's Meet The Press. The Alexander St. Press site also allowed you to annotate that clip, which is a great feature for teachers and librarians, etc. Alexander St. Press also has this with their classical music streaming subscription service, which in the spirit of full disclosure I pay for. They ALSO had a cool timeline where you could see what I call "hot spots" – places where others had made clips. The idea, I guess, is that spots on the timeline with more clusters would indicate a particular point of interest. Nothing new, because you see that all the time with streaming sports like the US Open's site where you can go back and watch previous moments in matches and then "go live" at any time. But the difference is, of course, that Alexander St. Press was using user-contributed clips.

So long story short (or just not as long), in a few weeks I need to present these ideas to some people and talk about how we think these features could be useful for our users. And the more I struggled with how to talk about these concepts without a prototype the more I thought I would a) sound like I'm crazy and b) like I'm full of hot air.

I decided that it was time to go back to some earlier tests of mine from early April and just build a prototype so we could just show it to people and not have to talk theoretical speak. I think it's generally easier to explain and convince people of the utility of software by showing it rather than telling it. Actions > words, right?

Well, early tests are working and only required me to add one line of Actionscript to our current Flash player and about only 50 lines of Javascript code are needed to keep the text and media synced. The tests I did were for some PBS videos we purchased along with closed captioning files.

I was so excited that it was finally working that I went home during those "4 days of madness" to write an HTML5 version which is virtually identical to the Flash version. It's got basic clip making features as well as a very basic tool inspired by this video score tutorial to make timed text files provided you have the audio and full text in hand. Eventually, I'll comment the code up and improve some options and post a download to the source for the HTML5 version. At work, we'll probably eventually offer the code as it's tweaked to meet our aesthetic needs, etc. As you'll see in the demo video below, I have no aesthetics!

I'll shut up now and leave you to the video if you're interested. I recommend watching it in HD so you can read the words on the page.

As my friend whom the HTML5 version is kinda named after likes to say:

More later …

SAVS: a Simple Audio/Verse Synchronizer from nitin arora on Vimeo.

Update, September 20, 2011: To avoid confusion as to what this does, I'm renaming this from "Simple Audio/Video Synchronizer" to "Simple Audio/Verse Synchronizer" or something …

:)

Update, October 16, 2011: Cool, I found one more thing that meets all the four goals at http://www.dinglabs.com. They're pitching it as a foreign language learning tool, but same difference. Also, that site led me to TranscriberAG, a tool for transcribing audio.

--------------

Related Content:

Written by nitin

September 5th, 2011 at 9:39 am

making a DOT graph for PHP include statements

leave a comment

A couple of months ago, I posted about my experience with making a Python dependency graph.

Of course, as the post states, I was originally looking for a way to make a graph showing the relationship among PHP files in regard to include statements.

Well, I'm home sick and after a few hours of trying to find an easy, out-of-box solution I gave up and rolled my own Python script to make me a DOT graph file.

I didn't have anything better to do.

:(

The results are pretty simplistic, but I'm happy enough with it for now.

The Python script takes three arguments: the directory in which the PHP files exist, whether to search recursively or not (0=no, 1=yes), and the name of the output file as such:

$ python makeDOT.py blog/wordpress 1 wordpressIncludes.dot

#####
#importing modules
import glob, re, sys, os, fnmatch
br = "\n"
tab = "\t"

#####
#exiting if all 3 arguments are not passed via command line
def fail():
    print ("ERROR: " + str(len(sys.argv)-1) + " of 3 required arguments provided.")
    sys.exit()

#####
#getting arguments passed via command line

#testing for root DIRECTORY string
try: myDir = sys.argv[1]
except: fail()

#testing for RECURSION boolean
try: myRec = sys.argv[2]
except: fail()

#testing for OUTPUT filename string
try: myFile = sys.argv[3]
except: fail()

#####
#making list of PHP files within DIRECTORY
if myRec == "0": #without recursion
    myDir2 = myDir + "/*.php"
    PHP_list = glob.glob(myDir2)
elif myRec == "1": #with recursion
    PHP_list = []
    for dirname, dirnames, filenames in os.walk(myDir):
        for filename in filenames:
            if fnmatch.fnmatch (filename,("*.php")):
                match = os.path.join(dirname,filename)
                PHP_list.append(match)

#make an empty list;
#tuples will go in the list;
#each tuple will contain a PHP filename and a PHP filename it includes
includeList = []

#iterate through each PHP file and place tuples in the list
for phpFile in PHP_list:
    fileOpen = open(phpFile, "r")
    #for each line in a PHP file
    for line in fileOpen:
            m = re.match(r"(.*)include(.*\()(.*)\)", line) #for include(),include_once()
            if m:
                matchFile = m.group(3)[1:-1]
                if matchFile[-4::] == ".php": #only PHP files
                    phpFile = phpFile.replace("\\","/")
                    matchFile = matchFile.replace("\\","/")
                    matchFile = matchFile.replace("\"","")
                    matchFile = matchFile.replace('\'',"")
                    includeList.append([phpFile[len(myDir)+1:], matchFile])
            else: pass

            m = re.match(r'(.*)require(.*\()(.*)\)', line) #for require(), require_once()
            if m:
                matchFile = m.group(3)[1:-1]
                if matchFile[-4::] == '.php': #only PHP files
                    phpFile = phpFile.replace("\\","/")
                    matchFile = matchFile.replace("\\","/")
                    matchFile = matchFile.replace("\"","")
                    matchFile = matchFile.replace('\'',"")
                    includeList.append([phpFile[len(myDir)+1:], matchFile])
            else: pass

#####
#creating DOT file
dot = open(myFile, "w")

#writing to DOT file
dot.write("digraph {" + br)
for a,b in includeList:
    dot.write(tab)
    dot.write("\"")
    dot.write(a)
    dot.write("\"")
    dot.write(" -> ")
    dot.write("\"")
    dot.write(b)
    dot.write("\"")
    dot.write(";")
    dot.write(br)
dot.write("}")
dot.close()

#####
#exiting
sys.exit()

I ran the Python script on the PHP scripts for MXMLiszt.

Then I used the "circo" layout engine in Graphviz – specifically the Gvedit.exe application – on this resultant DOT file.

Here's the result:


--------------

Related Content:

Written by nitin

July 30th, 2011 at 1:03 pm

AudioRegent 1.3.1 released

leave a comment

I've updated AudioRegent to version 1.3.1.

You can read an overview of the software and get the download link to the new version here.

The only reason I updated the software is because, as I've mentioned before, I've been having problems with Windows (and only recently at that) in terms of calling executables from the command line.

What seems to have helped is to no longer pass a command as a string a la:

RunSoxString = SoxPath + " ./outWavs/" + OggArray[cnt] + ws + "--comment-file comment.txt ./outOggs/" + str(OggArray[cnt])[:-4] + "." + outputType + ws + SoxOptions
RunSox = subprocess.Popen([RunSoxString], shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
RunSox.wait() #wait until the subprocess finishes

Now, it seems I have to pass it as a Python list (aka an array):

RunSoxString = SoxPath + " ./outWavs/" + OggArray[cnt] + ws + "--comment-file comment.txt ./outOggs/" + str(OggArray[cnt])[:-4] + "." + outputType + ws + SoxOptions
import shlex
RunSoxList = shlex.split(RunSoxString)
RunSox = subprocess.Popen(RunSoxList, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
RunSox.wait() #wait until the subprocess finishes

By the way, I totally haven't tested this new version enough to distribute it and I haven't tested it at all on a Linux box. But since no one's using it, I'm not too worried.

--------------

Related Content:

Written by nitin

July 28th, 2011 at 6:31 pm

Posted in digital audio,scripts

Tagged with , ,

MXMLiszt version 0.9.2 released

leave a comment

If anyone's interested, MXMLiszt version 0.9.2 is now available for download.

MXMLiszt is a web-based delivery and search/retrieval environment for MusicXML files and their manifestations.

The documentation and source-code download links are available here.

Here's the changelog:

0.9.2
- included Bach and Schubert MusicXML files from MusicSQL project (http://musicsql.googlecode.com/).
    - For the Bach, cleaned up diacritics (in titles only) and changed "Soprano", etc. to "Soprano", etc.
        - diacritics are still messed up in lyrics. I'm too lazy to fix them. :]
    - For the Schubert, changed "Part_1" through "Part_4" to "Violin 1", "Violin 2", "Viola", and "Cello".
    - original files available here:

http://musicsql.googlecode.com/files/Bach_SATB-1.0.zip

http://musicsql.googlecode.com/files/Schubert_quartets-1.0.zip

- adjusted <hr> rules in style.css to accomodate Internet Explorer 9
    - Removed "optimized for Firefox" in welcome.php since MXMLiszt now works well in IE, Firefox, Chrome, Safari, and Opera (see below).
- fixed generateIndex.php so the <img> tag now closes in this line:
        echo nl2br('<img src="png/' . $filenamePlain . '.pre.png" />'); //line #12
    - This was the only reason the Index view wasn't working in Opera.
        - Opera was the only browser that caught this error. :]
- made "Results" header for search results an <h2>, just as with the MIR results header.
- added two modules: startWatch.php and stopWatch.php to reduce coding redundancy in regard to reporting the time it takes for actions to finish.
- changed mxml2mods.xsl to output the MODS namespace.
    - adjusted mods.xsl, loadMODSasDC.php, and XQuery syntax as needed.
    - Sample XQueries using a namespace prefix:

        This is a Faust query example:
                    declare namespace mods = "http://www.loc.gov/mods/v3";
                    for $x in doc("../concat/concatMODS.xml")/hyperMODS/hypoMODS/mods:mods
                    let $x1 := $x//mods:subTitle
                    return $x1

        This is a Dante example:
                    declare namespace mods = "http://www.loc.gov/mods/v3";
                    for $x in doc("../concat/concatMODS.xml")/hyperMODS/hypoMODS
                    let $x1 := $x/mods:mods
                    where $x1//mods:subTitle contains text "You"
                    return data($x/@file)

- simplified some of the built in MODS related XQueries (same functionality, just less wordy).
- changed order of MODS search drop down terms on Search page.
- changed <i> and <b> to <em> and <strong>, respectively.
- replaced "pop1", etc. with better-named CSS variables like stickyNote and IndexPopup, etc. in style.css.
- added a streamed comment in each module with a one or two sentence description of what it does.
- added .htaccess file.
    - to hide root folder.
    - to make the "/~foo.xml" forward (with masking) to:"transmuteMXML.php$fname=musicXML/foo.xml".
        - adjusted mxml2mods.xsl accordingly.
    - to hide directory icons.
    - to use fancy indexing.
- changed displayMODS.php to display MODS files via an <iframe> only as a fallback if PHP XSL processing not available on server.
_______________________________________________________________________
0.9.1
- created mods.css file to display MODS on a transparent background.
- changed displayMODS.php to display MODS files via an <iframe>.
    - The previous version was using the mods.xsl stylesheet to parse the MODS element values in real-time.
_______________________________________________________________________
0.9.0
- this was the first version - that worked!
--------------

Related Content:

Written by nitin

July 23rd, 2011 at 10:29 am

Posted in music notation,news,scripts

Tagged with ,

PubMed2XL 1.0 available

leave a comment

I've uploaded a new version of PubMed2XL, a Windows application that converts article lists from PubMed.gov into Microsoft Excel files.

Unlike downloading the CSV directly from PubMed.gov, PubMed2XL gives users (OK … advanced users) the ability to customize the output but even the default format includes Abstract, links to each article, and even links to related articles, and reviews.

Here's an example of a spreadsheet made with PubMed2XL and here's the source file used to make it. The source file was downloaded from PubMed.gov using a search for "Mexican flu".

If you'd like to use the software you can download it for free.

If you notice any bugs or have any questions or remarks, please feel free to leave a comment on the site. Thanks!

--------------

Related Content:

Written by nitin

June 18th, 2011 at 2:28 pm

Posted in news,scripts

Tagged with , ,

dewey decimal nesting

leave a comment

Update, July 4, 2011: Gawd, this post is a disaster. I've got an updated version of the script below pretty much up and running here, but I won't get around to populating the "collection" with real data for a while. When I do, I hope I can remember to update this post. So, you've been warned. Read at your own risk.

:P

I'm toying with the idea of implementing something at work for our small video collection.

Out video ids are stored in an SQL database and apart from that it also has other data about the video like basic categories – like "American History" or whatevers – so people can locate videos on the same subject.

I was thinking, however, about using an easy, pre-existing taxonomy like the Dewey Decimal System to create nesting browsing.

The idea is by just "tagging" the video in the db table with a DDC number one would already know the nested context in which the subject category lies and it really wouldn't be hard to find a subject and the corresponding DDC number in the first place. It's not like it's LCSH or anything. Plus, DDC is based on 10's, so that should help.

Anywho, that video stuff's all down the road … maybe.

First, I needed to find out how to nest DDC numbers automatically from an SQL table. 

And I'm getting there with major help from the post here: http://www.thetechspace.com/2010/05/21/get-unlimited-parent-and-child-in-php.

So, say I have this table with flat DDC numbers.

id ddc
1 100
2 101
3 110
4 111
5 111.5
6 111.55
7 112
8 109.5
9 111.555
10 111.5555
11 111.52
12 101.5
13 111.525
14 111.2

 

Using the PHP code below a "top" level DDC number can be passed via the URL to a function that will return the 1st generation children of that DDC number and then recursively find the 1st generation children of the results until there are no children left. No more children … how sad.

BTW: Passing the display output style is also an option.

For example, going here:

http://127.0.0.1/deweyNester.php?top=100&display=verbose

would yield:

The $_GET starting value is: 100

SQL: SELECT * FROM csv_db.deweyTable WHERE ddc LIKE "10_" AND ddc NOT LIKE "100" ORDER by ddc
Child: 101
Parent: 100

SQL: SELECT * FROM csv_db.deweyTable WHERE ddc LIKE "101._" ORDER by ddc
Child: 101.5
Parent: 101

and going here:

http://127.0.0.1/deweyNester.php?top=111&display=dashed

would yield:

The $_GET starting value is: 111

-111.2
-111.5
--111.52
---111.525
--111.55
---111.555
----111.5555

Notice how in the first example 109.5 was not found because 109 isn't present in the ddc column of the table. That is to say, currently the script doesn't find orphans.

Anyway, this is a work in progress but it's been kind of fun playing with this at work today so here's the code for now:

<?php

$db_connect = mysql_connect("127.0.0.1","root","");
//yeah, yeah. no password. I know. Shutup! :]

//evaluate the DDC number
//return an appropriate snippet for query
function nextOfKin($arg)
 {
 if (substr($arg,-1) == 0)
   {
   $arg = '"'.substr_replace($arg,'',-1).'_" AND ddc NOT LIKE "' .$arg .'"';
   }

 elseif (substr($arg,3,1) == ".")
   {
   $arg = '"' .$arg .'_"';
   }

 else
   {
   $arg = '"' .$arg .'._"';
   }

 return $arg;
 }

//execute the SQL query recursively
function displayChildAndRoot($parent,$display)
 {
 $sql = "SELECT * FROM csv_db.deweyTable WHERE ddc LIKE " .nextOfKin($parent)
        ." ORDER by ddc";
 $result = mysql_query($sql);
 while ($row = mysql_fetch_array($result))
   {
   if ($display == "verbose")
    {
    echo "SQL: " .$sql ."<br />";
    echo "Child: " .$row['ddc'] ."<br />";
    echo "Parent: " .$parent ."<br />";
    echo "<br />";
    }

   elseif ($display == "dashed")
    {
    $dashLen = strlen($row['ddc']) - 3;
    if ($dashLen > 0)
     {
     $dashLen = $dashLen - 1;
     }
     echo str_repeat('-',$dashLen) .$row['ddc'] ."<br />";
    }

   displayChildAndRoot($row['ddc'],$display); //recurse
   }
 }

//get the starting DDC number per what's passed via the URL
if (empty($_GET["top"]))
 {
 $top = 100;
 echo "The DEFAULT starting value is: " .$top;
 }

else
 {
 $top = $_GET["top"];
 echo "The \$_GET starting value is: " .$top;
 }

//get the output type per what's passed via the URL
if (empty($_GET["display"]))
 {
 $display = "dashed";
 }

else
 {
 $display = $_GET["display"];
 }

echo "<br /><br />";

//make it happen!
displayChildAndRoot($top,$display);

?>

Update, June 15, 2011: Looking back, setting the top/root to 100 should have yielded all the DDC numbers except the aformentioned 109.5. I think the solution is to tweak the IF statement inside the nextOfKin() function like so:

 if (substr($arg,-2) == "00")
   {
   $arg = '"'.substr_replace($arg,'',-2).'__" AND ddc NOT LIKE "' .$arg .'"';
   }

Now, going here:

http://127.0.0.1/deweyNester.php?top=100&display=verbose

yields:

The $_GET starting value is: 100

SQL: SELECT * FROM csv_db.deweyTable WHERE ddc LIKE "1__" AND ddc NOT LIKE "100" ORDER by ddc
Child: 101
Parent: 100

SQL: SELECT * FROM csv_db.deweyTable WHERE ddc LIKE "101._" ORDER by ddc
Child: 101.5
Parent: 101

SQL: SELECT * FROM csv_db.deweyTable WHERE ddc LIKE "1__" AND ddc NOT LIKE "100" ORDER by ddc
Child: 110
Parent: 100

SQL: SELECT * FROM csv_db.deweyTable WHERE ddc LIKE "1__" AND ddc NOT LIKE "100" ORDER by ddc
Child: 111
Parent: 100

SQL: SELECT * FROM csv_db.deweyTable WHERE ddc LIKE "111._" ORDER by ddc
Child: 111.2
Parent: 111

SQL: SELECT * FROM csv_db.deweyTable WHERE ddc LIKE "111._" ORDER by ddc
Child: 111.5
Parent: 111

SQL: SELECT * FROM csv_db.deweyTable WHERE ddc LIKE "111.5_" ORDER by ddc
Child: 111.52
Parent: 111.5

SQL: SELECT * FROM csv_db.deweyTable WHERE ddc LIKE "111.52_" ORDER by ddc
Child: 111.525
Parent: 111.52

SQL: SELECT * FROM csv_db.deweyTable WHERE ddc LIKE "111.5_" ORDER by ddc
Child: 111.55
Parent: 111.5

SQL: SELECT * FROM csv_db.deweyTable WHERE ddc LIKE "111.55_" ORDER by ddc
Child: 111.555
Parent: 111.55

SQL: SELECT * FROM csv_db.deweyTable WHERE ddc LIKE "111.555_" ORDER by ddc
Child: 111.5555
Parent: 111.555

SQL: SELECT * FROM csv_db.deweyTable WHERE ddc LIKE "1__" AND ddc NOT LIKE "100" ORDER by ddc
Child: 112
Parent: 100

Update, June 15, 2011: This is why people do extensive testing! Now, I've changed the nextofKin() function yet again. The nesting wasn't as desired – maybe I should post on what those nesting requirements are? So here goes again. I know, I suck. But shutup!

function nextOfKin($arg)
 {
 if (substr($arg,-2) == "00")
   {
   $arg2 = '"'.substr_replace($arg,'',-2).'0_" OR ddc LIKE "'
   .substr($arg,0,1) .'_0" AND ddc NOT LIKE "' .$arg .'"';
   }

 elseif ((substr($arg,-1) == "0" and substr($arg,-2) != "00"))
   {
   $arg2 = '"'.substr_replace($arg,'',-1).'_" AND ddc NOT LIKE "' .$arg .'"';
   }

 elseif (substr($arg,3,1) == ".")
   {
   $arg2 = '"' .$arg .'_"';
   }

 else
   {
   $arg2 = '"' .$arg .'._"';
   }

 return $arg2;
 }
--------------

Related Content:

Written by nitin

June 14th, 2011 at 6:23 pm

Posted in scripts

Tagged with , , , ,

dynamic menus with TKinter

leave a comment

So, I've been thinking about being lazy in regard to dynamic GUI menu creation with Python using TKinter.

… and I'm waiting for it to be 8:30 so I can watch the NBA playoffs.

Basically, I was trying to figure out if there was a way to create a simple button menu without having to re-write the code that creates a button for each and every function I wanted to use.

So with apologies to the real programmers out there – especially if you are a Chicago Bulls fan, here's what I got.

At least it works.

from Tkinter import *

class yadayadayada():

    def __init__(self, root):

        #create a List with a tuple for:
            #1) every button that needs to be created and
            #2) what function it executes
        listOfFunctions = [("hi",self.hi),("bye",self.bye),("what",self.what)]

        #TK stuff
        frame = Frame(root)
        frame.pack()

        #iterate thru List and create buttons dynamically
        i = 0
        for stuff in listOfFunctions:

            buttonText = listOfFunctions[i][0] #first value in tuple
            buttonAction = listOfFunctions[i][1] #second value in tuple

            #make the button and assign the command to execute
            self.makeButton = Button(frame, text=buttonText, command=buttonAction)
            self.makeButton.pack()

            i = i + 1

    #just some placeholder functions
    def hi(self):
        print ("hi")

    def bye(self):
        print ("bye")

    def what(self):
        print ("what now?")

#make it go
root = Tk()
yadayadayada = yadayadayada(root)
root.mainloop()
--------------

Related Content:

Written by nitin

May 22nd, 2011 at 7:24 pm

Switch to our mobile site