Friday, August 6, 2021

Composting

Introduction

This post is the basis of my forth submission to Hacker Public Radio (http://www.hackerpublicradio.org). If you'd like to listen to the melodic sound of my voice please visit: http://hackerpublicradio.org/eps.php?id=3408. It is inspired by HPR episode 3157 entitled Composting by Klaatu. During the early 2000's, I lived in a single family home which had a number of oak tree's around it. Between the trees, other foliage, and grass, there was a large amount of yard waste. While my city (Baltimore, MD in the US) will pick up your yard waste if you put it in bags by the curb [1], I would use the oak leaves as mulch, and did have a mulch pile of leaves and other yard waste. At that time, I thought about composting food waste, but there is a big issue with rats in Baltimore, and I didn't look into ways to compost. I just knew I couldn't randomly mix it into my mulch pile. I am currently living in a different house, without any oak trees, and not as much yard waste (particularly since we hire someone to mow the grass every couple weeks). After listening to the Composting episode I was inspired to look into the best way to do it given my current living situation. The first thing I did was to look and see if there are any laws against composting in Baltimore City. The rat problem is big enough that the City purchased and distributed a large green plastic trash bin to every physical mailing address in the city. This is the bin you are required to use when putting out your trash. Given the situation, I wasn't sure it would be legal to do composting in your back yard. Much to my surprise, it is not only legal, but the city website has a web page on how to compost [2] and just recently started a pilot program for food scrap drop off with seven locations around the city [3].

Kitchen Compost Bin

After determining I wasn't going to be a scofflaw, I went to the Internet to see what kind of bins are available for purchase. While Klaatu gives great suggestions for low cost composting bins, I wanted something that would look nice sitting out on a shelf for the small inside bin. I found the Utopia Kitchen Compost Bin [4]. The bin is made of stainless steel and has a volume of 1.3 gallons (4.9 liters). The lid is rounded and has a series of holes around the top. The inside of the lid holds a circular shaped charcoal filter. The combination of holes and charcoal filter capture any odors generated by the food scraps. It works amazingly well and even with onion scraps you need to stick your nose to the holes and inhale deep to smell anything when the lid is closed. It holds three to seven days worth of food scraps, most of which end up being coffee grinds. We have had this bin for 10 months, and the charcoal filter is still effective. There are replacement filters available for this bin, but you could also cut other charcoal filters to fit inside the lid.

Outside Compost Bin

Given the potential rat and other small critter issues, I wanted the main, outside composter to be fully enclosed, and preferably not sitting directly on the ground. A quick search brings up a number of options, both composters that sit on the ground and ones that are tumbler style, which hang on a frame. I went with a tumbler style compost bin. This provided the desired feature of not being on the ground, and has the added advantage of making it easy to turn the compost every second or third day by just rotating the bin slowly for three or four full turns. I purchased the FCMP Outdoor IM4000 Tumbling Composter [5]. The composter is octagonal shaped column with two chambers inside it. This allows you to fill one chamber while the other side is finishing the composting process. There are also aeration holes for each chamber which can be open to different levels to moderate the amount of moisture. The combined volume of the two chambers is approximately 37 gallons (140 liters).

My Composting Experience

So far I have been very happy with this combination. I just emptied a chamber for the third time. I do have a bit of an issue with the compost being overly damp. I have mixed some drier yard waste in from time to time and that does help, but have had times when parts of it get a little slimy. I have also run into issues with flies and other bugs living in the chamber for a while, but generally I don't see them outside of the composter, just when I open the door to add more material. Not ideal, but not so bad that I did anything about it. I have also found certain things do take extra time to compost, and usually need some manual help to break down. Pits of mangoes and avocados in particular along with corn cobs take a long time to break down. They do start to compost, and are easy to crumble in your hands, but keep their basic shape for a long while. Egg shells don't really break down, as Klaatu mentioned, but they do become very brittle and I crumble them up manually along with the pits and corn cobs. Another issue I have found with damper compost, particularly in cooler months, it doesn't heat up enough to decompose the seeds of some plants. This ended up being a pleasant surprise this summer after mixing in the first batch of compost in our little herb garden during the spring. We now have a combination of plumb and medium sized tomato plants and some kind of squash plant growing in it. If you don't want random plants growing in your yard or flower beds, do be careful when composting plants with seeds [6].

Conclusion

While it takes a little extra effort, composting does reduce the amount of garbage you are sending to the dump, and does reduce the smell of your kitchen trash bin. It also gives a rewarding feeling as you watch the material break down into a rich dirt, and then mix it into your garden or yard. I recommend giving it a try, and posting your experience as another episode of Hacker Public Radio.

References

  1. Baltimore City Department of Public Works-Yard Waste
  2. Baltimore City Department of Public Works-Source Reduction
  3. Baltimore City Department of Public Works-Food Scrap Drop-Off Pilot Program
  4. Utopia Kitchen Compost Bin
  5. FCMP Outdoor IM4000 Tumbling Composter
  6. Composting Tomato Plants: When To Compost Tomatoes

Sunday, March 14, 2021

Spam Bot Honey Pot

This post is the basis of my third submission to Hacker Public Radio (http://www.hackerpublicradio.org). If you'd like to listen to the melodic sound of my voice please visit: http://hackerpublicradio.org/eps.php?id=3296

In this post, I will describe the method I chose to combat spam bots filling out my company's contact form. About 99% of the submissions we receive are spam, which makes filtering for valid messages painful. After some research into different methods, I decided to go with the honey pot method.

The honey pot method uses an extra text input field to lure the spam bot into filling it out. There are different suggestions for how to hide this extra field from valid users by using either javascript or CSS. With javascript, the honey pot section of the form is removed from the DOM when the page loads, hiding it from your users. The argument for this method is most bots don't implement javascript, so the honey pot field will not be hidden from them. I think that is a valid argument but I didn't want to include extra javascript in my page--so I went with the CSS method.

There are references at the end of the post to a couple of the articles I read on implementing the honey pot with either javascript or CSS. My take away was, one, don't use the CSS display property set to the value of none to take the input out of the DOM. Sufficiently smart enough bots may know to scan for this, especially if applied directly to the element. Also don't name your classes something obvious to your intent like "anti-spam-filter". My guess is the majority of the bots out there aren't that sophisticated, but I figured it couldn't hurt to follow those suggestions.

I was already using Bootsrap CSS for our site, so I decided to use Bootstrap's "sr-only" class. This class is used for elements that you only want visible to screen readers. It takes the element and uses a combination of absolute positioning, setting the size and width to 1 pixel, setting a negative left margin, and hiding content overflow to prevent the honey pot showing up visually. I figured if the bot was scanning CSS for classes or properties, this wouldn't trigger any warnings. It does bring up the issue of how to prevent impacting the experience of people using screen readers. I applied the aria-hidden attribute with a value of true to the label element surrounding the honey pot input field. "[this] removes that element and all of its children from the accessibility tree." So we now have the field hidden both visually in the browser and from assistive technolgies. Given the short end of the stick accesibility usually gets, I doubt there are any spam bots scanning for that ARIA attribute. For the minority of users who might be viewing with the classic lynx browser, I put 'For office use' as the label text before the honey pot, hoping this would get the message across without tipping off the bot to the intended purpose of the related input field.

The other main issue with this method is the value of the name attribute used for the input field. Some argue to use obfuscated values like "mmxxName" instead of "name", or "sxysPhone" for "phone". Apparently some bots will skip fields they don't recognize. By using more standard names for multiple honey pot fields, it easier to determine if it is a bot. The counter arguement to this naming scheme is about the user experience, by obfuscating the name, then browser's won't auto-fill the valid fields of the form. This also brings up the matter of not auto-filling the spam fields by the browser of your users. This is done by setting any of your honey pot input elements' "autocomplete" attributes to "off".

So far this spam filtering method is working nicely. I currently send any messages flagged as spam to a different email address with the subject prepended with the words "[Spam review]". Once I am confident there are not that many false positives, I will just skip sending flagged messages. The one issue I have experienced with this method is when using the tab key to move through the form. Since the input field is only visually hidden, it still receives focus as you tab through. If you happen to hit another key while still in the hidden field, it will get captured by the honey pot and then the submission will be flagged as spam.

I have created a sample form on my personal site. Please visit URL: http://www.horning.us/hpr/SpamBotHoneyPot.php to try it out. It is a simple PHP page using the GET method when submitting the form. Once you press the submit button you will see the form fields and their values, along with the result messages. I chose to use "URL" as the name for my honey pot input field. I use it on my example form, and I use it for my work form. For my work form, a URL is not something we ask to be submitted, and being a common field in forms, makes it very tempting for bots. In my example code, the CSS for hiding the hony pot section is from the minicss.org website's. Their "visibility-hidden" class is very similar to Bootstrap's "sr-only" class. I would be interested to hear if other's have implemented something similar. I would also love to hear from someone who uses a screen reader. Does it prevent the honey pot section from being read?

References

Monday, August 15, 2016

AngularJS's ng-repeat, and the browser that shall not be named

Introduction

This post is the basis of my second submission to Hacker Public Radio (http://www.hackerpublicradio.org). If you'd like to listen to the melodic sound of my voice please visit: http://hackerpublicradio.org/eps.php?id=2102

At my work, we are in the process of revamping our internal call logging system. Moving from .NET and Microsoft's ASPX pages for both the client side and back end processing, to an HTML5 based Single Page Application (SPA) using AngularJS for the client side interface with a .NET WebAPI service for the back end processing. The main page for both versions contains a list of the current days calls laid out in a table with 9 columns. Users are able to switch to a specific day's calls by selecting a date via a calendar widget, or by moving one day at a time via previous and next day buttons. By the end of a typical day, the page will contain between 40 and 50 calls.

During recent testing of the SPA client on the proprietary browser we all love to hate, or at least have a love/hate relationship with if you have to support it, I noticed that rendering of a whole days worth of calls would take seconds, freezing the UI completely. This made changing dates painful. As we reload the data any time you re-enter that page (a manual way to poll for new data until we implement either timer based polling or a push service through websockets), the page was almost unusable. The page rendered fine in both Mozilla and webkit based javascript JIT engines, but Microsoft's engine would choke on it.

After a bit of searching on "AngularJS slow rendering" and "AngularJS optimize", I found many references about using Angular's ng-repeat directive when rendering long lists of data (see references below for the main pages I read). I tried a couple of the methods mentioned to optimize the ng-repeat directive. I used the "track by" feature of ng-repeat to use the call's id as the internal id of the row, so ng-repeat didn't have to generate a hashed id for each row. I implemented Angular's one-time binding feature to reduce the number of watches being created (reducing the test day's number of watches from 1120 to 596), but even these two combined optimizations didn't have enough effect to render the page in an acceptable amount of time. The next optimization I played with was using ng-repeat with the limitTo filter. This limits the number of items rendered in the list that ng-repeat is looping through. This is particularly useful combined with paging of the data. I set the limitTo option to different values to see how it affected the rendering time. I found that rendering 5 rows was fast and consistent for every day's worth of data I viewed. From my reading, I knew if I updated the limitTo amount while keeping the array of items the same, ng-repeat would only render any un-rendered items, and not redo the whole limited list.

The code

<tr ng-repeat="c in results | limitTo:displayRenderSize">

Inside your directive, set an angular.$watch on the list of items to be rendered by ng-repeat. In this example the list is stored in the variable results.

return {
        scope: {
            results: "=",
    },
        link: function (scope, element, attrs) {
            scope.renderSizeIncrement = 5;
            scope.displayRenderSize = scope.renderSizeIncrement;

            scope.$watch('results', function () {
                if (scope.results) {
                    scope.displayRenderSize = scope.renderSizeIncrement;
                    scope.updateDisplayRenderSize();
                }
            });
            scope.updateDisplayRenderSize = function () {
                if (scope.displayRenderSize < scope.results.length) {
                    scope.displayRenderSize += scope.renderSizeIncrement;
                    $timeout(scope.updateDisplayRenderSize, 0);
                }
            }
        }
    }
}

Any time the results are updated. The displayRenderSize variable is reset to render the default number of items, and the updateDisplayRenderSize function is called. This function calls itself repeatedly via angular's $timeout service ($timeout is a wrapper for javascript's setTimeout function). It increments the displayRenderSize variable which is being watched by the limitTo filter of the main ng-repeat. Each time the displayRenderSize variable is incremented, the ng-repeat renders the next set of items. This is repeated until all the items in the list are rendered.

The magic happens because ng-repeat blocks any other javascript, which does not effect angular's digest path, until it is finished rendering. By calling the updateDisplayRenderSize with a timeout, the function doesn't get called again until after the next set of items is rendered. Making the $timeout delay 0, sets the function to be called as soon as possible after the ng-repeat digest cycle stops blocking. In this instance, the sum of the rendering time for parts of the list is shorter than the sum of the rendering time for all of the list at one time.

Conclusion

There are a couple small glitches with this solution. Scrolling can be a bit jerky as the chunk sized renders cause a series of micro UI freezes, instead of one big long one. Also, if you don't have a fixed or 100% percent wide table layout, and you don't have fixed column sizes, the table layout will dance a little on the screen until the columns have been filled with their largest amounts of data. This is the result of the table layout being re-calculated as more data fills it. That being said, overall, this solution works great. It moved the pause from seconds to under half a second or less—making the page go from unbearable to usable on Microsoft's latest browser offerings.

References

Friday, December 26, 2014

Some useful tools when compiling software on a Debian based distribution

introduction

This post is based on my first submission to Hacker Public Radio (http://www.hackerpublicradio.org). If you'd like to listen to the melodic sound of my voice please visit: http://hackerpublicradio.org/eps.php?id=1688

I have been working on an application using the Python programming language with the Enlightenment Foundation Libraries (EFL) libraries for the GUI interface. After acquiring a new laptop and installing a fresh copy of Ubuntu on it, I decided to set up the build environment I needed to be able to work on my project. I have been building from source the EFL libraries along with the Python-EFL wrapper libraries. For the last couple machines on which I have built the software, I would use the standard configure, make, and make install procedure. This time around I decided to create a debian package to use for installing the libraries. It had been a few years since I had created a .deb, so I googled for some tutorials, and found mention of the checkinstall program. After reading a couple blog posts about it I decided to try it out. checkinstall is run instead of "make install" , and will create a .deb file, and then install the newly created package.

cut and tr commands

To help speed up the configure process, I had previously created a file from my other builds that is a grep of my history for all the various "apt get install" commands of the libraries the EFL software needs to compile. Since my current operating system was a freshly installed distribution of Ubuntu, I needed to install the build-essential package first. After looking through my install file, and I decided to create a single apt-get install line with all the packages listed, instead of running each of the installs seperately. I knew I could grep the file, and then pass that to awk or sed, but my skill with either isn't that great. I did a little searching to see what other tools were out there and found the cut command and the tr command. Cut lets you print part of a line. You can extract set a field delimeter with the -d option and then list a range of fields to be printed with the -f option. The tr command can replace a character. I used this to replace the new line character that was printed by the cut command to generate a single line of packages which I piped to a file. A quick edit of the file to add "sudo apt-get install" at the beginning, add execute permissions to the file, and now I have a nice, easy way to install all the needed libraries.

apt-file and checkinstall

At least that was the idea. After installing the libraries, and running configure, I still received errors that libraries were missing. The machines from which my list of libraries was generated, had all been used for various development purposes, so some needed libraries were already installed on them, and so their installation had passed out of my history. Besides echoing to standard out the file configure can't find, it also creates a log file: config.log. Between the two it is relatively easy to figure out what library is needed. Often the libraries needed included their name in the .deb which has to be installed, and finding them is easy with an apt-cache search and grep of the library name. The hardest ones to find were often the X11 based references. In this case, I needed the scrnsaver.h header file. After googling, I found a reference to the needed package (libxss-dev) on Stack Exchange. The answer also showed how to use the apt-file command to determine in which package a file is included. I wish I had run into this before, there a few times where it took a number of searches on the internet to figure out which package I needed to install, and "apt-file find" would have saved time and frustration. A very handy tool for anyone developing on a debian based distribution. As it turns out, that was the last dependency that needed resolved. After a successful configure, and successful compile using the make command, I was ready to try out checkinstall. Running sudo checkinstall, brings up a series of questions about your package, helping you fill out the needed .deb meta-data. I filled out my name and email, name for the package, short description of the package, and let everything else go to the suggested defaults. After, that hit enter and checkinstall will create a debian package and install it for you. If you run "apt-cache search " you will see it listed, and "apt-cache show " will give you the details you created for the package. There are warnings on the Ubuntu wiki not to use this method for packages to be included in an archive or in a ppa. It does work great for a local install, and would use it to install on machines on my local network.

conclusion

After a short side trip into development setup, I'm back writing my application on my new laptop. While I am a big fan of binary packages, Debian being the first GNU/Linux distribution I ever used, sometimes you need to dive in and compile software from source. For me running configure, make, make install has been the easiest way to do this, and these days it usually isn't too difficult to get even moderately complex applications and libraries to build. The most tedious part can be resolving all the dependencies. Now, with apt-file in my tool belt, it will be even faster and easier. I will also be using checkinstall for future compiles. I do like being able to use package management tools to install, and un-install software. I hope others find these tools as useful as I have.

Tuesday, December 3, 2013

The Quest for Accessing LibreOffice Through VB .NET

(The Legend of The Headless Service)

The Goal: use LibreOffice (or OpenOffice) to provide layout and exporting of reports for an ASP .NET based website.

I lean towards LibreOffice as my preferred office suite, and chose to see if I could use the portable version of it to more easily avoid double install issues. Plus this theoretically makes it usable in situations where administration rights are not available. I have gone down the path of using the headless server mode as a Windows service, but it could be started and controlled from a webservice.

Getting the latest LibreOffice to run from VB .NET is not that hard if you are not trying to run in headless mode. Following most of the tutorials out there will get you running without too much problem. You run off the edge of the map whenever you try to connect to a headless version from .NET ("HC SVNT DRACONES" - "Here Be Dragons").

Development Environment
  • Window 8 Pro 64bit
  • Microsoft Visual Basic 2012
  • LibreOffice 4.1 Portable
    • install path: C:\Users\Public\LibreOfficePortable

Creating the service

References 1 and 3 provide detailed instructions for setting up LibreOffice as a service. Please read and follow their instructions for the basic procedure.

In a nut shell:
  1. Download and install Microsoft's "Windows Server 2003 Resource Kit Tools" (Ref. 13). This provides the needed instsrv.exe and srvany.exe programs
  2. Run, in the Command Prompt, "InstSrv.exe LibreOfficeService drive:\path\to\SrvAny.exe"  (may also have to provide the full path to InstSrv.exe).
  3. Run regedit and follow the instructions from Ref. 1 to create the needed keys.
    1. Application: C:\Users\Public\LibreOfficePortable\App\libreoffice\program\soffice.exe
    2. AppParameters: -headless -accept=socket,port=8100;urp; -nologo -nodefault -nofirststartwizard -nolockcheck -norestore -invisible -env:UserInstallation=file:///C:/Users/Public/LibreOfficePortable/Data/settings/$USERNAME
  4. Start and test to see if the service is running. See Ref. 3 for details.
The AppParameters key value are the LibreOffice command line arguments passed by the SrvAny program to LibreOffice when starting it up. This starts up LibreOffice in server mode listening for requests on port 8100. The -env:UserInstallation setting sets the path of LibreOffice's user defaults to a non-standard location to help prevent conflicts with other LibreOffice installations.

Writing the code

‘Bind him hand and foot and cast him into the outer darkness. In that place there will be weeping and gnashing of teeth.’ Matthew 22:13

I can look back now, and things don't seem that horrible, but it was a long couple days of roaming the Net, trying new bits of code, and working my way through one road block after another. I was almost ready to give up before I found the right combination of code to make things connect to a headless LibreOffice. The following test code shows how to create a new calc doc, add some fields to it and save it in ODS and XLS 97 formats.

For the impatient:

Imports System
Imports unoidl.com.sun.star.lang
Imports unoidl.com.sun.star.uno
Imports unoidl.com.sun.star.bridge
Imports unoidl.com.sun.star.frame
Imports Microsoft.Win32
Imports System.Runtime.InteropServices

Module Module1
  Private Const baseInstallationPath As String = "C:\Users\Public\LibreOfficePortable"

  Sub Main()

    InitOpenOfficeEnvironment()

    Dim arg(1) As unoidl.com.sun.star.beans.PropertyValue

    Dim localContext As unoidl.com.sun.star.uno.XComponentContext = uno.util.Bootstrap.bootstrap()

    Dim localServiceFactory As unoidl.com.sun.star.lang.XMultiComponentFactory = localContext.getServiceManager()

    Dim resolver As unoidl.com.sun.star.bridge.XUnoUrlResolver = localServiceFactory.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)

    'Initialize a Windows socket
   
    Dim s As System.Net.Sockets.Socket = New System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, Net.Sockets.SocketType.Stream, Net.Sockets.ProtocolType.IP)

    Dim multiServiceFactory As unoidl.com.sun.star.lang.XMultiServiceFactory = resolver.resolve("uno:socket,host=localhost,port=8100;urp;StarOffice.ServiceManager")

    Dim oDesk As unoidl.com.sun.star.frame.XComponentLoader = multiServiceFactory.createInstance("com.sun.star.frame.Desktop")

    'Create a new calc doc

    Dim oDoc As unoidl.com.sun.star.lang.XComponent = oDesk.loadComponentFromURL("private:factory/scalc", "_blank", 0, arg)

    Dim oSheets As unoidl.com.sun.star.sheet.XSpreadsheets = DirectCast(oDoc, unoidl.com.sun.star.sheet.XSpreadsheetDocument).getSheets
    Dim oXSheets As unoidl.com.sun.star.container.XIndexAccess = oSheets
    Dim oSheet As unoidl.com.sun.star.sheet.XSpreadsheet = DirectCast(oXSheets.getByIndex(0).Value, unoidl.com.sun.star.sheet.XSpreadsheet)
    oSheet.getCellByPosition(0, 0).setFormula("Month")
    oSheet.getCellByPosition(0, 1).setFormula("Dec")
    oSheet.getCellByPosition(1, 1).setValue(3900.37)

    'Save the doc
    arg(0) = Nothing
    'Save to ods format
    Call DirectCast(oDoc, unoidl.com.sun.star.frame.XStorable).storeToURL(PathConverter("C:\Users\Public\Documents\test") + Now.ToString("yyyyMMddHHmm") + ".ods", arg)
    'Save to xsl 97 format
    arg(0) = MakePropertyValue("FilterName", "MS Excel 97")
    Call DirectCast(oDoc, unoidl.com.sun.star.frame.XStorable).storeToURL(PathConverter("C:\Users\Public\Documents\test") + Now.ToString("yyyyMMddHHmm") + ".xls", arg)
    'Close the doc
    oDoc.dispose()
    oDoc = Nothing

  End Sub

  Private Sub InitOpenOfficeEnvironment()

    Dim urePath As String = baseInstallationPath + "\App\libreoffice\URE\bin"
    Dim unoPath As String = baseInstallationPath + "\App\libreoffice\program"
    Dim path As String = String.Format("{0};{1}", System.Environment.GetEnvironmentVariable("PATH"), urePath)
    System.Environment.SetEnvironmentVariable("PATH", path)
    System.Environment.SetEnvironmentVariable("UNO_PATH", unoPath)
  End Sub

  Public Function MakePropertyValue(ByVal cName As Object, ByVal uValue As Object) As Object
    Dim oPropertyValue As unoidl.com.sun.star.beans.PropertyValue = New unoidl.com.sun.star.beans.PropertyValue

    oPropertyValue.Name = cName
    Try
      oPropertyValue.Value = New uno.Any(uValue.GetType, uValue)
    Catch ex As unoidl.com.sun.star.uno.Exception
      ' All your unrecognized types are strings to me
      oPropertyValue.Value = New uno.Any(uValue.ToString)
    End Try

    MakePropertyValue = oPropertyValue
  End Function

  Private Function PathConverter(ByVal file As String) As String
    Try
      file = file.Replace("\", "/")
      Return "file:///" & file
    Catch ex As System.Exception
      Throw ex
    End Try
  End Function

End Module

To get this code working you will have to add references to the following libraries to your project.
  • cli_uno.dll
  • cli_ure.dll
  • cli_uretypes.dll
  • cli_oootypes.dll
  • cli_cppuhelper.dll
  • cli_basetypes.dll
These libraries can be found in the  "...\LibreOfficePortable\App\libreoffice\URE\bin" directory. If you are not using a portable version of LibreOffice, the libraries can be extracted from the installer .msi file (Ref 14).

UPDATE 2013-12-04: After loading LibreOffice 4.2.0.0 Alpha, I started getting the dreaded "Could not load type 'unoidl.com.sun.star.frame.XComponentLoader' from assembly 'cli_oootypes, Version=1.0.8.0, Culture=neutral, PublicKeyToken=ce2cb7e279207b9e'." error. The libraries shipped with the standard version of the office suite don't include everything in the cli_oootypes like previous versions did, or the portable version does. .NET is designed to trust and default to libraries in the GAC, so it will use them over the portable ones. So far the solution to this problem is to uninstall the regular version and just use the portable version.

Summary

These are the first major steps to my goal of creating an ASP .NET report service using LibreOffice. The code works when run from Visual Studio. I take it as a good sign that it won't be too difficult to set up the ASP environment correctly. My next post will be a more detailed breakdown of the code above. Explaining the various roadblocks I ran into, and how they were resolved.

References

  1. Creating a User Defined Service in Windows 7; Tim Davis; blog; 2009-09-28; "http://www.timdavis.com.au/general/creating-a-user-defined-service-in-windows-7/"; last visited 2013-13-03
  2. How to initialize the Windows socket library without admin rights; stackoverflow; forum; 2013-04-18; "http://stackoverflow.com/questions/16090329/how-to-initialize-the-windows-socket-library-without-admin-rights"; last visited 2013-13-03
  3. Run OpenOffice.org 3 as Windows service (updated instructions); A25 Apps; blog; 2009-09-29; "http://blog.a25apps.com/2009/09/29/run-openoffice-org-3-as-windows-service-updated-instructions/"; last visited 2013-13-03
  4. LibreOffice user profile; The Document Foundation;  Wiki; 2013-07-25 (last modified); "https://wiki.documentfoundation.org/UserProfile#Resetting_the_user_profile"; last visited 2013-13-03
  5. [Solved] How to use CLI UNO in MS Basic; Apache OpenOffice community forum; forum; 2009-08-10; "https://forum.openoffice.org/en/forum/viewtopic.php?f=20&t=21494"; last visited 2013-13-03
  6. uno.Any() problem with c#; Apache OpenOffice community forum; forum; 2010-07-01; "https://forum.openoffice.org/en/forum/viewtopic.php?f=44&t=32021#p252656"; last visited 2013-13-03
  7. MBARBON/OpenOffice-UNO-0.07/UNO.pm; meta::cpan; Mattia Barbon; "https://metacpan.org/source/MBARBON/OpenOffice-UNO-0.07/UNO.pm"; last visited 2013-13-03
  8. Programming OpenOffice.org with Visual Basic; Bernard Marcelly, Laurent Godard, Christophe Thibierge; 2006-05-06; Version 0.8; "http://www.kalitech.fr/clients/doc/VB_APIOOo_en.html"; last visited 2013-13-03
  9. .Net: Working with OpenOffice 3; Cypris' lookout; Renaud Bompuis; blog; 2008-11-06; "http://blog.nkadesign.com/2008/net-working-with-openoffice-3/"; last visited 2013-13-03
  10. How can I use OpenOffice in server mode as a multithreaded service?; stackoverflow; forum; 2009-04-09; "http://stackoverflow.com/questions/625241/how-can-i-use-openoffice-in-server-mode-as-a-multithreaded-service"; last visited 2013-13-03
  11. OpenOffice DLL CLI_UNO - Not compatible with .NET 4.0 framework; stackoverflow; forum; 2013-07-19; "http://stackoverflow.com/questions/17746328/openoffice-dll-cli-uno-not-compatible-with-net-4-0-framework"; last visited 2013-13-03
  12. OpenOffice in server mode; Technicus stultissimus; blog; 2011-03-12; "http://tecnicambalandia.blogspot.com/2011/03/openoffice-in-server-mode.html"; last visited 2013-13-03
  13. Windows Server 2003 Resource Kit Tools; Microsoft; "http://www.microsoft.com/en-us/download/details.aspx?id=17657"; last visited 2013-13-03
  14. How To Extract a Single File From a Large MSI (4 Ways); CSI:\>windows; Darwin Sanoy; 2010-04-18; "http://csi-windows.com/blog/all/27-csi-news-general/158-how-to-extract-a-single-file-from-a-large-msi-4-ways"; last visited 2013-13-03
  15. How to make libreoffice headless to work on CentOS 6.3; beta; Diego La Monica; blog; 2013-04-14; "http://diegolamonica.info/how-to-make-libreoffice-headless-to-work-on-centos-6-3/"; last visited 2013-13-03
  16. The Apache OpenOffice API Project; website; "http://www.openoffice.org/api/"; last visited 2013-13-03

Tuesday, June 5, 2012

Your Script-fu is better than mine

I have recently become addicted to the /r/picrequests subreddit on Reddit.com. This has lead to learning the art of colorizing b&w photographs, improving my photo touch up skills, and discovering more about my image editor of choice, the GIMP.

The GIMP has very nice scripting capabilities built into it. It's original scripting language, Script-fu, is based on Scheme. I have read tutorials on creating Script-fu scripts before, and have played briefly with the GIMP's built in scripting console, but never really figured out how things worked. Last week I was browsing through the /r/GIMP subreddit, and ran across a thread which described a manual process for creating a pixel dot mask for your image--a simplistic version of the early newspaper/print halftone dot look.

The described manual process is pretty straight forward, and as mentioned on the thread, perfect for scripting. I've always found it easier to dig in and learn a new language when I have a problem to solve, and this seemed like the perfect "problem" to solve while learning the GIMP's Script-fu system. My first GIMP script can now be found on the GIMP Plugin Registry website.

Tuesday, March 6, 2012

Grow Equality

My home state of Maryland recently passed legislation legalizing same sex marriages. This is a happy event, but not without a cloudy horizon. Even as the bill passed the Maryland House of Delegates (with a high degree of certainty that it would then pass the Maryland Senate and be signed into law by the Governor), there were already people stating they would put this up for referendum during the 2012 elections.
While much of the hard work to get this law passed in Maryland is finished, it does appear that a push to make sure people understand what is at the core of this bill will be recognized, and any referendum to repeal it is defeated. In an effort to do a little more than just vote no to any repeal of the new marriage law, I have created a flier which I hope captures the goal of this law. Please feel free to use any or all of the original artwork for the flier. This work is released under the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication , meaning you are free to use it however you'd like, with no need to license or attribute this work or any remix of this work--although it would be nice to know if people find it useful.

* The flyer in PDF format
* The flyer in Scribus format