Search Results: "bam"

15 April 2011

Clint Adams: Stand

Sing it, Lars!

18 February 2011

Vincent Sanders: Shedding

For some time now Melodie has wanted more outside storage.

The current outhouse is an 3 foot by 8 foot converted outside toilet. Due to its age (built 1884) this building is no longer watertight and is generally disintegrating at an alarming rate. One day soon it will have to be demolished. That day has not yet arrived, instead we purchased a plastic shed.

Unfortunately the only viable place for the new shed was next to the old one, this required removing a six foot section of flower bed complete with ivy, bamboo and an old sink.

Last Saturday I completed this removal and lay a concrete base ready to take the new shed. You would not think such a small area (2.8m square) would require so much material and effort to concrete over. 300Kg of 3:2:1 aggregate:sand:cement concrete mix went into the hole along with 100Kg of instant set concrete (for a rapid surface in the changable weather).

Thursday afternoon Geoff (my nice helpful neighbour) offered to assist me in the assembly of the shed. I re-arranged my work schedule (yay home working) and after three hours the shed was assembled.

This morning it occurred to me that my webcam had recorded a time-lapse movie of the construction. I uploaded it to YouTube and present it here for your amusement.

<iframe allowfullscreen="" frameborder="0" height="240" src="http://www.youtube.com/embed/brTXLO2R5D0?rel=0" title="YouTube video player" width="320"></iframe>

28 January 2011

Amaya Rodrigo: Indignez Vous!

If There is any sort of food for thought worth reading, this is it.
INDIGNEZ-VOUS! GET ANGRY! CRY OUT by St phane Hessel


St phane Hessel, author of Indignez-vous!
After 93 years, it is almost the final act. The end for me is not very far off any more. But it still leaves me a chance to be able to remind others of what acted as the basis of my political engagement. It was the years of resistance to the Nazi occupation -- and the program of social rights worked out 66 years ago by the National Council of the Resistance!

It is to Jean Moulin [murdered founder of the Council] that we owe, as part of this Council, the uniting of all elements of occupied France -- the movements, the parties, the labor unions -- to proclaim their membership in Fighting France, and we owe this to the only leader that it acknowledged, General de Gaulle. From London, where I had joined de Gaulle in March 1941, I learned that this Council had completed a program and adopted it on March 15th, 1944, that offered for liberated France a group of principles and values on which would rest the modern democracy of our country.

These principles and these values, we need today more than ever. It is up to us to see to it, all together, that our society becomes a society of which we are proud, not this society of immigrants without papers -- expulsions, suspicion regarding the immigrants. Not this society where they call into question social security and national retirement and health plans. Not this society where mass media are in the hands of the rich. These are things that we would have refused to give in to if we had been the true heirs of the National Council of the Resistance.









From 1945, after a dreadful drama [WWII], it was an ambitious
resurrection of society to which the remaining contingent of the Council
of the Resistance devoted itself. Let us remember them while creating
national health and pensions plans such as the Resistance wished, as its
program stipulated, "a full plan of French national health and social
security, aimed at assuring all citizens the means of existence whenever
they are unable to obtain them by a job; a retirement allowing the old
workers to finish their days with dignity."

The sources of energy, electricity, and gas, mines, the big banks, were
nationalized. Now this was as the program recommended: "... the return
to the nation of big monopolized means of production, fruits of common
labor, sources of energy, wealth from the mines, from insurance
companies and from big banks; the institution of a true economic and
social democracy involving the ousting of the big economic and financial
fiefdoms from the direction of the economy."

General interest must dominate over special interest. The just man
believes that wealth created in the realm of labor should dominate over
the power of money.

The Resistance proposed, "a rational organization of the economy
assuring the subordination of special interests to general interest, and
the emancipation of 'slaves' of the professional dictatorship that was
instituted just as in the fascist states," which had used the interim
[for two years after the war] government of the Republic as an agent.

A true democracy needs an independent press, and the Resistance
acknowledged it, demanded it, by defending "the freedom of the press,
its honor, and its independence from the State, the power of money and
foreign influence." This is what relieved restrictions on the press from
1944 on. And press freedom is definitely what is in danger today.

The Resistance called for a "real possibility for all French children to
benefit from the most advanced education," without discrimination.
Reforms offered in 2008 go contrary to this plan. Young teachers, whose
actions I support, went so far as refusing to apply them, and they saw
their salaries cut by way of punishment. They were indignant,
"disobeyed," judging these reforms too far from the ideal of the
democratic school, too much in the service of a society of commerce and
not developing the inventive and critical mind enough. 2

All the foundations of the social conquests of the Resistance are
threatened today.

The motive of the Resistance: indignation (Indignez-vous!)

Some dare to say to us that the State cannot afford the expenses of
these measures for citizens any more. But how can there be today a lack
of money to support and extend these conquests while the production of
wealth has been considerably augmented since the Liberation period when
Europe was in ruins? On the contrary, the problem is the power of money,
so much opposed by the Resistance, and of the big, boldfaced, selfish
man, with his own servants in the highest spheres of the State.

Banks, since privatized again, have proved to be concerned foremost for
their dividends and for the very high salaries of their leaders, not the
general interest. The disparity between the poorest and the richest has
never been so great, and amassing money, competition, so encouraged.

The basic motive of the Resistance was indignation!

We, the veterans of the resistance movements and combat forces of Free
France, we call on the young generation to live by, to transmit, the
legacy of the Resistance and its ideals. We say to them: Take our place,
"Indignez-vous!" [Get angry! or Cry out!].

The political, economic, intellectual leaders, and the whole society do
not have to give in, nor allow oppression by an actual international
dictatorship of the financial markets, which threatens peace and
democracy.

I wish for you all, each of you, to have your own motive for
indignation. It is precious. When something outrages you as I was
outraged by Nazism, then people become militant, strong, and engaged.
They join this current of history, and the great current of history must
continue thanks to each individual. And this current goes towards more
justice, more freedom, but not this unbridled freedom of the fox in the
henhouse. The rights contained in the UN Universal Declaration of Human
Rights of 1948 are just that, universal.

If you meet somebody who does not benefit from it, feel sorry for them
but help them to win their rights.

Two visions of history

When I try to understand what caused fascism, what made it so we were
overcome by Hitler and the Vichy [French government that collaborated
with Hitler], I tell myself that the propertied, with their selfishness,
were terrifically afraid of Bolshevik revolution. They were allowed to
lead with their fear.

But if, today as then, an active minority stands up, it will be enough;
we shall be the leavening that makes the bread rise. Certainly, the
experience of a very old person like me, born in 1917, is different from
the experience of the today's young persons. I often ask professors for
the opportunity to interact with their students, and I say to them: You
don't have the same obvious reasons to engage you. For us, to resist was
not to accept German occupation, defeat. It was comparatively simple.
Simple as what followed, decolonization. Then the war in Algeria.

It was necessary that Algeria become independent, it was obvious. As for
Stalin, we all applauded the victory of the Red Army against the Nazis
in 1943. But already we had known about the big Stalinist trials of
1935, and even if it was necessary to keep an ear open towards communism
to compensate against American capitalism, the necessity to oppose this
unbearable form of totalitarianism had established itself as an
obviousness. My long life presented a succession of reasons to outrage
me.

These reasons were born less from an emotion than a deliberate
commitment. As a young student at normal school [teachers college] I was
very influenced by Sartre, a fellow student. His "Nausea" [a novel],
"The Wall," [play], and "The Being and Nothingness" [essay] were very
important in the training of my thought. Sartre taught us, "You are
responsible as individuals." It was a libertarian message. The
responsibility of a person can not be assigned by a power or an
authority. On the contrary, it is necessary to get involved in the name
of one's responsibility as a human being.

When I entered the French Ecole Normale Superieure, Ulm Street, in Paris
in 1939, I entered it as a fervent adherent of the philosopher Hegel,
and I adhered to the thought of Maurice Merleau-Ponty. His teaching
explored concrete experience, that of the body and of its relations with
the senses, one big singular sense faced with a plurality of senses. But
my natural optimism, which wants all that is desirable to be possible,
carried me rather towards Hegel. Hegelism interprets the long history of
humanity as having a meaning: It is the freedom of man progressing step
by step. History is made of successive shocks, and the taking into
account of challenges. The history of societies thus advances; and in
the end, man having attained his full freedom, we have the democratic
state in its ideal form.

There is certainly another understanding of history. It says progress is
made by "freedom" of competition, striving for "always more"; it can be
as if living in a devastating hurricane. That's what it represented to a
friend of my father, the man who shared with him an effort to translate
into German "The Search for Time Lost" [novel] by Marcel Proust.

That was the German philosopher Walter Benjamin. He had drawn a
pessimistic view from a painting by the Swiss painter Paul Klee,
"Angelus Novus," where the face of the angel opens arms as if to contain
and push back a tempest, which he identifies with progress. For
Benjamin, who would commit suicide in September 1940 to escape Nazism,
the sense of history is the overpowering progression of disaster upon
disaster.

Indifference: the worst of attitudes

It is true the reasons to be indignant can seem today less clearly
related or the world too complex. Who's doing the ordering, who decides?
It is not always easy to differentiate between all the currents that
govern us. We are not any more dealing with a small elite whose joint
activities can be clearly seen. It is a vast world, of which we have a
feeling of interdependence.

We live in an interconnectivity as never before. But in this world there
still are intolerable things. To see them, it is well and necessary to
look, to search. I say to the young people, Search little, and that is
what you are going to find. The worst of attitudes is indifference, to
say "I can do nothing there, I'll just manage to get by." By including
yourself in that, you lose one of the essential elements that makes the
human being: the faculty of indignation and the commitment that is a
consequence of it.

They [young people] can already identify two big new challenges:

1. The huge gap which exists between the very poor and the very rich and
that does not cease increasing. It is an innovation of the 20th and 21st
centuries. The very poor in the today's world earn barely two dollars a
day. The new generation cannot let this gap become even greater. The
official reports alone should provoke a commitment.

2. Human rights and state of the planet: I had the chance after the
Liberation to join in the writing of the Universal Declaration of Human
Rights, adopted by the United Nations organization, on December 10th,
1948, in Paris at the palace of Chaillot. It was as principal private
secretary of Henry Laugier, the adjunct general-secretary of the UN, and
as and secretary of the Commission on Human Rights that I with others
was led to participate in the writing of this statement. I wouldn't know
how to forget the role in its elaboration of Ren Cassin, who was
national commissioner of justice and education in the government of Free
France in London in 1941 and won the Nobel peace prize in 1968, nor that
of Pierre Mend s-France in the Economic and Social Council, to whom the
text drafts we worked out were submitted before being considered by the
Third Committee (Social, Humanitarian and Cultural) of the General
Assembly. It was ratified by the 54 member states in session of the
United Nations, and I certified it as secretary.

It is to Ren Cassin that we owe the term "universal rights" instead of
"international rights" as offered by our American and British friends.
This [universal versus international] was key because, at the end of the
Second World War, what was at stake was to becomeereignty," which a
nation can emphasize while it devotes itself to crimes against humanity
on its own soil. Such was the case of Hitler, who felt himself supreme
and authorized to carry out a genocide. This universal statement owed
much to universal revulsion towards Nazism, fascism, and totalitarianism
-- and owes a lot, in our minds, to the spirit of the Resistance.

I had a feeling that it was necessary to move quickly so as not to be
dupes of the hypocrisy that there was in the UN membership, some whom
claimed these values already won but had no intention at all to promote
them faithfully -- claimed that we were trying to impose values on them.

I can not resist the desire to quote Article 15 of the Universal
Declaration of Human Rights (1948): "Everyone has the right to a
nationality." Article 22 says, "Everyone, as a member of society, has
the right to social security and is entitled to realization, through
national effort and international cooperation and in accordance with the
organization and resources of each State, of the economic, social and
cultural rights indispensable for his dignity and the free development
of his personality." And if this statement has a declarative scope, and
not statutory, the Declaration nevertheless has played a powerful role
since 1948. It saw colonized people take it up in their fight for
independence; it sowed minds in a battle for freedom.

I note with pleasure that in the course of last decades there has been
an increase in nongovernmental organizations (NGOs) and social movements
such as ATTAC (Association for the Taxation of Financial Transactions);

also FIDH (International Federation for Human Rights) and Amnesty
International, which are active and competitive. It is obvious that to
be effective today it is necessary to act in a network, to use all
modern means of communication.

To the young people, I say: Look around you, you will find topics that
justify your indignation facts about treatment of immigrants, of
"illegal" immigrants, of the Roma [aka Gypsies]. You will find concrete
situations that lead you to strong citizen action. Search and you shall
find!

My indignation regarding Palestine outrages by Israel [Indignez-vous!]

Today, my main indignation concerns Palestine, the Gaza Strip, and the
West Bank of Jordan. This conflict is outrageous. It is absolutely
essential to read the report by Richard Goldstone, of September 2009, on
Gaza, in which this South African, Jewish judge, who claims even to be a
Zionist, accuses the Israeli army of having committed "acts comparable
to war crimes and perhaps, in certain circumstances, crimes against
humanity" during its "Operation Cast Lead," which lasted three weeks.

I went back to Gaza in 2009 myself, when I was able to enter with my
wife thanks to our diplomatic passports, to study first-hand what this
report said. People who accompanied us were not authorized to enter the
Gaza Strip. There and in the West Bank of Jordan. We also visited the
Palestinian refugee camps set up from 1948 by the United Nations agency
UNRWA, where more than three million Palestinians expelled off their
lands by Israel wait even yet for a more and more problematical return.

As for Gaza, it is a roofless prison for one and a half million
Palestinians. A prison where people get organized just to survive.
Despite material destruction such as that of the Red Crescent hospital
by Operation Cast Lead, it is the behavior of the Gazans, their
patriotism, their love of the sea and beaches, their constant
preoccupation for the welfare of their children, who are innumerable and
cheerful, that haunt our memory. We were impressed by how ingeniously
they face up to all the scarcities that are imposed on them. We saw them
making bricks, for lack of cement, to rebuild the thousands of houses
destroyed by tanks. They confirmed to us that there had been 1400 deaths
including women, children, and oldsters in the Palestinian camp
during this Operation Cast Lead led by the Israeli army, compared to
only 50 injured men on the Israeli side. I share conclusions of the
South African judge. That Jews can, themselves, perpetrate war crimes is
unbearable. Alas, history does not give enough examples of people who
draw lessons from their own history. [The author, St phane Hessel, had
a Jewish father.]

Terrorism, or exasperation?

I know that Hamas [party of Palestine freedom fighters], which had won
the last legislative elections, could not help it that rockets were
launched on Israeli cities in response to the situation of isolation and
blockade in which Gazans exist. I think, naturally, that terrorism is
unacceptable; but it is necessary to acknowledge (from experience in
France) that when people are occupied by forces immensely superior to
their own, popular reaction cannot be altogether bloodless.

Does it serve Hamas to send rockets onto the town of Sd rot [Israeli
town across the border from Gaza]?

The answer is no. This does not serve their purpose, but they can
explain this gesture by the exasperation of Gazans. In the notion of
exasperation, it is necessary to understand violence as the regrettable
conclusion of situations not acceptable to those who are subjected them.

Thus, they can tell themselves, terrorism is a form of exasperation. And
that this "terrorism" is a misnomer. One should not have to resort to
this exasperation, but it is necessary to have hope. Exasperation is a
denial of hope. It is comprehensible, I would say almost natural, but it
still is not acceptable. Because it does not allow one to acquire
results that hope can possibly, eventually produce.

Nonviolence: the way we must learn to follow

I am persuaded that the future belongs to nonviolence, to reconciliation
of different cultures. It is by this way that humanity will have to
enter its next stage. But on this I agree with Sartre: We cannot excuse
the terrorists who throw bombs, but we can understand them. Sartre wrote
in 1947: "I recognize that violence in whatever form it may manifest
itself is a setback. But it is an inevitable setback because we are in a
world of violence. And if it is true that recourse to violence risks
perpetuating it, it is also true it is the sure means to make it stop."

To that I would add that nonviolence is a surer means of making violence
stop. One can not condone the terrorism, using Sartre or in the name of
this principle, during the war of Algeria, nor during the Munich Games
of 1972 the murder attempt made against Israeli athletes. Terrorism is
not productive, and Sartre himself would end up wondering at the end of
his life about the sense of violence and doubt its reason for being.

However, to proclaim "violence is not effective" is more important than
to know whether one must condemn or not those who devote themselves to
it. Terrorism is not effective. In the notion of effectiveness, a
bloodless hope is needed. If there is a violent hope, it is in the poem
of William Apollinaire "that hope is violent," and not in policy.

Sartre, in March 1980, within three weeks of his death, declared: "It is
necessary to try to explain why the world of today, which is horrible,
is only an instant in a long historical development, that hope always
has been one of the dominant forces in revolutions and insurrections,
and how I still feel hope as my conception of the future." [Note 5]

It is necessary to understand that violence turns its back on hope. It
is necessary to prefer to it hope, hope over violence. Nonviolence is
the way that we must learn to follow. So must the oppressors.
10

It is necessary to arrive at negotiations to remove oppression; it is
what will allow you to have no more terrorist violence. That's why you
should not let too much hate pile up.

The message of Mandela and Martin Luther King finds all its pertinence
in the world that overcame the confrontation of ideologies [e.g.,
Nazism] and conquered totalitarianism [e.g.,Hitler]. It is also a
message of hope in the capacity of modern societies to overcome
conflicts by a mutual understanding and a vigilant patience. To reach
that point is necessarily based on rights, against es, such as the
military intervention in Iraq.

We had this economic crisis, but we still did not initiate a new policy
of development. Also, the summit of Copenhagen against climatic warming
did not bring about a true policy for the preservation of the planet.

We are on a threshold between the terror of the first decade and the
possibilities of following decades. But it is necessary to hope, it is
always necessary to hope. The previous decade, that of 1990s, had been a
time of great progress. The United Nations had enough wisdom to call
conferences such as those of Rio on environment, in 1992, and that of
Beijing on women, in 1995. In September 2000, on the initiative of the
general secretary of United Nations, Kofi Annan, the 191 member
countries adopted a statement on the "eight objectives of the millennium
for development," by which they notably promised to reduce poverty in
the world by half before 2015.

My big regret is that neither Obama nor the European Union has yet
committed themselves to what should be the provision for a useful forum
bearing on the fundamental values.

Conclusion

How to conclude this call to be indignant? By saying still what, on the
occasion of the sixtieth anniversary of the program of the National
Council of the Resistance, we said on March 8th, 2004 -- we veterans of
the resistance movements and combat forces of Free France (1940-1945) --
that certainly "Nazism was conquered, thanks to the sacrifice of our
brothers and sisters of the Resistance and United Nations against
fascist barbarism. But this threat did not completely disappear, and our
anger against injustice is ever intact." [Note 6] Also, let us always be
called in "a truly peaceful insurrection against means of mass
communication that offer as a vista for our youth only the consumption
of mass trivia, contempt of the weakest and the culture, a generalized
amnesia, and the hard competition of all against all."

To those who will make the 21st century, we say with our affection:

TO CREATE IS TO RESIST; TO RESIST IS TO CREATE.

7 December 2010

Clint Adams: On respect, again

I disagree with Lars. Respect needs to be earned. It should not be a default, and it should not be demanded either on one's own behalf or for others, or you are conflating it with something incredibly ignoble. When you do not respect someone, and you show that person respect, you are being deceitful. Of this I disapprove.

4 November 2010

Clint Adams: Greedy sellouts

Thank you, Tim.

Jaldhar Vyas: All Hail Aqua Buddha!

My fellow Republicans and I got a nice early Diwali present on Tuesday. ~65 seats in the House ~6 in the senate, ~18 governorships and control of ~20 state legislatures. (Some races haven't been formally called yet.) A few disappointments though. no majority in the Senate and Harry Reid and Barney Frank were not defeated. Still overall its an election to celebrate. Here are a few thoughts. The Election System Is An Embarassment Once again there are several races where the outcome is in doubt because of technical problems with voting. Whatever politics we have, can we agree that it is damn stupid that we still can't get something as simple as counting ballots right? Prediction: The 2012 Republican presidential candidate will come from the Tea Party. While I may be a Republican, I am also a Cosmopolitan East Coast Elitist so the Tea Party didn't move me much. There were a couple of cases (NY and DE atleast) where their candidates were subpar and cost us victory but the best of the new Republicans also came out of this movement. I would rather vote for one of them than Romney, Huckabee, McCain, Gingrich etc. (With the exception of Sarah Palin who is just too polarizing I'm afraid.) The Tea Party itself will subside in a few years as all populist movements do. (Ask the Hope'n'changers.) Young People Are Dumb Part of leftist mythology is the idea that one day "the kids" are going to rise up against the mean old corporate overlords. It ain't going to happen. There was a huge upsurge in first time voters in 2008 but that was because Obama was a novelty act not because they had suddenly discovered the merits of Keynesianism. Now Obama is old and busted so they won't vote anymore. (Not until they have kids and a mortgage sometime in the future.) They'll spend time make cool ironic signs for the Rally to Promote Comedy Central but even the prospect of legalizing pot won't get them to the polling booths in sufficient numbers to defeat the oldies. Why? Because young people are dumb. Prediction: War With Iran If you're President Obama what do you do now? Bipartisanship? Yeah right. Look at what happened to Rep. Cao of Louisiana, the only Republican to vote for Obamacare and one of only two GOP congressmen to lose on Tuesday. Obama actively campaigned for his challenger. Any of the new Republicans who try and compromise with the President will end up under the bus sooner or later as they well know. The President could go full retard with the socialism (progressivism, liberalism whatever. It's all the same.) All his initiatives will be shot down but he can claim to be a martyr to the party of No. (Who will be joined in the Senate by Lieberman and whatever centrist Democrats who are up for reelection in 2012.) But this seems to be the path to a one-term presidency to me. Maybe that's what he wants. He could retire comfortably to the deanship of some Ivy League law school and make a lucrative killing on the rubber chicken circuit. But lets assume he wants to get back in the White House in 2012. One way to get back in touch with the voters is to start getting serious about foreign policy which has either been a joke (Remember the reset button?) a travesty or just copied from the Bush administration. In particular the Obama administration has completely failed in stopping Iran from gaining nuclear technology, sponsoring terrorism in Iraq, Afghanistan and Lebanon, and oppressing its own people. War with Iran would enhance his standing with Conservatives (hey it works for me!) most liberals would go along with it and the extreme Code Pink type loonies can safely be ignored. I say it happens before November 2012.

15 October 2010

Enrico Zini: Award winning code

Award winning code Me and Yuwei had a fun day at hhhmcr (#hhhmcr) and even managed to put together a prototype that won the first prize \o/ We played with the gmp24 dataset kindly extracted from Twitter by Michael Brunton-Spall of the Guardian into a convenient JSON dataset. The idea was to find ways of making it easier to look at the data and making sense of it. This is the story of what we did, including the code we wrote. The original dataset has several JSON files, so the first task was to put them all together:
#!/usr/bin/python
# Merge the JSON data
# (C) 2010 Enrico Zini <enrico@enricozini.org>
# License: WTFPL version 2 (http://sam.zoy.org/wtfpl/)
import simplejson
import os
res = []
for f in os.listdir("."):
    if not f.startswith("gmp24"): continue
    data = open(f).read().strip()
    if data == "[]": continue
    parsed = simplejson.loads(data)
    res.extend(parsed)
print simplejson.dumps(res)
The results however were not ordered by date, as GMP had to use several accounts to twit because Twitter was putting Greather Manchester Police into jail for generating too much traffic. There would be quite a bit to write about that, but let's stick to our work. Here is code to sort the JSON data by time:
#!/usr/bin/python
# Sort the JSON data
# (C) 2010 Enrico Zini <enrico@enricozini.org>
# License: WTFPL version 2 (http://sam.zoy.org/wtfpl/)
import simplejson
import sys
import datetime as dt
all_recs = simplejson.load(sys.stdin)
all_recs.sort(key=lambda x: dt.datetime.strptime(x["created_at"], "%a %b %d %H:%M:%S +0000 %Y"))
simplejson.dump(all_recs, sys.stdout)
I then wanted to play with Tf-idf for extracting the most important words of every tweet:
#!/usr/bin/python
# tfifd - Annotate JSON elements with Tf-idf extracted keywords
#
# Copyright (C) 2010  Enrico Zini <enrico@enricozini.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
import sys, math
import simplejson
import re
# Read all the twits
records = simplejson.load(sys.stdin)
# All the twits by ID
byid = dict(((x["id"], x) for x in records))
# Stopwords we ignore
stopwords = set(["by", "it", "and", "of", "in", "a", "to"])
# Tokenising engine
re_num = re.compile(r"^\d+$")
re_word = re.compile(r"(\w+)")
def tokenise(tweet):
    "Extract tokens from a tweet"
    for tok in tweet["text"].split():
        tok = tok.strip().lower()
        if re_num.match(tok): continue
        mo = re_word.match(tok)
        if not mo: continue
        if mo.group(1) in stopwords: continue
        yield mo.group(1)
# Extract tokens from tweets
tokenised = dict(((x["id"], list(tokenise(x))) for x in records))
# Aggregate token counts
aggregated =  
for d in byid.iterkeys():
    for t in tokenised[d]:
        if t in aggregated:
            aggregated[t] += 1
        else:
            aggregated[t] = 1
def tfidf(doc, tok):
    "Compute TFIDF score of a token in a document"
    return doc.count(tok) * math.log(float(len(byid)) / aggregated[tok])
# Annotate tweets with keywords
res = []
for name, tweet in byid.iteritems():
    doc = tokenised[name]
    keywords = sorted(set(doc), key=lambda tok: tfidf(doc, tok), reverse=True)[:5]
    tweet["keywords"] = keywords
    res.append(tweet)
simplejson.dump(res, sys.stdout)
I thought this was producing a nice summary of every tweet but nobody was particularly interested, so we moved on to adding categories to tweet. Thanks to Yuwei who put together some useful keyword sets, we managed to annotate each tweet with a place name (i.e. "Stockport"), a social place name (i.e. "pub", "bank") and a social category (i.e. "man", "woman", "landlord"...) The code is simple; the biggest work in it was the dictionary of keywords:
#!/usr/bin/python
# categorise - Annotate JSON elements with categories
#
# Copyright (C) 2010  Enrico Zini <enrico@enricozini.org>
# Copyright (C) 2010  Yuwei Lin <yuwei@ylin.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
import sys, math
import simplejson
import re
# Electoral wards from http://en.wikipedia.org/wiki/List_of_electoral_wards_in_Greater_Manchester
placenames = ["Altrincham", "Sale West",
"Altrincham", "Ashton upon Mersey", "Bowdon", "Broadheath", "Hale Barns", "Hale Central", "St Mary", "Timperley", "Village",
"Ashton-under-Lyne",
"Ashton Hurst", "Ashton St Michael", "Ashton Waterloo", "Droylsden East", "Droylsden West", "Failsworth East", "Failsworth West", "St Peter",
"Blackley", "Broughton",
"Broughton", "Charlestown", "Cheetham", "Crumpsall", "Harpurhey", "Higher Blackley", "Kersal",
"Bolton North East",
"Astley Bridge", "Bradshaw", "Breightmet", "Bromley Cross", "Crompton", "Halliwell", "Tonge with the Haulgh",
"Bolton South East",
"Farnworth", "Great Lever", "Harper Green", "Hulton", "Kearsley", "Little Lever", "Darcy Lever", "Rumworth",
"Bolton West",
"Atherton", "Heaton", "Lostock", "Horwich", "Blackrod", "Horwich North East", "Smithills", "Westhoughton North", "Chew Moor", "Westhoughton South",
"Bury North",
"Church", "East", "Elton", "Moorside", "North Manor", "Ramsbottom", "Redvales", "Tottington",
"Bury South",
"Besses", "Holyrood", "Pilkington Park", "Radcliffe East", "Radcliffe North", "Radcliffe West", "St Mary", "Sedgley", "Unsworth",
"Cheadle",
"Bramhall North", "Bramhall South", "Cheadle", "Gatley", "Cheadle Hulme North", "Cheadle Hulme South", "Heald Green", "Stepping Hill",
"Denton", "Reddish",
"Audenshaw", "Denton North East", "Denton South", "Denton West", "Dukinfield", "Reddish North", "Reddish South",
"Hazel Grove",
"Bredbury", "Woodley", "Bredbury Green", "Romiley", "Hazel Grove", "Marple North", "Marple South", "Offerton",
"Heywood", "Middleton",
"Bamford", "Castleton", "East Middleton", "Hopwood Hall", "Norden", "North Heywood", "North Middleton", "South Middleton", "West Heywood", "West Middleton",
"Leigh",
"Astley Mosley Common", "Atherleigh", "Golborne", "Lowton West", "Leigh East", "Leigh South", "Leigh West", "Lowton East", "Tyldesley",
"Makerfield",
"Abram", "Ashton", "Bryn", "Hindley", "Hindley Green", "Orrell", "Winstanley", "Worsley Mesnes",
"Manchester Central",
"Ancoats", "Clayton", "Ardwick", "Bradford", "City Centre", "Hulme", "Miles Platting", "Newton Heath", "Moss Side", "Moston",
"Manchester", "Gorton",
"Fallowfield", "Gorton North", "Gorton South", "Levenshulme", "Longsight", "Rusholme", "Whalley Range",
"Manchester", "Withington",
"Burnage", "Chorlton", "Chorlton Park", "Didsbury East", "Didsbury West", "Old Moat", "Withington",
"Oldham East", "Saddleworth",
"Alexandra", "Crompton", "Saddleworth North", "Saddleworth South", "Saddleworth West", "Lees", "St James", "St Mary", "Shaw", "Waterhead",
"Oldham West", "Royton",
"Chadderton Central", "Chadderton North", "Chadderton South", "Coldhurst", "Hollinwood", "Medlock Vale", "Royton North", "Royton South", "Werneth",
"Rochdale",
"Balderstone", "Kirkholt", "Central Rochdale", "Healey", "Kingsway", "Littleborough Lakeside", "Milkstone", "Deeplish", "Milnrow", "Newhey", "Smallbridge", "Firgrove", "Spotland", "Falinge", "Wardle", "West Littleborough",
"Salford", "Eccles",
"Claremont", "Eccles", "Irwell Riverside", "Langworthy", "Ordsall", "Pendlebury", "Swinton North", "Swinton South", "Weaste", "Seedley",
"Stalybridge", "Hyde",
"Dukinfield Stalybridge", "Hyde Godley", "Hyde Newton", "Hyde Werneth", "Longdendale", "Mossley", "Stalybridge North", "Stalybridge South",
"Stockport",
"Brinnington", "Central", "Davenport", "Cale Green", "Edgeley", "Cheadle Heath", "Heatons North", "Heatons South", "Manor",
"Stretford", "Urmston",
"Bucklow-St Martins", "Clifford", "Davyhulme East", "Davyhulme West", "Flixton", "Gorse Hill", "Longford", "Stretford", "Urmston",
"Wigan",
"Aspull New Springs Whelley", "Douglas", "Ince", "Pemberton", "Shevington with Lower Ground", "Standish with Langtree", "Wigan Central", "Wigan West",
"Worsley", "Eccles South",
"Barton", "Boothstown", "Ellenbrook", "Cadishead", "Irlam", "Little Hulton", "Walkden North", "Walkden South", "Winton", "Worsley",
"Wythenshawe", "Sale East",
"Baguley", "Brooklands", "Northenden", "Priory", "Sale Moor", "Sharston", "Woodhouse Park"]
# Manual coding from Yuwei
placenames.extend(["City centre", "Tameside", "Oldham", "Bury", "Bolton",
"Trafford", "Pendleton", "New Moston", "Denton", "Eccles", "Leigh", "Benchill",
"Prestwich", "Sale", "Kearsley", ])
placenames.extend(["Trafford", "Bolton", "Stockport", "Levenshulme", "Gorton",
"Tameside", "Blackley", "City centre", "Airport", "South Manchester",
"Rochdale", "Chorlton", "Uppermill", "Castleton", "Stalybridge", "Ashton",
"Chadderton", "Bury", "Ancoats", "Whalley Range", "West Yorkshire",
"Fallowfield", "New Moston", "Denton", "Stretford", "Eccles", "Pendleton",
"Leigh", "Altrincham", "Sale", "Prestwich", "Kearsley", "Hulme", "Withington",
"Moss Side", "Milnrow", "outskirt of Manchester City Centre", "Newton Heath",
"Wythenshawe", "Mancunian Way", "M60", "A6", "Droylesden", "M56", "Timperley",
"Higher Ince", "Clayton", "Higher Blackley", "Lowton", "Droylsden",
"Partington", "Cheetham Hill", "Benchill", "Longsight", "Didsbury",
"Westhoughton"])
# Social categories from Yuwei
soccat = ["man", "woman", "men", "women", "youth", "teenager", "elderly",
"patient", "taxi driver", "neighbour", "male", "tenant", "landlord", "child",
"children", "immigrant", "female", "workmen", "boy", "girl", "foster parents",
"next of kin"]
for i in range(100):
    soccat.append("%d-year-old" % i)
    soccat.append("%d-years-old" % i)
# Types of social locations from Yuwei
socloc = ["car park", "park", "pub", "club", "shop", "premises", "bus stop",
"property", "credit card", "supermarket", "garden", "phone box", "theatre",
"toilet", "building site", "Crown court", "hard shoulder", "telephone kiosk",
"hotel", "restaurant", "cafe", "petrol station", "bank", "school",
"university"]
extras =   "placename": placenames, "soccat": soccat, "socloc": socloc  
# Normalise keyword lists
for k, v in extras.iteritems():
    # Remove duplicates
    v = list(set(v))
    # Sort by length
    v.sort(key=lambda x:len(x), reverse=True)
# Add keywords
def add_categories(tweet):
    text = tweet["text"].lower()
    for field, categories in extras.iteritems():
        for cat in categories:
            if cat.lower() in text:
                tweet[field] = cat
                break
    return tweet
# Read all the twits
records = (add_categories(x) for x in simplejson.load(sys.stdin))
simplejson.dump(list(records), sys.stdout)
All these scripts form a nice processing chain: each script takes a list of JSON records, adds some bit and passes it on. In order to see what we have so far, here is a simple script to convert the JSON twits to CSV so they can be viewed in a spreadsheet:
#!/usr/bin/python
# Convert the JSON twits to CSV
# (C) 2010 Enrico Zini <enrico@enricozini.org>
# License: WTFPL version 2 (http://sam.zoy.org/wtfpl/)
import simplejson
import sys
import csv
rows = ["id", "created_at", "text", "keywords", "placename"]
writer = csv.writer(sys.stdout)
for rec in simplejson.load(sys.stdin):
    rec["keywords"] = " ".join(rec["keywords"])
    rec["placename"] = rec.get("placename", "")
    writer.writerow([rec[row] for row in rows])
At this point we were coming up with lots of questions: "were there more reports on women or men?", "which place had most incidents?", "what were the incidents involving animals?"... Time to bring Xapian into play. This script reads all the JSON tweets and builds a Xapian index with them:
#!/usr/bin/python
# toxapian - Index JSON tweets in Xapian
#
# Copyright (C) 2010  Enrico Zini <enrico@enricozini.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
import simplejson
import sys
import os, os.path
import xapian
DBNAME = sys.argv[1]
db = xapian.WritableDatabase(DBNAME, xapian.DB_CREATE_OR_OPEN)
stemmer = xapian.Stem("english")
indexer = xapian.TermGenerator()
indexer.set_stemmer(stemmer)
indexer.set_database(db)
data = simplejson.load(sys.stdin)
for rec in data:
    doc = xapian.Document()
    doc.set_data(str(rec["id"]))
    indexer.set_document(doc)
    indexer.index_text_without_positions(rec["text"])
    # Index categories as categories
    if "placename" in rec:
        doc.add_boolean_term("XP" + rec["placename"].lower())
    if "soccat" in rec:
        doc.add_boolean_term("XS" + rec["soccat"].lower())
    if "socloc" in rec:
        doc.add_boolean_term("XL" + rec["socloc"].lower())
    db.add_document(doc)
db.flush()
# Also save the whole dataset so we know where to find it later if we want to
# show the details of an entry
simplejson.dump(data, open(os.path.join(DBNAME, "all.json"), "w"))
And this is a simple command line tool to query to the database:
#!/usr/bin/python
# xgrep - Command line tool to query the GMP24 tweet Xapian database
#
# Copyright (C) 2010  Enrico Zini <enrico@enricozini.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
import simplejson
import sys
import os, os.path
import xapian
DBNAME = sys.argv[1]
db = xapian.Database(DBNAME)
stem = xapian.Stem("english")
qp = xapian.QueryParser()
qp.set_default_op(xapian.Query.OP_AND)
qp.set_database(db)
qp.set_stemmer(stem)
qp.set_stemming_strategy(xapian.QueryParser.STEM_SOME)
qp.add_boolean_prefix("place", "XP")
qp.add_boolean_prefix("soc", "XS")
qp.add_boolean_prefix("loc", "XL")
query = qp.parse_query(sys.argv[2],
    xapian.QueryParser.FLAG_BOOLEAN  
    xapian.QueryParser.FLAG_LOVEHATE  
    xapian.QueryParser.FLAG_BOOLEAN_ANY_CASE  
    xapian.QueryParser.FLAG_WILDCARD  
    xapian.QueryParser.FLAG_PURE_NOT  
    xapian.QueryParser.FLAG_SPELLING_CORRECTION  
    xapian.QueryParser.FLAG_AUTO_SYNONYMS)
enquire = xapian.Enquire(db)
enquire.set_query(query)
count = 40
matches = enquire.get_mset(0, count)
estimated = matches.get_matches_estimated()
print "%d/%d results" % (matches.size(), estimated)
data = dict((str(x["id"]), x) for x in simplejson.load(open(os.path.join(DBNAME, "all.json"))))
for m in matches:
    rec = data[m.document.get_data()]
    print rec["text"]
print "%d/%d results" % (matches.size(), matches.get_matches_estimated())
total = db.get_doccount()
estimated = matches.get_matches_estimated()
print "%d results over %d documents, %d%%" % (estimated, total, estimated * 100 / total)
Neat! Now that we have a proper index that supports all sort of cool things, like stemming, tag clouds, full text search with complex queries, lookup of similar documents, suggest keywords and so on, it was just fair to put together a web service to share it with other people at the event. It helped that I had already written similar code for apt-xapian-index and dde before. Here is the server, quickly built on bottle. The very last line starts the server and it is where you can configure the listening interface and port.
#!/usr/bin/python
# xserve - Make the GMP24 tweet Xapian database available on the web
#
# Copyright (C) 2010  Enrico Zini <enrico@enricozini.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
import bottle
from bottle import route, post
from cStringIO import StringIO
import cPickle as pickle
import simplejson
import sys
import os, os.path
import xapian
import urllib
import math
bottle.debug(True)
DBNAME = sys.argv[1]
QUERYLOG = os.path.join(DBNAME, "queries.txt")
data = dict((str(x["id"]), x) for x in simplejson.load(open(os.path.join(DBNAME, "all.json"))))
prefixes =   "place": "XP", "soc": "XS", "loc": "XL"  
prefix_desc =   "place": "Place name", "soc": "Social category", "loc": "Social location"  
db = xapian.Database(DBNAME)
stem = xapian.Stem("english")
qp = xapian.QueryParser()
qp.set_default_op(xapian.Query.OP_AND)
qp.set_database(db)
qp.set_stemmer(stem)
qp.set_stemming_strategy(xapian.QueryParser.STEM_SOME)
for k, v in prefixes.iteritems():
    qp.add_boolean_prefix(k, v)
def make_query(qstring):
    return qp.parse_query(qstring,
        xapian.QueryParser.FLAG_BOOLEAN  
        xapian.QueryParser.FLAG_LOVEHATE  
        xapian.QueryParser.FLAG_BOOLEAN_ANY_CASE  
        xapian.QueryParser.FLAG_WILDCARD  
        xapian.QueryParser.FLAG_PURE_NOT  
        xapian.QueryParser.FLAG_SPELLING_CORRECTION  
        xapian.QueryParser.FLAG_AUTO_SYNONYMS)
@route("/")
def index():
    query = urllib.unquote_plus(bottle.request.GET.get("q", ""))
    out = StringIO()
    print >>out, '''
<html>
<head>
<title>Query</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript">
$(function() 
    $("#queryfield")[0].focus()
 )
</script>
</head>
<body>
<h1>Search</h1>
<form method="POST" action="/query">
Keywords: <input type="text" name="query" value="%s" id="queryfield">
<input type="submit">
<a href="http://xapian.org/docs/queryparser.html">Help</a>
</form>''' % query
    print >>out, '''
<p>Example: "car place:wigan"</p>

<p>Available prefixes:</p>

<ul>
'''
    for pfx in prefixes.keys():
        print >>out, "<li><a href='/catinfo/%s'>%s - %s</a></li>" % (pfx, pfx, prefix_desc[pfx])
    print >>out, '''
</ul>
'''
    oldqueries = []
    if os.path.exists(QUERYLOG):
        total = db.get_doccount()
        fd = open(QUERYLOG, "r")
        while True:
            try:
                q = pickle.load(fd)
            except EOFError:
                break
            oldqueries.append(q)
        fd.close()
        def print_query(q):
            count = q["count"]
            print >>out, "<li><a href='/query?query=%s'>%s (%d/%d %.2f%%)</a></li>" % (urllib.quote_plus(q["q"]), q["q"], count, total, count * 100.0 / total)
        print >>out, "<p>Last 10 queries:</p><ul>"
        for q in oldqueries[:-10:-1]:
            print_query(q)
        print >>out, "</ul>"
        # Remove duplicates
        oldqueries = dict(((x["q"], x) for x in oldqueries)).values()
        print >>out, "<table>"
        print >>out, "<tr><th>10 queries with most results</th><th>10 queries with least results</th></tr>"
        print >>out, "<tr><td>"
        print >>out, "<ul>"
        oldqueries.sort(key=lambda x:x["count"], reverse=True)
        for q in oldqueries[:10]:
            print_query(q)
        print >>out, "</ul>"
        print >>out, "</td><td>"
        print >>out, "<ul>"
        nonempty = [x for x in oldqueries if x["count"] > 0]
        nonempty.sort(key=lambda x:x["count"])
        for q in nonempty[:10]:
            print_query(q)
        print >>out, "</ul>"
        print >>out, "</td></tr>"
        print >>out, "</table>"
    print >>out, '''
</body>
</html>'''
    return out.getvalue()
@route("/query")
@route("/query/")
@post("/query")
@post("/query/")
def query():
    query = bottle.request.POST.get("query", bottle.request.GET.get("query", ""))
    enquire = xapian.Enquire(db)
    enquire.set_query(make_query(query))
    count = 40
    matches = enquire.get_mset(0, count)
    estimated = matches.get_matches_estimated()
    total = db.get_doccount()
    out = StringIO()
    print >>out, '''
<html>
<head><title>Results</title></head>
<body>
<h1>Results for "<b>%s</b>"</h1>
''' % query
    if estimated == 0:
        print >>out, "No results found."
    else:
        # Give as results the first 30 documents; also use them as the key
        # ones to use to compute relevant terms
        rset = xapian.RSet()
        for m in enquire.get_mset(0, 30):
            rset.add_document(m.document.get_docid())
        # Compute the tag cloud
        class NonTagFilter(xapian.ExpandDecider):
            def __call__(self, term):
                return not term[0].isupper() and not term[0].isdigit()
        cloud = []
        maxscore = None
        for res in enquire.get_eset(40, rset, NonTagFilter()):
            # Normalise the score in the interval [0, 1]
            weight = math.log(res.weight)
            if maxscore == None: maxscore = weight
            tag = res.term
            cloud.append([tag, float(weight) / maxscore])
        max_weight = cloud[0][1]
        min_weight = cloud[-1][1]
        cloud.sort(key=lambda x:x[0])
        def mklink(query, term):
            return "/query?query=%s" % urllib.quote_plus(query + " and " + term)
        print >>out, "<h2>Tag cloud</h2>"
        print >>out, "<blockquote>"
        for term, weight in cloud:
            size = 100 + 100.0 * (weight - min_weight) / (max_weight - min_weight)
            print >>out, "<a href='%s' style='font-size:%d%%; color:brown;'>%s</a>" % (mklink(query, term), size, term)
        print >>out, "</blockquote>"
        print >>out, "<h2>Results</h2>"
        print >>out, "<p><a href='/'>Search again</a></p>"
        print >>out, "<p>%d results over %d documents, %.2f%%</p>" % (estimated, total, estimated * 100.0 / total)
        print >>out, "<p>%d/%d results</p>" % (matches.size(), estimated)
        print >>out, "<ul>"
        for m in matches:
            rec = data[m.document.get_data()]
            print >>out, "<li><a href='/item/%s'>%s</a></li>" % (rec["id"], rec["text"])
        print >>out, "</ul>"
        fd = open(QUERYLOG, "a")
        qinfo = dict(q=query, count=estimated)
        pickle.dump(qinfo, fd)
        fd.close()
    print >>out, '''
<a href="/">Search again</a>

</body>
</html>'''
    return out.getvalue()
@route("/item/:id")
@route("/item/:id/")
def show(id):
    rec = data[id]
    out = StringIO()
    print >>out, '''
<html>
<head><title>Result %s</title></head>
<body>
<h1>Raw JSON record for twit %s</h1>
<pre>''' % (rec["id"], rec["id"])
    print >>out, simplejson.dumps(rec, indent=" ")
    print >>out, '''
</pre>
</body>
</html>'''
    return out.getvalue()
@route("/catinfo/:name")
@route("/catinfo/:name/")
def catinfo(name):
    prefix = prefixes[name]
    out = StringIO()
    print >>out, '''
<html>
<head><title>Values for %s</title></head>
<body>
''' % name
    terms = [(x.term[len(prefix):], db.get_termfreq(x.term)) for x in db.allterms(prefix)]
    terms.sort(key=lambda x:x[1], reverse=True)
    freq_min = terms[0][1]
    freq_max = terms[-1][1]
    def mklink(name, term):
        return "/query?query=%s" % urllib.quote_plus(name + ":" + term)
    # Build tag cloud
    print >>out, "<h1>Tag cloud</h1>"
    print >>out, "<blockquote>"
    for term, freq in sorted(terms[:20], key=lambda x:x[0]):
        size = 100 + 100.0 * (freq - freq_min) / (freq_max - freq_min)
        print >>out, "<a href='%s' style='font-size:%d%%; color:brown;'>%s</a>" % (mklink(name, term), size, term)
    print >>out, "</blockquote>"
    print >>out, "<h1>All terms</h1>"
    print >>out, "<table>"
    print >>out, "<tr><th>Occurrences</th><th>Name</th></tr>"
    for term, freq in terms:
        print >>out, "<tr><td>%d</td><td><a href='/query?query=%s'>%s</a></td></tr>" % (freq, urllib.quote_plus(name + ":" + term), term)
    print >>out, "</table>"
    print >>out, '''
</body>
</html>'''
    return out.getvalue()
# Change here for bind host and port
bottle.run(host="0.0.0.0", port=8024)
...and then we presented our work and ended up winning the contest. This was the story of how we wrote this set of award winning code.

7 October 2010

John Goerzen: Why all the Obama hate?

I am really struggling with all this anti-Obama rhetoric, coming from both the right and the left. From where I sit, while he hasn t been perfect, he s accomplished quite a bit for us since he s been president. Consider: I don t get it. Liberals are claiming he s not doing enough, but look at what he s got to work with: Republicans filibustering just about everything in the Senate. I don t think that s Obama s fault. And the conservatives, as far as I can tell, are just yelling. I can t figure this out. They want to cut taxes, cut the deficit, and increase defense spending. Good luck with that.

3 October 2010

Clint Adams: F5566852EB92BD779CF137190EA756B5144843F5

Finally someone is talking about distributed name resolution. As usual, the suitability of the Monkeysphere model is underestimated. Someone tells me that this is because they do not have a three-letter protocol abbreviation.

13 September 2010

Amaya Rodrigo: Of inner peace and struggle

[Nothing related to Debian here, move on if you don't care about my recurring obsession with the end of the world, Cassandra pains, or Big Phat Living Room Revolution yearnings].

Although I am still looking for a community of anarcho-primitivists that want to accept me joining their frugal living, and simply slip off the social construct, the system, the fucking face of earth, call it what you will, I could find some comfort in my favourite feminist blogger's take on the subject of my midlife crisis regarding ecology, capitalism, patriarchy, child bearing, overpopulation, meat consumption and all the rumination of consuming thoughts that (still) make my life miserable and have kept me running away from human contact for a year.

[Emphasis mine]

At what point does human culture depart from the Natural? With the invention of computers? TV? Cars? The cotton gin? Electricity? Taco stands? Gunpowder? The printing press? Written language? Shoes? Crop cultivation? Yurts? The wheel? Did humans become unnatural when the good old days of picturesque, endless agrarian toil, feudal oppression, unchecked disease, ignorance, and death from dysentery at 35 turned into the bad new days of urban post-industrial capitalism where a pound of fair-trade organic coffee costs $12.99 and your email inbox is full of spam?

ah. Everything humans do, or have ever done, is natural. We can t do anything else. The idea that modern culture is un-natural is nostalgic and inaccurate. Living off the grid in a yurt is good in some absolute sense, whereas driving an SUV from a suburban bungalow to the stripmall is bad ? Come on. This a romantic, but misguided view. The cosmic reaction to a 20 Ford Expedition is the same as to a sanctimonious Prius: bupkis. The universe doesn t give a fuck about you or your lifestyle choices. It doesn t give a fuck about the economy, oil spills, or civil unrest in Blargistan. It doesn t give a fuck about katydids. Eventually our whole planet will be erased from space, and the galaxy won t bat an eye. The inevitable extinction of our species (imminent, according to research here at Spinster Laboratories) via the exhaustion of available resources is as natural as a fresh-picked peach. As Andre 3000 and other dude philosophers have observed, nothing is forever.

Yes, yes, when people use the word natural what they really mean is free of chemical additives and maybe some of the assorted hippie concepts that go with that narrative. Barter economies, home furnishings made from bamboo, vegan cookbooks, living in the country. While I would argue that it is just as natural for people to put chemical additives in things as it is to not put chemical additives in things, I admit that it is appealing to fantasize that the source of human misery is an unnatural isolation from Nature, and that doing yoga on an organic rubber mat and drinking organic spinach smoothies will put me back in sync with the cosmos.

But alas, I m already in sync with the cosmos, and so are you. In other words, this is it. This is what we ve become, and this is what we get. Which is not to say that a person can t fantasize about a verdant paradise full of songbirds and polar bears and Bengal tigers, untouched by human influence. Only, that world isn t a world we could actually live in. The minute you add contented children, lazy from a carefree day at the swimming hole, eating ripe plums on the porch at sunset to that scenario, natural history changes, and it s right back to our scorched-earth dystopia. Our giant brains use up resources, it s as simple as that.

As long as we re still here, though, we might as well try to make the best of it.

http://blog.iblamethepatriarchy.com/2010/06/19/heads-up-art-week-starts-on-monday/


Though the comfort is somewhat ephemeral, because deep inside, I know she's wrong, I know another way is feasible, but I have given up already, I have very well come to terms with extiction, I get an enormous pleasure from the thought of the very well deserved human mass suicide-by-cop^Wnature, and in fact, I trust and hope it will save me personally from facing the hard times ahead, as I am a damn coward, paralized by fear, hopeless about the flock ever getting it (is it so hard, really?), while doing as much as I can but completely overwhelmed by the need of changing a world everyone seems to like just as it is. I can certainly empathize with much more disturbed ways of airing similar anguish, among many other examples, such as The Unabomber, or The Weather Underground. I don't even want to go there as I know violence all too well and it is not fun to be on the receiving end. But I see the screaming desperation behind the motives of acts I am not at the liberty to discuss here. I wonder if consumption of resources in the form of books will numb the disorder or make it worse and what sort of medical arrangement the stablishment has for it. As you click away the previous links will mean nothing to you because a)it is Wikipedia after all, and b)you probably don't even understand what the problem of eating animal corpses is, humans are omnivores after all, and what is all this nonsense about dropping language altogether.

WTF, there was no comfort after all, and I am still a nutjob.

1 September 2010

Gunnar Wolf: Cycling, cycling everywhere!

I have been wanting to post for several days already, at least since this last Sunday. I have repeatedly bragged about taking part in the Ciclot n: The last Sunday every month, the city's government closes to automotive transit a ~33Km circuit, for cyclists to enjoy. And by cyclists, I mean people from all expertise ranges Well, the very elite bikers will not take part of such a massive thing, but there are people pedalling a couple of blocks, people taking their small kids to drive a bit, and I recognized an amazingly large proportion of people doing the whole route. Well, this last Sunday one lap was not enough for me I did two laps, ~65Km. (oh, and just for keeping the complaint current: After all, SportsTracker did release a version of thier software for the N95... But it requires Flash for using the webpage at all. I have several pointers at other applications... but am time-starved right now to start reviewing :-/ ) Anyway, I decided to do this double ciclot n in order to train for next week. If you are anywhere near Mexico City, you are invited - this is meant to be a large group ride, and looks very fun! Doble Marat n Ciclista Urbano del Bicentenario We are two weeks away from the 200 year conmemoration of the beginning of the Independence War in Mexico. A group of cyclists came up with the idea to organize a Double Marathon to celebrate! 84Km of biking in Mexico City: For some reason, the distance numbers in that map were made... in miles :-P Anyway, the planned route will be:
  1. Jardin de los periodistas ilustres (Delegaci n Venustiano Carranza)
  2. Aeropuerto Internacional de la Ciudad de M xico
  3. Circuito Bicentenario ( antes circuito interior )
  4. Monumento a La Raza - Hospital La Raza
  5. R o San Joaquin
  6. Viaducto Bicentenario ( carril confinado sin interrumpir la circulacion )
  7. Torres de Sat lite 50 aniversario
  8. Presidencia municipal de Tlalnepantla
  9. Presidencia municipal de Naucalpan
  10. Anillo Periferico Sur
  11. Secretar a de la Defensa
  12. Bosque de Chapultepec 1 y 2 secci n
  13. Segundo Piso del Distrito Federal
  14. Ciudad Universitaria patrimonio cultural de la humanidad
  15. Insurgentes Sur
  16. Miguel ngel de Quevedo
  17. Calzada de Tlapan
  18. Z calo centro historico del distrito federal
  19. Calle 16 de septiembre fin del recorrido
It looks very fun. Besides, although it is not that flat, it is one of the flattest long distance routes you will ever have. The toughest part will be IMO the Northern part of Circuito Bicentenario and possibly some bits of Perif rico towards Naucalpan. Then, a long flat stretch, with one long but not steep way up in Segundo Piso (near Las Flores), and a little stretch towards Ciudad Universitaria. Other than that, it looks very doable if you are in a moderately decent condition. And taking part in such a thing is very very worthy! As a final note... This same Sunday, it has been somewhat publicized the first D a Nacional de la Bicicleta (Bycicling National Day) will be held all over the country, kickstarting the National Cycling Crusade. Sounds nice, right? Even impressive? Yeah, but... If you look at the published information (in the page I just linked), you will see several cities are opening cyclist circuits. For one day only, which means, it does not build awareness among the population on how easy, how convenient and how fun it is to use the bicycle as means of transportation. And not only that The cyclist routes clearly make a point that cycling is a good way, at most, to have fun... But not a general habit we should all embrace. Lets see, as an example, the distances offered (only for the cities quoting route length): ...And so it goes. As you can see, several very important cities (i.e. Monterrey, Chilpancingo, Cuernavaca) put only a 2km route. 2Km by bike is... Nothing. 2Km is done at a leisurely pace in less than 15 minutes (I often sustain 20Km/h, which would mean 2Km in 6 minutes). And, in this short sample (the linked page has the information for several other states, but the pattern holds), most states are only making this in the largest city or two, completely forgetting the bulk of their territories. In my opinion, this "effort" was done backwardsly, and ends up delivering the exact opposite message to what should be done.

30 August 2010

Matt Zimmerman: Traveling at home

For me, the most enjoyable part of traveling is the inspiration that I derive from visiting different places, talking to people, and generally being outside of my normal environment. This bank holiday weekend, when so many Londoners visit faraway lands, my partner and I stayed in London instead, and my sought inspiration closer to home. The city has been delightfully quiet, and in contrast to the preceding week, the weather was mostly pleasant, apart from the sudden downpours the BBC described as squally showers .
Photo of deer in Richmond Park

Photo credit: M rcio Cabral de Moura


We spent Saturday afternoon in Richmond Park, a 2500-acre nature preserve easily accessible via public transport from London. The plentiful oak trees, fallow deer, and various species of water fowl made it easy to forget the city for a while. Having visited a few times on foot, I think it would be fun to cycle next time, and see different areas of the park. Afterward, we had dinner at a tapas restaurant in Parsons Green which offered notably excellent service as well as good food. By this time, it was nearly 7:00pm, and we took a chance on getting last-minute theatre tickets to see Jeff Goldblum and Mercedes Ruehl in Neil Simon s The Prisoner of Second Avenue. We arrived at the theatre just in time for the show, which was not sold out, and in fact had quite reasonable seats available. The show had several good laughs, holding up fairly well after nearly 40 years since the original Broadway production.
Photo of the exhibition at the Design Museum

Photo credit: Gary Bembridge


On Sunday, we visited the Design Museum for the first time. Having been disappointed by the nearby Fashion and Textile Museum, our expectations were not too high, but it turned out to be very worthwhile. The Brit Insurance Designs of the Year exhibition showcased designs from architecture, fashion, furniture, transport and more. Some of my favorites were: I was delighted to see that there were a half dozen or so exhibits which related to open source software. Even including the theatre tickets, it was a very inexpensive holiday compared to traveling overseas, and generated a lot less CO2. I was more than satisfied with the inspiration available within a relatively small radius. I don t think I ll give up traveling, as I really enjoy seeing friends who live far away, but I think I ll be more inclined to stay home during peak travel times and enjoy local activities.

25 August 2010

MJ Ray: Audio Processing Tips for ffmpeg

I did some sound file mangling earlier this week. I ve been using the Bambuser app for Symbian recently to capture some recordings. If you tell their site your User-Agent is a mobile browser, it ll work OK with free software icky but better than many video services today. Even when I was recording audio only, the site left me with flash video (flv) files which contained both audio (mp3) and video streams. Step one was to remove the blank video and convert to mp3: ffmpeg -i videofile -acodec copy -vn part1.mp3 Mobile service isn t great in rural Somerset around Weston-super-Mare, so some recordings were split into several parts. Step two is to combine them with cat part1.mp3 part2.mp3 >whole.mp3 That s OK, but it leaves some painful squawking at the join, where the player hits the header information of part2. If you re unlucky, it ll crash some players. So step three is to remove it: ffmpeg -i whole.mp3 -acodec copy whole-clean.mp3. Often I transcode to ogg vorbis at the same time with ffmpeg -i whole.mp3 whole-clean.ogg but it depends what I m doing with the recording. Are there any other handy ffmpeg tricks I could use here?

26 July 2010

Biella Coleman: New Publications

I have a few new (academic) publications out and most are on my website. Hope to get a copy of the Annual Review of Anthropology up there in the fall!

4 July 2010

Bernd Zeimetz: gimp-plugin-registry 3.5-1

During the last three months and since my last blog-post about gimp-plugin-registry a lot happened: Mainly a large number of new plugins was added, but also various enhancements and bugfixes went into the package, together with updates for various already included plugins. The GIMP screenshot with open FX-Foundry menu For those who don't know gimp-plugin-registry yet, it is a collection of scripts and plugins for The GIMP. The name is based on the webpage GIMP Plugin Registry, where most (new) plugins and scripts are listed. So far the package ships with 170 scripts/plugins. Most of the scripts are written in TinyScheme, but there are also several plugins in C or Python. Probably most noticeable is the inclusion of the GIMP FX Foundry, which is an awesome collection of 124 scripts. Below follows a list of all scripts and plugins as shown in the long description of the Debian package. New plugins are marked with a bold fontface. If there is any interest from other distributions to include the package, I'd be happy to help out to make an integration as easy as possible. The few interesting parts could be ripped out of debian/rules and shipped as a normal Makefile, so they could be used easily. More complicated is the generation of the package description and copyright information, but I guess instead of writing debian/coyright and debian/control, it should be possible to integrate the information into a rpm spec file template or similar files. So in case you're interested to port the package to Fedora, OpenSuSE or some other distribution, don't hesitate to contact me! The sources are available via git, see git.recluse.de for details. For wishes, suggestions and bug reports either use the Debian BTS or Launchpad. While I prefer bugs via the BTS, it might be easier for non-Debian users to file bugs in the Ubuntu Launchpad.

22 May 2010

Clint Adams: Cancelling bash, in command

There is an alternative to using bash, and that is zsh. If you want to defer running a command to the next line, you can invoke the push-line widget, bound by default (in the emacs keymap) to Ctrl-Q and ESC-q.

18 May 2010

Bernd Zeimetz: gimp-plugin-registry package updated

Yesterday I finally found the time to update gimp-plugin-registry, the (hopefully!) largest and best collection of plugins for The GIMP. As usual here comes a short summary of the changes: Hope you like my work, suggestions and bug reports are welcome as usual!

15 April 2010

Bernd Zeimetz: gimp-plugin-registry package updated

Yesterday I finally found the time to update gimp-plugin-registry, the (hopefully!) largest and best collection of plugins for The GIMP. As usual here comes a short summary of the changes: Hope you like my work, suggestions and bug reports are welcome as usual!

14 April 2010

Matt Zimmerman: Pop visualization

It s no surprise that information visualization and related fields have been active research topics in the past decade. The widespread availability of large, valuable data sets has created a need for improved tools and techniques for making sense of it. This is highly technical work, requiring expertise in design, mathematics, software and other fields, and there is a vibrant community of professionals and amateurs who experiment and critique the latest methods. In the geeky blogs that I follow, I see more and more amateur interest in visualization. Visualization is starting to take on political significance as well, as evidenced by the appointment of information design pioneer Edward Tufte to a US government advisory panel to help explain economic policy to the American public. A technology is confirmed to be truly and vitally relevant, though, when it enters the mainstream consciousness in the form of humor. In the case of visualization, geeks have been trading funny charts and graphs for many years, but this phenomenon seems to have finally crossed the chasm into popular Internet culture with the advent of the Venn diagram meme. Now, anyone with an elementary education and a drawing program can create their own chuckle-inducing infographics and enjoy their 15 minutes of Twitter fame. Likewise for the X as seen by Y two-dimensional grids, revealing how various (stereotyped) groups perceive each other. This is the future, becoming more evenly distributed by the minute.

9 April 2010

David Welton: US Exports: "The Cloud"?

An Economist special report in last week's print edition talks about how the US will need focus more on savings and exports:

A special report on America's economy: Time to rebalance I've been thinking about that for a while too, especially after the dollar's recent weakness, although it has been strengthening some, lately, apparently due to the state of Greece's finances... I think that the computing industry is, in general, well poised to take advantage of that. For instance, what could be easier to export than computing power or "Software as a Service"? All it takes is a few minutes for someone in Europe to sign up to a US-based service with a credit card. For instance, compare Linode's prices and good service with most of their European competitors (gandi.net for instance, who are good people, and you have to love that they put "no bullshit" right on their front page). Not that they don't have good service in Europe, but it's very difficult to compete on price with the dollar being significantly cheaper. With the dollar where it is right now, gandi is almost, but not quite, competitive with Linode. If you don't include taxes. If the dollar weakens again, though, things could easily tilt far in Linode's favor. Besides a weak dollar, I think it will be important for companies in a position to do so in the US to focus on "the rest of the world". The US is a big, populous country where it's very easy to forget about far-off lands. Compare my home town of Eugene, Oregon to where I live in Padova. Google Maps says that it takes 7+ hours to drive to Vancouver, Canada (which, to tell the truth, isn't all that foreign in that they speak English with an accent much closer to mine than say, Alabama or Maine). Going south, Google says it's 15+ hours just to San Diego, although I think that's optimistic myself, given traffic in California. From Padova, I can be in France in 5 hours, according to Google, 3 hours to Switzerland, 4 to Innsbruck, in Austria, less than 3 hours to the capital of Slovenia, Ljubljana, and around 3 hours to Croatia, too. And if you wanted to throw in another country, the Republic of San Marino is also less than 3 hours away, according to Google's driving time estimates. You could probably live your entire life in a place like Eugene and never really deal much with foreigners, whereas here, nearby borders are both a historic and an ever-present fact. The outcome of this is that, to some degree, people in the US have traditionally focused their businesses "inwards" until they got to a certain size. Which is, of course, a natural thing to do when you have such a big, homogenous market to deal with before you even start thinking about foreign languages, different laws, exchange rates and all the hassle those things entail. However, if exchange rates hold steady or favor the US further, and internal spending remains weaker, it appears as if it may be sensible for companies to invest some time and energy to attract clients in "the rest of the world". "Cloud" (anyone got a better term? this one's awfully vague, but I want to encompass both "computing power" like Linode or Amazon's EC2, as well as "software as a service") companies likely will have a much easier time of things: for many services, it's easy to just keep running things in the US for a while, and worry about having physical or legal infrastructure abroad later. Your service might not be quite as snappy as it may be with a local server, but it'll do, if it performs a useful function. Compare that with a more traditional business where you might have to do something like open a factory abroad, or at the very least figure out the details of how to ship physical products abroad and sell them, and do so in a way that you're somewhat insured against the large array of things that could go wrong between sending your products on their merry way, and someone buying them in Oslo, Lisbon or Prague. Since this barrier to entry is lower, it makes more sense to climb over it earlier on. As an example, Linode recently did a deal to provide VPS services from a London data center, to make their service more attractive to European customers. However, they still don't appear have marketing materials translated into various languages, and presumably they don't have support staff capable of speaking languages like Chinese, German or Russian either (well, at least not in an official capacity). This isn't to pick on them; they may have considered those things and found them too much of an expense/distraction/hassle for the time being - they certainly know their business better than I do - and that they simply are content to make do with English. Other businesses, however, may decide that a local touch is important to attracting clients. What do you need to look at to make your service more attractive to people in other countries? In no particular order:

There's certainly no lack of work there, but on the other hand, it's possible to do almost all of it from wherever you happen to be located, rather than spending lots of money and time flying around to remote corners of the globe, as is still common practice in many industries.

Next.

Previous.