カラースキーム作成ツール「Agave」は質が良かったし翻訳を取り込んでもらった思い入れもあるソフトだったんだけど、開発が止まっててパッケージも消えちゃって残念だなぁと思ってたのでBlenderにアドオンとして移植してみた。
UIはもうちょっと何とかしたいけどAPI的に制限あるからどうするのが正解だろう?
前回(↓)の続き。
nazodane.hatenadiary.org
前回のADDVAL>>SHIFT
を2進法に直すと以下のようになる。
>>> [bin((0xaaaaaaaaaaaaaaab * ((1 << (i+1)) - 1) &0xffffffffffffffff) >> (i+1)) for i in range(63)] ['0b101010101010101010101010101010101010101010101010101010101010101', '0b0', '0b1010101010101010101010101010101010101010101010101010101010101', '0b0', '0b10101010101010101010101010101010101010101010101010101010101', '0b0', '0b101010101010101010101010101010101010101010101010101010101', '0b0', '0b1010101010101010101010101010101010101010101010101010101', '0b0', '0b10101010101010101010101010101010101010101010101010101', '0b0', '0b101010101010101010101010101010101010101010101010101', '0b0', '0b1010101010101010101010101010101010101010101010101', '0b0', '0b10101010101010101010101010101010101010101010101', '0b0', '0b101010101010101010101010101010101010101010101', '0b0', '0b1010101010101010101010101010101010101010101', '0b0', '0b10101010101010101010101010101010101010101', '0b0', '0b101010101010101010101010101010101010101', '0b0', '0b1010101010101010101010101010101010101', '0b0', '0b10101010101010101010101010101010101', '0b0', '0b101010101010101010101010101010101', '0b0', '0b1010101010101010101010101010101', '0b0', '0b10101010101010101010101010101', '0b0', '0b101010101010101010101010101', '0b0', '0b1010101010101010101010101', '0b0', '0b10101010101010101010101', '0b0', '0b101010101010101010101', '0b0', '0b1010101010101010101', '0b0', '0b10101010101010101', '0b0', '0b101010101010101', '0b0', '0b1010101010101', '0b0', '0b10101010101', '0b0', '0b101010101', '0b0', '0b1010101', '0b0', '0b10101', '0b0', '0b101', '0b0', '0b1']
ようするにこんな感じに単純化できる。
>>> [(lambda t=0b101010101010101010101010101010101010101010101010101010101010101:(t >> i) * ((i&1)^1))() for i in range(63)] [6148914691236517205, 0, 1537228672809129301, 0, 384307168202282325, 0, 96076792050570581, 0, 24019198012642645, 0, 6004799503160661, 0, 1501199875790165, 0, 375299968947541, 0, 93824992236885, 0, 23456248059221, 0, 5864062014805, 0, 1466015503701, 0, 366503875925, 0, 91625968981, 0, 22906492245, 0, 5726623061, 0, 1431655765, 0, 357913941, 0, 89478485, 0, 22369621, 0, 5592405, 0, 1398101, 0, 349525, 0, 87381, 0, 21845, 0, 5461, 0, 1365, 0, 341, 0, 85, 0, 21, 0, 5, 0, 1]
最後の((((CMPVAL>>SHIFT) - !!((CMPVAL & ((1<
を2進法に直すと以下のようになる。
>>> [bin((lambda shift=i+1, mask=(1<<(i+1))-1:((0x5555555555555555 >> shift) - ((0x5555555555555555&mask) < ((0xaaaaaaaaaaaaaaab*mask) & mask)))&(0xffffffffffffffff>>shift))()) for i in range(63)] ['0b10101010101010101010101010101010101010101010101010101010101010', '0b1010101010101010101010101010101010101010101010101010101010101', '0b101010101010101010101010101010101010101010101010101010101010', '0b10101010101010101010101010101010101010101010101010101010101', '0b1010101010101010101010101010101010101010101010101010101010', '0b101010101010101010101010101010101010101010101010101010101', '0b10101010101010101010101010101010101010101010101010101010', '0b1010101010101010101010101010101010101010101010101010101', '0b101010101010101010101010101010101010101010101010101010', '0b10101010101010101010101010101010101010101010101010101', '0b1010101010101010101010101010101010101010101010101010', '0b101010101010101010101010101010101010101010101010101', '0b10101010101010101010101010101010101010101010101010', '0b1010101010101010101010101010101010101010101010101', '0b101010101010101010101010101010101010101010101010', '0b10101010101010101010101010101010101010101010101', '0b1010101010101010101010101010101010101010101010', '0b101010101010101010101010101010101010101010101', '0b10101010101010101010101010101010101010101010', '0b1010101010101010101010101010101010101010101', '0b101010101010101010101010101010101010101010', '0b10101010101010101010101010101010101010101', '0b1010101010101010101010101010101010101010', '0b101010101010101010101010101010101010101', '0b10101010101010101010101010101010101010', '0b1010101010101010101010101010101010101', '0b101010101010101010101010101010101010', '0b10101010101010101010101010101010101', '0b1010101010101010101010101010101010', '0b101010101010101010101010101010101', '0b10101010101010101010101010101010', '0b1010101010101010101010101010101', '0b101010101010101010101010101010', '0b10101010101010101010101010101', '0b1010101010101010101010101010', '0b101010101010101010101010101', '0b10101010101010101010101010', '0b1010101010101010101010101', '0b101010101010101010101010', '0b10101010101010101010101', '0b1010101010101010101010', '0b101010101010101010101', '0b10101010101010101010', '0b1010101010101010101', '0b101010101010101010', '0b10101010101010101', '0b1010101010101010', '0b101010101010101', '0b10101010101010', '0b1010101010101', '0b101010101010', '0b10101010101', '0b1010101010', '0b101010101', '0b10101010', '0b1010101', '0b101010', '0b10101', '0b1010', '0b101', '0b10', '0b1', '0b0']
ようするにこんな感じに単純化できる。
>>> [(lambda t=0b10101010101010101010101010101010101010101010101010101010101010:t >> i)() for i in range(63)] [3074457345618258602, 1537228672809129301, 768614336404564650, 384307168202282325, 192153584101141162, 96076792050570581, 48038396025285290, 24019198012642645, 12009599006321322, 6004799503160661, 3002399751580330, 1501199875790165, 750599937895082, 375299968947541, 187649984473770, 93824992236885, 46912496118442, 23456248059221, 11728124029610, 5864062014805, 2932031007402, 1466015503701, 733007751850, 366503875925, 183251937962, 91625968981, 45812984490, 22906492245, 11453246122, 5726623061, 2863311530, 1431655765, 715827882, 357913941, 178956970, 89478485, 44739242, 22369621, 11184810, 5592405, 2796202, 1398101, 699050, 349525, 174762, 87381, 43690, 21845, 10922, 5461, 2730, 1365, 682, 341, 170, 85, 42, 21, 10, 5, 2, 1, 0]
あまり最適化に使える気はしないけど多倍長の時に偶数と奇数それぞれで上位ビット消すだけで済むのは利点かな?
前回(↓)の続き。
nazodane.hatenadiary.org
前回のコードを適当にベクトライズするとこうなる。
// gcc rcollatz.c -O3 -march=haswell // clang rcollatz.c -O3 -mavx #include <stdint.h> #include <stdio.h> //#include <assert.h> void loop(uint64_t x, int l){ // assert(x&1); uint64_t xa[64]; for (int i = 0; i < 63; i++) xa[i] = x; for (int i = 0; i < 63; i++) xa[i] = xa[i] << (i+1); // shift + add vs. fma for (int i = 0; i < 63; i++) xa[i] = xa[i] + 0xaaaaaaaaaaaaaaab * ((1 << (i+1)) - 1); for (int i = 0; i < 63; i++) { if (0x5555555555555555 >= xa[i] /*暫定→*/ && xa[i] < 0xffff){ printf("l=%d::%0lx\n", l, xa[i]); if (l) loop(0xaaaaaaaaaaaaaaab * (xa[i] ^ 1), l-1); } } } int main(void){ uint64_t s = 1, x = 0; printf("l=ss::1\n"); for(int i = 1; i < 16; i++){ s <<= 2; s++; printf("l=s::%0lx\n", s); x <<= 2; x += (0xaaaaaaaaaaaaaaab << 2); loop(x, 99); } return 0; }
以下のコードはシフトより上と下に分けることが出来る。
bool ge_shift_add(uint32_t x){ return (CMPVAL >= (x<<SHIFT) + ADDVAL); }
そのためxのシフトを無くしてこう変形できるはず。
bool ge_shift_add2(uint32_t x){ return ((((CMPVAL>>SHIFT) - !!((CMPVAL & ((1<<SHIFT)-1)) < (ADDVAL & ((1<<SHIFT)-1))))&(0xffffffff>>SHIFT)) >= ((x + (ADDVAL>>SHIFT))&(0xffffffff>>SHIFT))); }
ADDVAL>>SHIFT
側をpythonで計算するとこんな感じ。
>>> print [(0xaaaaaaaaaaaaaaab * ((1 << (i+1)) - 1) &0xffffffffffffffff) >> (i+1) for i in range(63)] [6148914691236517205L, 0L, 1537228672809129301L, 0L, 384307168202282325L, 0L, 96076792050570581L, 0L, 24019198012642645L, 0L, 6004799503160661L, 0L, 1501199875790165L, 0L, 375299968947541L, 0L, 93824992236885L, 0L, 23456248059221L, 0L, 5864062014805L, 0L, 1466015503701L, 0L, 366503875925L, 0L, 91625968981L, 0L, 22906492245L, 0L, 5726623061L, 0L, 1431655765L, 0L, 357913941L, 0L, 89478485L, 0L, 22369621L, 0L, 5592405L, 0L, 1398101L, 0L, 349525L, 0L, 87381L, 0L, 21845L, 0L, 5461L, 0L, 1365L, 0L, 341L, 0L, 85L, 0L, 21L, 0L, 5L, 0L, 1L]
偶数が0、奇数が[(4**i)/3 for i in range(1, 33)]
の逆順になってる。
((((CMPVAL>>SHIFT) - !!((CMPVAL & ((1<<SHIFT)-1)) < (ADDVAL & ((1<<SHIFT)-1))))&(0xffffffff>>SHIFT))
側をpythonで計算するとこんな感じ。
>>> print [(lambda shift=i+1, mask=(1<<(i+1))-1:((0x5555555555555555 >> shift) - ((0x5555555555555555&mask) < ((0xaaaaaaaaaaaaaaab*mask) & mask)))&(0xffffffffffffffff>>shift))() for i in range(63)] [3074457345618258602L, 1537228672809129301L, 768614336404564650L, 384307168202282325L, 192153584101141162L, 96076792050570581L, 48038396025285290L, 24019198012642645L, 12009599006321322L, 6004799503160661L, 3002399751580330L, 1501199875790165L, 750599937895082L, 375299968947541L, 187649984473770L, 93824992236885L, 46912496118442L, 23456248059221L, 11728124029610L, 5864062014805L, 2932031007402L, 1466015503701L, 733007751850L, 366503875925L, 183251937962L, 91625968981L, 45812984490L, 22906492245L, 11453246122L, 5726623061L, 2863311530L, 1431655765L, 715827882L, 357913941L, 178956970L, 89478485L, 44739242L, 22369621L, 11184810L, 5592405L, 2796202L, 1398101L, 699050L, 349525L, 174762L, 87381L, 43690L, 21845L, 10922L, 5461L, 2730L, 1365L, 682L, 341L, 170L, 85L, 42L, 21L, 10L, 5L, 2L, 1L, 0L]
つまり、[(2**(i+2)-3-(-1)**i)/6 for i in range(63)]
の逆順になってる。
うーん、このあともシフト計算無くして行ける気がするけど、式が長くなって頭こんがらがっていくので今日はここまで。
別式の追加
前回(↓)の続き。
nazodane.hatenadiary.org
コラッツ問題の計算で、最後の手前の数字は「3の倍数かつ1を足すと2の累乗数になる数」になるはず(偶数処理を遅延した場合はそれに2の累乗数を掛ける必要あるけど、今回は遅延しないで考えることとする)。
1を足すと2の累乗数になる数というのは二進法で1が連続してる数のこと(e.g. 0b1、0b11、0b111、...)であり、
その中で3の倍数になるのは1の連続が偶数個の場合となっている (以下の検証はPython)。
>>> print [(2**x-1) for x in range(1, 32)] [1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215, 33554431, 67108863, 134217727, 268435455, 536870911, 1073741823, 2147483647] >>> print [(2**x-1)%3 for x in range(1, 32)] # 0の時に割り切れる [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1] >>> print [(2**(x*2)-1)%3 for x in range(1, 32)] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
3を掛ける前はどうなるかというと以下のようになる。
>>> print [(2**(x*2)-1)/3 for x in range(1, 32)] [1, 5, 21, 85, 341, 1365, 5461, 21845, 87381, 349525, 1398101, 5592405, 22369621, 89478485, 357913941, 1431655765, 5726623061, 22906492245, 91625968981, 366503875925, 1466015503701, 5864062014805, 23456248059221, 93824992236885, 375299968947541, 1501199875790165, 6004799503160661, 24019198012642645, 96076792050570581, 384307168202282325, 1537228672809129301] >>> print [bin((2**(x*2)-1)/3) for x in range(1, 32)] ['0b1', '0b101', '0b10101', '0b1010101', '0b101010101', '0b10101010101', '0b1010101010101', '0b101010101010101', '0b10101010101010101', '0b1010101010101010101', '0b101010101010101010101', '0b10101010101010101010101', '0b1010101010101010101010101', '0b101010101010101010101010101', '0b10101010101010101010101010101', '0b1010101010101010101010101010101', '0b101010101010101010101010101010101', '0b10101010101010101010101010101010101', '0b1010101010101010101010101010101010101', '0b101010101010101010101010101010101010101', '0b10101010101010101010101010101010101010101', '0b1010101010101010101010101010101010101010101', '0b101010101010101010101010101010101010101010101', '0b10101010101010101010101010101010101010101010101', '0b1010101010101010101010101010101010101010101010101', '0b101010101010101010101010101010101010101010101010101', '0b10101010101010101010101010101010101010101010101010101', '0b1010101010101010101010101010101010101010101010101010101', '0b101010101010101010101010101010101010101010101010101010101', '0b10101010101010101010101010101010101010101010101010101010101', '0b1010101010101010101010101010101010101010101010101010101010101']
ここから2**nを掛けて(右側に0を増やす)、1を引いて(LSBをクリアしてその下のビットを全て立てる)、3の倍数を作っては3で割るというのを繰り返していけば良いはず。
前二つの操作は合わせると0b1をクリアして右側に1を増やしていくということになる。
3で割り切れるかどうかは以下みたいに変形できるらしい(gcc -O3の結果より)。
#include <stdint.h> uint64_t is_divable3(uint64_t x){ return (x % 3 == 0); } uint64_t is_divable3_opt(uint64_t x){ return 0x5555555555555555 >= 0xaaaaaaaaaaaaaaab * x; }
上記を全て合わせると逆から計算するこんなコードが出来上がったけど上手く動いているかは未確認。
#include <stdint.h> #include <stdio.h> //#include <assert.h> void loop(uint64_t x, int l){ // assert(x&1); x = 0xaaaaaaaaaaaaaaab * (x ^ 1); for (int i = 1; i < 64; i ++){ x <<= 1; x += 0xaaaaaaaaaaaaaaab; if (0x5555555555555555 >= x /*暫定→*/ && x < 0xffff){ printf("l=%d::%0lx\n", l, x); if (l) loop(x, l-1); } } } int main(void){ uint64_t s = 1; printf("l=ss::1\n"); for(int i = 1; i < 16; i++){ s <<= 2; s++; printf("l=s::%0lx\n", s); loop(s, 99); } return 0; }
偶数のケースと1のケースを修正。
同じ値でループするケースを削除。
重複無くしたはず。
1億円欲しいからコラッツ予想に手を出してみる。
science.srad.jp
ja.wikipedia.org
まず偶数処理をまとめたコラッツ問題の計算プログラムを適当に書く。
// gcc collatz.c -march=haswell // ./a.out 13179928405231 // Copyright: Nazodane // License: GPLv2 or later #include <stdio.h> #include <x86intrin.h> int main(int argc, char *argv[]){ u_int64_t n = 0; if(argc < 2){ printf("./collatz num"); return 0; } sscanf(argv[1], "%lu", &n); u_int64_t step = _tzcnt_u64(n); u_int64_t odd = n >> step; // 偶数 / 2 を繰り返す // printf("%lu\n", step); while(odd > 1){ u_int64_t even = ((odd+1) + (odd<<1)); // 奇数 * 3 + 1 u_int64_t cnt = _tzcnt_u64(even); odd = even >> cnt; // 偶数 / 2 を繰り返す step += 1 + cnt; // printf("%lu\n", step); } printf("step = %lu\n", step); }
オーバーフローしやすくなるのを無視して偶数処理を遅延させる。
// gcc collatz.c -march=haswell // ./a.out 13179928405231 // Copyright: Nazodane // License: GPLv2 or later #include <stdio.h> #include <x86intrin.h> int main(int argc, char *argv[]){ u_int64_t n = 0; if(argc < 2){ printf("./collatz num"); return 0; } sscanf(argv[1], "%lu", &n); u_int64_t step = 0; u_int64_t x = n&-n; while(n != x){ // 奇数処理 n = ((n+x) + (n<<1)); x = n&-n; step++; } step += _tzcnt_u64(x); // 偶数処理 printf("step = %lu\n", step); }
適当に多倍長化してみる。
// gcc collatz.c -march=haswell // ./a.out 13179928405231 // Copyright: Nazodane // License: GPLv2 or later #include <stdio.h> #include <x86intrin.h> #define N 10000 int main(int argc, char *argv[]){ u_int64_t n[N] = {0}; if(argc < 2){ printf("./collatz num"); return 0; } for(int a = 1; a < argc; a++) sscanf(argv[a], "%lx", &n[argc - a - 1]); u_int64_t step = 0; u_int64_t idx = 0; while(idx < N && !n[idx]) idx++; // TODO: overflow check u_int64_t max = N-1; while(max > 0 && !n[max]) max--; // printf("idx:max = %lu:%lu\n",idx,max); u_int64_t x = n[idx]&-n[idx]; while(max != idx || n[idx] != x){ unsigned __int128 t = n[idx]; t = (t+x) + (t<<1); n[idx] = t; u_int64_t ovfl = t >> 64; if(idx == max && ovfl) max++; // TODO: overflow check for (int i = idx+1; i < max+1; i++){ t = n[i]; t = (t+ovfl) + (t<<1); n[i] = t; ovfl = t >> 64; if(i == max && ovfl) max++; // TODO: overflow check } while(idx < max && !n[idx]) idx++; x = n[idx]&-n[idx]; // printf("idx:max = %lu:%lu\n",idx,max); step++; } step += _tzcnt_u64(x) + idx*64; // 偶数処理 printf("step = %lu\n", step); }
下にある例を試してみる。
math.stackexchange.com
The best 500-digit number I found used 25858 steps, and is:
16910⋅2^1646−1=52907,40618,32017,54152,63867,78240,01344,94071,10672,87955,14970,95443,32426,37432,94723,15343,69589,15667,94197,77289,84251,30595,66986,13736,01999,30240,57853,88392,15872,66353,93648,16021,76528,02318,47325,39772,11544,04475,63943,10264,65156,58431,35122,30262,85026,21429,61128,92928,64147,40168,11368,14718,14844,43105,54823,58463,32284,16963,01649,12670,32815,41060,21677,81365,13557,54204,91127,46553,29004,21933,21888,08910,76179,94524,51718,32033,27205,55270,66366,57606,00582,53081,68267,14042,35673,44288,21454,35891,44482,68697,66804,20865,40074,26362,70517,10800,03191,26585,23809,38239
16進数に変換して16文字で区切ってコマンドラインに入れる。
$ ./a.out 10837FFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF step = 25858
上手く動いてるみたいだけど、さてここからどうしよう?
怪しい記事を見かけたので、こちらの環境で解析したAnitubeの広告配信経路をここに書いておきます。なおこれは一例であって、環境や機会により広告関連スクリプトの流れも変わるはずです。
とりあえず、以下のページのソースコードを開きます。
http://www.anitube.se/video/#####/XYZ
すると、ページのヘッダ、サイド、フッタ、動画の下の広告表示部分に以下のようなHTMLコードが埋めこまれています。これが、広告表示スクリプトを読み込むための起点となります。ここでは蘭Adglare社のスクリプトを読み込んでいます。
<!-- Advert Start --> <div id="pageAdvert" align="center"> <script async src='//anigrupo.engine.adglare.net/?#########'></script><span id=#########></span> </div> <!-- Advert End -->
その後、以下のURLのJavascriptが読み込まれ実行されます。(なお、URLの後ろの#########はzIDとのこと。)
//anigrupo.engine.adglare.net/?#########
スクリプトの内容は大幅に省略しますが、以下のような感じで、別のJavascriptを読み込むためのものです。
(前略)
AdGlare.loadJS('//anigrupo.engine.adglare.net/?#########&t=1&tt=##########-########');
loadJS関数でURLが色々加工された後、最終的に以下のURLにあるJavascriptが読み込まれ実行されます。
http://anigrupo.engine.adglare.net/?#########&t=1&tt=##########-########&winID=#####&screen=####x####&framed=0&vb=1&crIDsLoaded=&referer=http%3A%2F%2Fwww.anitube.se%2Fvideo%2F#####%2FXYZ
上記URLのJavascriptの内容はこんな感じ。
(前略) var AdGlareSettings_###### = { zID: #########, width: ###, height: ###, impURL: "//anigrupo.engine.adglare.net/imp?data=(略)", isThirdParty: true, autoClickTracking: true, isSync: false, alwaysOnScreen: false, alwaysOnScreenData: '', animationType: 'none', allowClose: true, closeButtonURL: '//anigrupo.cdn.adglare.net/inventory/close_button.png', isBase64Encoded: true, zoneHTML: "(BASE64っぽい文字列)", (略)} (略)document.write('<span id=zone'+this.settings.zID+'>'+this.settings.zoneHTML+'</span>'(略)
BASE64っぽい文字列をデコードすると、HTMLの断片が現れます。
<!-- ad tags Size: 728x90 ZoneId:#######--> <script type="text/javascript" src="http://js.sprout-ad.com/t/###/###/x#######.js"></script>
そして、そこに書かれたスクリプトが読み込まれます。このURL (*.sprout-ad.com) は日本のトラストリッジ社のものですね。
内容は下のような感じ。
(略) var di={(略),vd:"sprout-ad.genieesspv.jp",(略)}; (略) u+="//"+di.vd+"/yie/ld/jsk"; u+=(略)
そして、ここで以下のURLが生成されます。このURL (*.genieesspv.jp) は日本のジーニー社のものですね。
http://sprout-ad.genieesspv.jp/yie/ld/jsk?zoneid=#######&cb=###########&charset=UTF-8&loc=http%3A%2F%2Fwww.anitube.se%2Fvideo%2F#####%2FXYZ&referer=http%3A%2F%2Fwww.anitube.se%2Fvideo%2F#####%2FXYZ&sw=####&sh=####&topframe=0
生成されたURLからスクリプトが更に読み込まれます。内容は下のような感じ。
gen_tag = "%3cscript%20type%3d%27text%2fjavascript%27(略)%2fscript%3e";document.write(decodeURIComponent(gen_tag));
gen_tagのエスケープを解いてやると、ついに広告本体のHTMLが出てきます (謎なiframeも付属してましたが解説では省略)。今回は最終的な広告のURL (*.gsspat.jp) がジーニー社のものでした。
<script type='text/javascript'>(略)<a href=\"http:\/\/rt.gsspat.jp\/c?c=(略)&y=1&p=XXXXXXXXXXX&do=(略)&vs=(略)\" style=\"border:none;margin:0;padding:0;\" target=\"_top\" >\\n');(略)document.write(\"<img src=\\\"\" + scheme + \"\/\/rt.gsspat.jp\/b?p=XXXXXXXXXXX&y=1&v=(略)\\\" height='1' width='1' style='display: none;'>\");(略)</script>
ということで、今回調べた時は蘭Adglare社→日トラストリッジ社→日ジーニー社という流れでしたが、別の会社の広告が出てくることも確認していますし、経路はまだまだあるはずです。
それと、これだけでは契約の流れがどうなってるのかまでは分かりませんね。更に中間業者が挟まっている気がします。
# …にしても凄く長いタライ回しだなぁ…。