Friday, February 07, 2014

Neverwinter Nights Diamond Edition, Video Lag, Switchable Graphics

Recently I broke out Neverwinter Nights Diamond Edition (v1.69) again on my HP dv6 Pavilion laptop, but despite the AMD Radeon HD 6490M that the laptop comes with, I found almost unplayable video lag happening whenever I tried to move around in the game. It looked and felt like <1 FPS.


I did a quick google and there was mention here that NWN does not like multiple processors, and setting the CPU Affinity in nwnplayer.ini should fix it.
[Game Options]Client CPU Affinity=1

It did not fix the issue for me, so I had another look. Now my dv6 comes with Switchable Graphics - which is a feature where the laptop has both Intel Graphics and the Radeon HD 6490M, and can automatically switch between the two for different applications in order to save power and avoid heat.

Naturally I had checked that my Catalyst Control Center had Neverwinter Nights set for "High Performance" GPU when trying to play the game. However I noticed that when I used Neverwinter Night's graphics configuration utility, it initially complained about not finding the appropriate drivers. I dug deeper and found this issue: OpenGL Applications Cannot Use Discrete GPU with Intel + AMD Switchable Graphics

This issue affects a range of HP laptops with switchable graphics, including the Pavilion dv6/dv7/g4/g6 and the new ENVY series. The fix was surprisingly easy (documented in the link above). I had to go into my laptop BIOS and switch the Switchable Graphics mode from Dynamic to Static, which meant only one graphics card would be active at any time (instead of splitting graphics card usage by application), and then go into "High Performance GPU" mode whenever I wanted to play Neverwinter Nights.

Saturday, January 11, 2014

Building an executable JAR with maven

Making a JAR executable

One common thing I come across is building executable JARs in maven, i.e. JARs that you can run as:
java -jar myapp.jar
The following maven snippet makes the result JAR executable - that is com.myapp.Main (or your main class of choice) is executed when the jar is run by java as above. It does so by setting the main class in your JAR manifest. (You can learn more about main classes and manifests here)


   <build>
      <plugins>
         ...
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
               <archive>
                  <manifest>
                     <mainClass>com.myapp.Main</mainClass>
                  </manifest>
               </archive>
            </configuration>
         </plugin>
         ...
      </plugins>
   </build>

However, if your JAR has any dependencies, you may get class not found errors because java cannot find the dependencies. One way is to pull in those dependencies by specifying a class path, e.g.:
java -cp "mydependency1.jar;mydependency2.jar;lib/*" -jar myapp.jar
either specifying each jar or the wildcards (if using Java 6 or higher).

Distributing with a subdirectory of dependencies

Another way is to get your JAR to put those dependencies in a subdirectory when building the JAR, and reference them in the manifest. This is more convenient if you are packaging it to run on another machine or in a installer.
   <build>
      <plugins>
         ...
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
               <archive>
                  <manifest>
                     <addClasspath>true</addClasspath>
                     <mainClass>com.myapp.Main</mainClass>
                     <classpathPrefix>lib/</classpathPrefix>
                  </manifest>
               </archive>
            </configuration>
         </plugin>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
               <execution>
                  <id>copy-dependencies</id>
                  <phase>package</phase>
                  <goals>
                     <goal>copy-dependencies</goal>
                  </goals>
                  <configuration>
                     <outputDirectory>${project.build.directory}/lib</outputDirectory>
                  </configuration>
               </execution>
            </executions>
         </plugin>
         ...
      </plugins>
   </build>
This does two things -- get maven-dependency-plugin to copy the dependencies (and transitive dependencies) at package time into a lib subdirectory, and then tell maven-jar-plugin to add the classpath entries when writing the manifest for your JAR.


Distributing as a single JAR (containing all dependencies)


The above method is great, but sometimes you want to have everything in a single JAR. You can use maven-assembly-plugin instead to build a single jar containing everything.

   <build>
      <plugins>
         ...
         <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
               <descriptorRefs>
                  <descriptorRef>jar-with-dependencies</descriptorRef>
               </descriptorRefs>
               <archive>
                  <manifest>
                     <mainClass>com.myapp.Main</mainClass>
                  </manifest>
               </archive>
            </configuration>
            <executions>
               <execution>
                  <id>make-my-jar-with-dependencies</id>
                  <phase>package</phase>
                  <goals>
                     <goal>single</goal>
                  </goals>
               </execution>
            </executions>
         </plugin>
         ...
      </plugins>
   </build>

This will, in addition to the normal output jar, make another jar e.g. "myapp-jar-with-dependencies.jar" that contains all the classes and resources from the dependencies. You can run this directly:
java -jar myapp-jar-with-dependencies.jar
Note here that we are using maven-assembly-plugin to specify the main class instead of maven-jar-plugin as well.

This method does not always work. It comes with a warning that some libraries may not run properly if processed like that - I have not come across a case so far but recommend it only for small apps.


Thursday, January 09, 2014

Passing command line parameters to the maven release plugin

Today I re-learnt some things:

Passing command line parameters to the maven release plugin

When using the maven release plugin, e.g. with "release:prepare", the plugin will run a subprocess "mvn clean verify --no-plugin-updates" on the project. This will not pass any arguments that you specified to maven, example:
mvn -Pthis-profile -Duse.property=that release:clean release:prepare release:perform
will not pass those parameters to the subprocess. You need to define them with -Darguments to pass them, like:
mvn "-Darguments=-Pthis-profile -Duse.property=that" release:clean release:prepare release:perform 
See http://maven.apache.org/maven-release/maven-release-plugin/prepare-mojo.html#arguments

Why doesn't it work for me? Parent pom overwrite?

Note that if you use parent poms, they (or their ancestors) may specify the <arguments> configuration for the maven release plugin and passing in parameters via -Darguments will stop working.
<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-release-plugin</artifactId>
   ...
   <configuration>
      <arguments>-Dmy.property=this</arguments>
      ...
   </configuration>
</plugin>
the correct way would have been to define it like that:
      <arguments>-Dmy.property=this ${arguments}</arguments>
so that -Darguments would continue to work. If you find this, you can either change the parent pom or overwrite the configuration again in your project pom to allow -Darguments to work.

Passing multiple properties and shell escaping

When passing multiple arguments via the -Darguments method, the mind may logically use something like:
-Darguments='-Pthis-profile -Duse.property=that'
however this is not proper shell escaping, and the properties may not be passed correctly (you might end up passing a profile name of "this-profile -Duse.property=that"). You want:
"-Darguments=-Pthis-profile -Duse.property=that"

Proper googling

When you want to find information on -Darguments on maven, searching "maven -Darguments" is probably what you'll first search, but hold on -- search syntax means that will search for "maven" and - yes - omit all results with "Dargument" (which are probably the results you want). "maven Darguments" did the trick instead.



Wednesday, January 01, 2014

Migrate from SVN to Git/Github

Today I migrated the PyFileServer codebase from its original home in SVN on BerliOS to Github, without losing commit history

Here's how I did it.

First, I created a git version of the SVN repository locally using git-svn.
The first thing you need is a text file (users.txt) that maps your SVN users to Git/Github users, in the format:
user1 = First Last Name <email@address>





then you call:
/fs/migration> git svn clone --stdlayout -A users.txt svn://svn.berlios.de/pyfilesync pyfilesync
the --stdlayout flag indicates that the SVN repository follows the trunk/branches/tags standard structure, which aids in identification of branches. Git-svn will pull the commits from SVN and populate them in your repository as Git commits. Note: If it meets a user that is not in your users.txt file, the process will stop, but you can always fix the users.txt file, and then peruse into the repository and use "git svn fetch" to resume the process (you don't have to re-specify the users.txt location when calling git svn fetch).

This process automatically copies over the svn trunk as the local git master, but the svn branches and tags remain in the git repository as remote branches. To see these branches, use:
/fs/migration/pyfilesync> git branch -r

to "copy" the remote branches over as local branches, use:
/fs/migration/pyfilesync> git checkout -b <new local branch name> <remote branch name>
e.g.
/fs/migration/pyfilesync> git checkout -b code-review code-review
/fs/migration/pyfilesync> git checkout -b paste-prune paste-prune
...
SVN tags are also copied over as branches, and you have to re-tag them as Git tags if you wish.


Next, I created the Github repository project, and then cloned it onto my local computer.

/fs/migration> git clone https://github.com/cwho/pyfileserver.git

At this point I have my svn-import git repo at /fs/migration/pyfilesync, and my Github-cloned git repo at /fs/migration/pyfileserver

Then I went into the pyfileserver git repository, and added the pyfilesync repository as a remote repository:
/fs/migration/pyfileserver> git remote add -f svnimport ../pyfilesync
and merged the changes in the master branch (the pyfileserver repo is currently on master)
/fs/migration/pyfileserver> git merge svnimport/master
You have to bring over the remaining branches as well
/fs/migration/pyfileserver> git checkout -b code-review svnimport/code-review
/fs/migration/pyfileserver> git checkout -b paste-prune svnimport/paste-prune
... 

Finally, I push the new commits on the local pyfileserver git repository back to Github. All done!


The general schematic of what I did above looks like this:



References:

Sunday, June 18, 2006

var partition filling up

Recently I had the chance to do some work for a linux server and and encountered some problems with the /var partition filling up really quickly.

du vs df
There are two common tools for looking at disk usage. df which lists all the partitions in your system, with the amount of space used/free and percentage, and du, usually run as du -sh * which gives a listing of all the files in the current directory (including subdirectories). df is helpful in finding if a partition is filling up, and du helpful in finding out which subdirectory is contributing how much to that space usage.

MySQL InnoDB
If your /var/lib/mysql is filling up, its probably innodb tables.

I had MySQL 5.0, and am using innodb tables. The innodb database (unless you configure it to use a separate file for each table, which is useful for things like separate partitions for separate dbs) uses a number of redo (temp) log files (default is /var/mysql/iblogfile0 and /var/mysql/iblogfile1) as well as a appending transaction log (default /var/mysql/ibdata1). The log files have a fixed (small ~5M) size but the transaction log will (note this!) keep growing in size and will not shrink even if you delete records - it logs transaction history, not just data.

In our case the transaction log grew too large, so we added a new autoextend file on a larger partition, with monthly note to dump and reimport all innodb data to clear the transaction log. The following documentation link has details to both
http://dev.mysql.com/doc/refman/5.0/en/adding-and-removing.html


sendmail clientmqueue
Another candidate for "var filling up" troubles is /var/spool/clientmqueue . This is a mail queue that stores as files emails that could not be processed or otherwise need to be cached (for mostly retrying). This is separate from mqueue (google mqueue vs clientmqueue).

Why is clientmqueue filling up? Most likely there are undeliverable messages heading towards your users. If you are running a sendmail server, then likely your sendmail is being misconfigurated and undeliverable spam mail is being stored in clientmqueue.

If you aren't running a sendmail server, then the only way that undeliverable mail gets sent to your server is locally - invoking sendmail separately. You could check if there are automated scripts on your server sending users mail that is not being delivered. One likely cause is cron sending the root or owner user emails about cron jobs status or output. To fix this, you can add MAILTO="" to all the cron files in your system, including user/root crontabs and cron.daily, cron.weekly, etc. I also usually direct cron output to the null device by appending the cron job's command with > /dev/null, just in case.

We also found alternate workarounds like getting cron to use mail.local instead of sendmail to send emails (again google is your friend) but did not try to implement that.

Open files

The way linux treats open files is that if an open file is deleted, then the file doesn't actually get deleted until its closed. This means that for example if your application(s) is reading from/writing to a (log) file, and you delete the file from the shell, the file is not actually deleted until your application(s) close the file. Now the file is removed from the directory listing immediately, so its not apparent to the user that the file is still there and taking up space.

This is where du and df can report different stats - du, which looks at each file, will not report the space taken up by deleted open files. df which looks at disk/block usage, will. If you get a huge difference between the space usage indicated by du and df, this is usually the case.

One useful tool for seeing open files and the application/processes using them is lsof. e.g. lsof /var gives a listing of all the open files under /var as well as the process ids and associated running user using them.

In our case, we had rotated the Apache logs for the day but mistakenly left Apache such that some of its processes were still writing to the old log file (deleted), which grew to be quite big. Forcing Apache to return with httpd -k stop; httpd -k start did the trick. httpd -k restart might work as well, since I believe all processes are eventually deleted and recreated, but im not too sure when it would happen.

Sunday, May 28, 2006

Supporting CJK characters in MySQL

Recently I had to write some CJK/unicode characters from Java into MySQL. I use MySQL 5.1 and the connector mysql-connector-java-3.1.10-bin.jar .

The connector appears to be able to read CJK/unicode characters in text retrieved from queries correctly, if they were entered via MySQL query browser into the database properly as unicode. But writing CJK/unicode to the database (insert, update) using the connector using either a normal SQL statement or setString() with a PreparedStatement appeared to translate the CJK characters to a single ? (code 3F).

It appeared that I had to write the text data as bytes instead to get them written properly as unicode. I chose the encoding UTF-8. Then I changed the column specific encoding and charset for the text field to hold the CJK text as "utf8_ci" and "utf8_charset". Then to write the text in an insert operation using a PreparedStatement:

here we assume we already have the database Connection conn established, and we are trying to insert text from String cjkword:


PreparedStatement stmt = conn.prepareStatement("INSERT INTO cjktable (cjktext) VALUES ( ? )");
try {
stmt.setBytes(1, cjkword.getBytes("utf8"));
} catch(UnsupportedEncodingException e) {
stmt.setBytes(1, cjkword.getBytes());
}


the try block is to catch the exception (java.io.UnsupportedEncodingException), which occurs if you have specified an unsupported encoding. UTF8 should be supported (by Sun JDK anyway) so it should not occur.

--Edited per comments

Tuesday, May 09, 2006

Morning!

And after three months of non-blogging :), here is a view of my window at 5.20am in the morning.

Saturday, December 31, 2005

Monday, December 19, 2005

Messenging Galore

Sorry that there hasn't been any entries till today. I've been slightly busy. Academic. Home searching. No t-shirt from Google yet, but I believe in Christmas surprises :)

Just cleaned up my system yesterday, and took stock note of the number of internet messenging clients I use to keep up to date with diverse groups of friends, fellow professionals and family. Let's see:
- MSN Messenger
- Hamachi (the VPN functionality is really useful)
- Yahoo Messenger
- Skype
- Google Talk

How many internet messenging clients do YOU use?

Wednesday, October 26, 2005

This Day

SoC Results

Google posted the SoC results:
http://googleblog.blogspot.com/2005/10/supporting-open-source.html
I'm not on the map yet, but its still being updated.
=> Update: I'm now on the map.

Tuesday, October 04, 2005

Aftermath

The Good and Grateful

There hasn't been much entries after the completion of the program (not the project - which is still undergoing work, albeit much slowly since it gets interrupted by school assignments and the like). I did want to thank Google, Python Software Foundation and my mentor Ian Bicking again for offering the opportunity and providing the help throughout the project. I learnt a lot, technical wse - considering that this was my first foray into Python web services.


That linuxgazette article

Most of the reaction from the open source developer and academic community to the SoC program has been good. Admittedly there were a few kinks here and there, but nothing less would be expected on the first run of program. It was quite successful, and I am sure this experience will help for the next one (Code of Summer, or Code of Winter?).

What left a bad taste in my mouth was this linuxgazette article covering the "aftermath" of the event - "After the Summer of Code" (no, you don't have to read it to follow my criticism). The article points out criticism to the program, for which I do give it dubious merit, its hard to come out and point an accusing finger at a popular program.

But that's a nasty piece of journalism. Rather than presenting a coherent and informative description of the program and its faults (if any), it instead throws out random complaints elicited from various web pages and mailing lists (probably without even contacting the malefactors involved to see if their complaints had been true or successfully resolved), and turn them into rants.

It starts off with:
One of the biggest noises in Open Source this year was made by Google's announcement of the Summer of Code: a project to encourage students to participate in the development of open source projects during the summer holidays.
One of the biggest noises.... right.... An article is not a blog like this.

The article proceeds to reference the experience given a mentor, who gives some very useful and honest advice to future candidates. But instead of giving a balanced summary of its contents, the linuxgazette article quotes a paragraph from the "BAD APPLICATIONS" section and presents it as _A SUMMARY_ of the selection process, not only distorting meaning but giving the idea that the informative piece was no more than a rant about the quality of applications received.

The article proceeds to contradict itself with its criticism of the amount of "reward" given, USD4500. At first it mentioned that this was far too small for 2 months work, well below what a summer intern would earn in the US. In subsequent sections, it reversed its stance and pointed out that the reward was well above what other open source organizations are offering for contributions. I guess you can't make everyone happy.

Next, it draws attention to the imbalance in scope and perceived usefulness of selected projects (which is to be expected, given the diversity of mentoring organizations and students accepted), but particularly single out WinLibre for sponsoring three similar updating projects, and termed it a waste of money. You can draw your own conclusion, but IMHO the open source development model does encourage a certain amount of redundancy. What disgusted me was the utter lack of courtesy paid to those projects, when in the list of projects to follow, instead of listing these projects by name (obtainable by simply following the link) [python_rewrite_bertrand, updater, bodq], the author lists them as [Python/XML installer/updater, Another updater, Yet another installer/updater].

Finally, the list of projects provided in the article was incomplete, and totally fails to take into account that each project's scope, name and page location has changed since the commencement of the project. Perhaps the author should have contacted Google, to obtain the information provided at the conclusion of the program.

Now I usually have some respect for experienced professionals sharing their experiences on linuxgazette, especially with articles like "Learning to Program with DrScheme" (just before the offending article) and "Optimizing Website Images with the Littleutils" (just after), but I have to say that "After the Summer of Code" falls short of expectations.

Thursday, September 15, 2005

PyFileServer

The code for this project is available at:
Anonymous SVN: svn://svn.berlios.de/pyfilesync
Instructions here if you have difficulties.

Contact: fuzzybr80(at)gmail(dot)com

Tuesday, September 13, 2005

SVN and PyFileServer

Long time no post. No recent news on PyFileServer, except that I've submitted the DDJ SOC article.

Today I got an email expressing interest in PyFileServer (a good day!!) and wondering if it could be used to host an SVN repository. So I checked out the SVN internals and how its being accessed:
+ as a http(s):// url - with the server as Apache mod_svn_dav, using a partial/customized version of WebDAV and DeltaV
+ as a svn(+tunnel):// url - with the server as svnserve, using its own custom protocol
+ as a file:// url - using the ra_local library to access the repository directly.

PyFileServer was designed to allow custom resource layers (and lock/property libraries) to be implemented. For PyFileServer to host a SVN repository, the simplest solution might be:
[svn repos-file] <---- ra_local ------> [PyFileServer] <------ webdav ------> [svn client]

(1) I'll write a SVN abstraction layer that accesses a local repository (via ra_local). This allows PyFileServer users to browse and retrieve SVN repos contents, via webDAV clients.

(2) I'll extend the PyFileServer application to include DeltaV extensions to WebDAV. This allows the actual versioning portion (checkin/checkout), via webDAV clients.

(3) Here's this bit that provides difficulty - svn client and mod_svn_dav uses a partial/customized version of WebDAV/DeltaV to communicate, and its not documented in detail:
+ http://svnbook.red-bean.com/en/1.0/apcs02.html
+ http://svn.collab.net/repos/svn/trunk/subversion/libsvn_ra_dav/protocol
So while you'll be able to access the SVN repository via webDAV clients, you would not be able to do "svn co URL" where URL is PyFileServer hosted, unless PyFileServer reimplement or bind over mod_svn_dav in some way to speak their language.

I would be doing (1) and (2) on the way, as my studies and other projects allow. However, (3) might not be done for quite a while, so if you were wanting to use this for a production/workplace setup, you probably will not wait for it.

Wednesday, August 31, 2005

Release 0.2.1

Release 0.2.1:

+ completed MySQL resource layer at pyfileserver.addons.simplemysqlabstractionlayer. See http://cwho.blogspot.com/2005/08/more-screenshots.html

+ enhanced server and abstraction layers to allow choosing to support Entity tags/last modified/contentlength and ranges on a per resource basis. e.g. a resource that does not support last modified will not return the last modified header and no last modified testing If_Modified_Since, If_Unmodified_Since is done. see in interface methods supportRanges(), supportContentLength(), etc

+ More bug fixes as they are found.

Project page: http://pyfilesync.berlios.de/

Thanks :)

More screenshots

Documenting the progress...

Yes, I shared the "mysql" database. Security klaxons ringing? CSV Representation is working fine.



And so is live properties. cadaver doesnt show it of course, but the property namespace is ":".



Release coming up soon.

Tuesday, August 30, 2005

Database Resource Abstraction Layer

I've just put together a sample database abstraction layer to a MySQL database, for demonstration purposes:



The idea (not all these features are working yet) is to allow read only access via the above methodology. _ENTIRE_CONTENTS will return a CSV representation of the data (assuming no large objects or equivalent). If the table has a SINGLE primary key, records will be listed as resources with names as those keys - these have no content but all attribute fields are available as live properties of these resources.

Trying to implement these highlighted some weaknesses in the server - it is too file oriented. Properties like modified/creation date may not mean anything to a record or table, and contentlength is a problem - there is no file size, so the only way to calculate the content length for a table.... is to retrieve ALL the content.

The solution here is to tweak the server to make these optional, such that if contentlength or modified date support is not provided, server will not use them (no last modified, no IF_(UN)MODIFIED_SINCE matching for example) or return the corresponding headers, and to support some other properties that were previously left out since they did not have too much to do with files, like getcontentlanguage.

Not all of this will appear by the SoC deadline, but most likely by mid-September (next release).

Monday, August 29, 2005

Release 0.2

Release 0.2:
+ Added resource abstraction layers. samples:
pyfileserver.fileabstraction.FilesystemAbstractionLayer and
pyfileserver.fileabstraction.ReadOnlyFilesystemAbstractionLayer
+ Removed etagprovider. Entity tags is now an aspect of the resource
abstraction layer.
+ Added interfaces pyfileserver.interfaces.*
+ cleaned up interface to lock library to make it more developer-friendly
+ More bug fixes as they are identified

Trying to make an example of using the resource layer to share resources other than files. As of this moment I am installing MySQL and reading up on MySQLdb module....
http://www.kitebird.com/articles/pydbapi.html

Saturday, August 27, 2005

Release 0.1.3

Release 0.1.3:
Urgent fixes to some code in 0.1.2

Incorporated comments from code review except:
+ Architectural changes - dispatching
+ Additional information from exceptions (HTTPRequestException extended)
+ code in doMOVE / doCOPY (awaiting abstraction layer)
+ docstrings in websupportfuncs (awaiting abstraction layer)

More work on abstraction layer in progress...

Friday, August 26, 2005

Resource Abstraction Layer

Code is being refactored after an enlightening code review from my mentor -> thanks! :)

While that is being done (for the evaluation I think), I have also started halfway on a resource abstraction layer - that will allow the application to share resources from other sources (other than a filesystem).

A sample of the code below. I didn't want to make it too lengthy - but I've included path resolving and live properties (including etags and all the "dav" properties except the locking properties) as part of the abstraction layer, since it made sense to put them in. For example this could allow someone to share a database with tables as collections, records as resources and attributes as live properties of those resources. Thought I include the interface here as for comments.

All the code is commented (prefixed with #) since it seems blogger doesn't handle indentation well without something in front.


#class abstractionlayer(interface):
#
# def getResourceDescription(respath):
# """ returns a string containing resource description, e.g. "File", "Directory" """
#
# def getContentType(respath):
# """ returns the MIME Content-Type for resource: mimetypes.guess_type() """
#
# def getLastModified(respath):
# """ gets the Last Modified time (num of secs since epoch). Return 0 if not supported """
#
# def getContentLength(respath):
# """ gets the content length of the resource """
#
# def getEntityTag(respath):
# """ gets the entity tag for specified resource """
#
# def isCollection(respath):
# """ tests if this is a collection : os.path.isdir """
#
# def isResource(respath):
# """ tests if this is a non-collection resource : os.path.isfile """
#
# def exists(respath):
# """ tests if this resource exists : os.path.exists """
#
# def createCollection(respath):
# """ creates a collection : os.mkdir """
#
# def deleteCollection(respath):
# """ deletes a collection : os.rmdir """
#
# def openResourceForRead(respath):
# """ opens a resource for reading, returns stream """
#
# def openResourceForWrite(respath):
# """ opens a resource for writing, returns stream """
#
# def deleteResource(respath):
# """ deletes a resource : os.unlink """
#
# def copyResource(respath, destrespath):
# """ copies a resource : shutils.copy2 """
#
# def getContainingCollection(respath):
# """ returns the path of the collection containg the resource : os.path.dirname """
#
# def getContentsList(respath):
# """ returns a list of names of resources in this collection
# it is based on the assumption that names returned can be joinPath() with
# the specified path to form the path to the resource
# : os.listdir
# """
#
# def joinPath(rescollectionpath, resname):
# """ Joins the two path components intelligently : os.path.join """
#
# def splitPath(respath):
# """ Splits a path returning a tuple (containg collection path, # resource name) : os.path.split
# """
#
# def getProperty(respath, propertyname, propertyns):
# """ returns property value for resource. This should implement all the required
# webdav properties except locking properties
# """
#
# def isPropertySupported(respath, propertyname, propertyns):
# """ tests if the specified property is a live property supported. If it is not
# supported, the application will look for it in the dead properties library
# """
#
# def resolvePath(resheadpath, urlelementlist):
# """ resolves the given url sequence to a path. Example:
# the directory c:\Test was shared as http://localhost/testing/.
# Then user accessing http://localhost/testing/dir1/dir2/file1.txt
# will require resolvePath to return a valid path to file1.txt from
# resolvePath('c:\Test', ['dir1','dir2','file1.txt'].
#
# An exception exiting this function may result in return of a 404 File Not Found
# """

Tuesday, August 23, 2005

Release 0.1.2

Release 0.1.2:
+ Minor fixes to Tutorial
+ Added windowsdomaincontroller under pyfileserver.addons
+ Added Addons documentation section

The windowsdomaincontroller allows the user to authenticate against a Windows NT domain or a local computer, requires NT or beyond (2000, XP, 2003, etc).

This class requires Mark Hammond's Win32 extensions for Python:
http://starship.python.net/crew/mhammond/win32/Downloads.html
http://sourceforge.net/projects/pywin32/

Information on Win32 network authentication was from the following resources:
http://ejabberd.jabber.ru/node/55
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81402