xkcd

Say no to source-controlled credentials: .NET + RSA encryption

(This article was originally published at Blog - Alex Polozov. See Say no to source-controlled credentials: .NET + RSA encryption for more comments and better formatting.)

Let’s start with an axiom: you should never store any credentials in your source code in plain text, especially if the codebase is source-controlled. If you are doing it, there’s something seriously wrong with your architecture.1

Here’s one possible solution to this problem. Presumably you already have an OpenSSH pair of public/private keys. It will serve us nicely in this case:

  1. Generate a PEM version of your OpenSSH public key:

    $ openssl rsa -in ~/.ssh/id_rsa -pubout > ~/.ssh/id_rsa.pub.pem
    Enter pass phrase for ~/.ssh/id_rsa:
    writing RSA key
    

  2. Write your password in a plaintext file (say, admin_pass), and encrypt it (say, into admin_pass.enc):2

    cat admin_pass | openssl rsautl -encrypt -pubin -inkey ~/.ssh/id_rsa.pub.pem > admin_pass.enc
    

  3. Delete admin_pass from your hard drive.3

The resulting admin_pass.enc can be safely checked into the repository: one needs access to your private key in order to decrypt it:

cat admin_pass.enc | openssl rsautl -decrypt -inkey ~/.ssh/id_rsa

However, you probably don’t want to do even that. The best policy is to decrypt the credentials directly in your app, securely and in-memory. Presumably your favorite programming language/platform has some API for securely-stored memory objects (usually backed by the OS/hardware cryptography system). I am going to show an implementation for .NET below.

First, in order to use the OpenSSH keys in .NET infrastructure, we need to convert them both to PEM, and also generate the corresponding certificate and the PFX file. Here’s the process using my website and email as an example for the generated certificate (the exact values are not really important for our intended purpose):

$ openssl rsa -in ~/.ssh/id_rsa > ~/.ssh/id_rsa.pem
Enter pass phrase for ~/.ssh/id_rsa:
writing RSA key

$ openssl req -nodes -x509 -days 3650 -subj '/CN=www.alexpolozov.com/emailAddress=polozov@cs.washington.edu' -new -key ~/.ssh/id_rsa.pem -out ~/.ssh/certificate.crt

$ openssl pkcs12 -export -out ~/.ssh/certificate.pfx -inkey ~/.ssh/id_rsa.pem -in ~/.ssh/certificate.crt

Now let’s use this certificate to decrypt the password in C#:

public static SecureString DecryptCredentials(string certificateFile, SecureString pkPassphrase, 
                                              string encryptedFile) {
    string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
    string sshDir = Path.Combine(home, ".ssh");
    var cert = new X509Certificate2(Path.Combine(sshDir, certificateFile), pkPassphrase, 
                                    X509KeyStorageFlags.Exportable);
    using (var rsa = cert.PrivateKey as RSACryptoServiceProvider)
    using (var credentialStream = new FileStream(encryptedFile, FileMode.Open))
    using (var encrypted = new MemoryStream()) {
        credentialStream.CopyTo(encrypted);
        // Unfortunately, RSACryptoServiceProvider does not have a Decrypt() overload that
        // returns a SecureString (no idea why). Because of that, we have to store the decrypted
        // data briefly in a garbage-collected memory, and manually convert it into a secure 
        // representation as soon as possible.
        byte[] bytes = rsa.Decrypt(encrypted.ToArray(), false);
        var result = new SecureString();
        foreach (char c in Encoding.ASCII.GetChars(decrypted))
            result.AppendChar(c);
        GC.Collect();  // get rid of the decrypted bytes array
        return result;
    }
}

DecryptCredentials("certificate.pfx", Utils.SecurePrompt(), "admin_pass.enc");

The code uses a simple SecurePrompt function, which prompts the user for the SSH passphrase, encrypting one character at a time in a SecureString:

public static SecureString SecurePrompt(string prompt = "> ") {
    Console.Write(prompt);
    var password = new SecureString();
    while (true) {
        var input = Console.ReadKey(true);
        switch (input.Key) {
            case ConsoleKey.Enter:
                Console.WriteLine();
                return password;
            case ConsoleKey.Backspace:
                if (password.Length > 0) {
                    password.RemoveAt(password.Length - 1);
                    Console.Write("\b \b");
                }
                break;
            default:
                password.AppendChar(input.KeyChar);
                Console.Write("*");
                break;
        }
    }
}

  1. And with your undergraduate CS Security class, but I digress.
  2. rsautl has a maximum size limit on the data being encrypted, since it applies the RSA algorithm directly (as opposed to, say, AES). The limit is roughly equal to “[your key size] - [padding]”, which for common key sizes gives 200-400 bytes. Hopefully your password is pretty long, but it probably is not that long ☺
  3. Alternatively, you could avoid creating it in the first place, and simply cat the password from stdin.
xkcd

Подробно про казус Фейсбука и "согласованные акции"

Оригинал взят у leonwolf в Подробно про казус Фейсбука и "согласованные акции". Далее следует текст оригинала — для всех моих московских друзей.

Я создал ФБ-ивент "Народный сход для обсуждения приговора Алексею и Олегу Навальным" около 19.00 мск в пятницу, потратив на это примерно три минуты своего времени; ровно 24 часа спустя Фейсбук заблокировал этот ивент для всех пользователей, указавших Россию в качестве своего места жительства. На тот момент в ивенте было более 12500 отметок "я пойду" и свыше 60 тысяч приглашений было разослано. Мне, единственному администратору страницы мероприятия, никто не звонил, не писал, не предлагал каким-либо образом отредактировать контент - группу просто молча выпилили и все. Фейсбук сделал это на основании предписания Роскомнадзора, а тот, в свою очередь, выполнил предписание Генпрокуратуры, вынесенное в порядке, предусмотренном ублюдочным "законом Лугового", позволяющим Генпрокуратуре во внесудебном порядке блокировать сайты, призывающие, в том числе, "к массовым мероприятиям, проводящимся в нарушение установленного порядка", а, проще говоря, к несогласованным митингам.

Через пару часов после блокировки моего ивента стали возникать другие, и один из них - вот этот - собрал почти 15000 отметок "я пойду" за первые 16 часов - скорость роста в два раза больше, чем у первого ивента. Таким образом, Генпрокуратура, РКН и ФБ своими действиями нам явно помогли, еще раз доказав действенность эффекта Стрейзанд.

Испытывая чувство глубокой благодарности к ним всем в связи с этим, мы, однако, ни на секунду не вправе забывать о незаконности их действий. По российскому законодательству, уведомлять муниципальные органы власти о месте и времени проведения публичной акции (в форме митинга, шествия, пикетирования etc) необходимо не позднее чем за 10, но не ранее, чем за 15 дней до планируемой даты ее проведения. Таким образом, если бы мы хотели согласовать проведение народного схода 15.01.15, мы должны были бы обратиться в московскую мэрию в один из дней с 1 по 5 января. Если бы мы этого не сделали, или если бы мэрия не дала бы согласования, то, начиная с 6 января, наша акция была бы несогласованной и, хотя "закон Лугового" и антиконституционен, он мог бы к ней применяться в нынешнем исковерканном правовом поле Российской Федерации. До 6 января категория "согласованности" в отношении мероприятия, запланированного на 15 января, просто не применима. Оно не является согласованным, оно не является несогласованным, говорить о его "согласованности" - не больше смысла, чем говорить о характере не зачатого ребенка.

В сухом остатке: Генпрокуратура отдает, а РКН и ФБ исполняют, заведомо незаконные распоряжения (кто-то еще способен этому удивляться?). Работа с ФБ по разъяснению вышеуказанных тонкостей российского законодательства ведется через посредство общих друзей в ИТ-коммьюнити на самом высоком уровне. Посмотрим, сколько проживет новый ивент, а пока что - все записывайтесь в него и приглашайте друзей.

* * *

Вся эта история с ФБ и РКН, помимо того, что очень нам помогла, еще возбудила большую дискуссию на тему того, "надо ли пытаться сделать акцию согласованной?". Конечно же нет, никто ни в коем случае не будет обращаться в мэрию Москвы за какими-то согласованиями. "Народный сход" именно в том виде, в котором он предстоит 15 января, их и не требует: это форма прямой демократии, предусмотренная Конституцией. Мы не планируем ни митинга (с микрофоном, сценой, выступлениями), ни шествия, ни пикетирования. Люди вправе гулять вечером в центре города; вправе собираться мирно и без оружия. Никто не может запретить гражданину России в определенное время оказаться в определенном публичном месте Москвы, если он того хочет.

Более того, у мероприятия 15 января даже теоретически нет никаких "организаторов", которые могли бы обратиться в мэрию за этим самым согласованием. Это, мне кажется, лучше всего видно по истории с возникновением ивента после блокировки: окей, первый разместил я, его заблокировали, потом какие-то незнакомые мне люди сделали еще кучу ивентов, заблокируют их - люди сделают еще. Так это и работает с народными сходами. Я не собираюсь и не собирался ничего организовывать, я ведь только разместил в публичном доступе информацию, которую и так все знают - в случае несправедливого приговора надо встречаться вечером на Манежке. Если угодно, у этого мероприятия на данный момент около 15000 организаторов - или ни одного.

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

* * *

Но, честно говоря, меня так удивляет, что этот вопрос из далекого прошлого еще возникает у кого-то в конце 2014 года, что я все-таки попробую дать необходимые методологические разъяснения.

1. Очень опасная и неправильная штука - переносить механически успешные подходы из прошлого опыта на новый опыт, руководствуясь их внешним сходством. Типа, "раньше самые успешные публичные мероприятия были согласованными, значит и в этот раз, чтобы мероприятие было успешным, надо попытаться его согласовать". Это могло бы быть верно, если бы критерии успешности были теми же, но в данном случае это не так!

2. Фактически, у сторонников согласования есть только один аргумент: "на согласованное мероприятие больше людей придет". Я не очень в этом уверен; я вот бы лично на согласованное не пошел бы (потому что не вижу в нем смысла), а на несогласованное обязательно специально прилечу. И знаю много других людей, которые так думают. Время все-таки очень сильно изменилось по сравнению с тем, что было пять лет или три года тому назад.

3. Но пусть даже этот аргумент действует. Примем на секунду: "на согласованное мероприятия больше людей придет". Окей, возможно. Чтобы что? И тут я возвращаюсь к п.1. выше: а у нас какой критерий успешности?

4. Вот у многих прошлых мероприятий была цель - показать, что нас много. Почувствовать, что мы не одни. Возьмемся за руки друзья, белые ленты, воздушные шарики, вдохновляющие речи, красивые лица, все дела. Мне и сейчас кажется, что это была важная и хорошая цель, и очень хорошо, что все эти прекрасные митинги и шествия в Москве и других городах в 2011-2012 годах были. Или вот чудесный последний, сентябрьский Марш Мира: очень круто, несмотря на "крымнаш" и "84%", мы есть и нас много. Ну ОК, мы знаем, что нас много. Сейчас-то у нас цель другая немножечко. Мы идем восстанавливать справедливость. Мы идем людей вытаскивать из тюрьмы. Нам надо, чтобы два невиновных человека не получили 10 и 8 лет тюрьмы по несуществующему уголовному делу.

5. Вопрос: может ли любая согласованная акция приблизить нас к достижению этой цели (и, таким образом, быть успешной)? Ответ: нет. Пусть придет 100 тысяч, или 200 тысяч, или невероятные 500 тысяч. На согласованную площадку (это будет не Манежка, кстати, на Манежку согласования не дают). У нас за плечами бесценный опыт 2011-12 годов, и мы знаем, что от этого стены не рухнут. Путин не сбежит в женском платье в Северную Корею. Мы постоим и, воодушевленные, разойдемся - и не произойдет ничего. Гребаное ничего.

6. Таким образом и угроза согласованной акции на 100, 200 или 500 тысяч человек не будет ничего означать для тех, кто будет принимать решения, для тех, кто будет писать приговор Алексею и Олегу Навальным. Лично я уверен, что окончательное решение будет принимать лично Путин; вы можете со мной не соглашаться; возможно, это будет какой-нибудь вшивый Володин. Так или иначе, он будет оценивать последствия своего решения: "вот я согласую 10 лет, и вечером выйдет 200 тысяч на согласованный митинг на Болотку". Или: "вот я согласую 10 лет, и вечером выйдет 50 тысяч на несогласованный народный сход на Манежку".

7. Мы, конечно, не знаем наверняка, что потом произойдет у него в голове, но точно знаем, что первая альтернатива ему абсолютно понятна и абсолютно безопасна. И на его решение заведомо никак не повлияет. А вторая - повлиять может; по крайней мере шанс такой есть. Просто потому, что они не понимают, что с этим делать; просто потому, что они никогда с таким не сталкивались. Вот он видит 50000 "я пойду" в Фейсбуке под несогласованным мероприятием, и ему надо гадать - а на самом деле все 50000 выйдут? или только 5000? Или, наоборот, еще и больше выйдет? А выйдет 50000 - и что с ними сделать? Разогнать такое невозможно. Оставить стоять - создать опаснейший (для режима) прецедент на будущее, опрокинуть всю эту псевдоправовую конструкцию, связанную с "согласованиями", с управляемым протестом. Они ж так еще и во вкус войдут, и дальше будут выходить и не расходиться, и что тогда? (В автозаках Москвы - 600 посадочных мест, в отделениях полиции - около 5000; мы не знаем ни о каком инструментарии, который позволил бы властям сделать хотя бы что-то с группой в 50000 человек, которая собралась в определенном месте и не расходится). И здесь возникает шанс, что рука дрогнет - и братья Навальные выйдут на свободу. Чего мы и добиваемся, не так ли?

8. Таким образом, с точки зрения наших целей, с точки зрения успешности нашего мероприятия, кнопочки "я пойду" под согласованным мероприятием не имеют никакой ценности, и, напротив, огромную ценность имеет каждая нажатая кнопочка "я пойду" именно в нынешней конфигурации: когда нажимающий ее понимает, что речь идет о мероприятии, которое никто согласовывать не собирается, и, тем не менее, собирается на него пойти. Именно на такое мероприятие я иду сам, приглашаю всех своих друзей, и прошу всех вас приглашать своих друзей. Делая это, вы реально помогаете Алексею и Олегу. Реально помогаете сами себе.

Я рассуждаю исключительно прагматически, как вы видите, но я не вижу ни малейшего повода рассуждать иначе и терять благоразумие.
До встречи вечером 15 января на Манежке!


xkcd

Substitution mnemonics

(This article was originally published at Blog - Alex Polozov. See Substitution mnemonics for more comments and better formatting.)

(I overheard this at UW, from a graduate student who told me he doesn’t know the original author of this mnemonic either. Please do not attribute it to either of us).

In PL and formal logic, there exists a common notation, which I personally consider the worst possible notation choice of all times. Let’s say you have an expression E, in which you want to replace every occurrence of a variable x (or any other fixed subexpression, for that matter) with another variable y (again, or any other expression). This operation is called substitution1. In formal logic, λ-calculus, etc. there exists a bewildering soup of notations representing this simple transformation:

  • E[x → y] (“x is transformed into y”)
  • E[x ← y] (“x is replaced with y”)
  • E[x := y] (“assign y to every occurrence of x”)
  • E[y/x] (WTF?)

The first two (and their mirrored alternatives) are confusing on its own – you never know which substitution direction the arrow represents (is it “replace x with y” or “replace y with x”?). But the last one is notoriously ridiculous in that regard. It is too symmetric. How am I supposed to remember which variable substitutes the other one if the only thing denoting this relationship is a meaningless slash character in between? Some say this notation is the easiest to typeset – which is not true, because the third notation also doesn’t use any characters beyond standard ASCII, and it is unambiguous. Anyway, I usually tried to avoid the slash notation as much as possible whenever I could.

However, now I know a beautiful mnemonic, which breaks the “almost-symmetrical” relationship between x and y:

“Think of it as y falling over and squishing the x.”


  1. The actual formal definition of substitution is trickier, because you have to take into account which variables are free in E, and which are bound. The details are outside the scope of this post.
xkcd

On performance in .NET

(This article was originally published at Blog - Alex (Oleksandr) Polozov. See On performance in .NET for more comments and better formatting.)

Formerly, when someone asked me “How to make my C# program faster?”, my go-to advice was:

  1. Improve your computational complexity.
  2. Switch to a native language.

Of these suggestions, step #1 should take care of performance in most situations, if done properly. However, sometimes it is not enough. For example, you are writing a user-facing real-time performance-critical application, such as the C# compiler, and you need to look not only at the average performance, but at the 99th percentile. This is where step #2 used to take over… but not anymore. Currently, my go-to advice looks like this:

  1. Improve your computational complexity.
  2. Read “Writing High-Performance .NET Code”, Roslyn team blog, and the rest of the links provided below.
  3. Switch to a native language.

Measurement tools

“Writing High-Performance .NET Code” should be your desk book for any performance-critical .NET application. I found the following knowledge it provides most important:

  • What profiling tools exist in the .NET world (PerfView, ETW, CLR Profiler, dotTrace, dotMemory, Windbg…), how to use each one of them, how to answer specific questions with a combination of these tools, which metrics should you look at and why.
  • How exactly .NET GC works and why you should care. How to help .NET GC by managing your allocations and object lifecycle carefully.
  • JIT mechanics, NGEN, when to use each of them, startup rates.

In other words, when you have a specific problem with your .NET application, this book will show how to use the tools to locate who exactly is responsible for the bottleneck, how often it occurs, and so on. Often you will be surprised, because (assuming you’ve already gone through step #1) your greatest bottleneck is going to be either GC, allocations, JIT, boxing, or incorrect usage of .NET API. All of these subtle engineering details are quite unobvious if you don’t train yourself to keep them in mind.

Performance-minded coding

When you know the consequence of the problem (e.g. “my app spends 20% of the time in GC”, which arises because of “there’s this pinned handle that points to a long retention path that is being walked on every gen-2 collection”), the next step is to eliminate it. The series of links below (along with the accompanying chapters in “Writing High-Performance .NET Code”) explains the techniques for doing it. If you know that this particular path in your code is going to be performance-critical up to the 99th percentile (never optimize prematurely!), you should really think of these techniques as guiding principles to keep in mind every second during your coding process.

Here are some must-read articles for any .NET programmer that works with performance-critical code:

I’m going to list some of the mentioned techniques below, briefly. Again, the book and the sources above have already done it much better than me.

Avoid allocations

For every allocation you make, the .NET GC will spend a little more time on every future collection. If this instance is relatively long-lived, it’s going to eventually move to gen-1 and gen-2, and greatly affect the future GC times. But even if it is short-lived, the performance of gen-0 collection is going to matter in your higher percentiles anyway.

Some of the common sources of hidden allocations are:

  • LINQ queries: they allocate enumerators and lambda-representing objects that capture references in a closure. Also, eventually you need to convert a query to a list/array, and it’s going to expand itself several times in the process. Instead you should allocate a list/array of a known capacity beforehand, and do all the required work directly, without allocating hidden LINQ enumerators.
  • Lambdas: if they capture any references from the outer scope, they will be rewritten to compiler-generated objects. If your lambda operates in a generic context this object will not even be cached in place, and will be re-created every time. Consider refactoring your logic in such a way that lambda becomes non-capturing (such lambdas compile down to static methods), or get rid of the lambda altogether.
  • Strings: because they are immutable, every string modification allocates a new string object. This is most subtle in calls like string.Trim(' '), which actually returns a new string. Instead use index-based arithmetic on hot paths. For case-insensitive comparison, use the corresponding string.Compare overload instead of converting all your strings to lowercase with string.ToLower. Also, string concatenation for simple cases is much faster than string formatting.
  • Invoking a method with params always allocates an array, possibly of zero length. Consider creating specialized overloads for most common numbers of parameters.

Use object pooling

If you use some objects often but temporarily, consider allocating a pool of objects of this type once, and reuse them where necessary. For example, the interface that Roslyn uses for StringBuilders look somewhat like this:

internal static class StringBuilderPool {
    public static StringBuilder Allocate() {
        return SharedPools.Default<StringBuilder>().AllocateAndClear();
    }

    public static void Free(StringBuilder builder) {
        SharedPools.Default<StringBuilder>().ClearAndFree(builder);
    }

    public static string ReturnAndFree(StringBuilder builder) {
        SharedPools.Default<StringBuilder>().ForgetTrackedObject(builder);
        return builder.ToString();
    }
}

Which is then later used in the following manner:

public override string GetTextBetween(SyntaxToken token1, SyntaxToken token2) {
    var builder = StringBuilderPool.Allocate();
    CommonFormattingHelpers.AppendTextBetween(token1, token2, builder);
    return StringBuilderPool.ReturnAndFree(builder);
}

Compile your reflection calls into delegates

Method calling through Reflection is horrendously slow. If you know the signature of your method beforehand (and for some reason cannot agree on a common interface with the third party who implements the external method), you can use LINQ Expression Trees to compile your MethodInfo to a strongly-typed delegate. This needs to be done only once, after that you can keep a reference to the delegate, and call it whenever necessary with standard C# syntax.

The technique is described at Jon Skeet’s blog. Here’s how I used it in one of my recent projects:

public static TDelegate ToDelegate<TDelegate>(this MethodInfo method) {
     var parameterTypes = method.GetParameters().Select(p => p.ParameterType).ToArray();
     MethodInfo invokeMethod = typeof (TDelegate).GetMethod("Invoke");
     var @params = invokeMethod.GetParameters()
                               .Select((p, i) => Expression.Parameter(p.ParameterType, "arg" + i))
                               .ToArray();
     MethodCallExpression methodCall = Expression.Call(method,
         @params.ZipWith(parameterTypes).Select2(Expression.Convert));
     return Expression.Lambda<TDelegate>(Expression.Convert(methodCall, invokeMethod.ReturnType), 
         @params).Compile();
 }

Avoid boxing

Apart from obvious cases where people unnecessarily convert value types into objects (such as using now deprecated System.Collections namespace), there are some subtler ones:

  • String.Format boxes its arguments
  • Structs are boxed when used through their implemented interface. In particular, this happens when you use LINQ: List<T>.Enumerator is a struct, but LINQ methods treat it as IEnumerator<T>
  • Object.Equals(object other) is the source of all evil
  • Do not ever concatenate a string with anything other than a string
  • Calling GetHashCode on an enum causes boxing. Convert the enum instance to int first.

Use specialized collections for smaller sizes

An array outperforms a dictionary up to a certain number of elements, even though its lookup is O(n). The reason is all the boilerplate overhead that accompanies a dictionary (hashtable, bucket exploration, etc.). The exact tripping point depends on your particular code and has to be measured experimentally.

Know when to use structs and when not to

Structs give better performance than classes when they are small, consist of primitive types, and when they are not copied around often. The overhead of a class vtable is noticeable during garbage collection. However, classes are copied faster, because they are represented with just a pointer. On another hand, an array of classes will cause you a nightmare of cache misses (see reference locality). An array of structs neatly lies in memory as a single block, but would be a nightmare to copy as a function result. Bottom line, know your usecase and measure everything.

Note: you should always re-implement Equals, GetHashCode, and IEquatable<T>.Equals for your structs, because the default implementations use reflection to enumerate over the fields.

Compile your regular expressions

If you are going to reuse the same regular expression often, build it with a RegexOptions.Compiled flag. Do not ever use static methods of the Regex class, they are horrendously slow.

If your regular expressions do not require non-regular features such as lookaround or backreferences, consider using re2 instead of a default regex engine. It might yield you up to a 10x speedup. There is a .NET wrapper available, called Re2.Net.


I will stop here because I cannot possibly outline all of the techniques. Again, for the complete picture read the book, watch the talk, read the articles referenced above, know your tools, and measure everything carefully. Also, feel free to comment here if you want to contribute more advice!

Skiminok

Random thoughts on Swift

Based on my quick skimming session through the language guide.

Kind of expected from a modern language, would be surprised if it wasn't included:
  • Closures
  • Type inference
  • First-class collections and tuples
  • Generics with all kinds of boundary restrictions
  • Interoperability with existing libraries (in this case with C and Obj-C).

Surprisingly included, and it's nice:
  • ADTs and pattern matching
  • First-class Maybe monad
  • Bret Victor-style interactive IDE (let me make a sincere bow to Apple folks at this point)
  • Opt-in mutability
  • Lots of small inspirations from D, C#, Scala, etc.

However...
  • Reference counting instead of garbage collection. Cannot detect reference cycles, ergo manual weakref management.
  • I'm not quite sure how to combine "protocols" (read: interfaces) and "extensions" (read: mixins) into full-fledged traits and typeclasses. For example, how do I define a default method implementation for an interface a protocol?
    (Also, why the heck do you need so many new names for existing concepts?!)
  • Optional types are not quite Maybe, you can force the "unwrapping" with a ! operator (naturally, with a possible runtime exception). I foresee every single iOS developer just blindly doing it with every external optional they get.
  • Extremely closed infrastructure: iOS/MacOS only, proprietary compiler, etc. Hell, you need an iTunes account to even read language documentation.
  • Absolutely no first-class concurrency treatment. Moreover, there's even no library treatment for concurrency (even though it is not enough).
  • No stream processing sugar (read: comprehensions/LINQ). Well, at least they have map and reduce in the standard library, but that's about it.

Not sure how I feel about:
  • No exceptions. If you gave us some other monadic alternative, I might've put it in the "nice" section.
  • Some magic in interoperability. Apparently, they wrote "external parameters names" for many standard library functions and forgot to show them to the legacy Objective-C programmers.

Interesting. Let's see how it flies.

Published at Alex (Oleksandr) Polozov - Blog

Skiminok

Om, React и все-все-все

Замечательное описание. Я по своему роду занятий стараюсь в вебдев лезть настолько редко, насколько это вообще возможно (в частности, по многим из причин, описанных в этом посте), но прочитал с удовольствием.
Особенно отмечу рассказ про персистентное дерево, которое хранит состояние документа. Идеальная иллюстрация тем нытикам, которые «а нахрен сдались вообще эти ваши алгоритмы и олимпиады во Взрослой Жизни™».

Оригинал взят у tonsky в Om, React и все-все-все. Далее идёт текст оригинала.

React.js — это библиотека, недавно перевернувшая JavaScript-мир с ног на голову одной простой идеей: давайте оперировать не настоящими DOM-елементами, а JavaScript-классами, их изображающими. Синхронизацию этого симулякра с настоящим браузером отдадим библиотеке.


Оказалось, что если не трогать DOM, работать с объектами настолько дешево, что можно их даже не хранить, а всегда дергать функцию state → pseudo-dom, генерирующую каждый раз новый псевдо-дом. Это первое достижение React-а, сделать двухстороннюю синхронизацию данные-интерфейс односторонней. Мы всегда пишем, как из данных получить UI, и никогда не пишем, как один UI перевести в другой UI. На всякий случай еще раз: подход «а вот по этой кнопке скроем панельку» был хорош до определенного предела, пока сайт был в основном статический, с немного меняющимися частями. Сейчас же то, что рисуется в браузере при загрузке, и то, что там будет через 2 минуты, может не иметь ничего общего вообще. Поэтому подход «дайвайте опишем, как эволюционирует наш DOM» работает не очень из-за комбинаторного взрыва — слишком много способов, как он может эволюционировать.


Второе достижение React-а в том, что они реализовали концепцию «всё свое ношу с собой», придав компонентам адекватную стандартизованную структуру. Грубо говоря, в момент создания компонент сам себе нужные ресурсы выделяет и сохраняет в собственный стейт (таймеры, сокеты, листенеры), а в момент удаления — прибирает. Звучит банально, но здесь важен факт, что это есть. Ситуация аналогична проблеме неймспейсов — яйца выеденного не стоит, но в JS их забыли и каждый разработчик вынужден пускаться в собственную езду на лыжах по кирпичам. DOM-листенеры тоже, кстати, крепятся к компоненту, но уже самим react-ом. Это опять же важно для highly dynamic интерфейсов — руками за всеми ресурсами следить и замаешься, и не уследишь.


Получаем, что react-овские компоненты это такие маленькие самостоятельные кирпичики, которые действительно можно складывать в стену и они сами будут работать, не захламляя приложение в неожиданных местах типа регистрации в top-level listener или создаваемых, но никем не удаляемых setInterval.


В общем, я примерно всю революцию уже описал. Можно делать самодостаточные, переиспользуемые компоненты (у них честное воткнул-и-готово), очень простой и мощный data binding (произвольная js-функция state→dom, и не надо выкручиваться в ограничениях template bindinds, и вообще html с шаблоном не нужен), быстрая синхронизация с DOM. React.js маленький-легковесный и это, в целом, opinionless библиотека, которую можно совмещать с чем угодно. Используется Фейсбуком и Инстаграмом, куча баек про то, как интерфейс, переписанный на React, избавляется от проблем со скоростью отрисовки. Но главное, что с ростом количества динамических частей на странице код не начинает катиться в говно экспоненциально. В целом, прорыв уровня jQuery.


Теперь Om. Om — это ClojureScript-биндинг к React-у от David Nolen, главного коммитера ClojureScript, и первая вещь, которую надо про него понять — это не биндинг. Да, он использует React, оборачивает его в cljs интерфейсы, но на самом деле под этой (достаточно выгодной) этикеткой продает свои, совсем другие идеи.


Первая, и очень хорошая — зачем нам рендериться на любое изменение стейта, давайте рендериться один раз на requestAnimationFrame. Мы получим те же 60 fps и еще меньшую площадь соприкосновения с DOM, чем в React. За счет этого, например, он обогнал голый React в ToDoMVC перфтесте.


Вторая — это управление состоянием всего приложения. Если React в этом смысле был достаточно нейтрален (ну, ты, это, давай там сам как-нибудь сам), то у Om насчет состояния вполне четкие планы. Дэвид постаралася сохранить переиспользуемость компонентов и добавить несколько бонусов сверху. Если коротко, то состояние всех компонентов в Om — один большой atom, персистентная структура, а все компоненты получают view в эту структуру на то место, которое относится непосредственно к ним. Т.е. они получают такой handle (в терминах om — cursor), через который они могут читать кусочек этого большого дерева и писать в него. Если компоненту нужны подкомпоненты, можно создать под-курсор из своего курсора, например.


Эта простая идея дает два бенефита:


Возможность показывать в разных местах страницы одно и то же значение буквально. То есть, например, слева у нас таблица сотрудников (компонент table), и в колонке «пол» у них или Man, или Woman. А справа у нас text input для редактирования списка полов, и мы в нем меням Man на Male и в таблице все автоматом синхронизируется. Потому что оба компонента работают с курсором на одно и то же место в атоме. Из-за особенностей реализации text inputs в React можно даже сделать так, чтобы значение в таблице менялось по мере набора букв в text input.


Второй бенефит — это возможность работать с состоянием всего приложения как с чем-то цельным. Это персистентная структура, значит можно хранить историю состояний всего на 100 (например) версий назад, каждое состояние иммутабельное и все они разделяют кусочки, которые не изменялись. Элементарно прикручивается undo, причем на любую версию: ты просто говоришь om-у (а он react-у): давай сейчас вот это состояние рисуй, и react сам вычисляет оптимальный способ его нарисовать из текущего dom: где что удалить/добавить/подвинуть, чтобы получить целевое. Палитру History в фотошопе видели? Короче, бонус в том, что управление состоянием вынесено за скобки. Можно прикрутить логику синхронизации с сервером, undo, сохранение в localStorage — и всё это будет снаружи и отдельно, а не размазано по GUI-компонентам.


Там не всё идеально — документация мутная, курсоры излишне хитрожопо сделаны и не описаны (точнее, сейчас описаны, но это я доку написал), и вообще оно alpha. Но это уже, наверное, самый востребованный GUI-фреймворк на cljs — я думаю, из-за hype вокруг React + имени создателя. Я не то чтобы рекомендую, я скорее популяризирую хорошие идеи, плюс это еще такой спасательный круг тем, кто полезет в Om разбираться.


Вот здесь можно посмотреть на мои эксперименты: игра «41 носок» вживую, исходники.


Skiminok

О фактах печальных замолвите слово (продолжение)

Дополнение к предыдущей записи. Недавно появился такой проект — http://stopfake.org/ Он не идеален, но многие факты лжи СМИ на нём всё-таки опровергнуты корректно («бои в Симферополе», «украинские беженцы в Россию», «гибель россиян в Крыму»). Пожалуйста, давайте знакомым ссылки — пусть не ведутся на ложь. Мнений могут быть сотни, но факты, факты и только факты спасут мир.

UPD: Ещё лучше проект того же плана: http://fakecontrol.org/
Skiminok

О фактах печальных замолвите слово...

Во мне всё ещё зреет робкая надежда, что большая часть жертв информационной войны остаются восприимчивы к фактам. Поэтому я буду продолжать пытаться распространять факты (и требовать оных от своих собеседников).

(Пользуясь случаем, хочу установить своё личное отношение к обсуждениям сложившиейся ситуации. Конструктивные дискуссии с фактами и уважением приветствуются. Неадекватные высказывания с бросанием ярлыками как в сторону одной, так и другой стороны — просто игнорирую. Да, мне плевать, защищаете ли вы идеалы Майдана, Путина, масонской ложи или кого-то ещё: если вы не в состоянии вести спокойный и цивилизованный диалог без истерики и перехода на личности, с вами никто здесь не будет говорить.)

Оригинал взят у raymond_saint в российские провокаторы в Симферополе. Далее следует текст оригинала.

1. Сначала была фотография.

В абсолютном вакууме было понятно только, что это где-то в Украине.

2. Мой украинский товарищ подсказал, что номера крымские (АК=Автономия Крым?)

3. Затем был кусок "Вестей".
https://vine.co/v/MKPUve5hl5I
Симферополь. Одни российские солдаты притворяются мертвыми, пока другие лениво разглядывают крыши в прицелы. Очевидный розыгрыш.

4. Делаю пост в твиттер.


5. Сразу приходят ответы.






6. То есть приехали парни из Ялты, парк львов "Тайган" (именно это написано на автобусе, а не ЛЬВОВ-МАЙДАН)

Их сайт: http://taigan.com.ua/

7. Погуглил про ГМ-94.
Специально для ГМ-94 был разработан целый ряд 43мм унитарных выстрелов, включающих фугасные безосколочные гранаты, гранаты со слезоточивым газом, и выстрелы с резиновой "пулей".
http://world.guns.ru/grenade/rus/gm-94-r.html
It is intended mostly for various Spetsnaz elements of Russian army, FSB (Federal Security service) and MVD (Internal Affairs Ministry).
http://world.guns.ru/grenade/rus/gm-94-e.html

8. В довершение всего был найден тот самый репортаж "Вестей", для которого эти посредственные актеришки и были приглашены в Симферополь.
http://www.vesti.ru/only_video.html?vid=581456
(у напавших на оператора людей — георгиевская ленточка)

9. В качестве вишенки на торте запись 5-го канала.

Хм, может автобусы и вовсе не причем? В любом случае, никакие "бандеровцы" не могли понаехать через установленный 3 дня назад кордон беркутовцев на Перекопе.

10. И еще одна фоточка, которую я нарыл на греческом сайте.

Никакой крови под "ополченцами", очевидная подстава. Да и используй они боевые (фугасные) заряды для своих гранатометов, от российских солдат по идее должны были остаться только кишки на мостовой.

11. "Труп устал"

!int

О Пилюлькине

Относиться к происходящему в/на Украине можно по-разному, каждый имеет право на собственное мнение, но главное — не быть скотом. Коим, к сожалению, стал когда-то прекрасный писатель Сергей Лукьяненко.
Цитаты:
Но если хоть одна из писательских "персон", славивших майдан и майданутых, пишущих при том на русском и печатающихся в России, захочет появиться на российских конвентах - я буду против. Захочет публиковаться в России - приложу все силы, дабы помешать. Будьте последовательны, мерзавцы! Я отныне в Украину не езжу, в украинских конвентах не участвую, переводить свои книги на украинский запрещаю. Рекомендую и вам придерживаться того же правила. Хорошо?

source

> Вы хоть бы погибшим с обоих сторон соболезнование высказали...
Погибшим милиционерам - легко.
Погибшим погромщикам и фашистской мрази? Пусть горят в аду.

source

Я оставлю у себя на планшете "Спектр", "Искателей неба" и первые четыре "Дозора" на память о Писателе. Всё последующее, написанное Скотом, читать (а уж тем более покупать) не собираюсь.
Skiminok

Если пропал человек с телефоном

Оригинал взят у _adept_ в Если пропал человек с телефоном
Так как в моем родном городе пропадают люди, набросаю-ка я текстик - авось кому пригодится.

Если пропал человек с телефоном, и вы его ищете

Напишите ему SMS. Если SMS будет доставлен (то есть, вам пришел отчет о доставке) - у оператора сохранится запись с уникальным номером базовой станции, доставившей SMS. Это какая-никакая, но зацепка. Проверить, что SMS доставлен, можно только по отчету о доставке (delivery report). Если отправитель его не запросил (включается в настройках вашего телефона) - отчета не будет, равно как и уверенности, что SMS дошел.

Звонить (если там не берут трубку) - бестолку. Факт несостоявшегося разговора не фиксируется.

Дальше ищите способ добыть данные о том, что это за базовая, где она находится, и в какую сторону она вещает (базовые редко бывают всенаправленными).

Если телефон выключен, ищите способ добыть данные о месте последней регистрации в сети - там тоже будет уникальный номер базовой.

Если вы "пропали", и у вас есть телефон

Напишите SMS. Это может быть быстрее, чем звонить и ждать, возьмут там трубку или нет. Если вам удасться отправить SMS (не важно, будет он доставлен или нет), то у оператора сохранится запись с уникальным номером базовой, которая его приняла.

Для андроида есть приложения вроде этого, которые могут отправлять "тревожный SMS" с вашими кординатами. Приложение по ссылке отправит SMS после 2-5 кратного нажатия на power. Disclaimer: я видел и другие приложения, но ни одно из них не тестировал.

Если есть возможность - имейте при себе два телефона двух операторов. Больше шансов, что хоть одна сеть будет доступна "в случае чего", больше шансов получить данные хоть от одного оператора. Если удалось получить данные обоих операторов - резко сузится область поиска.

Как добыть данные о базовой

Я знаю, как это сделать в рамках закона и судебного процесса. Но с этим сейчас вы сами знаете как ... Мне приходит в голову только писать в социальных сетях просьбы о помощи - мир не без добрых людей, авось кто-то из имеющих доступ и откликнется.

Чтобы вам смогли помочь, в просьбу включите:

* Номер телефона абонента, который пропал. Если знаете, укажите также IMEI (серийник телефона) и IMSI (серийник сим-карты). Если знаете еще какие-то ID (номер контракта, например) - укажите и их. Имя-фамилия не нужны, т.к. полных тезок в базе оператора могут быть сотни.

* Дата и время звонков или СМС-ов, которые были приняты телефоном.

* Для каждого звонка или СМС-а укажите, с какого номера звонили или писали, в какое время (как можно точнее, до секнуд - убедитесь, что ваши часы идут точно)

* для СМС отдельно укажите время отправления и время получения отчета о доставке. СМС-ы без отчетов о доставке указывайте в крайнем случае.

* Укажите, как можно связаться с вами на условиях анонимности. Создайте документ на collabedit.com и укажите его ссылку. Создайте документ в google docs (google drive) и дайте права на редактирование всем желающим, и укажите его ссылку. Мониторьте правки в этом документе.

Коммутатор мобильной связи в час может обработать несколько десятков миллионов событий. Чем точнее вы опишете данные для поиска - тем больше шансов на успех.

Например
Помогите найти Ивана Иванова!

Его номер телефона: 380xxyyyzztt
В ЧЧ:ММ ДД.ММ.ГГГГ ему был отправлен смс с номера ..., в ЧЧ:ММ пришел отчет о доставке.
В ЧЧ:ММ ДД.ММ.ГГГГ мы ему дозвонились с номера такого-то. Трубку кто-то снял, но ничего не сказал. Звонок продолжался примерно Х секунд.
В ЧЧ:ММ телефон уже был выключен.

Нужны любые сведения о местонахождении телефона в это время или базовых станциях, которые обслужили эти сообщения, а также месте последней регистрации в сети. Любые сведения можно анонимно оставить на collabedit.com/xyt23v или <ссылка на google docs>

PS
А еще я интересуюсь SMS-ами о "регистрации в качестве участников массовых волнений"

UPD: уже не интересуюсь, там написано, почему