Oleg Andreev

Month
Filter by post type
All posts

Text
Photo
Quote
Link
Chat
Audio
Video
Ask

March 2009

Mar 26, 2009
#management #design
Math.random() and srand in AS3

There’s no “srand” function in AS3. That is you cannot seed random number generator.

And when you get the very same results each time swf is loaded you find this:

External image

However, if you need true randomness in an event-driven application, you can do this:

setInterval(Math.random, 10)

Flash Player will run Math.random() in background producing different random values at different points of time.

Mar 26, 20091 note
#as3 #random #workaround #security #screenshot
Balanced priority queue (weighted queue)

In a regular priority queue entry with priority N is taken before all the entries with priority M (given N > M).

Sometimes, however, 3-priority entry should not beat one hundred of 1-priority items. It seems natural to introduce a double-linked list of weighted nodes, where newly inserted node can come in front of a limited number of nodes with a total weight less then a weight of a new node.

Illustration. Given a stream of nodes with weights:

[1a, 2, 1b, 3, 1c, 1d, 4, 1e]

weighted queue intermediate states would be:

[1a]
[2, 1a]
[2, 1a, 1b]
[2, 3, 1a, 1b]
[2, 3, 1a, 1b, 1c]
[2, 3, 1a, 1b, 1c, 1d]
[2, 3, 1a, 4, 1b, 1c, 1d]
[2, 3, 1a, 4, 1b, 1c, 1d, 1e]

In such queue priority “N” means skipping N items of priority 1.

Mar 17, 20091 note
#queue #algorithms #math
WhatTheFont: helps to find a name for the font using image recognitionnew.myfonts.com
Mar 16, 2009
#fonts #image recognition #ai
refuckflash.rb: reclone working directory to refresh Flash CS3 classpath buggist.github.com
Mar 13, 2009
#gist #code #git #refuck #flash #classpath #snippet #script #util
Let your mom double click buttons safely (AS3 snippet) gist.github.com
Mar 11, 2009
#as3 #ui #actionscript #click #gist #code
The simplest and the most beautiful state machine implementation in AS3gist.github.com
Mar 11, 2009
#actionscript #as3 #state machine #code
Evening, easy listening

Observation: office becomes nicer when everybody leaves :-)

Mar 9, 2009
#observations #office #evening #actionscript
“
// I dedicate all this code, all my work, to my wife, Darlene, who will 
// have to support me and our three children and the dog once it gets 
// released into the public.
”
—Stack Overflow: What is the best comment in source code you have ever encountered?
Mar 6, 2009
#code #humor #stackoverflow #<>
Creating dangling branches in Git

Say, you want to keep some auxiliary info inside your git repository: tickets, post-commit/post-receive hooks, wiki pages etc. Storing them inside a folder might not be a good idea: you’d probably want to have same content across all the branches. It is natural to keep such data in a separate branch.

Given that, you can create your “tickets” branch simply by checking out new branch, removing all the code, adding initial files and committing it. This works great until you get bored with the irrelevant history in the tail of the git-log. It is rather easy to disconnect your branch from the old history: just take the latest tree id, create an orphan commit (that is: without parent commits) and reset branch to this commit.

# emit tree id for the latest commit
$ git log -1 --pretty=format:%T

# emit new commit id
$ echo "initial commit" | git commit-tree <tree-id>

# reset current branch to this commit id
$ git reset --hard <commit-id>


Put it in a single bash command:

$ git reset --hard `echo "initial commit" | git commit-tree \`git log -1 --pretty=format:%T\``

Dangling branches are great for keeping meta-data of any sort: .git/config files, tickets, hooks, documentation, tickets.


PS. Since you can store hooks inside repository itself, you can have a self-contained deployment system like Capistrano without any additional tools installed on a server. Hooks can even update themselves on each post-receive hook before actual deployment recipes are run. This allows you to specify all the dependencies in the source repository and even setup them with a single “git push” command. All manual setup you have to do initially is to clone local repository inside .git/hooks folder (yes, inside itself) and check out hooks branch appropriate for your environment. Ain’t that sweet?

Mar 4, 20092 notes
#git #advanced #branches #dangling #deploy #capistrano
TraceMonkey analysis and visualizationblog.mozilla.com

Nice article showing efficiency and inefficiency of TraceMonkey. Must read.

Mar 1, 2009
#tracemonkey #js #vm #optimization #visualization #graphs
2x performance increase using denormalized MySQL storagebret.appspot.com

FriendFeed stores all entities with all properties in a single table and uses separate tables for specific indexes. After retrieving entities from the index, application reapplies query to fight some data inconsistencies. Eventually, “cleaner” process updates indexes with the actual data. This strategy greatly reduces administration efforts (indexes can be created or update asynchronously) and makes latency 2x lower.
(Thanks Application Error for the link)

Mar 1, 2009
#mysql #schemaless #db #latency #experience #performance

February 2009

man git-commit-tree
DIAGNOSTICS
       You don't exist. Go away!
           The passwd(5) gecos field couldn't be read

       Your parents must have hated you!
           The passwd(5) gecos field is longer than a giant static buffer.

       Your sysadmin must hate you!
           The passwd(5) name field is longer than a giant static buffer.
Feb 25, 2009
#git #humor #fun #man #diagnostics #errors
ruby inject mastery
def movie_events_grouped_by_titles_and_theaters
   events = Event.all.inject({}) do |titles, event|
     ((titles[event.title] ||= {})[event.theater] ||= []) << event
     titles
   end
end 
(my response to the mail list discussion; in russian)
Feb 24, 2009
#ruby #inject #snippet
~/.gitconfig
[user]
    name = Oleg Andreev
    email = oleganza@gmail.com

[apply]
    whitespace = strip

[diff]
    color = auto
    rename = copy

[pager]
    color = true

# this one is very cool: 
#   green means "to be committed" 
#   red means "not to be committed"
[status]
    color = auto
Feb 24, 2009
#git #gitconfig
Github storygist.github.com

Must read.

Feb 20, 2009
#git #github #story #keynote #gist #success #failure #reading
GitHub is a social network, indeed

Today I have received a letter:

Hello Oleg,

I’m a Io newbie. I was watching some of your sample code on Github (loved funnyFactorial ;-) when I discovered your “learning french” subdir. I’m french and would be pleased to answer / comment / whatever about that language (not so human).

^_^
Feb 18, 2009
#github #french #social #help #curiosity #learning #git #io #email
Unpublished MySQL FAQsqlanywhere.blogspot.com
Feb 18, 2009
#humor #sql #mysql #faq #blog #db #stupid
Github pagesgithub.com

Github offers you a HTTP server for static data at http://yourname.github.com. Publishing is easy: just push content to git@yourname.github.com. (It is two months already, how could I miss!)

Feb 17, 2009
#github #git #pages
Git cookbook: commit id for a given path
$ git rev-list -n 1 HEAD <path/to/folder>

Returns the latest commit, which modified a given path. This is useful to find out whether something has recently changed in the particular folder.

Feb 17, 2009
#git #howto
Time-driven development

Young hacker looks at the figures: “2 hours for the feature Foo, 4 hours for the feature Bar”. He feels that kind of pressure: “I have to make it! I have to type faster, think faster, test faster.”

This is an awful feeling. So here’s the (possible) solution to this situation: try to think of time as of money you are investing. Tell yourself how much time of your life would you invest into this piece of #$@^ (of course, take into account your rate/salary). Now it looks like you score the feature Foo for just 2 hours: it doesn’t worth 4 hours or more. Spend 10-15 minutes for planning the way to spend that much time and do your best. If some trouble strikes and you’re out of time, just give up. Go to another feature and let this to be discussed on a weekly meeting when there’s time to schedule next iteration.

If the client wants a fixed price for software, you will not have any additional time. In such case - either do a dirty job, or work all the night. You to decide.

Feb 16, 20091 note
#time #planning #tdd
Feb 12, 2009
#trace trees #vm #paper #pdf #tree
English—2

And when they drop back to French, discussion becomes a complete nonsense.

Feb 11, 2009
#english #french #nonsense #stupid
English

At this very moment I’m attending a meeting at The Big Company in France. There are six french folks around me speaking English instead of French. The only reason for that is me — I don’t speak French. It’s a bit hard for everyone to speak and understand English and initially I was a little bit ashamed of that. But soon I realized that the difficulty of speaking English makes everyone to focus on the essentials and prevents spoiling everyone’s time on the nonsense. Sweet.

Feb 11, 2009
#language #communication #france #french #english
“The current version of TeX is 3.1415926; it was last updated in March 2008. The design was frozen after version 3.0, and no new feature or fundamental change will be added, so all newer versions will contain only bug fixes. Even though Donald Knuth himself has suggested a few areas in which TeX could have been improved, he indicated that he firmly believes that having an unchanged system that will produce the same output now and in the future is more important than introducing new features. For this reason, he has stated that the “absolutely final change (to be made after my death)” will be to change the version number to π, at which point all remaining bugs will become features. Likewise, versions of METAFONT after 2.0 asymptotically approach e, and a similar change will be applied after Knuth’s death.”—Wikipedia article on TeX versioning. By the way, Perl 6 milestones are numbered with 2 Pi decimal digits.
Feb 10, 2009
#versions #pugs #perl #perl6 #tex #knuth #humor #pi
Zed Shaw's great presentation on how to save your soul in the corporate worldvimeo.com

See also slides (in a form of Factor plain text source code)

Feb 10, 2009
#factor #ruby #java #zed #shaw #stupid #video #presentation #slides #howto
Code colorizing QuickLook plugin code.google.com
Feb 10, 2009
#mac #quicklook #code #colorizing
[idea] Cloning subdirectory from a git repository

Apparently, there’s no conceptual problem with cloning a subdirectory like:

$ git clone git@server:project.git/docs/howto

You should just keep track of those tree objects referencing to “/”, “/docs” and “/docs/howto”, but fetch no references except children of the “/docs/howto” tree.

Feb 9, 20091 note
#git #idea #design
Better package system

There’s a problem in Ruby: what if your application requires two libraries and both of them require incompatible versions of another library?

API designers who are smart enough create a namespace for each major version (MyLib::API1, MyLib::API2 etc.) so that you can have multiple versions of the same code in run time.

There’s a better solution however. Io language does not make you to modify the global state: source code can be loaded in any other object. This means that you don’t have to pollute library code with a version-based namespaces but you still able to load as many instances of the library as you want. Just make sure you keep them in your private objects.

Dreams come true:

MyParser := Package load(“XMLParser”, “e1fc39a02d786”)

Feb 9, 2009
#ruby #io #package #versions #api
Ruby and Rails dictionaries for Mac OS Xpriithaamer.com

You definitely should try these.

Feb 9, 20091 note
#ruby #rails #dictionary #mac #utility
Exceptions

Exceptions are meant to be… ehm… exceptional. Exceptions are thrown when the code could not be executed further. They are meant to be thrown right at the point where something went wrong and passed up the stack till the program termination. Programmer should only provide “ensure” (in Ruby; or “finally” in Java) block to clean up. Programmer should never use “catch”/“rescue” block. Never.

There’s one little thing, however.

Sometimes you run your program and get silly exceptions like “connection lost” or “division by zero”. You become unhappy about it and you decide to implement an interface to deal with such errors. For example, when connection is lost you could show a message or do something smart (depends on the purpose of your program, of course).

But please remember: never ever catch exceptions you don’t know about (no “rescue nil” or “rescue => e”!). You should be very picky at what you are catching. Uncaught exception simply pops up in a system message or a log entry, so you can learn it. But silently caught exception might hide some nasty error from your eyes. And you wouldn’t be able to see in a stack trace what had happened few milliseconds before.

Feb 6, 2009
#exceptions #oop
Re: Stop picking on alias_method_chain

Both Ben and Yehuda are wrong. They both use messy metaprogramming where Ruby has a nice solution already. It is a chain of modules and a super method. If the base functionality is provided in a module it looks like this: module BaseFeatures def hello "Hello, world!" end end module AnyGreetingPlugin def hello(arg = "world") super.sub(/world/, arg) end end class MyConfiguration include BaseFeatures include AnyGreetingPlugin include AnotherPlugin end If your base functionality is packed in a class, rather than in a module — no problem, the solution is pretty much the same: class MyConfiguration < BaseFeatures include AnyGreetingPlugin include AnotherPlugin end

Now let me respond to each point from the Ben’s article:

1. “The method names don’t properly describe what is going on”. Module name describes what particular functionality it adds to the methods it contains.

2. “The base method shouldn’t care what other modules are doing, modularity is broken”. That’s not the case when you use regular modules.

3. “Logic is not 100% contained”. Logic is 100% contained: no magical macros anywhere.

4. “Promotes messy code”. Again, nothing to even seem messy.

5. “Exposes a documentation flaw”. When you think modules it is easy to separate concerns and understand how every little aspect of functionality affects everything else. You don’t have to speak any other language except Ruby. You think of module chains and message passing: no structure is created dynamically where not necessary. Only thing you have to do: describe in the documentation what this particular class or module is supposed to do. Then provide examples of a default configurations (when some modules are included in a single class) to make the picture complete. Respect the language. Keep it simple, stupid.

Feb 3, 20092 notes
#ruby #metaprogramming #design #api #kiss
Re: refactoring data models
(e-mail conversation with a colleague)

class User < ActiveRecord::Base; end
class Artist < User; end
class Investor < User; end

I don’t understand why this would be a very bad idea ? All the users are stored in a same table as they have a lot of attributes and not much differ…

This starts with a naming of a user. As i wrote you recently, “User” name completely hides “role” from you, so it seems natural to put all the roles into User model. However, huge models tend to become harder and harder to modify and understand.

If you think of it that way:

- Person - holds authentication info
- Artist - holds info about music and albums
- Investor - holds info about artists and finance
the following becomes easy to play with:

- Person has many Artists (say, i can create several accounts for a number of my bands)
- Artist info can be edited by a group of People (my band members would like to update the news page/wiki/whatever)
- I (as a person) can represent several investors, or none at all.
- Investor can manage a number of artists, and/or a single artist can have several investors.

The reason to separate models by tasks is the very same as to separate objects from the top global Object class into more specific ones.

Speaking scientifically, it is just about “normalization” of a relational database.

If you have duplicating attributes, you have three equally good options (depending on your situation):

1. Mix them in using a module (e.g. “EntityWithTitleAndDescription”) if the duplication is just a coincidence, not a big deal (just to put some duplication into a single file to keep things cleaner).

2. Implement a separate model and associate it with appropriate models (e.g. “Account” could mediate between Person and Project to manage wikis/pages/documents/artists/etc. to avoid hardcore polymorphism between Person and Project). This is the case in a Basecamp-like app, where people have individual data as well as data, shared by a group (project).

3. Leave duplication as is: Coincidence pattern

Sometimes you have to have STI, but i believe this is not the case. E.g. i have PublicFolder and Inbox subclasses of a class Folder because they are a little special per se, not by their association to other folders.

Feb 3, 20091 note
#ruby #models #design #refactoring #sti #dry

January 2009

Rant on reinvetion of HTTP four.livejournal.com
Jan 30, 2009
#http #rant #fastcgi #phusion #passenger #scgi #protocol
“Any work produced since March 1, 1989, with or without copyright notice, is under copyright until 70 years after the death of the author, or, again, in the in the case of works where the author is unknown or anonymous, until 95 years after their first publication or 120 years after their creation, whichever is shorter.”—What is Public Domain? — Freebase.com guidelines.
Jan 30, 2009
#copyright #public domain #reebase #guidlines #freedom #liberty
“When I’m writing code within an object, my mental model puts me as the object interacting with other objects and “self” is the natural english expression of this. The use of “this” instead suggests some external command issuer directing the object that may have a perspective on the system that is different and wider than the object’s perspective.”—Steve Dekorte on “This vs. Self”
Jan 30, 2009
#io #self #this #language #oop #perspective #mental model #dekorte
AutoGit zero-configuration ruby package managergithub.com
Jan 29, 2009
#git #ruby #package #library #github #zero-configuration #oss #open source
“The ONLY alternative to the spaghetti stack approach, for the world of mutable stack variables they present, is the “stack/heap strategy”. And all you do here is you start with a stack, just like in Potion, but as soon as a continuation is captured, you turn your stack into a DAG in the heap and you throw it the fuck away. That’s it.”—William Morgan on continuations implementation strategies (_why’s Potion github page)
Jan 28, 2009
#continuations #design #vm
“the entire system is a joint development and operations concern, but that instead of letting developers loose on the production system, operations people should be let loose on development”—http://www.hokstad.com/operations-is-a-development-concern.html
Jan 27, 2009
#management #operations #development #concerns
Jan 27, 20091 note
#ruby #code #picture #image
Statistics-based optimization strategy

Process consists of a number of phases. Each phase provides a feedback on its performance.

Instead of defining some performance threshold for each phase to start optimization at and asking ourselves “when should we start optimizing this?”, we should rather ask ourselves “which phase is to be optimized now?”. That is, we should collect all feedback, sort it and start optimizing most important phases first. Naturally, we end the process when we are not getting any visible performance gains anymore.

This strategy can be applied to dynamic programming language runtime as well as to any other controllable process.

Jan 23, 2009
#optimization
Method dispatch: hotspot metric

At each callsite (source code point, where method dispatch happens) we can count

1) number of calls to a method

2) time spent inside the method

3) time spent in callsite (total time across all methods called at the point).

Time can be measured either in byte code instructions, machine instructions or in microseconds.

Lets look at possible situations:

In real code, we don’t meet frequently called very slow methods: it is often done by bad design and could not be efficiently optimized in runtime. But this chart helps us to define a metric for “hot spot” identification: the place in the code, where we start runtime optimization.

Such “hotspot” metric would be callsite time * number of calls. The higher this number, the higher priority should be given to such callsite at optimization phase.

Why don’t we just start with a top-level method? If we start from the very top, we would spend enormous amount of time optimizing the whole program instead of really interesting parts.

Jan 23, 2009
#oop #optimization
Modular bash settings under Git controlgithub.com

Now i can easily bring my favorite aliases and commands to different environments: macbooks, linux and freebsd servers.

Jan 20, 2009
#bash #git
Ruby :symbols

Ruby symbols should be just immutable strings to avoid all that mess with string/symbol keys in option hashes. Just treat every literal string as immutable one. You could even keep this nice syntax with a colon to save some keystrokes.

So, basically:

String.should < ImmutableString
“symbol”.should == :symbol

Parser still fills a table of symbol when it encounters literal strings in the source code. So the unique number is just a string object_id.

When you compare two strings, you compare ids first and if they are not the same, you proceed with byte comparison. No need to convert :symbol.to_s.

How to make string a mutable one? Just #dup or #clone it.

“symbol”.dup.class.should == String

Jan 7, 2009
#ruby #strings #design #ideas

December 2008

Class loading methods

1. “Classic”: explicit require and manual dependencies resolution.

Pros: no bugs.
Cons: lazy programmers want to write and maintain less code.

2. “Rails method” (dependencies.rb): catch const_missing in runtime, guess the file name, load it.

Pros: zero-configuration, good automatic dependencies resolution.
Cons: file name guessing is a constraint, hard to debug runtime threading issues.

3. “Merb method” (load everything in a loop, reload failed files):

Pros: zero-configuration, moderate automatic dependencies resolution, no threading issues, issues are explicit and may arise in a bootstrap process only.
Cons: twice loaded constants yield warning, hidden repeated configuration bugs may appear.

4. “io language method” (load everything sorted by filename):

Pros: no bugs, zero-configuration, easy to understand, optional manual dependencies resolution.
Cons: 2-5% of files are named with ugly prefixes like A0_message.io (higher priority) or Z_exceptions.io (lower priority).

Note: no method saves you from manual resolution of the two-way referencing issue (when A references B and B references A). You still have to create a special “header” file to put bootstrap definitions into.


Conclusion: Merb method is essentially Io method with additional “feature” (which is buggy by nature) of double loading files in case of LoadError. If you name your files according to Io method and resolve all interdependencies manually, Merb will load them once and in the correct order.

Dec 23, 2008
#ruby #threads #frameworks #practices #loading #classes #lib
Source control situation

We have a small team working with SVN. I like to write code under Git. Everyone is okay with command line except Sylvaine, our designer. She uses nice update/commit menu item in the Finder for her SVN-tracked PSD files.

So, here are all the facts:

0. We are working with Mac OS X.
1. I want all revisions stored on my machine.
2. I want good branch support for the source code.
3. I don’t need sophisticated branches for PSD-like documents.
4. Sylvaine probably does not want to open terminal to type “ga maquette.psd && gc ‘new block ’ && gush”. She wants to do this from the Finder with few clicks.
5. We have awful Mac GUIs for both Git and Mercurial (none for Git and halfass MacMercurial)
6. We have git-svn which works fine.

Result: keep individual documents under SVN, enjoy GUI and use git-svn in the Terminal. For source code use Git.

Everybody might be happy.

Dec 21, 2008
#git #hg #svn #git-svn #mac #scm
“Legacy is a function of you over time […] it is your own evolvement of your taste, preferences and knowledge.”—DHH at RailsConf Europe'08
Dec 20, 20081 note
#legacy #dhh #conf #video #software
“Anyone who agrees that piracy is not theft should logically conclude that counterfeiting of currency doesn’t constitute theft.”—Steve is right. That’s why you should take currency as a piece of untrusted paper (in which we all happen to believe). Do invest in something valuable. Like your head, children or a business.
Dec 20, 2008
#piracy #theft #money #currency #dekorte
Dec 20, 2008
#education #xkcd #humor #career

November 2008

Church encoding in Pythonjtauber.com
Nov 27, 2008
#python #church #fp
Next page →
20152016
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
201420152016
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
201320142015
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
201220132014
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
201120122013
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
201020112012
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
200920102011
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
200820092010
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
200720082009
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
200620072008
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
200520062007
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
200420052006
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
200320042005
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
200220032004
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
200120022003
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
200020012002
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
199920002001
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
199819992000
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
199719981999
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
199619971998
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
199519961997
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
199419951996
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
199319941995
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
199219931994
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
199119921993
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
199019911992
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
198919901991
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
198819891990
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
198719881989
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
198619871988
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
19861987
  • January
  • February
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December