<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Category: open-source | Strongly Emergent]]></title>
  <link href="http://stronglyemergent.com//blog/categories/open-source/atom.xml" rel="self"/>
  <link href="http://stronglyemergent.com//"/>
  <updated>2017-10-31T10:50:08-07:00</updated>
  <id>http://stronglyemergent.com//</id>
  <author>
    <name><![CDATA[Strongly Emergent Systems]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Generating vCards In Python]]></title>
    <link href="http://stronglyemergent.com//blog/2011/generating-vcards-in-python/"/>
    <updated>2011-05-02T15:21:10+00:00</updated>
    <id>http://stronglyemergent.com//blog/2011/generating-vcards-in-python</id>
    <content type="html"><![CDATA[<p>At work recently, I had to test an address book application.
Part of the requirement for testing was that it handle large numbers of contacts gracefully - 100, 1000, 5000, or 10,000.
My personal address book is nowhere near that big
(and I&rsquo;m not about to use it for testing),
so I turned to Python.
[The vCard format][vcard-wiki] is pretty much a special kind of text file,
so it&rsquo;s easy to create new vCards,
and a vCard can contain multiple contacts by just concatenating contacts.</p>

<p>I didn&rsquo;t find exactly what I needed already in existence,
so I wrote up a basic script to do it, and in case anyone else needs it, here it is.
It is released under the Apache Software License 2.0,
and I hope you find it useful.</p>

<p><noscript><pre>
#!/usr/bin/python

&quot;&quot;&quot;Generates an abitrary number of valid .vcf vCard contacts based on the
parameters set at the beginning of the file. See also:
http://softwareas.com/vcard-for-developers
http://en.wikipedia.org/wiki/VCard
&quot;&quot;&quot;

import random, sys

################################## Parameters ##################################

# We&#39;ll use this data no matter what the user tells us.

# What fields shall be populated?
target_fields = {&quot;Name&quot;:True,
                 &quot;FullName&quot;:True,
                 &quot;Organization&quot;:True,
                 &quot;Address&quot;:True,
                 &quot;Title&quot;:True,
                 &quot;Phone&quot;:True,
                 &quot;Email&quot;:True,}

# Data that we&#39;ll use to populate the cards&#39; fields.
first_names = [&quot;Alice&quot;, &quot;Bob&quot;, &quot;Carol&quot;, &quot;David&quot;, &quot;Elena&quot;, &quot;Farquahd&quot;, &quot;Gretel&quot;,
               &quot;Hans&quot;, &quot;Iris&quot;, &quot;Junichi&quot;, &quot;Khalisha&quot;, &quot;Lee&quot;, &quot;Mina&quot;, &quot;Nassif&quot;,
               &quot;Oba&quot;, &quot;Prudha&quot;, &quot;Hida&quot;, &quot;Kaiu&quot;, &quot;Aaron&quot;, &quot;Sangamon&quot;,
               &quot;Ferdinand&quot;, &quot;Sanjay&quot;, &quot;Asok&quot;]
last_names = [&quot;Smith&quot;, &quot;Jones&quot;, &quot;Smythe&quot;, &quot;Jorgenson&quot;, &quot;Kim&quot;, &quot;Luxury-Yacht&quot;,
              &quot;Throatwarbler-Mangrove&quot;, &quot;Cooper&quot;, &quot;Black&quot;, &quot;Ahmedinejad&quot;,
              &quot;al-Tikriti&quot;, &quot;al-Bagram&quot;, &quot;von Trapp&quot;, &quot;von der Wallenheim&quot;,
              &quot;Gamgee&quot;, &quot;Proudfoot&quot;, &quot;Brewer&quot;, &quot;Kagehiro&quot;, &quot;Ng&quot;,
              &quot;Nguyen&quot;, &quot;Salzmann&quot;, &quot;Bear&quot;, &quot;Powers&quot;,&quot;Kusanagi&quot;, &quot;Dengo&quot;,
              &quot;Mukherjee&quot;,&quot;Balaam&quot;]

# Street numbers will be generated at random.  All addresses are
# situated in Anytown, CA, ZIP 12345, United States of America.

streets = [&quot;Paper Street&quot;, &quot;Fictional Lane&quot;, &quot;Placid Avenue&quot;, &quot;Blank Road&quot;,
           &quot;Suspicious Parkway&quot;]

orgs = [&quot;Monty Python&#39;s Flying Circus&quot;, &quot;Golden Egg Bonus Company, LLC&quot;,
        &quot;Dewey Cheatham &amp; Howe, Tax and Family Law&quot;, &quot;Improv Everywhere&quot;,
        &quot;Owl-Stretching Enthusiasts&#39; Club&quot;, &quot;International R. Mutt Fan Club&quot;,
        &quot;Paper Street Soap Company&quot;, &quot;River City Pool Table Company&quot;,
        &quot;Desert Bus Runs&quot;, &quot;Impossibilities Inc&quot;, &quot;The X-Men&quot;]

titles = [&quot;Mercenary&quot;, &quot;Chief Tomfoolery Engineer&quot;, &quot;Nonsense Supervisor&quot;,
          &quot;Skylark&quot;, &quot;Isn&#39;t It About Time For Lunch&quot;, &quot;Famous Author&quot;,
          &quot;Fictional Person&quot;, &quot;Space Traveller&quot;, &quot;Architect&quot;,
          &quot;International Person Of Mystery&quot;, &quot;Sith Lord&quot;, &quot;Sith Apprentice&quot;,
          &quot;Sith Intern&quot;, &quot;Archaeologist&quot;, &quot;Scout&quot;, &quot;Heavy&quot;, &quot;Sniper&quot;]

# Phone numbers will be generated in the form 555-NNNN.
# Email addresses will be generated in the form  firstname.lastname@example.com

################################## Actions ###################################

class CardFiller:
    &quot;&quot;&quot;A class whose instances take the basic dataset we&#39;re working with,
    shuffle it, and grind through generating VCard entries based on it. &quot;&quot;&quot;
    def __init__(self, first_names, last_names, streets, orgs, titles):
        self.first_names = first_names
        self.last_names = last_names
        self.streets = streets
        self.orgs = orgs
        self.titles = titles

    def prepare(self):
        for lst in [self.first_names, self.last_names,
                    self.streets, self.orgs, self.titles]:
            random.shuffle(lst)

    def fill_card(self, target_fields, position):
        &quot;&quot;&quot;Takes data and fills in fields, then creates a list of formatted
        lines that can be written into a .vcf file. Takes a position argument
        that it basically interprets as modulo the length of the list.&quot;&quot;&quot;
        new_card = [&quot;BEGIN:VCARD&quot;, &quot;VERSION:2.1&quot;,]
        # Fill the Name field.
        if &quot;Name&quot; in target_fields:
            namefield = &quot;N:&quot;
            namefield += str(self.last_names[position % len(self.last_names)])
            namefield +=&quot;;&quot;
            namefield += str(self.first_names[position % len(self.first_names)])
            new_card.append(namefield)
        if &quot;FullName&quot; in target_fields:
            fnamefield = &quot;FN:&quot;
            fnamefield += str(self.first_names[position % len(self.first_names)])
            fnamefield += &quot; &quot;
            fnamefield += str(self.last_names[position % len(self.last_names)])
            new_card.append(fnamefield)
        if &quot;Organization&quot; in target_fields:
            orgfield = &quot;ORG:&quot;
            orgfield += str(self.orgs[position % len(self.orgs)])
            new_card.append(orgfield)
        if &quot;Title&quot; in target_fields:
            titlefield = &quot;TITLE:&quot;
            titlefield += str(self.titles[position % len(self.titles)])
            new_card.append(titlefield)
        if &quot;Phone&quot; in target_fields:
            phonefield = &quot;TEL;WORK;VOICE:(&quot;
            phonefield += str(random.randrange(100,999))
            phonefield += &quot;) 555-&quot;
            phonefield += &quot;%04d&quot; % random.randrange(0,9999)
            new_card.append(phonefield)
        if &quot;Address&quot; in target_fields:
            addrfield = &quot;ADR;WORK:;;&quot;
            addrfield += str(random.randrange(1,18234))
            addrfield += &quot; &quot;
            addrfield += str(self.streets[position % len(self.streets)])
            addrfield += &quot;;Anytown;CA;12345;United States of America&quot;
            new_card.append(addrfield)
        if &quot;Email&quot; in target_fields:
            emailfield = &quot;EMAIL;PREF;INTERNET:&quot;
            emailfield += str.lower(self.first_names[position % len(self.first_names)])
            emailfield += str.lower(self.last_names[position % len(self.last_names)])
            emailfield += &quot;@example.com&quot;
            new_card.append(emailfield)
        new_card.append(&quot;REV:%d&quot; % random.randrange(100,500))
        new_card.append(&quot;END:VCARD&quot;)
        return new_card


def rolodex_engine(card_limit, target_fields):
    &quot;&quot;&quot;Iterates over a range to generate a list of strings that can be
    sent to file or to stdout and which constitute a valid vcard file.
    Most programs that read vcards can accept a file that contains
    multiple vcards - all you have to do is concatenate them.&quot;&quot;&quot;
    card_engine = CardFiller(first_names, last_names, streets, orgs, titles)
    card_engine.prepare()
    rolodex = []
    for i in range(1, card_limit+1):
        new_card = card_engine.fill_card(target_fields, i)
        for line in new_card:
            rolodex.append(line)
    return rolodex

################################### Execution ##################################

if __name__ == &#39;__main__&#39;:
    &quot;&quot;&quot;Run a variety of sanity checks regarding the arguments to the
    script.  If there are no command-line arguments, give the user a
    hint. If the arguments are weird, quit and ask them to try
    again. User input and the filesystem: two pain-in-the-butt parts
    of software engineering.&quot;&quot;&quot;
    # Sanity checks.
    if len(sys.argv) != 3:
        print &quot;This script requires exactly two arguments: \n&quot;,
        print &quot;* The number of vCards to generate \n&quot;,
        print  &quot;* The name of the file to store them in. \n&quot;
        sys.exit()
    if type(sys.argv[2]) != type(&quot;string&quot;):
        print &quot;The first argument must be a number, the second a name.&quot;
        sys.exit()
    try:
        int(sys.argv[1])
    except ValueError:
        print &quot;The first argument must be a number, the second a name.&quot;
        sys.exit()
    if int(sys.argv[1]) &gt; 2**16:
        print &quot;Try generating less than 65,000 cards.&quot;
        sys.exit()
    if len(sys.argv[2]) &gt; 128:
        print &quot;Try a shorter filename.&quot;
        sys.exit()
    card_limit = int(sys.argv[1])
    card_export_file = sys.argv[2]
    # Writing to disk.
    try:
        with open(&quot;./%s&quot; % card_export_file, &quot;r&quot;) as rolodex_file:
            print &quot;A file with that name already exists.&quot;
            sys.exit()
    except IOError, ioerr_msg:
        try:
            with open(&quot;./%s&quot; % card_export_file, &quot;w&quot;) as rolodex_file:
                rolodex = rolodex_engine(card_limit, target_fields)
                for c in rolodex:
                    rolodex_file.write(c)
                    rolodex_file.write(&quot;\n&quot;)
        except IOError, ioerr_msg:
            print &quot;The script couldn&#39;t create a file for the vcards.&quot;
            print &quot;The specific problem was &#39;%s&#39;&quot; % ioerr_msg
</pre></noscript><script src="https://gist.github.com/brighid/58519d5849701a1f4ec2.js?file=vcard_generator.py"> </script></p>

<p>Writing this was basically like doing sit-ups in Python&mdash;not really challenging,
but demanded like all serious tasks that you sit down and devote time and concentration to it.
After that, results come easily.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[I'll Build My Own Phone OS! With Blackjack! And Hookers!]]></title>
    <link href="http://stronglyemergent.com//blog/2010/ill-build-my-own-phone-os-with-blackjack-and-hookers/"/>
    <updated>2010-08-16T06:01:41+00:00</updated>
    <id>http://stronglyemergent.com//blog/2010/ill-build-my-own-phone-os-with-blackjack-and-hookers</id>
    <content type="html"><![CDATA[<p>System administration is about making hard decisions.</p>

<p>This just amounts to saying that it&rsquo;s knowledge work.
More specifically, it&rsquo;s about making annoying, difficult decisions about computers and networks.
What parts of the system are trustworthy, and what can enter the system that I shouldn&rsquo;t trust?
What does the current state of the system tell me about what&rsquo;s likely to break?
What looks urgent but can be safely ignored? What is the tradeoff curve of time and money that solutions to my current problem offer?
System administration requires a specific body of technical knowledge and experience to answer questions like that.
That&rsquo;s why I think that, despite a certain amount of doomsaying, the world is going to need sysadmins for a good long time.
The underlying body of technical knowledge will change, certainly, but sysadmins, like other knowledge workers, are people who can make hard decisions in a specific area of expertise, and I believe we&rsquo;re going to need that for the whole of the foreseeable future.</p>

<p>One of the primary reasons that we need that is to spare other people from making hard decisions - both people who have better things to do than make those specific decisions, and people who don&rsquo;t have the expertise necessary to make good decisions in the given area.
I believe that the open source movement consistently blurs together those kinds of people.</p>

<p>Now, I should make it clear up front that I love the open source community.
I am writing this post on a machine whose OS descends from open-source BSD, sending it to a machine that runs an open-source web server on another open-source OS, I spend umpty-ump hours a day staring at emacs, and my plans for the future include contributing both code and dollars to the open-source movement.
I acknowledge that the world would be tremendously impoverished if open-source software either stopped existing or never had existed, and I want a future in which more of the world runs on open-source software.
I feel the same way about open-source software that I feel about America: its flaws frustrate me mostly because it could be <strong>so awesome</strong> if they were solved.</p>

<p>That said - the fundamental bargain that open-source software offers, especially that which descends most directly from the UNIX tradition, is that Great Power can be yours if you&rsquo;re willing to scale a learning curve.
That&rsquo;s a good bargain - but it requires that you take up the burden of making hard decisions at least for a little while.
That&rsquo;s where we start to run into trouble, because the willingness to accept that bargain is not universal - people may be willing or unwilling to accept it at different times, and those times vary among people.
The other bargain that software can offer is that basic functionality can be yours quickly, and who knows whether Great Power is available or not.
Often it isn&rsquo;t.</p>

<p>People don&rsquo;t take that second bargain because they&rsquo;re stupid.
They take it because they have better things to do with their time, because they need a specific task done instead of Great Power, or because they&rsquo;ve been burned before in the process of trying to use the Great Power of complicated tools.
I&rsquo;m fine with that: not everyone should be obliged to be a sysadmin.
As both a sysadmin and a developer, it&rsquo;s my job to make hard decisions that save other people from making hard decisions for just this reason.
If I just pass along hard decisions, then I probably haven&rsquo;t done well by the users.
The problem isn&rsquo;t even the hard decisions, really - it&rsquo;s when you force your users to make them, especially when you <em>surprise</em> them with having to make those decisions.</p>

<p>Yes, a computer is a complicated general-purpose tool.
It is built of a huge assembly of spectacularly fiddly little parts, both physical and logical.
It is a wonder of the modern age&mdash;but so is a 2010 Honda Civic, and most people want to use that to get from place to place, rather than to be impressed with the wonders of the era they live in.
Just the same with computers: if you sit down at a computer and start thinking about the computer itself, you&rsquo;re probably a developer, a sysadmin, or an enthusiast.
More likely, you sat down at a computer because you have a task that you want to do.
You want to send email, play Farmville, or do your taxes.
You want to use the tools to do that task, not to fiddle with the tools themselves.</p>

<p>Software for a general audience is a failure if it asks everyone to be their own sysadmin.
<a href="http://www.amazon.com/gp/product/0789723107?ie=UTF8&amp;tag=stronemerg-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0789723107">Whole books have been written about this.</a> And this is where we, finally, arrive at iOS, Android, and the title of this post.
The extent to which Android has become a <a href="http://tvtropes.org/pmwiki/pmwiki.php/Main/StartMyOwn">Build My Own</a> OS bothers me.
Android is a good OS - but it is at its worst when it asks people to become the sysadmins of their own phones.
The promise of Great Power in phone form is compelling, and there&rsquo;s a chunk of the market that needs it badly (hello, mobile system administration!).
But that&rsquo;s not the whole market - and that&rsquo;s why iOS, which offers a different bargain, is doing so well.</p>

<p>Not everyone wants to make hard decisions about their computer - and they shouldn&rsquo;t have those decisions forced onto them unless and until it&rsquo;s absolutely necessary.
I think that part of why desktop OSes have gotten away with doing as much of that as they have is that they can take advantage of the existing number of people who have some expertise and are willing to be free support for their friends, family, and neighbor.
A bigger part, though, is that you can walk away from a desktop computer that&rsquo;s giving you issues.
Press &ldquo;cancel&rdquo; until whatever it is goes away.
That&rsquo;s much less of an option with a phone&mdash;if you own an iPhone, an Android phone, or another modern smartphone, you probably have it with you during almost all of your waking hours.
If it starts making your life harder instead of easier, you have to deal with that all of the time.</p>

<p>So here we have the iPhone, which has been <a href="http://www.macworld.com/article/151235/2010/05/apple_rolls.html">gathering momentum</a> for years, which has a maniacal focus on user experience, and which is to a fault willing to take hard decisions out of users' hands.
The iPhone and descendants have made Apple several zillion dollars.
Here also we have the Blackberry, which prospered by offering a phone that could do email, and delivering on that promise very well.
And here finally we have the Android OS, which promises to be like an iPhone only &ldquo;more open&rdquo; and with multitasking and on other carriers.
Unfortunately, the tradeoff there is that to a significant extent, Android devices ask you to make harder decisions, and to have to sysadmin your phone.</p>

<p>Android is offering a different bargain.
There are a lot of times the Android bargain sounds really good to me: I&rsquo;ve already made that bargain a lot of times, and it doesn&rsquo;t frighten me.
But that bargain is not a recipe for mass-market success, and it makes the Android devices perilously prone to broken promises, especially when third parties can break Android&rsquo;s promises (for example, bundled un-removable applications and UI badness).
When we developers think of Apple, we probably don&rsquo;t think of them with great fondness because of their iron-fisted control over the App Store.
But Apple hasn&rsquo;t broken promises: they promised to be jerks about the App store and to focus on their vision of the iPhone.
Android, on the other hand - sometimes you can barely tell what it&rsquo;s promising, and its identity is fragmented and conflicting.</p>

<p>The future is getting brighter, though.
Android devices are getting better at not forcing users to make hard decisions they didn&rsquo;t sign up for.
iOS devices are getting <a href="http://www.apple.com/ipad">magical</a>.
Everyone else is gradually catching up with those two, because the hard decisions in question are getting easier as we as a society learn how to cope with them.
Of course there will always be more and newer hard decisions - but that&rsquo;s what your sysadmins are here for.</p>
]]></content>
  </entry>
  
</feed>
