Shantanu's Blog
Database Consultant
April 29, 2024
Partitioning and bucketing S3 data
Let's assume we need to optimize this query. The data is stored in S3 (around a few TB)
SELECT * FROM "bucketing_blog"."noaa_remote_original"
WHERE
report_type = 'CRN05'
AND ( station = '99999904237'
OR station = '99999953132'
OR station = '99999903061'
OR station = '99999963856'
OR station = '99999994644'
);
There are around 14325 unique stations and report_type column contain around 13 types.
1) The first thing that can be tried is to create a table with partitioning (using report_type)
CREATE TABLE "bucketing_blog"."athena_non_bucketed"
WITH (
external_location = 's3://<your-s3-location>/athena-non-bucketed/',
partitioned_by = ARRAY['report_type'],
format = 'PARQUET',
write_compression = 'SNAPPY'
)
AS
SELECT * FROM "bucketing_blog"."noaa_remote_original";
If you need faster and cheaper query, use buckets
CREATE TABLE "bucketing_blog"."athena_bucketed"
WITH (
external_location = 's3://<your-s3-location>/athena-bucketed/',
partitioned_by = ARRAY['report_type'],
bucketed_by = ARRAY['station'],
bucket_count = 16,
format = 'PARQUET',
write_compression = 'SNAPPY'
)
AS
SELECT * FROM "bucketing_blog"."noaa_remote_original"
I created 16 buckets because that is the maximum number of stations that may appear in the SQL query.
https://aws.amazon.com/blogs/big-data/optimize-data-layout-by-bucketing-with-amazon-athena-and-aws-glue-to-accelerate-downstream-queries/
Labels: athena, aws
July 06, 2021
Quick test tables in Athena
If you quickly ant to test data using athena query, use with syntax as shown below:
WITH countries(country_code) AS (VALUES 'pol', 'CAN', 'USA')
SELECT upper(country_code) AS country_code
FROM countries
In this example aggregate expression uses "OVER" function.
WITH students_results(student_id, result) AS (VALUES
('student_1', 17),
('student_2', 16),
('student_3', 18),
('student_4', 18),
('student_5', 10),
('student_6', 20),
('student_7', 16))
SELECT
student_id,
result,
count(*) OVER (
ORDER BY result
) AS close_better_scores_count
FROM students_results
Labels: athena, aws
May 28, 2021
Athena and Unicode text
Athena supports unicode characters very well. For e.g. if the datafile looks like this...
"Root_word";"Word";"Primary";"Type";"Code";"Position";"Rule"
"अँटिबायोटिक","अँटिबायोटिक","अँटिबायोटिक","Primary","","",""
"अँटिबायोटिक","अँटिबायोटिकअंती","अँटिबायोटिक","Suffix","A","7293","001: 0 अंती ."
"अँटिबायोटिक","अँटिबायोटिकअर्थी","अँटिबायोटिक","Suffix","A","7293","002: 0 अर्थी ."
"अँटिबायोटिक","अँटिबायोटिकआतून","अँटिबायोटिक","Suffix","A","7293","003: 0 आतून ."
"अँटिबायोटिक","अँटिबायोटिकआतूनचा","अँटिबायोटिक","Suffix","A","7293","004: 0 आतूनचा ."
"अँटिबायोटिक","अँटिबायोटिकआतूनची","अँटिबायोटिक","Suffix","A","7293","005: 0 आतूनची ."
"अँटिबायोटिक","अँटिबायोटिकआतूनचे","अँटिबायोटिक","Suffix","A","7293","006: 0 आतूनचे ."
"अँटिबायोटिक","अँटिबायोटिकआतूनच्या","अँटिबायोटिक","Suffix","A","7293","007: 0 आतूनच्या ."
"अँटिबायोटिक","अँटिबायोटिकआतूनला","अँटिबायोटिक","Suffix","A","7293","008: 0 आतूनला ."
This create table statement is all I need...
create external table myptg (
root_word varchar(255),
derived_word varchar(255),
stemmed_word varchar(255),
type varchar(255),
code varchar(255),
position varchar(255),
rule varchar(255)
)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'
WITH SERDEPROPERTIES (
'separatorChar' = '\;',
'quoteChar' = '\"',
'escapeChar' = '\\'
)
LOCATION 's3://ptg1/mc/'
TBLPROPERTIES ("skip.header.line.count"="1");
I can create a supporting table like this...
create external table gamabhana (derived_word varchar(255))
LOCATION 's3://ptg1/mc2/'
TBLPROPERTIES ("skip.header.line.count"="1");
A new table can be created using the syntax something like this...
create external table anoop (
serial_number int,
root_word varchar(255),
stem1_word varchar(255),
stem2_word varchar(255),
stem3_word varchar(255),
stem4_word varchar(255),
stem5_word varchar(255),
stem6_word varchar(255),
stem7_word varchar(255)
)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'
WITH SERDEPROPERTIES (
'field.delim' = ',',
'escape.delim' = '\\',
'line.delim' = '\n'
)
LOCATION 's3://ptg1/mc3/'
TBLPROPERTIES ("skip.header.line.count"="1");
And then run a join statement like this...
create table gamabhana_match as
select a.derived_word, b.root_word, b.stemmed_word, b.type, b.code, b.position, b.rule, c.stem1_word, c.stem2_word, c.stem3_word, c.stem4_word, c.stem5_word, c.stem6_word, c.stem7_word
from gamabhana as a left join myptg as b
on b.derived_word = a.derived_word
left join anoop as c
on c.derived_word = a.derived_word
It will scan around 2 GB data (in this case) and the cost will be around 1 cent per query. This can also be done in MySQL. But importing data and building indexes is not easy. Unlike Athena, MySQL allows unlimited queries for free!
Athena is good for data that is important and accessed rarely.
Labels: athena, aws, usability
April 17, 2021
crawl indian language websites
CommonCrawl builds and maintains an open repository of web crawl data that can be accessed and analyzed by anyone.
https://commoncrawl.org/
Here are 3 easy steps to download the data in any language, for e.g. Marathi or Gujarati
1) Clone the repo git clone https://github.com/qburst/common-crawl-malayalam.git
2) Change language code from mal to mar at the line -
AND content_languages LIKE 'mal%'"
The other codes are: hin (Hindi), mal (Malayalam), mar (Marathi), guj (Gujarati)
Run this shell script after replacing XXX with your AWS access and security key.
./extract_malayalam_warcs.sh XXX XXX 2021-10 s3://nlp-malayalam
3) Change unicode range from mal: range(3328, 3456) to your own desired language range, for e.g. devnagari: range(2304, 2432) Gujarati: range(2688, 2816)
Run this shell script after replacing XXX with your AWS access and security key.
./filter_malayalam.sh XXX XXX s3://nlp-malayalam/2021-10/warcs s3://nlp-malayalam/2021-10/output2
Filtered and unfiltered data will be available in output2 sub-folder of s3 bucket.
_____
Update:
The good French guys from Sorbonne University and inria have extracted sentences from common crawler for all languages and made them available at
https://oscar-corpus.com/
I have no words to thank them. The paper is available here...
http://corpora.ids-mannheim.de/CMLC7-final/CMLC-7_2019-Oritz_et_al.pdf
Without this data, it would have been very difficult to extract reliable data for languages like Marathi, Gujarati.
Labels: athena, aws, python, shell script
October 24, 2020
Using Bucketing in Amazon Athena
To reduce the data scan cost, AWS Athena provides an option to bucket your data. This optimization technique can perform wonders on reducing cost.
Like partitioning, columns that are frequently used to filter the data are good candidates for bucketing. However, unlike partitioning, with bucketing it’s better to use columns with high cardinality as a bucketing key. For example, Year and Month columns are good candidates for partition keys, whereas userID and sensorID are good examples of bucket keys. By doing this, you make sure that all buckets have a similar number of rows.
Bucketing is a technique that groups data based on specific columns together within a single partition. These columns are known as bucket keys. By grouping related data together into a single bucket (a file within a partition), you significantly reduce the amount of data scanned by Athena, thus improving query performance and reducing cost.
For example, imagine collecting and storing clickstream data. If you frequently filter or aggregate by Sensor ID, then within a single partition it’s better to store all rows for the same sensor together.
CREATE TABLE TargetTable
WITH (
format = 'PARQUET',
external_location = 's3://<s3_bucket_name>/curated/',
partitioned_by = ARRAY['dt'],
bucketed_by = ARRAY['sensorID'],
bucket_count = 3)
AS SELECT *
FROM SourceTable
You can run the select query like this:
select * from TargetTable where dt= '2020-08-04-21' and sensorID = '1096'
Labels: athena, aws
August 24, 2020
Manage Athena tables using python module wrangler
# create a boto session
import boto3
my_session = boto3.Session(
aws_access_key_id="xxx",
aws_secret_access_key="xxx",
region_name="us-east-1",
)
# use wrangler to upload parquet files to S3
# use the database created in glue
import awswrangler as wr
wr.s3.to_parquet(
df=df,
path="s3://test1623/noaa/",
dataset=True,
database="awswrangler_test",
table="noaa",
partition_cols=["year"],
boto3_session=my_session,
)
# Read Athena query into pandas dataframe
df = wr.athena.read_sql_query(
"select * from noaa limit 10", database="awswrangler_test", boto3_session=my_session
)
https://aws.amazon.com/blogs/big-data/optimize-python-etl-by-extending-pandas-with-aws-data-wrangler/
Labels: athena, aws
July 31, 2020
Using Athena to preview large S3 files
Athena can also be used for quickly previewing the csv or text files saved in S3.
# vi symlink.txt
s3://some_bucket/abc_servers_backup/bulk_205_aws/db/xyz_no_details_202006.csv.gz
As you can see, I have saved the entire path in a symbolic links text file and uploading it to S3 using this command...
aws s3 cp symlink.txt s3://132cols/symlink/
I will now use the path of symbolic links file while creating the table as shown below.
CREATE EXTERNAL TABLE test_bulk (
dummy_col string)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '~'
ESCAPED BY '\\'
LINES TERMINATED BY '\n'
STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.SymlinkTextInputFormat'
OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.IgnoreKeyTextOutputFormat'
LOCATION 's3://132cols/symlink/'
TBLPROPERTIES ('has_encrypted_data'='false');
The important point to note is that I have changed the comma , in "FIELDS TERMINATED BY" parameter to tile ~ or else I would get only the first column. Due to this change, I can see the entire row in a single column called "dummy_col". This tip will be useful when you want to check what's in a large file without downloading it first. This method can also be used to re-check if the file that you have uploaded to S3 is valid and readable.
Labels: athena, aws
April 28, 2020
More about Athena query
Here is how we can run a single query across multiple regions.
-- Create a table with a single id column
CREATE EXTERNAL TABLE ids(id bigint)
PARTITIONED BY (region string)
ROW FORMAT DELIMITED
-- Add two partitions, use two buckets from two regions
ALTER TABLE ids ADD PARTITION (region='us')
LOCATION 's3://my-us-bucket/ids'
ALTER TABLE ids ADD PARTITION (region='eu')
LOCATION 's3://my-eu-bucket/ids'
-- Count the distinct ids, in all regions
SELECT COUNT(DISTINCT id)
FROM ids
https://aws.amazon.com/blogs/apn/running-sql-on-amazon-athena-to-analyze-big-data-quickly-and-across-regions/
Labels: athena
April 13, 2020
Redshift Spectrum
Athena and redshift both are great database. But there are times when we need a bridge to connect them. For e.g. when we need to join a redshift table with Athena. Redshift spectrum can be used in such cases.
1) Create an IAM role called "RedshiftCopyUnload" using the cloudformation template shown in this example:
https://stackoverflow.com/questions/58816446/template-to-create-iam-role-for-spectrum-s3-access
2) Create database using the Role created in the first step:
create external schema spectrum_schema from data catalog
database 'spectrum_db'
iam_role 'arn:aws:iam::XXX:role/RedshiftCopyUnload'
create external database if not exists;
3) Create external table:
create external table spectrum_schema.testme (number bigint)
row format delimited fields terminated by '|'
stored as textfile
location 's3://texport/c_pincode_data/';
4) Create internal table native to redshift using select query on external table:
create table mypincode as select * from spectrum_schema.testme limit 10;
Labels: athena, redshift
March 12, 2020
Analyze S3 storage usage using inventory
1) Enable inventory for the bucket
2) Create a table using athena to read the inventory data
3) Run a select query
1) Enable inventory using boto as shown in this stack thread:
https://stackoverflow.com/questions/60615911/use-boto-to-enable-inventory
2) Replace $InventoryBucket, $InventoryPrefix, $Bucket, and $InventoryName with the configuration.
CREATE EXTERNAL TABLE inventory(
bucket string,
key string,
size bigint,
last_modified_date timestamp,
e_tag string,
storage_class string,
is_multipart_uploaded boolean,
replication_status string,
encryption_status string
)
PARTITIONED BY (dt string)
ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.orc.OrcSerde'
STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.SymlinkTextInputFormat'
OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.IgnoreKeyTextOutputFormat'
LOCATION 's3://$InventoryBucket/$InventoryPrefix/$Bucket/$InventoryName/hive';
The location URL will look something like this...
LOCATION 's3://testme16/invent/testme16/myinventory/hive';
Repair table to read partitions:
MSCK REPAIR TABLE inventory;
3) Replace $Yesterday with yesterday’s timestamp (e.g., 2020-03-03-00-00):
SELECT prefix, SUM(size)/1000/1000/1000 AS total_size FROM (
SELECT regexp_extract(i.key, '([^\/]*\/).*', 1) AS prefix, i.size
FROM inventory AS i WHERE i.dt = '$Yesterday'
) GROUP BY prefix ORDER BY total_size DESC;
https://cloudonaut.io/how-to-analyze-and-reduce-s3-storage-usage/
Labels: athena, aws
February 19, 2020
Manage athena tables using python
Here is 4 or 5 lines of code to read data from athena table into pandas
dataframe.
from pyathena import connect
from pyathena.pandas.util import to_sql
bucket = ‘my_bucket_name’
conn = connect(
aws_access_key_id=access,
aws_secret_access_key=secret,
s3_staging_dir="s3://"
+ bucket + "/tutorial/staging/",
region_name="us-east-1",
)
ndf = pd.read_sql("SELECT * FROM sampledb.todel limit 100",
conn)
# pandas dataframe to Athena table
to_sql(ndf, "sample_table", conn, "s3://" + bucket +
"/tutorial/s3dir/",
schema="sampledb",
index=False, if_exists="replace")
_____
The following script will display output of "show create table" command for all tables. It will also create a new excel file called "output.xlsx". 10 records from each table will be saved on separate sheets of the file. Running this script is recommended to learn more about the tables you have saved in Athena.
import pandas as pd
from pyathena import connect
from pyathena.pandas.util import to_sql
conn = connect(
aws_access_key_id="XXX", aws_secret_access_key="XXX",
s3_staging_dir="s3://as-athena-qquery-results-5134690XXXX-us-east-1/todel/",
region_name="us-east-1",
)
dbname = pd.read_sql("show databases", conn)
mydict = dict()
for db in dbname["database_name"]:
mydict[db] = pd.read_sql("show tables in {0}".format(db), conn)
newdict = dict()
for k in mydict.keys():
for i in mydict[k].values:
newdict["{0}.{1}".format(k, i[0])] = pd.read_sql("show create table {0}.{1}".format(k, i[0]), conn)
# print the create table output:
for i in newdict.keys():
for x in newdict[i].values:
print(x[0])
print("\n")
# select 10 records from each table and save as excel sheets:
datadict = dict()
for k in mydict.keys():
for i in mydict[k].values:
try:
datadict["{0}.{1}".format(k, i[0])] = pd.read_sql( "select * from {0}.{1} limit 10".format(k, i[0]), conn)
except:
pass
with pd.ExcelWriter("output.xlsx") as writer:
for k, v in datadict.items():
v.to_excel(writer, sheet_name=k)
Labels: athena, aws, pandas, python
Import csv data and convert it to parquet in athena
# Let's assume we have a large file that we need to import in athena, here are the commands to be used.
# gunzip -c panindia_pincode.csv.gz | head
"1","110016","DELHI","DELHI","","","",""
"2","110027","DELHI","DELHI","","","",""
"3","110062","DELHI","DELHI","","","",""
# create a table in athena
CREATE EXTERNAL TABLE pandindia_pincode (
serial_number string,
pincode_number string,
client_city string,
client_state string,
dummy1 string,
dummy2 string,
dummy3 string,
dummy4 string)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'
WITH SERDEPROPERTIES (
'serialization.format' = ',',
'field.delim' = ',',
"quoteChar" = "\""
)
LOCATION 's3://datameetgeo/pincode/'
TBLPROPERTIES ('has_encrypted_data'='false');
## create parquet file format table
CREATE TABLE default.pandindia_pincode_parq
with (format='PARQUET', external_location='s3://datameetgeo/parquetpincode/'
) AS
SELECT * FROM default.pandindia_pincode
Labels: athena, aws, redshift
February 16, 2020
Using partitions in Athena table
Here is a create table query that will create a partitioned table. The column "product_category" that is used for partitions, is not part of create table statement and still shows up in the select query.
CREATE EXTERNAL TABLE `reviews`(
`marketplace` varchar(10),
`customer_id` varchar(15),
`review_id` varchar(15),
`product_id` varchar(25),
`product_parent` varchar(15),
`product_title` varchar(50),
`star_rating` int,
`helpful_votes` int,
`total_votes` int,
`vine` varchar(5),
`verified_purchase` varchar(5),
`review_headline` varchar(25),
`review_body` varchar(1024),
`review_date` date,
`year` int)
PARTITIONED BY (
`product_category` varchar(25))
ROW FORMAT SERDE
'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe'
STORED AS INPUTFORMAT
'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat'
LOCATION
's3://amazon-reviews-pds/parquet'
In order to populate the table, we will need to use the alter table statement.
ALTER TABLE reviews ADD
partition(product_category='Apparel')
location 's3://amazon-reviews-pds/parquet/product_category=Apparel/'
partition(product_category='Automotive')
location 's3://amazon-reviews-pds/parquet/product_category=Automotive'
partition(product_category='Baby')
location 's3://amazon-reviews-pds/parquet/product_category=Baby'
partition(product_category='Beauty')
location 's3://amazon-reviews-pds/parquet/product_category=Beauty'
partition(product_category='Books')
location 's3://amazon-reviews-pds/parquet/product_category=Books'
partition(product_category='Camera')
location 's3://amazon-reviews-pds/parquet/product_category=Camera'
partition(product_category='Grocery')
location 's3://amazon-reviews-pds/parquet/product_category=Grocery'
partition(product_category='Furniture')
location 's3://amazon-reviews-pds/parquet/product_category=Furniture'
partition(product_category='Watches')
location 's3://amazon-reviews-pds/parquet/product_category=Watches'
partition(product_category='Lawn_and_Garden')
location 's3://amazon-reviews-pds/parquet/product_category=Lawn_and_Garden';
Around 1 TB data per category is already saved in the given S3 bucket in parquet format.
# aws s3 ls --human s3://amazon-reviews-pds/parquet/product_category=Apparel/
2018-04-09 06:35:35 115.0 MiB part-00000-495c48e6-96d6-4650-aa65-3c36a3516ddd.c000.snappy.parquet
2018-04-09 06:35:35 115.3 MiB part-00001-495c48e6-96d6-4650-aa65-3c36a3516ddd.c000.snappy.parquet
2018-04-09 06:35:36 114.9 MiB part-00002-495c48e6-96d6-4650-aa65-3c36a3516ddd.c000.snappy.parquet
2018-04-09 06:35:35 115.2 MiB part-00003-495c48e6-96d6-4650-aa65-3c36a3516ddd.c000.snappy.parquet
2018-04-09 06:35:35 115.3 MiB part-00004-495c48e6-96d6-4650-aa65-3c36a3516ddd.c000.snappy.parquet
2018-04-09 06:35:39 115.3 MiB part-00005-495c48e6-96d6-4650-aa65-3c36a3516ddd.c000.snappy.parquet
2018-04-09 06:35:39 115.4 MiB part-00006-495c48e6-96d6-4650-aa65-3c36a3516ddd.c000.snappy.parquet
2018-04-09 06:35:39 114.8 MiB part-00007-495c48e6-96d6-4650-aa65-3c36a3516ddd.c000.snappy.parquet
2018-04-09 06:35:39 115.3 MiB part-00008-495c48e6-96d6-4650-aa65-3c36a3516ddd.c000.snappy.parquet
2018-04-09 06:35:40 115.3 MiB part-00009-495c48e6-96d6-4650-aa65-3c36a3516ddd.c000.snappy.parquet
If you are planning to use csv instead of parquet, then you will have to change the serialization, input / output formats in the create table statement.
Labels: athena, aws
February 15, 2020
Manage Athena tables using PyAthena
PyAthena is an indispensable toolfor Amazon Athena.
import pandas as pd
from pyathena import connect
from pyathena.pandas.util import to_sql
# create connection object
conn = connect(aws_access_key_id="xxx",
aws_secret_access_key="xxx",
s3_staging_dir="s3://testme162/tutorial/staging/",
region_name="us-east-1",
)
# You may have a very large dataframe instead of this...
df = pd.DataFrame({"a": [1, 2, 3, 4, 5, 6, 7, 8, 11, 21, 545]})
# use the helper function
to_sql(df, "todel", conn, "s3://testme162/tutorial/s3dir/",
schema="sampledb", index=False, if_exists="replace")
# read the athena data into a new dataframe
ndf = pd.read_sql("SELECT * FROM sampledb.todel limit 100", conn)
Labels: athena, aws, python
October 02, 2019
Redshift VPC with subnet issue
I was trying to launch an Amazon Redshift cluster in a specific VPC, but I could not select any VPC in the drop-down list. I checked that a VPC exist (though it's not default one!)
In order to resolve this, follow these 3 steps to create a cluster subnet group.
1) click "Security" from redshift console.
2) On the Subnet Groups tab, click Create Cluster Subnet Group.
3) Specify a Name, Description, VPC ID and Click add "all the subnets" link.
Labels: athena, aws, redshift
October 01, 2019
Load parquet data into redshift table
Here is the copy command to load data from parquet file format to existing table in redshift.
copy favoritemovies from 'S3://some_bucket/parquet_file/'
iam_role 'arn:aws:iam::0123456789012:role/RedshiftCopyUnload'
The IAM role needs to be created using the steps mentioned below:
To create an IAM role to allow Amazon Redshift to access AWS services
1) Open the IAM Console.
2) In the navigation pane, choose Roles.
3) Choose Create role.
4) Choose AWS service, and then choose Redshift.
5) Under Select your use case, choose Redshift - Customizable and then choose Next: Permissions.
6) The Attach permissions policy page appears. choose
AmazonS3ReadOnlyAccess, AWSGlueConsoleFullAccess and AmazonAthenaFullAccess.
7) Choose Next: Tags.
8) Choose Next: Review.
9) For Role name, type a name for your role, for example RedshiftCopyUnload. Choose Create role.
Now you need to attach the role to the current cluster.
1) Sign in to the AWS Management Console and open the Amazon Redshift console
2) In the navigation pane, choose Clusters.
3) In the list, choose the cluster that you want to manage IAM role associations for. Choose Manage IAM Roles.
4) Select your IAM role from the Available roles list to associate or remove current one.
5) choose Apply Changes to update the IAM roles that are associated with the cluster.
1) https://docs.aws.amazon.com/redshift/latest/mgmt/authorizing-redshift-service.html
2) https://docs.aws.amazon.com/redshift/latest/mgmt/copy-unload-iam-role.html#copy-unload-iam-role-associating-with-clusters
Labels: athena, aws, redshift
Archives
June 2001
July 2001
January 2003
May 2003
September 2003
October 2003
December 2003
January 2004
February 2004
March 2004
April 2004
May 2004
June 2004
July 2004
August 2004
September 2004
October 2004
November 2004
December 2004
January 2005
February 2005
March 2005
April 2005
May 2005
June 2005
July 2005
August 2005
September 2005
October 2005
November 2005
December 2005
January 2006
February 2006
March 2006
April 2006
May 2006
June 2006
July 2006
August 2006
September 2006
October 2006
November 2006
December 2006
January 2007
February 2007
March 2007
April 2007
June 2007
July 2007
August 2007
September 2007
October 2007
November 2007
December 2007
January 2008
February 2008
March 2008
April 2008
July 2008
August 2008
September 2008
October 2008
November 2008
December 2008
January 2009
February 2009
March 2009
April 2009
May 2009
June 2009
July 2009
August 2009
September 2009
October 2009
November 2009
December 2009
January 2010
February 2010
March 2010
April 2010
May 2010
June 2010
July 2010
August 2010
September 2010
October 2010
November 2010
December 2010
January 2011
February 2011
March 2011
April 2011
May 2011
June 2011
July 2011
August 2011
September 2011
October 2011
November 2011
December 2011
January 2012
February 2012
March 2012
April 2012
May 2012
June 2012
July 2012
August 2012
October 2012
November 2012
December 2012
January 2013
February 2013
March 2013
April 2013
May 2013
June 2013
July 2013
September 2013
October 2013
January 2014
March 2014
April 2014
May 2014
July 2014
August 2014
September 2014
October 2014
November 2014
December 2014
January 2015
February 2015
March 2015
April 2015
May 2015
June 2015
July 2015
August 2015
September 2015
January 2016
February 2016
March 2016
April 2016
May 2016
June 2016
July 2016
August 2016
September 2016
October 2016
November 2016
December 2016
January 2017
February 2017
April 2017
May 2017
June 2017
July 2017
August 2017
September 2017
October 2017
November 2017
December 2017
February 2018
March 2018
April 2018
May 2018
June 2018
July 2018
August 2018
September 2018
October 2018
November 2018
December 2018
January 2019
February 2019
March 2019
April 2019
May 2019
July 2019
August 2019
September 2019
October 2019
November 2019
December 2019
January 2020
February 2020
March 2020
April 2020
May 2020
July 2020
August 2020
September 2020
October 2020
December 2020
January 2021
April 2021
May 2021
July 2021
September 2021
March 2022
October 2022
November 2022
March 2023
April 2023
July 2023
September 2023
October 2023
November 2023
April 2024
May 2024
June 2024
August 2024
September 2024
October 2024
November 2024
December 2024
January 2025
February 2025
April 2025
June 2025
July 2025
August 2025
November 2025
March 2026
July 2026
September 2026
