Author Archive
Juli 8, 2010 at 12:27 pm · Filed under AWS, Ruby
Building on this article here is a simple ruby script, that copies files between two buckets of the same S3 account, omitting files already present (by name).
This variant adds a list of path prefixes, so you can selectively copy only certain directories of your buckets.
Furthermore it copies the original buckets ACLs for each key.
require 'rubygems'
require 'right_aws'
aws_access_key_id = 'YOUR AMAZON ACCESS KEY'
aws_secret_access_key = 'YOUR AMAZON SECRET ACCESS KEY'
source_bucket = 'SOURCE BUCKET NAME'
target_bucket = 'TARGET BUCKET NAME'
prefixes = [PATH_PREFIX1, PATH_PREFIX2, ...]
s3 = RightAws::S3Interface.new(aws_access_key_id, aws_secret_access_key)
copied_keys = Array.new
(prefixes || ['']).each do |prefix|
s3.incrementally_list_bucket(target_bucket, {:prefix => prefix}) do |key_set|
copied_keys << key_set[:contents].map{|k| k[:key]}.flatten
end
end
copied_keys.flatten!
(prefixes || ['']).each do |prefix|
s3.incrementally_list_bucket(source_bucket, {:prefix => prefix}) do |key_set|
key_set[:contents].each do |key|
key = key[:key]
if copied_keys.include?(key)
puts "#{target_bucket} #{key} already exists. Skipping..."
else
puts "Copying #{source_bucket} #{key}, setting acl"
retries=0
begin
s3.copy(source_bucket, key, target_bucket)
acl = s3.get_acl(source_bucket, key)
s3.put_acl(target_bucket, key, acl[:object])
rescue Exception => e
puts "cannot copy key, #{e.inspect}\nretrying #{retries} out of 10 times..."
retries += 1
retry if retries <= 10
end
end
end
end
end
November 28, 2009 at 12:26 pm · Filed under Allgemein, Javascript
Coverflow has become a de facto visualization standard for the presentation of collections of images, be it covers or portraits.
There are a number of implementations for usage on web pages (e.g. this one) but the usable ones require Adobes Flash and thus won’t run on the iPhone.
When looking for HTML5 canvas based implementations I found this promising implementation based on the YUI library.
Though workig, it has three major drawbacks: It is rather overengineered and difficult to tweak, it uses YUI (whereas I prefer the more lightweight jQuery) and it performs poorly with image sizes bigger than thumbnails.
After trying to change the code for a while I decided to do a reimplementation in jQuery. The result can be seen on the MomoFlow demo page. Here are two screenshots:
CoverFlow using canvas and jQuery
Quicklook mode
The used 3D transformation is superbly described on the YUI blog .
My implementation caches the rendered canvases per rendering angle. Further speed increments are made possible by adjusting the mesh width used for the slicing transformation depending on the achieved framerate.
The result performs beautifully in recent Safari, Chrome and Opera, decently on Firefox. It also works flawlessly on the iPhone. Keyboard control is coming soon.
I do still need help on IE, maybe the image composition is too demanding for ExplorerCanvas?Â
The code is available on github: http://github.com/momolog/momoflow.
Comments and improvements are very much welcome!
Oktober 21, 2009 at 11:03 am · Filed under Allgemein
Since MySQL does neither have real check constraints nor a way to raise an exception in a stored procedure, we found it not instantly obvious, how we could *reject* a certain row on insert, based on a certain condition.
A nice way we found was to set the value in question to NULL, based on the condition and let the NOT NULL constraint do its work.
ALTER TABLE sessions MODIFY session_id varchar(255) NOT NULL;
DROP TRIGGER IF EXISTS check_sessionid;
DELIMITER $$
CREATE TRIGGER check_sessionid BEFORE INSERT ON sessions
FOR EACH ROW BEGIN
IF NOT NEW.session_id REGEXP '^[[:xdigit:]]{32}$' THEN
SET NEW.session_id = NULL;
END IF;
END;
$$
DELIMITER ;
The trigger will let any 32 character string with only HEX characters for the column session_id pass and rejects the rest.
> INSERT INTO sessions (session_id) VALUES ('ffffffffffffffffffffffffffffffff');
Query OK, 1 row affected (0.01 sec)
> INSERT INTO sessions (session_id) VALUES ('fffffffffffffffffffffffffffffffg');
ERROR 1048 (23000): Column 'session_id' cannot be null
Happy triggering.
Oktober 18, 2009 at 5:46 pm · Filed under Allgemein, MacOSX, Note to self, Ruby
Suche nach Wort unter dem Cursor in vim: #
.
jssh
ist eine JavaScript Shell, die den Firefox per Port 9997 fernsteuerbar macht.
Download z.B. hier.
y
erzeugt einen YAML dump auf der Rails console, mehr dazu hier.
=3D
ist ein escaptes “=” in quoted_printable.
sudo /usr/libexec/locate.updatedb
aktualisiert unter MacOSX sofort die locate
Datenbank.
rake db:migrate:redo
führt unter rails die letzte Migration rückwärts und sofort wieder vorwärts aus, so dass sich die Vorwärts-Action korrigieren läßt
ack -Q
bringt ack dazu, literal, also ohne RegExp zu suchen.
Oktober 1, 2009 at 11:24 am · Filed under MacOSX, Note to self
In den single user mode (root shell) starten, beim Neustart:
[CMS] s
In den verbose mode (boot log) starten:
[CMD] v
In den safe mode (nur core kexts) starten:
[SHIFT]
September 4, 2009 at 11:05 am · Filed under Javascript
Javascript allows naming and assigning functions at the same time like:
var vname = function fname() {}
The function name fname
is available only inside the function as a local variable:
var vname = function fname(){
console.log(typeof vname); // function
console.log(typeof fname); // function
}
console.log(typeof vname); // function
console.log(typeof fname); // undefined
If we “redefine” this local variable inside of the function, we get a strange effect:
var vname = function fname(){
console.log(typeof vname); // function
console.log(typeof fname); // undefined !!!
var fname = 1;
console.log(typeof fname); // number
}
console.log(typeof vname); // function
console.log(typeof fname); // undefined
Obviously the interpreter sees the variable declaration var fname
on entrance into the function and does not provide the function variable at all.
August 27, 2009 at 11:01 am · Filed under Note to self
find . -newerBt '10 minutes ago' -depth 1 -print 2>/dev/null
Juni 24, 2009 at 9:59 pm · Filed under Postgresql
Die im vorletzten Artikel vorgestellte Lösung hat den Nachteil, den ganzen Table my_table
zu locken.
Das ist dann ein Problem, wenn criterion
mittels unique constraint eindeutig gemacht wird und nach der Funktion eine zeitaufwendige Funktion (z.B. eine Suche) in derselben Transaktion folgt: Dann warten nämlich alle Prozesse, die ein findOrCreate
machen wollen, unabhängig mit welchem Wert für criterion
, auf den Abschluss der ersten Transaktion, da erst zu diesem Zeitpunkt sichergestellt werden kann, dass die Spalte wirklich unique ist.
Eigentlich sollte es aber möglich sein, dass parallele Transaktionen mit anderen Werten für criterion
unbehelligt ausgeführt werden.
Mit dem folgenden, von Martin Heistermann und Stephan Lüderitz vorgeschlagenen Ansatz, umgeht man dieses Problem elegant:
CREATE OR REPLACE FUNCTION findOrCreate(
 IN criterion_in text,
 OUT record_id integer, OUT is_new bool) AS
$$
DECLARE
BEGIN
  INSERT INTO
   my_table (criterion)
  VALUES
   (criterion_in)
  RETURNING id INTO record_id;
  SELECT true INTO is_new;
EXCEPTION
  WHEN unique_violation THEN
    SELECT false, id into is_new, record_id FROM my_table
WHERE criterion=criterion_in;
END
$$ language plpgsql;
Wie in dieser Präsentation (PDF) beschrieben, läßt PostgreSQL das parallele Einfügen verschiedener Werte mittels findOrCreate
zu, zwingt aber bei zwei Transaktionen, die denselben Wert einfügen wollen, die zweite, mit dem Insert auf das Ende der ersten zu warten.
Findet die (potentiell teure) Suche in der Transaktion nach findOrCreate statt, wird diese gar nicht mehr ausgeführt, da findOrCreate per Exception die von der ersten Transaktion neu eingefügte Zeile ermittelt und gleich mit deren Ergebnissen weitermachen kann.
Mai 19, 2009 at 9:57 pm · Filed under Allgemein
Kampagne gegen Terroristen in Deutschland. Sehr schön.
Mai 16, 2009 at 5:31 pm · Filed under Postgresql
Oft steht man vor dem Problem, einen Datensatz anhand eines Kriteriums zu finden bzw. ihn, falls nicht vorhanden, einzufügen. Bei derartigen Operationen ist es wichtig darauf zu achten, dass nicht mehrere Prozesse, die quasi gleichzeitig diesen Datensatz suchen, eine race condition hervorrufen.
Hier eine Lösung mittels stored procedure für postgresql. Dabei wird eine race condition zwischen Suche und Einfügen vermieden und nur minimales Locking gebraucht:
CREATE OR REPLACE FUNCTION findOrCreate(
IN criterion_in text,
OUT id int, OUT is_new bool) AS
$$
DECLARE
BEGIN
LOCK TABLE my_table;
SELECT false, id FROM my_table WHERE criterion=criterion_in INTO is_new, id;
IF id IS NULL THEN
INSERT INTO
my_table (criterion)
VALUES
(criterion_in)
RETURNING id INTO id;
SELECT true INTO is_new;
END IF;
RETURN;
END
$$ language plpgsql;
Man beachte die praktischen OUT-Parameter, die es ermöglichen, diese Funktion wie folgt aufzurufen:
SELECT id, is_new FROM findOrCreate(criterion);
Rückgabewerte sind id
und is_new
, die einem die Datenbank-Id angeben, und ob diese neu angelegt wurde.
Der Table-Lock wird beim Beenden der Funktion (die immer implizit eine Transaktion ist) automatisch beendet.
« Previous entries ·
Next entries »