Homepage
Preface();
Recently, I was lucky to be part of an awesome project called the Breaking Boundaries Tour.
This project is about two brothers, Omar and Greg Colin, who take their Stella scooters to make a full round trip across the United States. And, while they are at it, try to raise funding for Surfer’s Healing Folly Beach – an organization that does great work enhancing the lives of children with autism through surfing . To accommodate this trip, they wished to have a site where visitors could follow their trail live, as it happened. A marker would travel across the map, with them, 24/7.
Furthermore, they needed the ability to jump off their scooters, snap a few pictures, edit a video, write some side info and push it on the net, for whole the world to see. Immediately after they made their post, it had to appear on the exact spot they where at when snapping their moments of beauty.
To aid in the live tracking of their global position, they acquired a dedicated GPS tracking device which sends a latitude/longitude coordinate via a mobile data network every 5 minutes.
Now, this (short) post is not about how I build the entire application, but rather about how I used PostGIS and PostgreSQL for a rather peculiar matter: deducting timezone information.
For those who are interested though: the site is entirely build in Python using the Flask “micro framework” and, of course, PostgreSQL as the database.
Timezone information?
Yes. Time, dates, timezones: hairy worms in hairy cans which many developers hate to open, but have to sooner or later.
In the case of Breaking Boundaries Tour, we had one major occasion where we needed the correct timezone information: where did the post happen?
Where did it happen?
A feature we wanted to implement was one to help visitors get a better view of when a certain post was written. To be able to see when a post was written in your local timezone is much more convenient then seeing the post time in some foreign zone.
We are lazy and do not wish to count back- or forward to figure out when a post popped up in our frame of time.
The reasoning is simple, always calculate all the times involved back to simple UTC (GMT). Then figure out the clients timezone using JavaScript, apply the time difference and done!
Simple eh?
Correct, except for one small detail in the feature request, in what zone was the post actually made?
Well…damn.
While you heart might be at the right place while thinking: “Simple, just look at the locale of the machine (laptop, mobile phone, …) that was used to post!”, this information if just too fragile. Remember, the bothers are crossing the USA, riding through at least three major timezones. You can simply not expect all the devices involved when posting to always adjust their locale automatically depending on where they are.
We need a more robust solution. We need PostGIS.
But, how can a spatial database help us to figure out the timezone?
Well, thanks to the hard labor delivered to us by Eric Muller from efele.net, we have a complete and maintained shapefile of the entire world, containing polygons that represent the different timezones accompanied by the official timezone declarations.
This enables us to use the latitude and longitude information from the dedicated tracking device to pin point in which timezone they where while writing their post.
crSo let me take you on a short trip to show you how I used the above data in conjunction with PostGIS and PostgreSQL.
Getting the data
The first thing to do, obviously, is to download the shapefile data and load it in to our PostgreSQL database. Navigate to the Timezone World portion of the efele.net site and download the “tz_world” shapefile.
This will give you a zip which you can extract:
$ unzip tz_world.zip
Unzipping will create a directory called “world” in which you can find the needed shapefile package files.
Next you will need to make sure that your database is PostGIS ready. Connect to your desired database (let us call it bar) as a superuser:
$ psql -U postgres bar
And create the PostGIS extension:
CREATE EXTENSION postgis;
Now go back to your terminal and load the shapefile into your database using the original owner of the database (here called foo):
$ shp2pgsql -S -s 4326 -I tz_world | psql -U foo bar
As you might remember from the PostGIS series, this loads in the geometry from the shapefile using only simple geometry (not “MULTI…” types) with a SRID of 4326.
What have we got?
This will take a couple of seconds and will create one table and two indexes. If you describe your database (assuming you have not made any tables yourself):
public | geography_columns | view | postgres
public | geometry_columns | view | postgres
public | raster_columns | view | postgres
public | raster_overviews | view | postgres
public | spatial_ref_sys | table | postgres
public | tz_world | table | foo
public | tz_world_gid_seq | sequence | foo
You will see the standard PostGIS bookkeeping and you will find the tz_world table together with a gid sequence.
Let us describe the table:
\d tz_world
And get:
So we have:
- gid: an arbitrary id column
- tzid: holding the standards compliant textual timezone identification
- geom: holding polygons in SRID 4326.
Also notice we have two indexes made for us:
- tz_world_pkey: a simple B-tree index on our gid
- tzid: holding the standards compliant textual timezone identification
This is a rather nice set, would you not say?
Using the data
So how do we go about using this data?
As I have said above, we need to figure out in which polygon (timezone) a certain point resides.
Let us take an arbitrary point on the earth:
- latitude: 35.362852
- longitude: 140.196131
This is a spot in the Chiba prefecture, central Japan.
Using the Simple Features functions we have available in PostGIS, it is trivial to find out in which polygon a certain point resides:
SELECT tzid
FROM tz_world
WHERE
ST_Intersects(ST_GeomFromText(‘POINT(140.196131 35.362852)’, 4326), geom);
And we get back:
tzid
————
Asia/Tokyo
Awesome!
In the above query I used the function ST_Intersects which checks if a given piece of geometry (our point) shares any space with another piece. If we would check the execute plan of this query:
EXPLAIN ANALYZE SELECT tzid
FROM tz_world
WHERE
ST_Intersects(ST_GeomFromText(‘POINT(140.196131 35.362852)’, 4326), geom);
We get back:
QUERY PLAN
——————————————————————————————————————————
Index Scan using tz_world_geom_gist on tz_world (cost=0.28..8.54 rows=1 width=15) (actual time=0.591..0.592 rows=1 loops=1)
Index Cond: (‘0101000020E61000006BD784B446866140E3A430EF71AE4140’::geometry && geom)
Filter: _st_intersects(‘0101000020E61000006BD784B446866140E3A430EF71AE4140’::geometry, geom)
Total runtime: 0.617 ms
That is not bad at all, a runtime of little over 0.6 Milliseconds and it is using our GiST index.
But, if a lookup is using our GiST index, a small alarm bell should go off inside your head. Remember my last chapter on the PostGIS series? I kept on babbling about index usage and how geometry functions or operators can only use GiST indexes when they perform bounding box calculations.
The latter might pose a problem in our case, for bounding boxes are a very rough approximations of the actual geometry. This means that when we arrive near timezone borders, our calculations might just give us the wrong timezone.
So how can we fix this?
This time, we do not need to.
This is one of the few blessed functions that makes use of both an index and is very accurate.
The ST_Intersects first uses the index to perform bounding box calculations. This filters out the majority of available geometry. Then it performs a more expensive, but more accurate calculation (on a small subset) to check if the given point is really inside the returned matches.
We can thus simply use this function without any more magic…life is simple!
Implementation
Now it is fair to say that we do not wish to perform this calculation every time a user views a post, that would not be very efficient nor smart.
Rather, it is a good idea to generate this information at post time, and save it for later use.
The way I have setup to save this information is twofold:
- I only save a UTC (GTM) generalized timestamp of when the post was made.
- I made an extra column in my so-called “posts” table where I only save the string that represents the timezone (Asia/Tokyo in the above case).
This keeps the date/time information in the database naive of any timezone and makes for easier calculations to give the time in either the clients timezone or in the timezone the post was originally written. You simply have one “root” time which you can move around timezones.
On every insert of a new post I have created a trigger that fetches the timezone and inserts it into the designated column. You could also fetch the timezone and update the post record using Python, but opting for an in-database solution saves you a few extra, unneeded round trips and is most likely a lot faster.
Let us see how we could create such a trigger.
A trigger in PostgreSQL is an event you can set to fire when certain conditions are met. The event(s) that fire have to be encapsulated inside a PostgreSQL function. Let us thus first start by creating the function that will insert our timezone string.
Creating functions
In PostgreSQL you can write functions in either C, Procedural languages (PgSQL, Perl, Python) or plain SQL.
Creating functions with plain SQL is the most straightforward and most easy way. However, since we want to write a function that is to be used inside a trigger, we have even a better option. We could employ the power of the embedded PostgreSQL procedural language to easily access and manipulate our newly insert data.
First, let us see which query we would use to fetch the timezone and update our post record:
UPDATE posts
SET tzid = timezone.tzid
FROM (SELECT tzid
FROM tz_world
WHERE ST_Intersects(
ST_SetSRID(
ST_MakePoint(140.196131, 35.362852),
4326),
geom)) AS timezone
WHERE pid = 1;
This query will fetch the timezone string using a subquery and then update the correct record (a post with “pid” 1 in this example).
How do we pour this into a function?
CREATE OR REPLACE FUNCTION set_timezone() RETURNS TRIGGER AS $$
BEGIN
UPDATE posts
SET tzid = timezone.tzid
FROM (SELECT tzid
FROM tz_world
WHERE ST_Intersects(
ST_SetSRID(
ST_MakePoint(NEW.longitude, NEW.latitude),
4326),
geom)) AS timezone
WHERE pid = NEW.pid;
RETURN NEW;
END $$
LANGUAGE PLPGSQL IMMUTABLE;
First we use the syntax CREATE OR REPLACE FUNCTION to indicate we want to create (or replace) a custom function. Then we tell PostgreSQL that this function will return type TRIGGER.
You might notice that we do not give this function any arguments. The reasoning here is that this function is “special”. Functions which are used as triggers magically get information about the inserted data available.
Inside the function you can see we access our latitude and longitude prefixed with NEW. These keywords, NEW and OLD, refer to the record after and before the trigger(s) happened. In our case we could have used both, since we do not alter the latitude or longitude data, we simply fill a column that is NULL by default. There are more keywords available (TG_NAME, TG_RELID, TG_NARGS, …) which refer to properties of the trigger itself, but that is beyond today’s scope.
The actual SQL statement is wrapped between double dollar signs ($$). This is called dollar quoting and is the preferred way to quote your SQL string (as opposed to using single quotes). The body of the function, which in our case is mostly the SQL statement, is surrounded with a BEGIN and END keyword.
A trigger function always needs a RETURN statement that is used to provide the data for the updated record. This too has to reside in the body of the function.
Near the end of our function we need to declare in which language this function was written, in our case PLPGSQL.
Finally, the IMMUTABLE keyword tells PostgreSQL that this function is rather “functional”, meaning: if the inputs are the same, the output will also, always be the same. Using this caching keyword gives our famous PostgreSQL planner the ability to make decisions based on this knowledge.
Creating triggers
Now that we have this functionality wrapped into a tiny PLPGSQL function, we can go ahead and create the trigger.
First you have the event on which a trigger can execute, these are:
- INSERT
- UPDATE
- DELETE
- TRUNCATE
Next, for each event you can specify at what timing your trigger has to fire:
- BEFORE
- AFTER
- INSTEAD OF
The last one is a special timing by which you can replace the default behavior of the mentioned events.
For our use case, we are interested in executing our function AFTER INSERT.
CREATE TRIGGER set_timezone
AFTER INSERT ON posts
FOR EACH ROW
EXECUTE PROCEDURE set_timezone();
This will setup the trigger that fires after the insert of a new record.
Wrapping it up
Good, that all there is to it.
We use a query, wrapped in a function, triggered by an insert event to inject the official timezone string which is deducted by PostGIS’s spatial abilities.
Now you can use this information to get the exact timezone of where the post was made and use this to present the surfing client both the post timezone time and their local time.
For the curious ones out there: I used the MomentJS library for the client side time parsing. This library offers a timezone extension which accepts these official timezone strings to calculate offsets. A lifesaver, so go check it out.
Also, be sure to follow the bros while they scooter across the States!
And as always…thanks for reading!
POSTS
IT技術とギャンブルの関連性、歴史、そして将来
IT技術の発展とギャンブルの関連性 IT技術とギャンブルというのは、一見関連性がないように思われますが、実は深いつながりがあります。 この記事では、その関連性と歴史、そして現代にギャンブルにおいてIT技術がどのように生かされているのかについて解説します。 昔はシンプルなギャンブルばかりだった ギャンブルの歴史は古く、古代エジプトの時代から庶民が行っていたことは有名です。 そして、その様式は時代と共に変化していますが、IT技術の発展と普及の以後では大きく違います。 こうした技術が普及する前は、ギャンブルにおける計算はあくまで人間が簡単に行えるものに限られていたり、不正防止技術もアナログな方法が用いられていたりして、シンプルでわかりやすいものが大半でした。 そして、プレイヤーがルールに対して深い理解をしていないとそもそもプレイが難しいものや、「親」と呼ばれるゲームマスターが必要だったりと、気軽にプレイがしづらいものも多くありました。 しかし、IT技術もしくは電子計算技術が一般的になるにつれて、計算のスピードアップ化、そしてそれに伴う複雑な計算の増加や、「親」の電子化により、プレイの難易度は飛躍的に低下していきます。 そして、それに伴いプレイ人口の増加や、情報通信技術による国を超えた勝負が可能になりました。 パチンコなど、電子機械を使うギャンブルの登場 日本における最もポピュラーなギャンブルはパチンコですが、これもIT技術なくしてはプレイできません。 パチンコを行うための機器は電子的に操作されており、それにより玉の出方や確率などはプログラムによって制御されています。 近年では、最新の技術を用いたグラフィックや仕組みを活用しており、ますます高度化が激しくなっており、プレイヤーを魅了しています。 競馬など、既存のギャンブルも徐々に電子化 IT技術の普及前は、競馬等のギャンブルが盛んでしたが、こちらも時代に合わせて電子化が進んでいます。 たとえば、電子的なセンサーを利用してどの馬が勝利したのかを判定したり、馬券の倍率も確率論等を用いて数学的に決定されています。 これらは、IT技術が可能にした非常に早い計算速度を誇るコンピュータにより可能になりました。 IT技術を用いたギャンブルの次のステージはオンラインカジノ そして現在は、IT技術を更に駆使した次世代のギャンブルとして、オンラインカジノが主流になりつつあります。 オンラインカジノというのは、その名の通りインターネット上にカジノを再現したもので、これは近年のインターネット通信技術の発展により生まれました。 従来のギャンブルと比較して、オンラインカジノには下記の利点があることから、プレイ人口は増え続けています。 いつでもどこでもプレイできる 実際に店舗を構える必要がなく、すべての要素がオンライン上で再現されていることから、インターネットに接続できるデバイスさえあれば、いつでもどこでもプレイ可能です。 オンラインカジノはグラフィックや演出に凝ったものが多いのですが、近年はスマートフォンの高性能化が進んでおり、こうした高いスペックが要求されていたゲームも気軽になったことも人気の理由の一つです。 高い還元率 他のギャンブルと比べて経営にまつわるコストが低く、それが高い還元率を実現しています。 どのギャンブルでも、その運営には、店舗の賃料、人件費など多くの費用がかかっていましたが、オンラインカジノなら、基本的にはサイトの運営と変わらない上、サーバーさえ十分に用意すればプレイヤーが増えれば増えるほど売上に対する粗利益の割合が高くなるため、ビジネスとしても魅力的です。 したがって、運営側からしても高い還元率でプレイヤーを集める方が良いという判断が合理的とも言えます。 お得な入金不要ボーナス
オンラインカジノで勝てない人必見。勝つための基本を学ぶ
オンラインカジノがはじまったのはいつだろう?管理人が大学生の時にはすでに、周囲で大流行していたので、少なくとも20数年前、ブロードバンド黎明期にはもう多くのオンラインカジノが存在していた。シンプルなポーカーやスロットマシンばかりプレイしていたが、ネット上でそういったギャンブルに熱くなれるというのが非常に新しい感覚で、日夜夢中でプレイしていたのを覚えている。オンラインカジノが出現する前は、模範的な学生よろしく麻雀とパチンコ店でのスロットマシンに生活の全てをささげていたが、それらはいわゆる「カジノ」という感覚とは異なっていた。当時は4号機、5号機が全盛のスロットマシンの隆盛期。毎月のように登場する、新機能を備えた新台に全国のスロッターは年がら年中ワクワクしっぱなしであった。4号機といえばもちろん、「クランキーコンドル」「花火」「サンダー」「バーサス」また沖スロの「シオサイ」など、名機しかないありさまで、当時を思い出すたびに「あの頃は幸せだったなぁ」と感慨にふけるのであった。4号機はまだリーチ目が主体のゲーム性だったため、DDT打法による機械割の増加とリーチの察知により勝率を飛躍的に上げることができたのが何よりうれしかった。また、露骨過ぎないリールの滑りによるリーチ目の構成など、マニアに訴える部分が大きかったように思われる。いまだに、忘れられない感動的なリーチ目、忘れられない連続BIGなど、プロスポーツの名場面に勝るともおとらない感動の瞬間を自分の手で作り出していた、あの日々。特に「クランキーコンドル」のゲチェナ(右リール下段チェリー付き7)からのBIG、そしてあのレギュラーボーナス中のなんともいえないBGMは初めて付き合った彼女とのデートの思い出と同じくらい、管理人の人生において胸を震わせる大切な出来事である。 当時は客付きの良い店は大盤振る舞いのイベントをバンバン開催していたため、早朝からイベントに並び、つかんだ高設定台を閉店まで打ち切って、その後は雀荘へ行き朝まで打ち、また早朝からパチンコ屋の列に並ぶといった、エンドレスギャンブル漬け生活が常態化し、身体的な疲労は常にピークを振り切っていたものの、精神的には深い満足に包まれていたように思う。 オンラインカジノで勝つために そんな暮らしが変化し始めたのが、オンラインカジノの登場だろう。わざわざ店に行かなくても遊べる、というのは生来ずぼらな私たちギャンブラーという人種にとっては何よりも魅力的である。そして今と変わらず当時も、オンラインカジノは初心者に対して優しく、多くの初回特典を付けてくれていた。プレイを始めた当初はなかなか勝率が安定しなかったが、しばらくするとかなり良い確率で勝てるようになってきた。要因は単純にオンラインカジノについて勉強したこと。オンラインカジノで勝てない人はネット上の情報でもとりあえずは十分なので、少し時間を割いて情報収集してみよう。基本的なゲームルールや特典が比較できたりする便利なサイトがいくらでもでてくるだろう。今となってはパチンコやスロットもしぶくなり、一緒に麻雀に行く友だちもいなくなったが、オンラインカジノとの付き合いだけは残っており、相変わらず安定した勝率をほこっている。 大体はビデオスロットがメインだが、シンプルにポーカーやルーレットを楽しむこともしばしば。何をプレイしても焦って変な賭け方をしなければ、大負けをすることはなくなった。何より大事なことは、負けがこんでも熱くならないこと、これにつきる。できればその日に使う金額を決めておいて、それがなくなったらその日は終了。また明日に賭ける、そんな気持ちで楽にプレイするといいかもしれない。 ギャンブルの種類は変われど、根底にある感動は変わらない。初めての気持ちを忘れずにいつでも新鮮な気持ちで勝負に臨みたいものである。
オンラインカジノで使用されているテクノロジーとは?
最近世界中で人気を集めているオンラインカジノ。そんなオンラインカジノは日々進化しており、様々な最新テクノロジーが使用されています。 そのため、IT産業で働いている人にとっては、オンラインカジノ業界はかなりのビジネスチャンスだとも言えます。 そこでこの記事では、オンラインカジノで使用されているテクノロジーを紹介します。 プログラミング カジノゲームの制作には、多くのプログラミング言語が使用されています。ゲーム制作に使用されているプログラミング言語には、C#、C++、Unity、JavaScript、Ruby、Swiftなどがあります。 これらの言語を使用して、常にクオリティーの高いカジノゲームが制作されているのです。 また、人気のオンラインカジノはHTML5を使用して、スマートフォンからもプレイできるようにしています。 AR(人工現実)とVR(仮想現実) まだ実用されていませんが、少しずつオンラインカジノで採用されているのがARとVRです。 最近ではライブディーラーカジノゲームにAR、VRを採用しようという動きがあります。これらの技術を使用すると、専用のヘッドセットをつけてオンラインカジノをプレイすると、まるで本物のカジノにいるような感覚を味わうことができます。 カジノルームの中を自由に動き回ることができたり、他のプレイヤーがプレイしている様子を見ることができたりなど、リアルな体験をすることができるのです。 本当にARとVRが実装された場合、オンラインカジノのライブカジノゲームのクオリティーは格段に上がることでしょう。 ブロックチェーン 最近ではビットコインなどの仮想通貨を使用することができるオンラインカジノが増えています。これらのオンラインカジノでは、ビットコイン、イーサリアム、リップル、ライトコイン、ビットコインキャッシュなどの仮想通貨を使用して、入出金することができます。 また、これらの仮想通貨を使用する場合、アカウントを作成する際に住所や氏名を登録する必要がなくなります。さらに、仮想通貨を使用することで、本人確認書類を提出せずに入出金をすることが可能になります。そのため、匿名性が高く、より安全にオンラインカジノをプレイすることができるのです。 また、オンラインカジノが仮想通貨に対応している場合、法定通貨に換金することなく、仮想通貨のままカジノゲームをプレイすることができます。この場合、為替手数料を気にする必要がなくなります。 このようにブロックチェーンテクノロジーを使用することで、オンラインカジノの利便性が大きく高まっているのです。 ブロックチェーンはますます進化しており、最近ではNFTが注目されています。これらがオンラインカジノに採用されることで、ますます楽しみ方の幅が広がっていくことでしょう。 乱数ジェネレータ オンラインカジノをプレイする際には、ゲームの公平性が大切です。オンラインカジノではゲームの結果をオペレーター側で操作できないように、乱数ジェネレータを採用しています。 カジノゲームはランダムな数字を発生させるシステムのことであり、この機能をカジノゲームに搭載することで、常にゲームの結果がランダムに発生するようになります。そのため、プレイヤー全員が平等にカジノゲームを楽しむことができます。 乱数ジェネレータが搭載されていれば、カジノ側が稼ぎやすいように裏で操作されることがないので安心です。