Brian Rosenthal's Weblog

3/31/2007

Kiva.org

Filed under: — brian @ 4:27 pm

This is the coolest idea I’ve seen, possibly in my entire life, and the best gift idea that I’ve ever seen:

http://www.kiva.org

Kiva.org is a new idea in economic development. It’s peer-to-peer micro-lending, the way Skype is peer-to-peer telephony.

What the developing world needs most is access to capital, and this site lets you loan as little as $25 to small businesses around the world, to buy farming equipment, inventory for stores, etc.

My wife and I loaned money to street vendor can buy more inventory in her soda business in Nigeria:
http://www.kiva.org/app.php?page=businesses&action=about&id=3847

The idea is: let people loan money to entrepreneurs around the world, interest free. You can basically browse entrepreneurs (like facebook) and see what businesses they run, and what they want to expand.

And the coolest thing is you can give a gift to someone, and they get to choose who gets the loan, and when the loan is repaid, you can either take the money out, or re-loan it to another entrepreneur.

Kiva loans almost $500,000 / month to entrepreneurs in the third world, through interest-free loans to non-profit banks that act as loan officers.

Check out:

NYTimes:
NYT coverage

CNN:
CNN Coverage

I learned about this through Matt Flannery, the founder, and now my friend Zvi Boshernitzan, is now helping them scale up their web site. (I’m pretty impressed at its speed… Kiva.org is super-fast)

Commonality Variability Analysis

Filed under: — brian @ 4:25 pm

I just went to SDWest (awesome!) and learned about commonality variability analysis. I think it’s one of the most important advances in computer science theory out there, and it’s worth a blog entry. Zvi and I spent years trying to come up with a core idea for how to measure the virtues of abstractions, and it’s the closest thing I’ve seen to a foundational theory.

CVA has two important ideas:
1. Contain what varies and only what varies.
2. To find abstractions, find differences that play the same role.

2/8/2007

Programs that are too complex.

Filed under: — brian @ 2:40 am

Programs should be no more complicated than the problems they are trying to solve. Ideally, they should be much less complicated, because the complexity can be reduced to interfaces to extremely mature software.

However, there is an intrinsic complexity to most problems, and in an effort to express and control that complexity, programs often invent layer upon layer of complexity, making the management of such applications expensive, and sometimes, impossible.

12/13/2006

Finally… linguistic parsing.

Filed under: — brian @ 12:24 pm

http://www.linuxdevices.com/news/NS6184618910.html

Chickenfoot…

Filed under: — brian @ 12:23 pm

An amazing plugin. Will revolutionize medicine by automating medical billing.

Agh. Mysql is dropping support for debian linux.

Filed under: — brian @ 12:22 pm

http://developers.slashdot.org/article.pl?sid=06/12/13/1515217&from=rss

9/5/2006

Tools that everyone should learn.

Filed under: — brian @ 2:00 am

Just like many people who grew up in the 60’s and 70’s resisted the Internet and computers in general, only to decide that they had to catch up later, our generation is missing the use of the Internet in collaboration.

Every single person should learn:
1. How to create a wiki and use it to keep notes on projects.
2. How to use del.icio.us bookmarking.

6/21/2006

Django

Filed under: — brosenth @ 11:06 pm

Okay, I’m excited about a web framework. Django is everything I could ever want in a web framework.

- A model for the Data-tier
- MVC separation
- A flexible and powerful templating language
- An integrated user model
- specification-driven, for the most part.
- developed with a very good methodology.

Seems very much like what we’ve been doing here at Robocommerce in python. I think it’s about time to open-source our results.

1/18/2006

How to Build Enterprise Software

Filed under: — brosenth @ 12:23 pm

“Efficient Enterprise Programming”

Chapter I: Introduction

No field suffers more from redundancy and re-invention than software development.

The goal of this book is to provide a software developer with a paradigm to eliminate as much risk as possible from developing new software for the enterprise. In this book, we attempt to outline techniques that can make some of the most time-intensive and error-prone parts of software trivial and easy.

Each technique is explained with (a) a discussion of the issue it addresses, (b) a theoretical description of the technique, © a recipe for implementing the technique.

Some of the techniques in this book are new and developed by the authors. Others are well-known and humbly described based on our experience.

The structure of this book will be:

Chapter II: Measuring programming techniques

One standard is that programmers, when they adopt these techniques, rarely ever go back.

Intent.
You’re writing software for someone else, possibly another developer, possibly a future you.

Conciseness.

Chapter III: Languages - necessary features of a language for efficient enterprise programming.

Chapter IV: Programming the data layer of enterprise applications
- dbentity

Chapter V: Testing
A. Unit Regression Testing: Build a growing library of regression tests.

B. Funcational Testing: Embrace functional testing tools
- Selenium

Chapter VII: User Interfaces
- Model View Controllers
- Templating

Chapter VI: Specification-driven programming
- Forms
- Reports

Chapter VII: Data Manipulation
- Transforms - a higher level language

Traditionally most programs spend most of their time manipulating objects, arrays, and dictionaries. Here, I describe a technique to eliminate most of that.

Chapter VIII: Programming with ledgers
- The core ideas behind ledger-based programming
- Types of ledgers - operational and double-entry

5/22/2005

Evaluating Third party CMS software to integrate with

Filed under: — brian @ 3:11 pm

Plone: An excellent cms. We would write a “cmsclient” class which would access the ZODB for content and possibly cache results.

Xaraya: Seems worth looking at. We would write a “cmsclient” class to access the xaraya database directly.

Midgard: Too heavy a footprint. Requires re-compiling PHP and adding lots of extensions. Spent two days trying to install it to no avail.

Our own CMS: Seems like a lot of work for a commoditized product.

RoboCMS

Filed under: — brian @ 3:05 pm

Here’s the best option I’ve got so far:

Write a “cms client” class and manage the content in another, already built application.

The cms client would expose only a few methods:
1. get($id_or_path)
2. get_children($id_or_path)
3. get_parents($id_or_path) … would return the same as the PARENTS array in Zope.

Then, there could be different “cms clients” depending on what third-party content management software a user would use.

Content Management - the state of the world.

Filed under: — brian @ 3:02 pm

Well, prompted by Alan Runyan, co-author of Plone, we’ve been thinking a lot recently about Content Management lately.

Because E-commerce is more about content management than we originally thought.

If you take a look at some of the most successful e-commerce sites, you’ll find a lot of “content” (wine.com, proactive.com, etc.).

As much as these sites showcase a product catalog, they are far more about a lifestyle brand, and to effectively communicate that message, a company must have an easy-to-use content management system.

So, Robocommerce needs a content management system.

Well, we already have one. Our current strategy is to allow users to edit content via an ftp-style interface (Using WinSCP), where they have permissions over their content directory. That works fine for editing the site, but the approach has a few glaring gaps:

1. It does not support “properties".
2. It does not support sort order.
3. It doe not support titles for content.
4. It does not support content re-use.
5. It does not support an end-user triggering a commit into our version control system.

It’s strengths are:
1. It supports contextual editing (through a separate interface).
2. It leverages the file system.

In a future posting, I’ll outline the direction that we’re headed.

4/10/2005

Adding a drop shadow to a web page that is centered

Filed under: — brian @ 2:46 pm

Adding a background that includes a drop shadow to a web page is tricky because the drop shadow must stay around the content.

Here is the effect:
Click here to view the page below


<html>
<head>
<base href="http://www.robocommerce.com/" />
<title>Centering Test<title>
<style type="text/css">
<!--
body {
    margin: 0px;
    background-image: url(/test/aaron/images/bg.jpg);
    background-position: center top;
}
div#main {
    margin: 56px 0px 0px 10px;
    width: 739;
    height: 647;
    background-image: url(/test/aaron/images/bg2.gif);
    background-position: top;
    color: white;
}
// -->
</style>
</head>
<body>
<center>
<div id="main">Body text</div>
</center>
</body>
</html>

Building a VB 6 Installer

Filed under: — brian @ 11:33 am

1. Download and install “Microsoft Windows Installer 1.1″
2. Compile ("make") the output of your VB project, and close VB 6.
3. Run the installer program (Visual Studio 6 -> Enterprise Tools)
4. Create a new project ("VB Installer Project")
5. In the “File System” section, create a folder in the “User’s Start Menu” called “Programs", another inside with your company name, then move the existing shortcut in there.
6. Set the target for where the MSI file will be created (Project -> Properties -> Output)
7. Select Build -> Build configuration -> Release
8. Build the project

4/5/2005

Three dimensional documentation

Filed under: — brian @ 12:54 am

Documentation for a system should really be three dimensional - it should be by subsystem, topic… then, by “layer” (user interface, design, programming) … like google maps.

3/20/2005

Customizing plone sites

Filed under: — brian @ 3:09 pm

Well, I’ve now customized a fair enough amount of plone sites to publish a few helpful hints on the subject. Here’s what I’ve learned.

Who should read this article

This article is written for someone who knows how to program, knows a bit about python, and wants to learn more about setting up plone web sites. It is written for people who want to do significant customization of the look and feel of plone sites and want a quick read on how I did this one in particular. I have included much of the code I used for the customization here, to better describe exactly how I did what I did. You will need a bit of exposure to Zope Page Templates. To try this out, you will need to have plone installed on your Zope web server.

1. Overview

Customizing a plone site is usually nothing more than customizing the default skin, so it’s in that light that you want to think about it.

I’m going to describe how I recently customized a plone site to look like letsgetready.org. The new site is here. There were many things involved that are common for plone customizations. They are:

  1. Having a splash page
  2. Rebuilding the main menu to be “section-aware”
  3. Rebuilding the left menu to use only published content.
  4. Making image alignment work
  5. Properly handling external links
  6. Adding a link in the footer to manage the site.
  7. Changing the logo
  8. Optimizing for performance.

2. Getting started.

2a. Uploading images:

Create a folder /images/ off the root and upload images there throughout this project. You might want to do this part entirely in advance, or not.

3. Customize the columns

We want to have two columns (not three), so go and set that in the properties of the root of the plone site. There is a list of portlets to be displayed on the left side and the right side. Remove those on the right and leave only the navigation on the front. You might want to leave logging in on the left.

4. Set the colors

That would be here:
plone_styles/base_properties (for setting colors)

5. Change the footer and colophon to what you want.

plone_templates/colophon (making it smaller and adding link to RoboCommerce)
plone_templates/footer (adding a “manage” link to /folder_contents")
The styles here are in:
plone_styles/plone.css

Colophon:


<p i18n:translate="text_conforms_to_standards" class="discreet">
        Powered by <a target="blank" href="http://www.plone.org">Plone</a>
        and <a target="blank"
        href="http://www.robocommerce.com">RoboCommerce</a>
</p>

Footer:


<span i18n:translate="description_copyright" tal:omit-tag="">
© 1998-2005 Let's Get Ready! 45 Columbus Avenue New York, NY 10023-6992.
<a href="folder_contents">manage</a>
</span>

6. Remove most of this, to not include the byline (leave the date modified here)
plone_content/document_byline (to remove the username)

7. I wanted this on the bottom left, so I customized its look:
plone_templates/global_searchbox

8. Change the logo:
plone_images/logo.jpg (to logo.gif, possibly)… note, you must also change the base_properties to do this
Also, change the logo’s position here:
plone_styles/plone.css

9. Make external links open in _blank windows, and also not have little icons next to them by looking in this file:
plone_ecmascript/plone_javascripts.css (to make external links not have an icon next to them)

Here is the link, valid as of March, 2005:
http://plone.org/documentation/how-to/open-external-links-in-new-window

10. This is where we’re going to put the main menu:
plone_templates/global_sections

Remove most of it, and instead use a macro defined in
/includes
… called top_menu. Notice how it is “section-aware":


<div tal:omit-tag="" metal:define-macro="top_menu">
<table cellpadding=0 cellspacing=0 border=0 align=left>
<tr>
<td><a href="/about/"><img alt="About"
		border=0
        tal:define="selected python:test(here.getSectionFromURL() == 'section-about', 1, 0)"
        tal:attributes="src python:test(selected, '/images/mainmenu/about_selected.gif'
                                , '/images/mainmenu/about_unselected.gif');
                       onmouseout python:test(selected
                              , 'this.src='/images/mainmenu/about_selected.gif''
                              , 'this.src='/images/mainmenu/about_unselected.gif'');"
	onmouseover="this.src='/images/mainmenu/about_mouseover.gif';"
	onmouseout="this.src='/images/mainmenu/about_unselected.gif';"
	src="/images/mainmenu/about_unselected.gif"></a></td>
<td bgcolor="white"><img src="/images/tp.gif" width="1" height="1"></td>
<td><a href="/programs/"><img alt="Programs"
		border=0
        tal:define="selected python:test(here.getSectionFromURL() == 'section-programs', 1, 0)"
        tal:attributes="src python:test(selected, '/images/mainmenu/programs_selected.gif'
                                            , '/images/mainmenu/programs_unselected.gif');
                                       onmouseout python:test(selected
                              , 'this.src='/images/mainmenu/programs_selected.gif''
                              , 'this.src='/images/mainmenu/programs_unselected.gif'');"
	onmouseover="this.src='/images/mainmenu/programs_mouseover.gif';"
	onmouseout="this.src='/images/mainmenu/programs_unselected.gif';"
	src="/images/mainmenu/programs_unselected.gif"></a></td>
<td bgcolor="white"><img src="/images/tp.gif" width="1" height="1"></td>
<td><a href="/get_involved/"><img alt="Get Involved"
		border=0
        tal:define="selected python:test(here.getSectionFromURL() == 'section-get_involved', 1, 0)"
        tal:attributes="src python:test(selected, '/images/mainmenu/getinvolved_selected.gif'
                        , '/images/mainmenu/getinvolved_unselected.gif');
                       onmouseout python:test(selected
                              , 'this.src='/images/mainmenu/getinvolved_selected.gif''
                              , 'this.src='/images/mainmenu/getinvolved_unselected.gif'');"
	onmouseover="this.src='/images/mainmenu/getinvolved_mouseover.gif';"
	onmouseout="this.src='/images/mainmenu/getinvolved_unselected.gif';"
	src="/images/mainmenu/getinvolved_unselected.gif"></a></td>
<td bgcolor="white"><img src="/images/tp.gif" width="1" height="1"></td>
<td><a href="/resources/"><img alt="College Access Resources"
		border="0"
        tal:define="selected python:test(here.getSectionFromURL() == 'section-resources', 1, 0)"
        tal:attributes="src python:test(selected, '/images/mainmenu/resources_selected.gif'
                                , '/images/mainmenu/resources_unselected.gif');
                       onmouseout python:test(selected
                              , 'this.src='/images/mainmenu/resources_selected.gif''
                              , 'this.src='/images/mainmenu/resources_unselected.gif'');"
	onmouseover="this.src='/images/mainmenu/resources_mouseover.gif';"
	onmouseout="this.src='/images/mainmenu/resources_unselected.gif';"
	src="/images/mainmenu/resources_unselected.gif"></a></td>
<td bgcolor="white"><img src="/images/tp.gif" width="1" height="1"></td>
<td><a href="/donate/"><img alt="Donate"
		border="0"
        tal:define="selected python:test(here.getSectionFromURL() == 'section-donate', 1, 0)"
        tal:attributes="src python:test(selected, '/images/mainmenu/donate1_selected.gif'
                            , '/images/mainmenu/donate1_unselected.gif');
                       onmouseout python:test(selected
                              , 'this.src='/images/mainmenu/donate1_selected.gif''
                              , 'this.src='/images/mainmenu/donate1_unselected.gif'');"
	onmouseover="this.src='/images/mainmenu/donate1_mouseover.gif';"
	onmouseout="this.src='/images/mainmenu/donate1_unselected.gif';"
	src="/images/mainmenu/donate1_unselected.gif"></a></td>
<td><img src="/images/mainmenu/end.gif"></td>
</tr>
</table>
</div>

11. plone/get_menu should be a python method to get a string that can be put in the left menu.

	

# get the section… contentPath = context.portal_url.getRelativeContentPath(context) obj = context parents = [] for i in range(0,len(contentPath) - 1): parents.append(obj.getParentNode()) obj = obj.getParentNode() parents.reverse() parents.append(context) print ‘<div id="left_menu">’ if len(parents) > 0: title = parents[0].get_short_title() print ‘'’<a class="level1″ href="%s">%s”’ % (parents[0].absolute_url_path(), title) for obj in parents[0].objectValues(): if (obj.id == ‘index_html’): continue if hasattr(context, ‘portal_workflow’): workflow = context.portal_workflow try: title = obj.get_short_title() if workflow.getInfoFor(obj,’review_state’)==’published’: print ‘'’<div class="level2″><a class="level2″ href="%s">%s</a> <div style="margin: 0px; padding: 0px;"><img src="/images/menu/TopLevelBar.gif"></div> ‘'’ % (obj.absolute_url_path(), title) for obj2 in obj.objectValues(): if (obj2.id == ‘index_html’): continue if workflow.getInfoFor(obj2,’review_state’)==’published’: print ‘'’<a class="level3″ href="%s">> %s”’ % (obj2.absolute_url_path(), obj2.get_short_title()) for obj3 in obj2.objectValues(): if (obj3.id == ‘index_html’): continue if workflow.getInfoFor(obj3,’review_state’)==’published’: print ‘'’<a class="level4″ href="%s">> %s”’ % (obj3.absolute_url_path(), obj3.get_short_title()) for obj4 in obj3.objectValues(): if (obj4.id == ‘index_html’): continue if workflow.getInfoFor(obj4,’review_state’)==’published’: print ‘'’<a class="level5″ href="%s">> %s”’ % (obj4.absolute_url_path(), obj4.get_short_title()) for obj5 in obj4.objectValues(): if (obj5.id == ‘index_html’): continue if workflow.getInfoFor(obj5,’review_state’)==’published’: print ‘'’<a class="level6″ href="%s">> %s”’ % (obj5.absolute_url_path(), obj5.get_short_title()) print ‘</div>’ except: pass print ‘</div>’ return printed

12. We’ll need a function like this:
plone/get_short_title
… because sometimes we’ll need a shorter title to go into the menu. NOTE: You’ll have to add this property short_title in the ZMI (just under the plone root):

try:
    chain = context.aq_chain
except:
    chain = [context]
if chain[0].hasProperty('short_title'):
    return getattr(context, 'short_title')
else:
    return context.title_or_id()

13. plone_templates/header

Eyeball this and see what is not necessary. We don’t need a minimum width requirement… we don’t need different stylesheets for small, medium, and large text…

14. plone_styles/ploneCustom.css

Here is where any left_menu styles should go.

15. plone_portlets/portlet_navigation (to change the look and features of the menu)

Here is where get_menu should be called, and I replaced the entire contents of portlet_navigation to the following (contents of the macro, not the file)


<div class="left_navigation" tal:content="structure here/get_menu"></div>

16. Allowing end-users to manage content on the homepage.

The homepage was built by just creating a template: index_html in the root. It has access to all methods, so it can basically copy header and main_document from the skins.

However, you want a user to be able to manage its contents.

Here is how you do that. You add something like this to the homepage, where homepage_content/left and …/right are valid content nodes in plone:

<div tal:content="structure here/homepage_content/left/CookedBody"
    style="position: absolute; top: 247px; left: 0px;">
</div>
<div tal:content="structure here/homepage_content/right/CookedBody"
    style="position: absolute; top: 420px; left: 490px;">
</div>

Mozilla Web Developer Tools 0.8

Filed under: — brian @ 2:45 pm

1. If you develop web pages, install the Developer Tools located here (or a more recent version if you can find one):
Web Developer Tools v0.8

This will add a toolbar to your mozilla browser with menus to help you do the following:
1. Forms -> View details lets you easily view the details of forms on the screen
2. CSS -> View CSS wil list out all of the CSS files so you can figure out what is causing your page to look the way it does. You can even edit the CSS on the fly to experiment around with different options.
3. Forms -> Convert POSTs to GETS will let you generate links that you can embed in other places
4. Information -> Display ID and Class Details will actually show you the id and class of any block elements on the page.
5. Information -> Display Topographic Information will show you the z-index levels on the page
6. Miscellaneous -> Clear Cache is a quick link to clear your cache.
7. Outline -> Block Elements and Outline->Table Cells
8. Resize -> 800 x 600 is good if you’re interested.
9. Validation -> Validate HTML and Validate CSS
10. There is a quick link to view source

3/14/2005

Netsuite

Filed under: — brian @ 1:25 pm

Good front page ui. Really interesting software package
http://www.netsuite.com/portal/home.shtml

2/25/2005

IBM getting behind PHP

Filed under: — brian @ 3:04 pm

http://developers.slashdot.org/article.pl?sid=05/02/25/1311249&tid=169

Looks like IBM is thinking like us.

2/23/2005

The wrong way to build accounting and inventory management systems

Filed under: — brian @ 2:36 pm

Well, I have spent two years now doing nothing but building back-end e-commerce technology, and I wanted to just briefly say a few of the thing I learned, which will save you time, if you are trying to build back-end technology that tracks financial transactions, or inventory transactions.

Accounting is a really important concept to understand before you begin building these systems. The reason is that accounting theory specifies how to build a system where you can never have contradictory information.

Here is the first wrong way to build an accounting system:

1. Have a table for products, with a “quantity” field that you update when you change the quantity of the product.

Now, you say, well, I’ll keep a log of changes, and then I’ll know why the inventory changed.

Really? What will you do if the changes do not add up to the quantity field?

Well, you say, I’ll adjust the quantity field then.

Well, then, why would you have the field in the first place?

It’s redundant. Completely redundant, and completely unable to be audited.

2. Build an e-commerce system without a centralized ledger

Wrong. Wrong. Wrong. Wrong.

No matter how you try to build an e-commerce system, if you don’t have a centralized ledger, you won’t be able to have a good idea of what’s going on in your system.

Having a ledger is actually quite easy. You have two tables: “transactions” and “ledger".

You define a set of account types, where an account is a combination of an account type and an account id.

For example, the account storing how much customer store credit someone has is ("ACCT_TYPE_STORE_CREDIT", customer_id).

Now, the transaction model is a transaction is a (type, from_entries, to_entries, args)

You negate the from_entries when you enter them in the ledger, but they have to be positive before they are negated.

Hmmm…. feel free to contact me to talk about this if you’re doing it… we spent a year and a half learning how to do this one right.

Powered by WordPress