All of the interesting technological, artistic or just plain fun subjects I'd investigate if I had an infinite number of lifetimes. In other words, a dumping ground...
Friday, 30 November 2007
c++ qsort, threaded qsort and shell sort
Threaded qsort runs out of memory for creating new threads at around 600 threads.
Making the stack size smaller with NEED_STACK might be able to fix is but I couldn't work out how.
PTHREAD_THREADS_MAX is set to 16384 on this system so that is not the problem.
It relies on the fact that C++ vectors are stored in contiguous memory.
/*
* "The C++ Programming Language 3rd Ed. Bjarne Stroustrup Pg. 334"
* Copyright 2007 Timothy O'Hare
*/
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
#include <pthread.h>
#include <memory>
using namespace std;
/*****************************************************
* template sort
*/
template<class T> void sort(vector<T>&); // declaration
void f(vector<int>& vi, vector<string>& vs)
{
time_t start = time(0);
sort(vi);
time_t taken = time(0) - start;
cout << "time taken for roll your own: " << taken << " secs" << endl;
sort(vs);
}
template<class T> void sort(vector<T>& v) // definition
// Shell sort (Knuth, Vol.13, pg.84)
{
const size_t n = v.size();
for (int gap=n/2; 0<gap; gap/=2)
for (int i=gap; i<n; i++)
for (int j=i-gap; 0<=j; j-=gap) {
//cout << "i:" << i << ", j:" << j << ", gap: " << gap << ", n:" << n << ", v[j]: " << v[j] << endl;
if (v[j+gap] < v[j])
swap(v[j], v[j+gap]);
}
}
/*****************************************************
* Log
*/
class Log {
public:
void co(string s);
static Log Instance();
ostream& operator << (ostream& os );
protected:
Log() { pthread_mutex_init(&logMutex, NULL); };
private:
static std::auto_ptr<Log> theSingleInstance;
//static Log * l;
pthread_mutex_t logMutex;
};
Log Log::Instance()
{
if (theSingleInstance.get() == 0)
theSingleInstance.reset (new Log);
return *theSingleInstance;
/*if (!l) {
l = new Log();
}
return *l;*/
}
void Log::co(string s)
{
pthread_mutex_lock(&logMutex);
cout << s;
pthread_mutex_unlock(&logMutex);
}
ostream& Log::operator << (ostream& os)
{
pthread_mutex_lock(&logMutex);
cout << os;
pthread_mutex_unlock(&logMutex);
}
/*****************************************************
* q sort
*/
template<class T> int partition(vector<T>& v, int left, int right, int pivot)
{
T pivotVal = v[pivot];
swap(v[pivot], v[right]);
int store = left;
for (int i = left; i < right; i++) {
if (v[i] < pivotVal) {
swap(v[i], v[store]);
store++;
}
}
swap(v[store], v[right]);
return store;
}
template<class T> void qsort(vector<T>& v, int left, int right)
{
if (right > left) {
int pivot = left;
int newPivot = partition(v, left, right, pivot);
//cout << "recursive newpviot: " << newPivot << ", left: " << left << ", right: " << newPivot-1 << endl;
qsort(v, left, newPivot-1);
//cout << "recursive newpviot: " << newPivot << ", left: " << newPivot+1 << ", right: " << right << endl;
qsort(v, newPivot+1, right);
}
}
/*****************************************************
* q sort threaded
*/
void prtv(string s, vector<int> &v)
{
ostringstream st;
Log log = Log::Instance();
if (v.size() > 1) {
st << s << ": size:" << v.size() << ":";
log.co(st.str());
st.str("");
for (int i = 0; i <= v.size()-2; i++) {
//cout << "v[" << i << "]:" << v[i] << ",";
st << v[i] << ",";
log.co(st.str ());
st.str("");
}
}
if (v.size() > 0) {
//cout << "v[" << v.size()-1 << "]:" << v[v.size()-1] << endl;
st << v[v.size()-1] << endl;
log.co(st.str());
st.str("");
} else {
st << s << ": size:" << v.size() << endl;
log.co(st.str());
st.str("");
}
}
int partition2(vector<int> &v, int left, int right, int pivot)
{
/*ostringstream st;
Log log = Log::Instance();
st << "End of partition: pivot: " << pivot << ", l: " << left << ", r: " << right << endl;
log.co(st.str());*/
int pivotVal = v[pivot];
swap(v[pivot], v[right]);
int store = left;
for (int i = left; i < right; i++) {
if (v[i] < pivotVal) {
swap(v[i], v[store]);
store++;
}
}
swap(v[store], v[right]);
//prtv("end of partition2", v);
return store;
}
typedef struct {
vector<int>& v;
int left;
int right;
} qs_t;
int threads;
void *qsort_threaded(void * q)
{
Log log = Log::Instance();
ostringstream s;
qs_t r1 = *(qs_t *)q;
vector<int> &v = r1.v;
int left = r1.left;
int right = r1.right;
qs_t r2 = *(qs_t *)q;
//vector<int> &v = r2.v;
//int left = r2.left;
//int right = r2.right;
//vector<int> &v = ((qs_t *)q)->v;
//int left = ((qs_t *)q)->left;
//int right = ((qs_t *)q)->right;
/*ostringstream st;
st << "begin: left " << left << ", right " << right << endl;
log.co(st.str());*/
//prtv("begin", v);
if (right > left) {
//int pivot = right/2;
int pivot = left;
int newPivot = partition2(v, left, right, pivot);
pthread_t *tid1 = NULL;
pthread_t *tid2 = NULL;
//s << "pivot:" << newPivot << ", left: " << left << ", right: " << right << endl;
//log.co(s.str());
r1.left = left;
r1.right = newPivot-1;
/*s.str("");
s << "th1: pivot:" << newPivot << ", left: " << r1.left << ", right: " << r1.right << endl;
log.co(s.str());*/
threads++;
tid1 = new pthread_t;
if (pthread_create(tid1, NULL, &qsort_threaded, (void*)&r1)) {
perror("Failed to create initial allocation thread 1:");
return (void*)-1;
}
r2.left = newPivot + 1;
r2.right = right;
/*s.str("");
s << "th2: pivot:" << newPivot << ", left: " << r2.left << ", right: " << r2.right << endl;
log.co(s.str());*/
threads++;
tid2 = new pthread_t;
if (pthread_create(tid2, NULL, &qsort_threaded, (void*)&r2)) {
perror("Failed to create initial allocation thread 2:");
return (void*)-1;
}
int i = 0;
if (tid1) {
if (0 != pthread_join(*tid1, NULL)) {
perror("pthread join tid1");
}
}
if (tid2) {
if (0 != pthread_join(*tid2, NULL)) {
perror("pthread join tid2");
}
}
} /*else {
st.str("");
st << "end: left " << left << " <= right " << right << endl;
log.co(st.str());
}*/
/* for (int j=0; j<v.size()-1; j++) {
t[j] = v[j];
}*/
return (void*)0;
}
std::auto_ptr<Log> Log::theSingleInstance;
int main(int argc, char * argv[])
{
vector<int> vi;
threads = 0;
// create a vector of random ints
int loop_cnt;
if (argc == 1)
loop_cnt = 600;
else
loop_cnt = atoi(argv[1]);
srand(time(NULL));
for( int i = 0; i < loop_cnt; i++ ) {
int num = (int) rand() % loop_cnt;
vi.push_back(num);
//cout << num << ",";
}
//cout << endl;
// copy it
vector<int> vi_builtin(vi);
vector<int> vi_qsort(vi);
vector<int> vi_qsort_threaded(vi);
// create a vector of strings
vector<string> vs;
vs.push_back("1");
vs.push_back("zerbra");
vs.push_back("towel");
vs.push_back("shovel");
vs.push_back("apple");
// built in sort
time_t start = time(0);
sort(vi_builtin.begin(), vi_builtin.end());
time_t taken = time(0) - start;
cout << "time taken for builtin: " << taken << " secs" << endl;
// qsort
start = time(0);
qsort(vi_qsort, 0, vi_qsort.size()-1);
taken = time(0) - start;
cout << "time taken for qsort: " << taken << " secs" << endl;
// qsort threaded
qs_t q = {vi_qsort_threaded, 0, vi_qsort_threaded.size()-1};
start = time(0);
qsort_threaded((void*)&q);
taken = time(0) - start;
cout << "time taken for qsort threaded: " << taken << " secs" << endl;
// shell sort
f(vi, vs);
// check if any values are different
for( int i = 0; i < vi.size(); i++ ) {
if (vi[i] != vi_builtin[i] ||
vi_qsort[i] != vi_builtin[i] ||
vi_qsort_threaded[i] != vi_builtin[i] )
cerr << "vi[i] " << vi[i] << " != " << vi_builtin[i]
<< " or vi_qsort[i] " << vi_qsort[i]
<< " or vi_qsort_threaded[i] " << vi_qsort_threaded[i] << endl;
}
// print them out
/*cout << "qsort_threaded result" << endl;
for( int i = 0; i < vi_qsort_threaded.size(); i++ ) {
cout << vi_qsort_threaded[i] << ",";
}
cout << endl;*/
cout << "thread count: " << threads << endl;
return 0;
}
Thursday, 29 November 2007
Only the Paranoid Survive
Andrew S. Grove
Sooner or later, something fundamental in your business world will change.
I'm often credited with the motto, "Only the paranoid survive." I have no
idea when I first said this, but the fact remains that, when it comes to
business, I believe in the value of paranoia. Business success contains the
seeds of its own destruction. The more successful you are, the more people
want a chunk of your business and then another chunk and then another until
there is nothing left. I believe that the prime responsibility of a manager
is to guard constantly against other people's attacks and to inculcate this
guardian attitude in the people under his or her management.
Wednesday, 28 November 2007
Monday, 26 November 2007
BZFlag - Multiplayer 3D Tank Game
3D first person Tank Simulation.
http://sourceforge.net/projects/bzflag/
Thursday, 22 November 2007
Bugzilla Addons
http://wiki.mozilla.org/Bugzilla:Addons
Wednesday, 21 November 2007
Infrarecorder free CD/DVD burning
InfraRecorder is a free CD/DVD burning solution for Microsoft Windows. It
offers a wide range of powerful features; all through an easy to use
application interface and Windows Explorer integration.
InfraRecorder is released under GPL version 2.
Features
Create custom data, audio and mixed-mode projects and record them to
physical discs as well as disc images.
Supports recording to dual-layer DVDs.
Blank (erase) rewritable discs using four different methods.
Record disc images (ISO and BIN/CUE).
Fixate discs (write lead-out information to prevent further data from
being added to the disc).
Scan the SCSI/IDE bus for devices and collect information about their
capabilities.
Create disc copies, on the fly and using a temporary disc image.
Import session data from multi-session discs and add more sessions to
them.
Display disc information.
Save audio and data tracks to files (.wav, .wma, .ogg, .mp3 and
.iso).
Alfresco & Jaspersoft - content management and business intelligence
Alfresco is the Open Source Alternative for Enterprise Content Management (ECM), providing Document Management, Collaboration, Records Management, Knowledge Management, Web Content Management and Imaging.
http://www.jaspersoft.com/
World's leading commercial open source business intelligence solutions for developers and businesses.
Monday, 19 November 2007
C# programming
Andy McMullan
http://www.andymcm.com/dotnetfaq.htm
C# FAQ for C++ programmers
Andy McMullan
http://www.andymcm.com/csharpfaq.htm
C# Language Specification
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/csspec/html/CSharpSpecStart.asp
http://www.codeplex.com/
CodePlex is Microsoft's open source project hosting web site. Start a new
project, join an existing one, or download software created by the
community.
C# Programmer's Reference
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/csref/html/vcoricprogrammersreference.asp
C# Programming
http://www.hitmill.com/programming/dotNET/csharp.html#microsoft
SOAP financial news
http://www.strikeiron.com/MTFinancialNews
This stock screening tool helps determine how a stock is likely to
react to commonly occurring news events (e.g., earnings, analyst
upgrades and downgrades, etc.) based on how it has reacted to
similar events in the past.
Friday, 16 November 2007
E8 (mathematics)
E8 (mathematics)
From Wikipedia, the free encyclopedia
- The correct title of this article is E8 (mathematics). It features superscript or subscript characters that are substituted or omitted because of technical limitations.
In mathematics, E8 is the name given to a family of closely related structures. In particular, it is the name of some exceptional simple Lie algebras as well as that of the associated simple Lie groups. It is also the name given to the corresponding root system, root lattice, and Weyl/Coxeter group, and to some finite simple Chevalley groups . It was discovered between the years of 1888-1890 by Wilhelm Killing.
The designation E8 comes from Wilhelm Killing and Élie Cartan's classification of the complex simple Lie algebras, which fall into four infinite families labeled An , Bn, Cn, Dn, and five exceptional cases labeled E6, E7, E8, F4, and G2. The E8 algebra is the largest and most complicated of these exceptional cases, and is often the last case of various theorems to be proved.
http://upload.wikimedia.org/wikipedia/commons/f/fe/E8_graph.svg
Google AJAX Feed + Firefox extensions => Piggy Bank and Solvent
Piggy Bank is a Firefox extension that turns your browser into a mashup
platform, by allowing you to extract data from different web sites and mix
them together.
Piggy Bank also allows you to store this extracted information locally for
you to search later and to exchange at need the collected information with
others.
http://simile.mit.edu/wiki/Solvent
Why do I need screen scrapers?
Piggy Bank needs web pages to embed information in a format that it can
understand. This format is called RDF (Resource Description Framework) and
its main advantage is that makes machine processing a lot easier.
Unfortunately, at these very early stages, not many web pages embed or link
to such "purer" RDF information. Piggy Bank, however, is capable of
executing a particular screen scraper on particular pages in order to
"extract" the information it needs.
In short, screen scrapers allow you to turn a regular web page into a
regular web page plus semantic data, and thus frees the data from the
page/site that contains it.
http://code.google.com/apis/ajaxfeeds/
What is the Google AJAX Feed API?
With the AJAX Feed API, you can download any public Atom or RSS feed using
only JavaScript, so you can easily mash up feeds with your content and
other APIs like the Google Maps API.
The Google AJAX Feed API takes the pain out of developing mashups in
JavaScript because you can now mash up feeds using only a few lines of
JavaScript, rather than dealing with complex server-side proxies. Making it
easy to quickly integrate feeds on your website, as shown below.
Thursday, 15 November 2007
Map reduce open source style
Hadoop and Distributed Computing at Yahoo!
http://developer.yahoo.net/blog/archives/2007/07/yahoo-hadoop.htmlOpen Source Distributed Computing: Yahoo's Hadoop Support
July 25, 2007
For the last several years, every company involved in building large web-scale systems has faced some of the same fundamental challenges. While nearly everyone agrees that the "divide-and-conquer using lots of cheap hardware" approach to breaking down large problems is the only way to scale, doing so is not easy.
The underlying infrastructure has always been a challenge. You have to buy, power, install, and manage a lot of servers. Even if you use somebody else's commodity hardware, you still have to develop the software that'll do the divide-and-conquer work to keep them all busy.
It's hard work. And it needs to be commoditized, just like the hardware has been...
We too have been dealing with this at Yahoo. Analyzing petabytes of data takes a lot of CPU power and storage. And given the way our needs (and the web as a whole) have been growing, there will likely be dozens of similarly demanding applications before long.
To build the necessary software infrastructure, we could have gone off to develop our own technology, treating it as a competitive advantage, and charged ahead. But we've taken a slightly different approach. Realizing that a growing number of companies and organizations are likely to need similar capabilities, we got behind the work of Doug Cutting (creator of the open source Nutch and Lucene projects) and asked him to join Yahoo to help deploy and continue working on the [then new] open source Hadoop project.
What started here as a 20 node cluster in March of 2006 was up to nearly 200 a month later and has continued to grow as it eats terabytes and terabytes of data. It wasn't long after that our code contributions back to Hadoop really started to ramp up as well.
http://lucene.apache.org/hadoop/Hadoop is a software platform that lets one easily write and run applications that process vast amounts of data.
Here's what makes Hadoop especially useful:
- Scalable: Hadoop can reliably store and process petabytes.
- Economical: It distributes the data and processing across clusters of commonly available computers. These clusters can number into the thousands of nodes.
- Efficient: By distributing the data, Hadoop can process it in parallel on the nodes where the data is located. This makes it extremely rapid.
- Reliable: Hadoop automatically maintains multiple copies of data and automatically redeploys computing tasks based on failures.
Hadoop implements MapReduce, using the Hadoop Distributed File System (HDFS) (see figure below.) MapReduce divides applications into many small blocks of work. HDFS creates multiple replicas of data blocks for reliability, placing them on compute nodes around the cluster. MapReduce can then process the data where it is located.
Hadoop has been demonstrated on clusters with 2000 nodes. The current design target is 10,000 node clusters.
Hadoop is a Lucene sub-project that contains the distributed computing platform that was formerly a part of Nutch.
For more information about Hadoop, please see the Hadoop wiki.
Running Hadoop MapReduce on Amazon EC2 and Amazon S3
http://developer.amazonwebservices.com/connect/entry.jspa?externalID=873&categoryID=112Wednesday, 14 November 2007
Linux changes to stop wearing down the harddisk
Jonathan Corbet
Various fixes have been gathered on the Ubuntu wiki page, but the basic
idea is to change the power savings setting for the hard disk using hdparm
-B 254 /dev/hda (or /dev/sda). The 254 value sets the least aggressive
power savings mode; some users are reporting that 255 will disable power
management completely, while others say it has no effect.
The biggest change distributions can make to help alleviate this problem is
to reduce the number of writes, especially nearly useless writes, to the
disk. One of the culprits reported for Ubuntu is the acpid power management
daemon writing battery status to a logfile every 15 seconds, which seems
like a good way to ensure the battery life reduces more quickly than it
should. Some logging could be deferred or disabled when running from
battery.
Using the relatime option when mounting filesystems is another, fairly
simple, change that could be made to significantly reduce disk writes that
are likely to be pointless. Fedora 8 enables that option by default for all
systems, battery powered or not, for the disk performance increase that it
gives. People running older kernels, before 2.6.20 added the relatime
option, may want to consider disabling atime updates altogether using the
noatime mount option.
Miro - watch free internet video channels and play any video file
http://www.getmiro.com/ - some people have had problems with it
Azureus with the RSS Feed Scanner plugin to automate tv downloads using
tvrss.net feeds
http://www.deluge-torrent.org/News:Portal
Deluge is a lightweight, Free Software, cross-platform BitTorrent client.
Full Encryption
Trackerless Support
WebUI
Plugin System
Much more..
Tuesday, 13 November 2007
Find current version on Nokia phone
keypad.
Google Gphone - Android - An Open Handset Alliance Project
The Open Handset Alliance, a group of more than 30 technology and mobile companies, is developing Android: the first complete, open, and free mobile platform. To help developers get started developing new applications, we're offering an early look at the Android Software Development Kit.
http://code.google.com/android/adc.html
Cool apps that surprise and delight mobile users, built by developers like you, will be a huge part of the Android vision. To support you in your efforts, Google has launched the Android Developer Challenge, which will provide $10 million in awards -- no strings attached -- for great mobile apps built on the Android platform.
PostgreSQL Git repository
And public Git hosting
http://repo.or.cz/
repo.or.cz is a public Git hosting site.
You can create a project here and then publish your development by pushing
to it, or even enable push access for multiple developers.
Alternately, you can just set up a mirror of any project published elsewhere
and we will provide pull and gitweb access for the project.
(read more, incl. terms&conditions)
This service is BETA.
The service is maintained by Petr Baudis,
please contact him with any requests, proposals or issues.
Register project | Register user
How to grab a project?
git clone mirror_URL
See the crash courses at git.or.cz
for more detailed introduction. You can find out the mirror_URL
for each project at the project's summary page.
Store encrypted passwords in PostgreSQL
encrypted passwords in database
in most applications you have some variant of this table:
CREATE TABLE users (
id serial PRIMARY KEY,
username TEXT NOT NULL,
passwd TEXT
);
and, usually, the passwd stores user password in clear text way.
this is usually not a problem, but in case you'd like to add password encryption in database, there are some ways to do it - and i'll show you which way i like most.
first solution is a no-brainer. make the app crypt the password and do whatever is neccessary.
now, this looks like a fine solution until you'll have more than 1 application that will be checking/setting passwords. and - usually - you will.
after all - even if you do not plan to put another website on the same database, odds are one day you'll want to change user password from psql. and what then?
so, it is better to leave the encryption job to postgres itself.
to make it so, we'll do some "magic".
first, let's make our users table in a way that it will automatically convert entered password to encrypted.
to do it - we will need pgcrypto module from contrib directory. if you dont know what i'm talking about - that's really bad, as contrib modules are extremly useful.
if you're using pre-packaged postgresql, there should be package named postgresql-contrib-your-version or similarly. just install it.
then, find pgcrypto.sql file. usually you can find it in places like /usr/share/postgresql/contrib/pgcrypto.sql, /usr/local/share/postgresql/contrib/pgcrypto.sql, /usr/local/pgsql/share/postgresql/contrib/pgcrypto.sql or similar.
when you have the file, just connect to your database of choice (using superuser account) and issue (from psql):
\i /home/pgdba/work/share/postgresql/contrib/pgcrypto.sql
which will load the pgcrypto module to your database.
now, for some more interesting fun.
for our users table, we'll add a simple trigger:
CREATE OR REPLACE FUNCTION trg_crypt_users_pass() RETURNS TRIGGER AS
$BODY$
DECLARE
BEGIN
IF substr(NEW.passwd, 1, 3) <> '$1$' THEN
NEW.passwd := crypt( NEW.passwd, gen_salt('md5') );
END IF;
RETURN NEW;
END;
$BODY$
LANGUAGE 'plpgsql';
CREATE TRIGGER trg_crypt_users_pass BEFORE INSERT OR UPDATE ON users FOR EACH ROW EXECUTE PROCEDURE trg_crypt_users_pass();
you might wander why there is this if-with-substr.
it's simple - we want to encrypt only the password that do not start with '$1$'. reason? crypted password will start with '$1$', and if we didn't put the "if" there, the first update to users table (even if it wouldn't touch passwd field) would scramble the password, thus rendering account unusable.
now, let's test if it works:
INSERT INTO users (username, passwd) VALUES ('depesz', 'depesz');
INSERT INTO users (username, passwd) VALUES ('NULL-user', NULL);
INSERT INTO users (username, passwd) VALUES ('test', ' ');
INSERT INTO users (username, passwd) VALUES ('foo', '$1$');
and what is in the table?
# SELECT * FROM users;
id | username | passwd
----+-----------+------------------------------------
1 | depesz | $1$Im51jH1k$/9AOm/t.4BixxF7YzZ5hx0
2 | NULL-user | [null]
3 | test | $1$ik3jkoki$UO4MSNsHSb5SQdq7GeZRS/
4 | foo | $1$
(4 rows)
ok, works as expected. the case with passwd = '$1$' is dubious, and we could "fix" the issue with adding length-check to trigger, but it doesn't really bother
me, so i'll leave it as it is - after all, to make a full check i would have to use a regexp, which is not really nice.
so, now our table has encrypted passwords. and i can easily search for users:
# select * from users where username = 'depesz' and crypt('depesz', passwd) = passwd;
id | username | passwd
----+----------+------------------------------------
1 | depesz | $1$Im51jH1k$/9AOm/t.4BixxF7YzZ5hx0
(1 row)
bad password check:
# select * from users where username = 'depesz' and crypt('bad-password', passwd) = passwd;
id | username | passwd
----+----------+--------
(0 rows)
now. it's not really "easily". i could definitely do better than that.
so, let's introduce another datatype: "password":
CREATE DOMAIN password as TEXT;
now, let's convert data:
alter table users alter column passwd type password;
ok, but having another datatype doesn't give me anything good. yet.
i'd like to be able to do things like:
select * from users where username = 'depesz' and passwd = 'depesz';
without all this "crypt()" mess. so, let's write some small, custom operators.
because passwords can only "match" or "not match" we will need only 2 operators: "=" and "<>". so, there goes the code:
CREATE FUNCTION password_leq(password, TEXT) RETURNS bool as $BODY$
SELECT crypt($2, $1) = $1::text;
$BODY$ language sql immutable;
CREATE OPERATOR = (
leftarg = password,
rightarg = text,
negator = <>,
procedure = password_leq
);
CREATE FUNCTION password_lne(password, TEXT) RETURNS bool as $BODY$
SELECT crypt($2, $1) <> $1::text;
$BODY$ language sql immutable;
CREATE OPERATOR <> (
leftarg = password,
rightarg = text,
negator = =,
procedure = password_lne
);
CREATE FUNCTION password_req(TEXT, password) RETURNS bool as $BODY$
SELECT crypt($1, $2) = $2::text;
$BODY$ language sql immutable;
CREATE OPERATOR = (
leftarg = text,
rightarg = password,
negator = <>,
procedure = password_req
);
CREATE FUNCTION password_rne(TEXT, password) RETURNS bool as $BODY$
SELECT crypt($1, $2) <> $2::text;
$BODY$ language sql immutable;
CREATE OPERATOR <> (
leftarg = text,
rightarg = password,
negator = =,
procedure = password_rne
);
now, thanks to this we can:
# select * from users where passwd = 'depesz'::text;
id | username | passwd
----+----------+------------------------------------
1 | depesz | $1$Im51jH1k$/9AOm/t.4BixxF7YzZ5hx0
(1 row)
but, unfortunatelly, this will fail:
# select * from users where passwd = 'depesz';
id | username | passwd
----+----------+--------
(0 rows)
reason is very simple - postgresql, when running this query will implicitly cast 'depesz' to 'password', so the "=" operator will be called for (password = password) and not for (password = text)!
to make it working we'll need 2 more operators:
CREATE FUNCTION password_beq(left password, right password) RETURNS bool as $BODY$
DECLARE
left_crypted bool;
right_crypted bool;
BEGIN
left_crypted := ( substr(left, 1, 3) = '$1$' );
right_crypted := ( substr(right, 1, 3) = '$1$' );
IF (left_crypted) AND (NOT right_crypted) THEN
RETURN crypt(right, left)::TEXT = left::TEXT;
END IF;
IF (NOT left_crypted) AND (right_crypted) THEN
RETURN crypt(left, right)::TEXT = right::TEXT;
END IF;
RETURN left::TEXT = right::TEXT;
END;
$BODY$ language plpgsql immutable;
CREATE OPERATOR = (
leftarg = password,
rightarg = password,
negator = <>,
procedure = password_beq
);
CREATE FUNCTION password_bne(password, password) RETURNS bool as $BODY$
SELECT NOT password_beq($1, $2);
$BODY$ language sql immutable;
CREATE OPERATOR <> (
leftarg = password,
rightarg = password,
negator = =,
procedure = password_bne
);
now, the password_beq function is quite complex. what it does? it tries to guess which side of comparison is encrypted, and which is not.
when only one side of comparison has '$1$' at the beginning, it crypts the other argument, and then compares. if both, or none of arguments have '$1$' - it just compares them as simple strings.
now, i can:
# select * from users where passwd = 'depesz';
id | username | passwd
----+----------+------------------------------------
1 | depesz | $1$Im51jH1k$/9AOm/t.4BixxF7YzZ5hx0
(1 row)
so, without modifying client code i modified storage of password to make them crypted. which is good, at the very least for me.
this solution has one slight "issue" which can be perceived both as a drawback, or as a bonus benefit:
# select * from users where passwd = '$1$Im51jH1k$/9AOm/t.4BixxF7YzZ5hx0';
id | username | passwd
----+----------+------------------------------------
1 | depesz | $1$Im51jH1k$/9AOm/t.4BixxF7YzZ5hx0
(1 row)
that is - instead of using standard password i can also authenticate using its hash. whether it's good i leave for you to decide - for me it's definitely a benefit.
Monday, 12 November 2007
Friday, 9 November 2007
CD DVD burning and other cool applications
http://www.getpaint.net/ Paint.net
http://bluemars.org/clipx/
http://www.scootersoftware.com/
http://www.regexbuddy.com/
http://timesnapper.com/
Your Life: The Movie
TimeSnapper lets you play back your week just like a movie. You can play it at any speed you like, and jump in at any time you like.
When it's time to fill out that dreaded timesheet, TimeSnapper is a savior. No need to tear your hair out trying to remember where all the time went.
http://taskix.robustit.com/
http://www.launchy.net/
http://www.inkscape.org/
Wednesday, 7 November 2007
Javascript Plotting
Chartr is a bit of Ruby glue to interface with the Plotr Javascript library, available here: solutoire.com/plotr/
Chartr is written by David N. Welton for DedaSys LLC.
Some time ago I was looking for a charting framework for Prototype and I couldn't find it, just because there's none. So that's where it all started. I came across PlotKit, a well written piece of javascript that enables developers to use Canvas or SVG elements for rendering bar, line and pie charts. The only thing was that PlotKit needed the Mochikit library to work. So I took some parts of PlotKit and wrote some parts myself. The result is a lightweight charting framework (12kb!) named Plotr. It's released under the BSD license.
Drop IO
http://drop.io/
Each drop is:
A private place for storing and sharing photos, video, audio, notes, docs, etc. Each is accessible only to those whom you tell exactly where to look.
No signup and no 'account'. We don't even ask for your email. Create as many drops as you want, and access each at: drop.io/thedropname.Tuesday, 6 November 2007
2007 Restaurant Winners SMH
Simon Thomsen and Catherine Keenan
September 4, 2006
Restaurant of the year Becasse, city
Chef of the year Katrina Kanetani, pastry chef, Pier, Rose Bay
Best new restaurant Bentley Restaurant & Bar, Surry Hills
Best regional restaurant Fins, Byron Bay
The Sydney Morning Herald Award for Professional Excellence Tony Bilson of Bilson's, for his commitment to fine dining, the marriage of food and wine, his influence on the next generation of chefs and for 35 years of great food.
The Sydney Morning Herald Silver Service Award Toni Urquhart of No. 2 Oak Street, Bellingen, for enthusiastic, charming, genuine, warm-hearted country hospitality and being a great sommelier to boot.
The Good Food Guide Sommelier Award Nick Hildebrandt of Bentley Restaurant & Bar, for showing us a bigger world of wine that's accessible, fascinating and, best of all, fun.
The Josephine Pignolet Young Chef of the Year Award Philip Wood from Tetsuya's. The young chef receives a return international flight courtesy of Qantas, along with the chance to work in leading European restaurants, a substantial cash prize from food suppliers and leading Sydney chefs, and a set of Furitechnics knives.
Editors' picks
Favourite bistro Bistrode, Surry Hills
Favourite Mediterranean VINI, Surry Hills
Favourite Asian Billy Kwong, Surry Hills
Favourite pizza La Disfida, Haberfield
Favourite yum cha Marigold Citymark, Haymarket
Favourite bar Bambini Wine Room, city
Favourite cafe Brasserie Bread, Banksmeadow
City
Three hats
Bilson's, Claude's, est., Guillaume at Bennelong, Marque, Pier, Quay, Tetsuya's
Two hats
Aria, Becasse, Bentley Restaurant & Bar, Bistro Moncur, Buon Ricordo, Iceberg's Dining Room & Bar, Lucio's, Omega, Pello, Pier Tasting Room, Pilu at Freshwater, Rockpool, Sean's Panaroma, Yoshii
One hat
Alchemy 731, Assiette, Astral, The Bathers' Pavilion Restaurant, Billy Kwong, Bird Cow Fish, Bistro CBD, Bistro Moore, Bistrode, The Boathouse on Blackwattle Bay, buzo, Catalina Rose Bay, Coast, Fish Face, Flying Fish, Forbes & Burton, Forty One, Galileo, Grand National, Il Piave, Jonah's, La Sala, Longrain, Lo Studio, Lotus, Mezes at Omega, Milsons, Otto, Restaurant Atelier, Restaurant Balzac, Restaurant Sojourn, Sailors Thai Restaurant, Three Weeds, The Wharf, Ying's
Regional
Two hats
Collits' Inn (Hartley Vale), Fins (Byron Bay), Solitary (Leura Falls)
One hat
Ashcrofts (Blackheath), Bannister's (Mollymook), Boomerang (Byron Bay), Caveau (Wollongong), Courgette (Canberra City), Darley's (Katoomba), dish (Byron Bay), Eschalot (Bowral), The Journeyman (Berrima), Lolli Redini (Orange), Lochiel House (Kurrajong Heights), Neila (Cowra), No. 2 Oak Street (Bellingen), Ottoman Cuisine (Barton), Restaurant II (Newcastle), The River (Moruya), Sage (Braddon), Tonic (Millthorpe), Vulcans (Blackheath), Zest (Nelson Bay)KeyRegular expressions with C on Linux
man regex
REGCOMP(3)
Linux Programmers Manual
REGCOMP(3)
NAME
regcomp, regexec, regerror, regfree - POSIX regex functions
SYNOPSIS
#include <sys/types.h>
#include <regex.h>
int regcomp(regex_t *preg, const char *regex, int cflags);
int regexec(const regex_t *preg, const char *string, size_t nmatch,
regmatch_t pmatch[], int eflags);
size_t regerror(int errcode, const regex_t *preg, char *errbuf,
size_t errbuf_size);
void regfree(regex_t *preg);
POSIX REGEX COMPILING
regcomp is used to compile a regular expression into a form that is
suitable for subsequent regexec searches.
regcomp is supplied with preg, a pointer to a pattern buffer storage
area; regex, a pointer to the null-terminated string and cflags, flags used
to determine the type of compilation.
All regular expression searching must be done via a compiled pattern
buffer, thus regexec must always be supplied with the address of a regcomp
initialized pattern buffer.
cflags may be the bitwise-or of one or more of the following:
REG_EXTENDED
Use POSIX Extended Regular Expression syntax when
interpreting regex. If not set, POSIX Basic Regular Expression syntax is
used.
REG_ICASE
Do not differentiate case. Subsequent regexec searches using
this pattern buffer will be case insensitive.
REG_NOSUB
Support for substring addressing of matches is not required.
The nmatch and pmatch parameters to regexec are ignored if the pattern
buffer supplied was compiled with this flag set.
REG_NEWLINE
Match-any-character operators donât match a newline.
A non-matching list ([^...]) not containing a newline does
not match a newline.
Match-beginning-of-line operator (^) matches the empty string
immediately after a newline, regardless of whether eflags, the execution
flags of regexec, contains REG_NOTBOL.
Match-end-of-line operator ($) matches the empty string
immediately before a newline, regardless of whether eflags contains
REG_NOTEOL.
C++ algorithm examples
#include <iostream>
#include <algorithm>
#include <numeric>
#include <vector>
/* count_if */
void count_if() {
int nums[] = { 0, 1, 2, 3, 4, 5, 9, 3, 13 };
int start = 0;
int end = 9;
int target_value = 3;
int num_items = std::count_if( nums+start,
nums+end,
std::bind2nd(std::equal_to<int>(), target_value) );
std::cout << " nums[] contains " << num_items << " items matching " << target_value << std::endl;
}
/* accumulate */
void accumulate() {
int nums[] = { 0, 1, 2, 3, 4, 5, 9, 3, 13 };
int start = 0;
int end = 9;
int target_value = 3;
int num_items = std::accumulate( nums+start,
nums+end,
target_value);
std::cout << " accumulate result: " << num_items << std::endl;
}
/* adjacent_difference */
void adjacent_difference() {
int nums[] = { 0, 1, 2, 3, 4, 5, 9, 3, 13, 0 };
int start = 3;
int end = 4;
int result = 0;
std::adjacent_difference( nums+start,
nums+end,
&result);
std::cout << " adjacent_difference: result: " << result << std::endl;
}
/* adjacent find */
void adjacent_find() {
std::vector<int> v1;
for( int i = 0; i < 10; i++ ) {
v1.push_back(i);
// add a duplicate 7 into v1
if( i == 7 ) {
v1.push_back (i);
}
}
std::vector<int>::iterator result;
result = std::adjacent_find( v1.begin(), v1.end() );
if( result == v1.end() ) {
std::cout << " Did not find adjacent elements in v1" << std::endl;
} else {
std::cout << " Found matching adjacent elements starting at " << *result << std::endl;
}
}
/* binary_search
Note: list has to be in order beforehand for it to work
*/
void binary_search()
{
int nums[] = { -242, -1, 0, 5, 8, 9, 11 };
int start = 0;
int end = 7;
for( int i = 0; i < 10; i++ ) {
if( std::binary_search( nums+start, nums+end, i ) ) {
std::cout << " nums[] contains " << i << std::endl;
} else {
std::cout << " nums[] DOES NOT contain " << i << std::endl;
}
}
}
/* copy */
void copy()
{
std::vector<int> from_vector;
for( int i = 0; i < 10; i++ ) {
from_vector.push_back( i );
}
std::vector<int> to_vector(10);
std::copy( from_vector.begin(), from_vector.end(), to_vector.begin() );
std::cout << "to_vector contains: ";
for( unsigned int i = 0; i < to_vector.size(); i++ ) {
std::cout << to_vector[i] << " ";
}
std::cout << std::endl;
}
/* copy_backward */
void copy_backward()
{
std::vector<int> from_vector;
for( int i = 0; i < 10; i++ ) {
from_vector.push_back( i );
}
std::vector<int> to_vector(15);
std::copy_backward( from_vector.begin(), from_vector.end(), to_vector.end() );
std::cout << "to_vector contains: ";
for( unsigned int i = 0; i < to_vector.size(); i++ ) {
std::cout << to_vector[i] << " ";
}
std::cout << std::endl;
}
int main ()
{
count_if();
accumulate();
adjacent_difference();
adjacent_find();
binary_search();
copy();
copy_backward();
return 0;
}
The Curse of Xanadu
By Gary Wolf
It was the most radical computer dream of the hacker era. Ted Nelson's Xanadu project was supposed to be the universal, democratic hypertext library that would help human life evolve into an entirely new form. Instead, it sucked Nelson and his intrepid band of true believers into what became the longest-running vaporware project in the history of computing - a 30-year saga of rabid prototyping and heart-slashing despair. The amazing epic tragedy.
Ten Tips for a (Slightly) Less Awful Resume
Today's scientific question is: why are the resumes of programmers so uniformly awful? And how do we fix them? The resumes, that is.
If you've spent more than approximately seventeen kiloseconds as an industry programmer, you've had to review bad tech resumes. It's just part of the job. Programmer resumes ultimately have to be gauged by programmers — it takes one to know one. So it winds up being a kind of karmic revenge on you for bad resumes that you've written. C'mon, you know you've done it. You even knew it was bad when you were writing it. Admit it! You listed HTML under programming languages, didn't you? Argh!
So why are tech resumes so bad? You know what I mean. You see the craziest stuff on resumes. Like the candidate who proudly lists every Windows API call she's ever used. Or the candidate who lists every course he took starting from junior high school. Or the one who lists college extension courses he took while doing time for armed robbery.
Execution in the Kingdom of Nouns
Hello, world! Today we're going to hear the story of Evil King Java and his quest for worldwide verb stamp-outage.
Caution: This story does not have a happy ending. It is neither a story for the faint of heart nor for the critical of mouth. If you're easily offended, or prone to being a disagreeable knave in blog comments, please stop reading now.
Comparison of different SQL implementations
The goal of this page — which is a work in progress — is to gather information relevant for people who are porting SQL from one product to another and/or are interested in possibilities and limits of 'cross-product' SQL.
The following tables compare how different DBMS products handle various SQL (and related) features. If possible, the tables also state how the implementations should do things, according to the SQL standard.
Standard / PostgreSQL / DB2 / MS SQL Server / MySQL / Oracle
Friday, 2 November 2007
Anyterm - A Terminal Anywhere
Introduction
Have you ever wanted SSH or telnet access to your system from an "internet
desert" - from behind a strict firewall, from an internet cafe, or even
from a mobile phone? Anyterm is a combination of a web page and a web
server module that provides this access - see the demos.
Anyterm can use almost any web browser and even works through firewalls.
There is experimental support for mobile phones using WAP. If you join
my.anyterm.org you can access your systems straight away via our server
with no software to install anywhere. Alternatively, you can run the
Anyterm software on your own system - see the deployment examples.
We can also help you to integrate Anyterm-type functionality into your own
applicatons, for example to web-enable a legacy system, or an embedded
system. Contact us for details.
How It Works
Anyterm consists of some Javascript on a web page, an XmlHttpRequest
channel on standard ports back to the server, and an Apache module. The
module uses a pseudo-terminal to communicate with a shell or other
application, and includes terminal emulation. Key presses are picked up by
the Javscript which sends them to the Apache module; changes to the
emulated screen are sent from the module to the Javascript which updates
its display. Performance is quite reasonable and SSL can be used to secure
the connection.
my.anyterm.org
my.anyterm.org is designed for systems administrators and others who want
the benefit of access from anywhere using Anyterm, but who don't want to
risk installing the Anyterm software on their own servers. For a small
charge you can use our Anyterm installation to connect to your own systems.
tim's shared items
Blog Archive
-
▼
2007
(118)
-
▼
November
(46)
- Universal Digital Library
- c++ qsort, threaded qsort and shell sort
- Only the Paranoid Survive
- Using pictures as a captcha
- BZFlag - Multiplayer 3D Tank Game
- Bugzilla Addons
- Infrarecorder free CD/DVD burning
- Alfresco & Jaspersoft - content management and bus...
- Open-source software rated: Ten alternatives you need
- C# programming
- Hash functions
- Userfriendly comic strip
- Password MD5 cracking
- SOAP financial news
- E8 (mathematics)
- Google AJAX Feed + Firefox extensions => Piggy Ban...
- PyQT4 Python GUI programming
- Yahoo developer series - movies
- Map reduce open source style
- Linux changes to stop wearing down the harddisk
- Miro - watch free internet video channels and play...
- A Practical Introduction to GNU Privacy Guard in W...
- Exetel SMS API
- Money Bookers Automatic Payments
- Find current version on Nokia phone
- Google Gphone - Android - An Open Handset Alliance...
- Sports Arbitrage Betting program
- PostgreSQL Git repository
- Store encrypted passwords in PostgreSQL
- Visual studio build script
- CD DVD burning and other cool applications
- Javascript Plotting
- Tango icon library
- Drop IO
- Google mapplets
- Add any page to iGoogle
- 2007 Restaurant Winners SMH
- Cool CSS for a webpage
- Regular expressions with C on Linux
- c++ count_if example
- C++ algorithm examples
- The Curse of Xanadu
- Ten Tips for a (Slightly) Less Awful Resume
- Execution in the Kingdom of Nouns
- Comparison of different SQL implementations
- Anyterm - A Terminal Anywhere
-
▼
November
(46)
Well, just to remind you, Visual Studio project file is MSBuild script file and so each project can be built using "MSBuild MySuperProject.csproj" command. So most people have build script already, but they never use it outside Visual Studio, which is where you are completely to the point.
Oleg Tkachenko on November 1, 2007 03:30 AM