sea

В. Брагилевский в Киеве 18.11.2017

Теперь официально. Виталий Брагилевский в Киеве 18 Ноября 2017 года Суббота Институт Математики НАН Украины. Бесплатно. Будет видео в записи. Please Share TWIMC.

sea

KVS STREAM

-module(kvs_stream).
-manpage('https://kvs.n2o.space/man/kvs_stream.htm').
-copyrihgt('Synrc Research Center').
-author('Maxim Sokhatsky').
-license('ISC').
-include("kvs.hrl").
-export([ new/0, top/1, bot/1, take/2, drop/2, load/1, save/1, down/1, up/1, cons/2, snoc/2,
          check/0, seek/1, rewind/1, next/1, prev/1, add/2, remove/2 ]).

% section: kvs_stream prelude

se(X,Y,Z) -> setelement(X,Y,Z).
e(X,Y) -> element(X,Y).
cv(R,V) -> se(#cur.writer,R, V).
cb(R,V) -> se(#cur.bot,   R, V).
ct(R,V) -> se(#cur.top,   R, V).
cl(R,V) -> se(#cur.left,  R, V).
cr(R,V) -> se(#cur.right, R, V).
cd(R,V) -> se(#cur.dir,   R, V).
sn(M,T) -> se(#iter.next, M, T).
sp(M,T) -> se(#iter.prev, M, T).
si(M,T) -> se(#iter.id, M, T).
el(X,T) -> e(X, T).
tab(T) -> e(1, T).
et(T) -> e(#cur.top, T).
eb(T) -> e(#cur.bot, T).
id(T) -> e(#iter.id, T).
en(T) -> e(#iter.next, T).
ep(T) -> e(#iter.prev, T).
dir(0) -> top;
dir(1) -> bot.
acc(0) -> prev;
acc(1) -> next.

% section: next, prev

next (#cur{reader=[]}=C) -> {error,[]};
next (#cur{reader=B} =C) -> pos(kvs:get(tab(B),en(B)),C,right(C)).
prev (#cur{reader=[]}=C) -> {error,[]};
prev (#cur{reader=B} =C) -> pos(kvs:get(tab(B),ep(B)),C,left(C)).

left (#cur{left=0,right=0,dir=D}) -> swap(D,{0,  0});
left (#cur{left=0,right=R,dir=D}) -> swap(D,{0,  R});
left (#cur{left=L,right=R,dir=D}) -> swap(D,{L-1,R+1}).
right(#cur{left=0,right=0,dir=D}) -> swap(D,{0,  0});
right(#cur{left=L,right=0,dir=D}) -> swap(D,{L,  0});
right(#cur{left=L,right=R,dir=D}) -> swap(D,{L+1,R-1}).

swap(1,{L,R}) -> {R,L};
swap(0,{L,R}) -> {L,R}.

pos({ok,R},C,{X,Y}) -> C#cur{reader=R,left=X,right=Y};
pos({error,X},C,_)  -> {error,X}.

% section: take, drop

drop(N,#cur{dir=D}=C) -> drop(acc(D),N,C).
take(N,#cur{dir=D}=C) -> take(acc(D),N,C,[]).

take(_,_,{error,_},R) -> lists:flatten(R);
take(_,0,_,R) -> lists:flatten(R);
take(A,N,#cur{reader=B}=C,R) -> take(A,N-1,?MODULE:A(C),[B|R]).

drop(_,_,{error,X}) -> {error,X};
drop(_,0,C) -> C;
drop(A,N,C) -> drop(A,N-1,?MODULE:A(C)).

% rewind

rewind(#cur{writer=[]}=C) -> {error,[]};
rewind(#cur{dir=D,top=T,bot=B,writer=V}=C) ->
    C#cur{writer=id(kvs:get(tab(V),select(D,T,B)))}.

select(0,T,B) -> T;
select(1,T,B) -> B;
select(P,P,X) -> X;
select(P,N,X) -> N.

% seek

seek(#cur{writer=[]}=C) -> C;
seek(#cur{bot=X,reader=P,dir=0}=C) when element(2,P) == X -> C;
seek(#cur{top=X,reader=P,dir=1}=C) when element(2,P) == X -> C;
seek(#cur{top=T,bot=B,left=L,right=R,dir=0,reader=P}=C) ->
     C#cur{reader=id(kvs:get(tab(P),B)),left=0,right=L+R};
seek(#cur{top=T,bot=B,left=L,right=R,dir=1,reader=P}=C) ->
     C#cur{reader=id(kvs:get(tab(P),T)),left=L+R,right=0}.

% new, save, load, up, down, top, bot

new   () -> #cur{id=kvs:next_id(cur,1)}.
save (C) -> kvs:put(C), C.
load (K) -> case kvs:get(cur,K) of {ok,C} -> C; E -> E end.
up   (C) -> C#cur{dir=0}.
down (C) -> C#cur{dir=1}.
top  (C) -> seek(down(C)).
bot  (C) -> seek(up(C)).

% add

add(M,#cur{dir=D}=C) when element(2,M) == [] ->
    add(dir(D),si(M,kvs:next_id(tab(M),1)),C);
add(M,#cur{dir=D}=C) ->
    add(dir(D),M,C).

inc(#cur{left=L,right=R,dir=D}) -> swap(D,{L+1,R}).

cons(M,C) -> add(top,M,C).
snoc(M,C) -> add(bot,M,C).

add(bot,M,#cur{bot=T,writer=[]}=C) ->
    Id=id(M), N=sn(sp(M,T),[]), kvs:put(N),
    C#cur{writer=N,reader=N,bot=Id,top=Id};

add(top,M,#cur{top=B,writer=[]}=C) ->
    Id=id(M), N=sp(sn(M,B),[]), kvs:put(N),
    C#cur{writer=N,reader=N,top=Id,bot=Id};

add(top,M,#cur{top=T, writer=V}=C) when element(2,V) /= T ->
    add(top, M, rewind(C));

add(bot,M,#cur{bot=B, writer=V}=C) when element(2,V) /= B ->
    add(bot, M, rewind(C));

add(bot,M,#cur{bot=T,writer=V,reader=P}=C) ->
    Id=id(M), H=sn(sp(M,T),[]), N=sn(V,Id), kvs:put([H,N]),
    {L,R} = inc(C), C#cur{reader=select(V,P,N),writer=H,bot=Id,left=L,right=R};

add(top,M,#cur{top=B,writer=V,reader=P}=C) ->
    Id=id(M), H=sp(sn(M,B),[]), N=sp(V,Id), kvs:put([H,N]),
    {L,R} = inc(C), C#cur{reader=select(V,P,N),writer=H,top=Id,left=L,right=R}.

% remove

remove(I,#cur{writer=[]}=C) -> {error,val};
remove(I,#cur{writer=B,reader=X}=C) ->
    {ok,R}=kvs:get(tab(B),I), kvs:delete(tab(B),I),
    join(I,[fix(tab(B),X)||X<-[ep(R),en(R)]],C).

fix(M,[])     -> [];
fix(M,X)      -> fix(kvs:get(M,X)).
fix({ok,O})   -> O;
fix(_)        -> [].

dec(#cur{left=0,right=0,dir=D}) -> swap(D,{0,  0});
dec(#cur{left=L,right=0,dir=D}) -> swap(D,{L-1,0});
dec(#cur{left=0,right=R,dir=D}) -> swap(D,{0,R-1});
dec(#cur{left=L,right=R,dir=D}) -> swap(D,{L-1,R}).

m(I,_,I,_,I,L,R,P,V) -> {R,R};
m(_,I,I,_,I,L,R,P,V) -> {R,L};
m(I,_,_,I,I,L,R,P,V) -> {L,R};
m(_,I,_,I,I,L,R,P,V) -> {L,L};
m(I,_,_,_,I,L,R,P,V) -> {sn(V,id(R)),P};
m(_,I,_,_,I,L,R,P,V) -> {sp(V,id(R)),P};
m(_,_,I,_,I,L,R,P,V) -> {V,sn(P,id(L))};
m(_,_,_,I,I,L,R,P,V) -> {V,sp(P,id(L))};
m(_,_,_,_,I,L,R,P,V) -> {V,P}.

join(I,[[],[]],C) ->
    {X,Y} = dec(C),
    C#cur{top=[],bot=[],writer=[],reader=[],left=X,right=Y};

join(I,[[], R],#cur{reader=P,writer=V}=Cur) ->
    N=sp(R,[]), kvs:put(N), {X,Y} = dec(Cur),
    {NV,NP} = m(en(V),ep(V),en(P),ep(P),I,[],N,P,V),
    Cur#cur{top=id(N), writer=NV, reader=NP, left=X, right=Y};

join(I,[L, []],#cur{reader=P,writer=V}=Cur) ->
    N=sn(L,[]), kvs:put(N), {X,Y} = dec(Cur),
    {NV,NP} = m(en(V),ep(V),en(P),ep(P),I,N,[],P,V),
    Cur#cur{bot=id(N), writer=NV, left=X, reader=NP, right=Y};

join(I,[L,  R],#cur{reader=P,writer=V}=Cur) ->
    N=sp(R,id(L)), M=sn(L,id(R)), kvs:put([N,M]), {X,Y} = dec(Cur),
    {NV,NP} = m(en(V),ep(V),en(P),ep(P),I,N,M,P,V),
    Cur#cur{left=X, reader=NP, writer=NV, right=Y}.

% TESTS

check() ->
    te_remove(),
    test1(),
    test2(),
    drop(),
    create_destroy(),
    next_prev_duality(),
    test_sides(),
    rewind(),
    ok.

rewind() ->
    Empty = {'user2',[],[],[],[],[],[],[],[]},
    C = #cur{top=T,bot=B,left=L,right=R,writer=V,reader=P} =
    save(
    add(Empty,down(
    add(Empty,up(
    add(Empty,down(
    add(Empty,up(
    add(Empty,new())))))))))),
    PId = id(P),
    VId = id(V),
    B = VId,
    PId = B - 4,
    ok.

test_sides() ->
    Empty = {'user2',[],[],[],[],[],[],[],[]},
    #cur{top=T,bot=B,left=L,right=R,writer=V,reader=P} =
    save(
    add(Empty,up(
    add(Empty,down(
    add(Empty,new())))))),
    PId = id(P),
    VId = id(V),
    VId = T,
    PId = B - 1,
    1 = T - B,
    L = R = 1.

next_prev_duality() ->
    Cur = new(),
    [A,B,C] = [ kvs:next_id('user2',1) || _ <- lists:seq(1,3) ],
    R = save(
        add({'user2',A,[],[],[],[],[],[],[]},
        add({'user2',B,[],[],[],[],[],[],[]},
        add({'user2',C,[],[],[],[],[],[],[]},
        Cur)))),
    X = load(id(Cur)),
    X = next(
        next(
        prev(
        prev(X)))).

test2() ->
    Cur = new(),
    [A,B,C,D] = [ kvs:next_id('user2',1) || _ <- lists:seq(1,4) ],
    [] = take(-1,
         up(
         bot(
         remove(A,
         remove(B,
         remove(C,
         remove(D,
         add({'user2',A,[],[],[],[],[],[],[]},
         add({'user2',B,[],[],[],[],[],[],[]},
         add({'user2',C,[],[],[],[],[],[],[]},
         add({'user2',D,[],[],[],[],[],[],[]},
         up(Cur)))))))))))).

create_destroy() ->
    Cur = new(),
    [A,B,C,D] = [ kvs:next_id('user2',1)
             || _ <- lists:seq(1,4) ],
    [] = take(-1,
         remove(B,
         remove(D,
         remove(A,
         remove(C,
         add({'user2',D,[],[],[],[],[],[],[]},
         add({'user2',C,[],[],[],[],[],[],[]},
         add({'user2',B,[],[],[],[],[],[],[]},
         add({'user2',A,[],[],[],[],[],[],[]},
         up(new())))))))))).

test1() ->
    [A,B,C,D] = [ kvs:next_id('user2',1) || _ <- lists:seq(1,4) ],
    R  = save(
         add({'user2',D,[],[],[],[],[],[],[]},
         add({'user2',C,[],[],[],[],[],[],[]},
         add({'user2',B,[],[],[],[],[],[],[]},
         add({'user2',A,[],[],[],[],[],[],[]},
         new() ))))),
    X  = take(-1,top(R)),
    Y  = take(-1,bot(R)),
    X  = lists:reverse(Y),
    L  = length(X).

drop() ->
    #cur{id=S}=save(new()),
    P = {'user2',[],[],[],[],[],[],[],[]},
    S1 = save(
         add(P,
         add(P,
         add(P,
         add(P,
         load(S)))))),
    S2= drop(2,S1),
    2 = length(take(-1,S2)),
    4 = length(take(-1,S1)),
    ok.

te_remove() ->
    #cur{id=S}=save(new()),
    P = {'user2',[],[],[],[],[],[],[],[]},
    S1 = save(
         add(P,
         add(P,
         add(P,
         add(P,
         load(S)))))),
    4 = length(take(-1,S1)),
    S2 = save(top(S1)),
    S3 = save(remove(S2#cur.top-1,S2)),
    List = take(-1,top(S3)),
    Rev  = take(-1,bot(S3)),
    List = lists:reverse(Rev),
    3 = length(List),
    {S3,List}.
sea

Swift Model Generator from Erlang Types

-module(roster_swift).
-export([parse_transform/2]).
-compile(export_all).
-define(SRC, "apps/roster/priv/macbert/").

parse_transform(Forms, _Options) -> switch(directives(Forms)), Forms.
directives(Forms) -> lists:flatten([ form(F) || F <- Forms ]).

switch(List) ->
    file:write_file(?SRC++"Source/Decoder.swift",
    iolist_to_binary(lists:concat([
       "func parseObject(name: String, body:[Model], tuple: BertTuple) -> AnyObject?\n"
       "{\n    switch name {\n",
       [case_rec(X) || X <- List],
       "    default: return nil\n"
       "    }\n}"
    ]))).

act(List,union,Args,Field,I) -> act(List,union,Args,Field,I,simple);
act(List,Name,Args,Field,I) -> act(List,Name,Args,Field,I,keyword).

act(List,Name,Args,Field,I,Fun) ->
%    io:format("Keyword: ~p~n",[{Name,Args}]),
    lists:concat([tab(1),List,".",Field,
    " = body[",I,"].parse(bert: tuple.elements[",I+1,"]) as? ",
    ?MODULE:Fun(Name,Args,{Field,Args}),"\n"]).

case_rec({Atom,T}) ->
    List = atom_to_list(Atom),
    Lower = string:to_lower(List),
    Var = "a" ++ List,
    lists:concat([ "    case \"", List, "\":\n"
    "        if body.count != ", integer_to_list(length(T)), " { return nil }\n",
    io_lib:format("        let ~s = ~s()\n",[Var,List]),
    [ tab(2) ++ act(Var,Type,Args,Field,I-1) ||
         {{_,{_,_,{atom,_,Field},Value},{type,_,Type,Args}},I} <- lists:zip(T,lists:seq(1,length(T))) ],
    "        return " ++ Var ++ "\n" ]).

form({attribute,_,record,{List,T}})  ->
   [X|Rest]=atom_to_list(List),
   case X >= $A andalso X =< $Z andalso List /= 'Client'
                                orelse List == io
                                orelse List == error
                                orelse List == ok2
                                orelse List == error2
                                orelse List == ok of true
      -> spec(List,T),
         class(List,T),
         {List,T};
    _ -> [] end;
form(Form) ->  [].

class(List,T) ->
   file:write_file(?SRC++"/Model/"++atom_to_list(List)++".swift",
   iolist_to_binary(case lists:concat([ io_lib:format("\n    var ~s",
                [ infer(Name,Args,atom_to_list(Field))])
               || {_,{_,_,{atom,_,Field},Value},{type,_,Name,Args}} <- T ]) of
               [] -> [];
               Fields -> lists:concat(["\nclass ",List," {", Fields, "\n}"]) end)).

spec(List,T) ->
    file:write_file(?SRC++"/Spec/"++atom_to_list(List)++"_Spec.swift",
    iolist_to_binary("func get_"++atom_to_list(List) ++ "() -> Model {\n  return " ++ premodel(List,T) ++ "}\n")).

premodel(List,T) ->
    D = 1,
    Model = tab(D) ++ string:join([ model({type,X,Type,Args},D+1) || {_,_,{type,X,Type,Args}} <- T ],",\n"++tab(D)),
    erlang:put(List,Model),
    io_lib:format("Model(value:Tuple(name:\"~s\",body:[\n~s]))",[atom_to_list(List), Model]).

tab(N) -> lists:duplicate(4*N,$ ).

model({type,_,nil,Args},D)     -> "Model(value:List(constant:\"\"))";
model({type,_,binary,Args},D)  -> "Model(value:Binary())";
model({type,_,atom,Args},D)    -> "Model(value:Atom())";
model({type,_,list,[{type,_,atom,[]}]},D)    -> "Model(value:List(constant:nil, model:Model(value:Atom())))";
model({type,_,list,[{type,_,binary,[]}]},D)  -> "Model(value:List(constant:nil, model:Model(value:Binary())))";
model({type,_,list,[{type,_,integer,[]}]},D) -> "Model(value:List(constant:nil, model:Model(value:Number())))";
model({_,_,list,[{_,_,record,[{_,_,Name}]}]},D) -> lists:concat(["Model(value:List(constant:nil,model:get_",Name,"()))"]);
model({type,_,list,[Union]},D)    -> "Model(value:List(constant:nil, model:"++ model(Union,D) ++ "))";
model({type,_,record,[{atom,_,Name}]},D)        -> lists:concat(["get_",Name,"()"]);
model({type,_,list,Args},D)    -> "Model(value:List(constant:nil))";
model({type,_,boolean,Args},D) -> "Model(value:Boolean())";
model({atom,_,Name},D)         -> lists:concat(["Model(value:Atom(constant:\"",Name,"\"))"]);
model({type,_,term,Args},D)    -> "Model(value:nil)";
model({type,_,integer,Args},D) -> "Model(value:Number())";
model({type,_,tuple,any},D)    -> "Model(value:Tuple())";

model({type,_,union,Args},D)   -> io_lib:format("Model(value:Chain(types:[\n~s]))",
                                  [tab(D) ++ string:join([ model(I,D+1) || I <- Args ],",\n"++tab(D))]);

model({type,_,tuple,Args},D)   -> io_lib:format("Model(value:Tuple(name:\"\",body:[\n~s]))",
                                  [tab(D) ++ string:join([ model(I,D+1) || I <- Args ],",\n"++tab(D))]);

model({type,_,Name,Args},D)    -> io_lib:format("Model(~p): Args: ~p~n",[Name,Args]).

keyword(X,Y,_Context) -> keyword(X,Y).
keyword(record, [{atom,_,Name}]) -> lists:concat([Name]);
keyword(list, [{type,_,record,[{atom,_,Name}]}]) -> lists:concat(["[",Name,"]"]);
keyword(list, [{type,_,atom,[]}]) -> lists:concat(["[","String","]"]);
keyword(list, Args)   -> "[AnyObject]";
keyword(tuple,any)    -> "[AnyObject]";
keyword(term,Args)    -> "AnyObject";
keyword(integer,Args) -> "Int";
keyword(boolean,Args) -> "Bool";
keyword(atom,Args)    -> "StringAtom";
keyword(binary,Args)  -> "String";
keyword(union,Args)   -> "AnyObject";
keyword(nil,Args)     -> "AnyObject".

infer(union,Args,Field) -> Field ++ ": " ++ simple(union,Args,{Field,Args}) ++ "?";
infer(Name,Args,Field)  -> Field ++ ": " ++ keyword(Name,Args,{Field,Args}) ++ "?".

simple(A,[{type,_,nil,_},{type,_,Name,Args}],Context) -> keyword(Name,Args,Context);
simple(A,[{type,_,Name,Args},{type,_,nil,_}],Context) -> keyword(Name,Args,Context);
simple(_,_,_) -> "AnyObject".
sea

IO PROTOCOL


1.

-record(error, {code=[] :: [] | binary()}).
-record(ok,    {code=[] :: [] | binary()}).
-record(io,    {code=[] :: [] | #ok{} | #error{},
                data=[] :: [] | <<>> | {atom(),binary()|integer()}}).

2.

Form: {error,
          [{typed_record_field,
               {record_field,15,{atom,15,code},{nil,15}},
               {type,15,union,[{type,15,nil,[]},{type,15,binary,[]}]}}]}

Form: {ok,[{typed_record_field,{record_field,16,{atom,16,code},{nil,16}},
                               {type,16,union,
                                     [{type,16,nil,[]},
                                      {type,16,binary,[]}]}}]}

Form: {io,[{typed_record_field,
               {record_field,17,{atom,17,code},{nil,17}},
               {type,17,union,
                   [{type,17,nil,[]},
                    {type,17,record,[{atom,17,ok}]},
                    {type,17,record,[{atom,17,error}]}]}},
           {typed_record_field,
               {record_field,18,{atom,18,data},{nil,18}},
               {type,18,union,
                   [{type,18,nil,[]},
                    {type,18,binary,[{integer,18,0},{integer,18,0}]},
                    {type,18,tuple,
                        [{type,18,atom,[]},
                         {type,18,union,
                             [{type,18,binary,[]},
                              {type,18,integer,[]}]}]}]}}]}

3.

-module(swift).
-compile({parse_transform, swift}).
-export([parse_transform/2]).
-compile(export_all).

parse_transform(Forms, _Options) ->
    Directives = directives(Forms),
    Result = lists:flatten([directives(Forms)]),
    file:write_file("model.swift", list_to_binary(Result)),
    Forms.

directives(Forms) -> lists:flatten([ form(F) || F <- Forms ]).

form({attribute,_,record,{List,T}})  ->
   [X|Rest]=atom_to_list(List),
   case X >= $A andalso X =< $Z orelse List =:= io
                                orelse List == error
                                orelse List == ok of true -> class(List,T); _ -> [] end;
form(Form) ->  [].

class(List,T) ->
   case lists:concat([ io_lib:format("\n    var ~s",
                [ infer(Name,Args,nitro:to_list(Field))])
               || {_,{_,_,{atom,_,Field},Value},{type,_,Name,Args}} <- T ]) of
               [] -> [];
               Fields -> lists:concat(["\nclass ",List," {", Fields, "\n}"]) end.

keyword(list)    -> "String?";
keyword(term)    -> "AnyObject?";
keyword(integer) -> "Int?";
keyword(boolean) -> "Bool?";
keyword(atom)    -> "String?";
keyword(binary)  -> "String?";
keyword(union)   -> "AnyObject?";
keyword(nil)     -> "AnyObject?".

infer(union,Args,Field) -> Field ++ ": " ++ simple(Args);
infer(Name,Args,Field)  -> Field ++ ": " ++ keyword(Name).

simple([{type,_,nil,_},{type,_,Name,_}]) -> keyword(Name);
simple([{type,_,Name,_},{type,_,nil,_}]) -> keyword(Name);
simple(_) -> "AnyObject?".

4.

$ cat roster.swift

class error {
    var code: String?
}
class ok {
    var code: String?
}
class io {
    var code: AnyObject?
    var data: AnyObject?
}
sea

Свисс Эмоушинс

Когда у меня еще не было паспорта, из всей Европы мне не хотелось побывать нигде. Я вырос в европейском городишке, по сути ебаное село 100 тыс населения в 400 км от Киева на юг, но очень красивое. Когда старшие друзья мне показывали свои фотки Саграды де Фамилия упоротого Гауди и шотландские замки у меня хуй не ставал ни на что, потому что в Каменце-Подольском, где я родился, была и есть своя крепость, и свой архитектурный фьюжин 7 народов (евреев, поляков, армян, турков, литовцев, украинцев, русских), и желания ездить в Еропу, чтобы повтыкать на очередной замок, собор, костёл или маленькие улочки с ресторанчиками, не было никакого — все это я и так видел.

Но Швейцария другое дело, я туда всегда хотел попасть, прямо таки незакрытый гештальт. Просто я был нищебродом и просить делать визу у друзей не было никакого желания, даже если вы и считаете, что это не унижение.  Но как вы знаете, нам дали БЕЗВИЗ и первым делом я решил закрыть детские травмы, побывав в самой дорогом городе Европы и самой дорогой стране и определить — наконец нищеброд я или нет.

Приблизительно я набросал такой план на 4 дня:

Tickets: 1000, Hotel: 2000, Per Day: 500 x 4 = 2000, Airport Gifts: 500

Пятерочку должен осилить каждый Java-синьор, поэтому если у вас тоже не закрыт гештальт можете ориентироваться на меня. Написав эту СМС своей жене с предварительным планом, она забукала такие отели:

1. ZenCity (Geneva), 2. Eden (Montreux), 3. Mirador (Vevey), 4. AirBnB

Collapse )
sea

Архивариус

Полистал свой ЖЖ за последние 14 лет. Вообщем убивать все не очень хочется, особенно доставляют посты в период повышенного резонанса в 2010—2011 гг. Тогда в воздухе серотонин прямо стоял топором. Посты с тегом dharma надо перенести на отдельный ресурс типа http://5ht.co/dharma/ и инкрустировать их музычкой типа http://ns.synrc.com/music/dharma/sound.htm Когда-то в молодости хотел прямо книгу из своих постов с тегом дхарма ебануть, но с мудростью такие желания, конечно, быстро проходят, не надо ничего писать, все тексты написаны, надо их только перевести и прочитать. Такой проект тоже есть: http://nying.ma/sa.bcad.htm

А всё, что касается cs разделить на пару категорий, условно: "продакшин", "кок" и "фантазии". Продакшин касается в основном только эрланг проектов и synrc. Для synrc начал перезапуск на новом домене n2o.space, такое же же ждет и жежешечку. 5ht.co был наброском, будем продолжать.

В принципе стихов тоже достаточно в жжшечке, думаю какую-то брошюрку можно было бы выпустить.
sea

Санкционный Куб

Предлагаю Куб с дискретными измерениями: {русский, украинец}, {за санкции, против санкции}, {пользуется сервисами агрессора, не пользуется}

thedeemon — vk.com и yandex.com не пользуется, против санкций, русский
dmytrish — vk.com и yandex.com не пользуется, против санкций, украинец
maxim — в целом пользуется сервисами агрессора, за санкции, укрианец
errorrishe — не пользуется, за санкции, украинец
...

Регистрируйтесь в каментах :-) или добавляйте измерения, например {есть дети, нет детей} и т.д.
sea

Сервисы ЖЖ

А активити лог неплохой в ЖЖ появился! Интересно, полит-изгнанники на dreamwidth его видят? Палитра контрольных элементов в жежешечке приятная, достойна того, по крайней мере, чтобы ее спиздить.