Monday, 9 January 2012
Handmade lamp/alarm clock with Android charge
Tags:
Android,
DIY,
lamp alarm
Взбрело мне в голову поиграться с микросхемами. Поскольку от схемотехники я уже далёк, то решил сделать для начала что-то простое, но полезное, а затем уже двигаться к сложному и just-for-fun. Выписал список идей, составил таблицу истинности плюсов и минусов, отсортировал в порядке усложнения...
В итоге, решил сделать световой будильник с использованием Андроида. В чём суть?
| Reactions: |
Saturday, 24 September 2011
Influence, Robert Cialdini
Tags:
books,
Cialdini,
influence,
psychology
В последнее время я стал достаточно много читать и решил поделиться немного с вами. Очередную книгу по психологии мне посоветовал друг. Встречайте: Robert Cialdini, Influence.
Честно говоря, я люблю психологию в доступном изложении, но, к сожалению, к подобным книгам отношусь с опаской. Слишком громкое название, за которым автор обычно прячет достаточно известные принципы, которые разжевываются по триста раз и вода в тексте, в которой утопаешь, забыв о сути книги. Не совсем понимаю почему многократное повторение так любят авторы подобной литературы, но мне это не подходит. Именно по данной причине, например, я не могу читать Карнеги Дейла. Так что же мне понравилось в данной книге?
| Reactions: |
Sunday, 19 June 2011
Immigration process (search for a work)
Tags:
expat,
immigration,
work permit,
work search
"Люди думают, что будут счастливы, если переедут в Париж, а потом оказывается: куда бы ты ни поехал, ты берёшь с собой себя." (с)овершенно точно.
Сегодня мы поговорим о вопросах поиска работы за пределами родной страны. Данный пост по сути родился из моего опыта и всё учащающихся вопросах о процессе иммиграции. Хочется начать рассказ с самого начала: с поиска работы, ибо только подписанный контракт на сегодняшний день - залог долгосрочной визы. Речь, естественно об IT.
Данный пост почему-то захотелось оформить в стиле поучительного TO-DO списка. Итак, поехали:
0. Определись с тем, чего именно ты хочешь. Какова твоя цель, что ты за человек, где истоки твоего желание, чтобы не получилось как в эпиграфе.
1. Страна или страны. Этот выбор стоит сделать на достаточно раннем этапе.
1.1. Изучи иммиграционное законодательство целевой страны. Обычно достаточно изучить материалы на сайтах посольств или консульств. Там есть большинство документов и описанных процессов.
1.2. Узнай какие типы виз тебе подходят. В некоторых странах действуют программы для "Highly Skilled Immigrants", по которым тебе вообще не нужен рабочий контракт, для получения визы. Достаточно соответствовать некому набору критериев. (Большинство таких программ, к сожалению, закрылись или в процессе закрытия)
1.3. Изучи рынок. Узнай какие вакансии преимущественно попадают на IT рынок данной страны, какие у них зарплаты. Здесь сильно помогают monster.com и glassdoor.com
1.4. Изнай сколько налогов ты будешь платить, сколько стоит жилье, сколько тебе понадобится на еду (для начала умножай на два с тем расчетом, что ты будешь тратить больше пока не освоишься).
2. Вылижи резюме.
2.1. Резюме должно быть на английском, а не на его подобии.
2.2. Вот собственно: CV style. Мои взгляды особо не поменялись :)
2.3. Составь сопроводительное письмо. Небольшое, не раздражай читающего, но из которого станет понятно, что ты адекватный человек, ищешь работу и тебе нужна виза. Последний пункт очень важен: лучше не тратить времени зря и искать сразу тех, кто понимает, что на данный момент ты ВНЕ целевой страны.
2.4. Ну и наконец, используй PDF :) Хотя лучше иметь заготовки в разных форматах.
3. Параллельно можно начинать искать вакансии, но инфо из первого пункта стоит знать заранее, чтобы чувствовать себя более комфортно в разговоре.
3.1. Составь список компаний, которые работают в данной стране. Выписывай и крупные, и маленькие. Можно искать через тот же Monster например, но одного источника мало. Многие крупные компании вообще не работают через агенства - о их вакансиях можно узнать только у них на сайте.
3.2. Составь себе табличку, где будешь собирать данные о компаниях, их контакты и ссылки на вакансии, на которые ты выслал своё резюме. Стоит помнить куда именно ты отсылал письма и как называются вакансии (может сильно пригодится).
3.3. Будь готов, что если кто-то заинтересуется - будут звонить. Телефонный контакт для HR очень важен: он более надёжен + позволяет хоть немного оценить адекватность и наличие языка. Если можешь говорить только в определённое время - укажи это в резюме.
3.4. Писать надо всем. Неважно есть у компании открытая вакансия или нет. Не важно, что в вакансии указано, что требуются жители только определённой страны. Всякое бывает. Главное, ты не должен скрывать, что ты сам находишься вне этой определённой страны.
3.5. Если какая-то компания нравится больше всего, через день после отсылки резюме перезвони и уточни получили ли они твоё письмо.
4. Ну и BodyShop
4.1. Такие фирмы, как Епам, Люксофт и множество других перевозят людей. Они получают процент от твоей з/п в итоге. Этот вариант стоит рассматривать в самый последний момент, ибо условия работы зачастую пониже будут + есть свои нюансы. Из позитивных моментов - компания берёт на себя всё оформление.
5. Немного психологии.
5.1. Будь готов, что многие не отвечают вообще.
5.2. Пойми, что процесс может быть очень длительным.
5.3. Если кто-то пригласил на собеседование, это еще не победа. Иногда надо пройти 6-8 собеседований в одной и той же компании, чтобы устроится на работу.
P.S. Если кто-то не в курсе про источник картинки: Поросёнок Петя
| Reactions: |
Wednesday, 6 April 2011
PostgreSQL. Redirect data to child partition.
Tags:
db,
partitioning,
plpython,
postgres,
variable table name
На одном из недавно "вверенных" проектов жил поживал PostgreSQL с настроенным разбиением данных по таблицам-разделам в зависимости от значений (т.н. Partitioning). Особенности работы с БД были таковы, что раз в сутки в таблицы "вливалось" достаточно большое кол-во данных (десятки миллионов строк) и до следующего "вливания" база работала только на отдачу данных.
Проблема, а точнее даже не проблема, а пожелание заключалось в следующем: ПО, которое занималось подготовкой, фильтрацией и, собственно заливкой данных, занималось еще и тем, что вычисляло тот самый, нужный раздел (child table), в который данные нужно сложить. Это приводило к:
- невозможности менять условия разбиения данных достаточно гибко (изменения должны быть синхронизированы на стороне БД и кода);
- иногда в разделы попадали некорректные данные, так как заливка данных осуществлялась пакетно, с помощью операции COPY и нужный раздел определялся для всего пакета один;
- необходимо было заранее создавать таблицы разделов.
Решение, приведенное ниже - не панацея, но кому-то может пригодиться:
CREATE TRIGGER redirect_to_child
BEFORE INSERT ON parent
FOR EACH ROW
EXECUTE PROCEDURE redirect_to_child();
Затем, экспериментируя с процедурой redirect_to_child() выяснилось, что на стандартном PlPgsql написать достаточно гибкую функцию, которая бы перенаправляла данные в нужный раздел не получается, так как на этапе запуска функции не известно название таблицы, в которую нужно вставлять данные. Таким образом приходиться использовать EXECUTE для формирования динамического SQL, но это не решает всех проблем, так как теперь нельзя использовать NEW.*, потому что полученный SQL выполняется вне контекста триггерной функции и соответственно не видит структуры NEW.
В PostgreSQL 8.4 появилось ключевое слово USING, которое позволяет обойти проблему с использованием NEW.*, но скорость работы данного триггера оставляла желать лучшего.
В результате всех экспериментов родился небольшой велосипедик на PlPython, который сам создаёт нужные таблички и перенаправляет вставку данных. Нижеприведенный кусочек кода, решает все задачи, описанные в начале статьи, а по времени работает всего около 5-ти раз медленнее "чистой" вставки, что для моих условий было более чем приемлемо. Собственно код:
CREATE OR REPLACE FUNCTION redirect_to_child()
RETURNS trigger AS
$BODY$
import datetime
# TD['new'] -> inserted data
new_data = TD['new']
values = new_data.values()
date_occured = new_data['occured'].split()[0]
s_year, s_month = date_occured.split('-')[:2]
# TD['table_name'] -> table name, that triggered this function.
parent_table_name = TD['table_name']
# Child table name pattern is <parent_table>_<year>_<month>.
child_table_name = '_'.join([parent_table_name, s_year, s_month])
try:
insert_plan = SD[child_table_name]
except KeyError:
# Check whether child table exists.
child_table_result = plpy.execute(("SELECT * FROM information_schema.tables"
" WHERE table_catalog = CURRENT_CATALOG"
" AND table_schema = CURRENT_SCHEMA"
" AND table_name = '%s'") % (child_table_name, ))
if child_table_result.nrows() == 0 :
# Need to create child table
year = int(s_year)
month = int(s_month)
min_range_date = datetime.date(year, month, 1)
max_range_date = datetime.date(year + ((month + 1) / 12), (month + 1) % 12, 1)
create_sql = ("CREATE TABLE %(child)s ("
" id BIGINT DEFAULT nextval('%(parent)s_id_seq'::text) PRIMARY KEY,"
" CHECK ( occured >= DATE '%(min)s' AND occured < DATE '%(max)s' )"
") INHERITS (%(parent)s);") \
% {'parent': parent_table_name,
'child':child_table_name,
'min':min_range_date.isoformat(),
'max':max_range_date.isoformat() }
plpy.execute( create_sql )
plpy.execute( "ALTER TABLE %s OWNER TO tableowner;" % child_table_name )
# Prepare insertion plan.
questions_marks = ','.join(['$%d' % x for x in xrange(1, len(new_data) + 1)])
col_types = plpy.execute( ("SELECT column_name, data_type"
" FROM information_schema.columns"
" WHERE table_catalog = CURRENT_CATALOG"
" AND table_schema = CURRENT_SCHEMA"
" AND table_name = '%s'"
" AND column_name <> 'id';")
% parent_table_name );
type_hash = dict((column["column_name"], column["data_type"])
for column in col_types)
column_names = new_data.keys();
types = [type_hash[k] for k in column_names]
insert_sql = ("INSERT INTO %s (%s) VALUES (%s);" %
(child_table_name,
', '.join(column_names),
questions_marks))
insert_plan = plpy.prepare(insert_sql, types)
# Cache insertion plan for reuse in the same transaction.
SD[child_table_name] = insert_plan
# Insert data to child table
plpy.execute( insert_plan, values )
# Skip insertion to parent table
return "SKIP";
$BODY$
LANGUAGE 'plpythonu';
ALTER FUNCTION redirect_to_child() OWNER TO tableowner;| Reactions: |
Blogspot expandable posts
Tags:
cut,
expandable,
lj-cut,
Read more,
usability
Давно я не писал сюда. Сегодня решил исправится и первым делом настроил себе красивый скрипт для длинных статей.Встречайте:Ссылка "Read more" появляется только в тех статьях, которые действительно этого заслуживают (и где я собственноручно проставил нужный тег). Работает всё предельно просто, код взят отсюда. Правда пришлось самую малость допилить.
| Reactions: |
Tuesday, 22 June 2010
Видео прокси для вещания в локальной сети
Tags:
broadcasting,
video proxy,
vlc
В период чемпионата мира по футболу очень хотелось следить за ходом матчей в живую, да вот беда - работа. Решение казалось бы банально - on-line видео трансляции, но не я один такой заинтересованный оказался. А при 30-40 одновременных потоках входящий Интернет канал оставляет остальным сотрудникам офиса лишь маленькую надежду на закачку чего бы то ни было.Очень быстро родилась идея организовать видео прокси, которое бы принимало on-line трансляцию и раздавало видео поток в сети. Локальный трафик не так значим, как входящий интернет трафик, потому приступил к реализации. Выбор пал на VLC media player, который сначала показался несколько монстроидальным, но в дальнейшем оправдал все надежды.
Итак, что такое VLC player? Это open-source программный комплекс, позволяющий творить с видео чудеса. В плейере уже находиться масса возможностей, фактически плейер может одновременно выступать и сервером и клиентом. В поставку входят интерфейсы для удалённого управления (telnet, http), так что можем смело ставить vlc на консольную виртуальную машину (здесь и далее все команды приводятся для Ubuntu):
sudo aptitude install vlc vlc-plugin-*
Далее запускаем VLC с активным http интерфейсом удалённого управления:
vlc -vvv -I http --http-host 10.1.6.3:8181
, здесь
- -vvv - verbose опция (количество букв v отображает уровень логов)
- -I - включает один из интерфейсов удалённого управления (здесь http)
- --http-host - задаёт имя (ip) которое пользователь должен ввести, чтобы попасть в админ часть и порт, который будет слушать встроенный сервер
В принципе данного интерфейса хватает для экспериментов. Для лучшей наглядности лучше сразу же нажать кнопочку "Help".Первым делом, я нажал кнопку "Open", ввёл адрес сервера (для экспериментов было выбрано футбольное on-line вещание ICTV) и... И насладился цветной картинкой ASCII видео в консоли удалённого сервера. Поборов восхищение и отключив видео - нашел в http интерфейсе кнопку "Stream output", которая и привела меня к победе. Догадался одновременно заполнить обе секции перед нажатием кнопки "Play":
- в Input (Open кнопка) адрес вещания в интернете.
- в Stream output выбрал http, ввёл адрес (всё тот же 10.1.6.3), указал порт (на этот раз 8080, чтобы не пересекаться с админкой) и отметил тип кодирования "MPEG TS"
И на последок консольный вариант запуска:
vlc -vvv -I http --http-host 10.1.6.3:8181 http://<internet.on-line.video.url> -sout "#transcode{vcodec=mp2v,vb=1024,scale=1}:std{access=http,mux=ts,dst=10.1.6.3:8080}"
| Reactions: |
Friday, 18 June 2010
Несколько наблюдений о PostgreSQL
Tags:
create index,
db,
postgres
1. Postgresql 8.4 + PostGis 1.5.1 оказался в 4 раза производительнее при использовании st_intersects на большом кол-ве данных, нежели Postgresql 8.3 + PostGis 1.32. Слышали про магическое "\d" в psql? Не знаете какие же запросы делает этот оператор? Вот вам лекарство: "\set ECHO_HIDDEN t"
3. Как вывод из предыдущего пункта, напрашивается решение следующих вопросов:
* "А как создать таблицу, но только если она еще не существует?"
* "А как создать индекс, но только если он еще не существует?"
В Postgresql это решается обёрткой создания в функцию следующего вида:
CREATE OR REPLACE FUNCTION create_tables_if_not_exist()
RETURNS void AS
$BODY$
BEGIN
IF NOT EXISTS ( select * from pg_class where relname = 'countries' ) THEN
CREATE TABLE countries
(
id serial NOT NULL,
geom geometry,
name character varying(80),
cid integer,
CONSTRAINT countries_pkey PRIMARY KEY (id)
)
WITH (OIDS=FALSE);
END IF;
END;
$BODY$ language 'plpgsql';
| Reactions: |
Monday, 29 March 2010
Neo4J - java graph DB
Tags:
graph database,
graphs,
neo4j,
nosql
Недавно я рассказывал про граф ориентированные базы данных. А сегодня хочу поделиться с Вами историей использования одной из них. Встречайте Neo4J.Итак немного о самой системе: Neo4J предлагает Вам полноценную базу данных с транзакциями, индексами (Lucene), несколькими режимами работы и низким порогом вхождения, благодаря очень простой структуре. Все коды открыты и доступны, а приложение поставляется под двойной лицензией AGPL для некоммерческого использования и тарифная сетка для коммерческого. Для начала использования данной базы Вам достаточно знать джаву и понимать чего Вы хотите от сетевой структуры данных (графа).
Мне, при моём знакомстве, была интересна производительность при больших объемах данных и удобство работы с самой БД. Начнём с удобства и создадим базу данных с большим кол-вом вершин и ребёр. Для этого используем специальный класс доступа к БД, который оптимизирован под вставку:
batchGraphDb = new BatchInserterImpl( dbpath, stringProps );
batchIndexService = new LuceneIndexBatchInserterImpl( batchGraphDb );
, где dbPath - путь к файлам будущей базы данных, а stringProps - настройки.
Cоздадим несколько вершин следующим образом:
Map<String, Object> properties = new HashMap<String, Object>();
properties.put("a_key", 5);
properties.put("b_key", "some string");
long createdNode = batchGraphDb.createNode(properties);
batchIndexService.index(createdNode, "a_key", properties.get("a_key"));
Далее в идеале стоит вызвать метод batchIndexService.optimize(); который приведёт индексы в порядок и продолжим создавать рёбра:
Map<String, Object> edgeProperties = new HashMap<String, Object>();
edgeProperties.put("length", 345);
edgeProperties.put("version", "7.5");
long startNodeId = batchIndexService.getSingleNode("a_key", 5);
long endNodeId = batchIndexService.getSingleNode("a_key", 7);
batchGraphDb.createRelationship(
startNodeId,
endNodeId,
DynamicRelationshipType.withName("trust"),
edgeProperties);
Не хитрые манипуляции создают ребро из одной вершины в другую с типом "trust" и собственными свойствами. Ну и на последок закрытие соединения с БД:
if ( null != batchIndexService ) batchIndexService.shutdown();
if ( null != batchGraphDb ) batchGraphDb.shutdown();
Данные готовы, а нам не терпиться проверить её производительность. Показатели качества будут озвучены в следующем посте, а пока можно ознакомиться с другой статьей на эту тему: MySQL vs. Neo4j on a Large-Scale Graph Traversal
| Reactions: |
Wednesday, 17 March 2010
Graph DB
Tags:
graph database,
graphs
Что такое граф, я думаю все знают, а вот зачем для них понадобились свои собственные базы данных? Дело всё в том, что для структуры данных типа граф, набор действий зачастую несколько отличается от привычных нам вставок, обновлений и выборок по заданным условиям. Чего только стоят поиск в ширину и глубину. В принципе на небольших объемах данных традиционные способы представления себя оправдывают, но если предположить, что ваш граф начинает расти и в нём становится несколько миллионов вершин и десятки миллионов связей - реляционные базы данных загибаются под попытками провернуть нужное кол-во join-ов дабы удовлетворить многим условиям выборки при прохождении графа в случае поиска.
Что представляет собой граф ориентированная БД - это хранилище, которое использует некоторые априорные знания о графах, для формирования своей внутренней структуры. В таких базах поиск по критерию зачастую происходит не самым эффективных способом, а вот вычитка связей вершины, и вершин связей сильно оптимизирована. Таким образом обход графа (traversing) становиться операцией, которая в несколько раз быстрее аналогичной родственной реализации в реляционных БД.
Для ознакомления можно взглянуть на:
| Reactions: |
Friday, 15 January 2010
10 истин про Erlang...
Tags:
erlang,
functional language
Недавно заинтересовался функциональными языками и так уж случилось, что под руки попался Erlang. А что Вы о нём знаете?1. Erlang - еденица интенсивности телефоммуникационной нагрузки (кол-во траффика)
2. Erlang - датский учёный конца 19, начала 20 веков. Вплотную занимался теориями массового обслуживания и распределениями веротностей разнообразных параметров в разных сферах коммутационных сетей. Его формулы и теории используют по сей день. Его самый известный труд описывает принцип работы Коммутатора с точки зрения мат. статистики и по сути вводит понятие семафора.
3. Erlang - функциональный язык программирования, разработанный компанией Ericsson, оптимизированный для многопоточности и до сих пор использующийся в больших системах реального времени.
4. В Erlang языке нет переменных. Точнее они представленны в виде неизменяемых констант. Никакие две переменные не могут иметь одно и то же имя в пределах их области видимости.
5. Erlang исполняется в виртуальной машине.
6. Парадигма программирования на Erlang позволяет порождать процессы. Erlang-процессы это что-то сродни привычным всем потокам, но со своим уникальным адресным пространством и гораздо более легковеснее ОС-зависимых потоков. Erlang виртуальная машина сама управляет своими процессами.
7. Любые два Erlang-процесса могут обмениваться сообщениями, даже если они запущены в виртуальных машинах на разных компьютерах. Для этого достаточно знать IP-адрес и пароль доступа к запрашиваемой виртуальной машине.
8. Erlang позволяет менять код на лету.
9. Erlang не поддерживает строки напрямую, зато поддерживает массивы. Модель представления массива в памяти - однонаправленный список. Посему в языке определены стандартные операции "добавить в голову массива элемент" и "взять\удалить головной элемент массива"
10. Erlang поддерживает циклы только за счет хвостовой рекурсии. Правда компилятор-интерпретатор умён и если придерживаться определённых правил рекурсия при исполнении всё же будет представлена циклом, но это не меняет впечатления программиста при прочтении исходных кодов.
index
3. Erlang - функциональный язык программирования, разработанный компанией Ericsson, оптимизированный для многопоточности и до сих пор использующийся в больших системах реального времени.
4. В Erlang языке нет переменных. Точнее они представленны в виде неизменяемых констант. Никакие две переменные не могут иметь одно и то же имя в пределах их области видимости.
5. Erlang исполняется в виртуальной машине.
6. Парадигма программирования на Erlang позволяет порождать процессы. Erlang-процессы это что-то сродни привычным всем потокам, но со своим уникальным адресным пространством и гораздо более легковеснее ОС-зависимых потоков. Erlang виртуальная машина сама управляет своими процессами.
7. Любые два Erlang-процесса могут обмениваться сообщениями, даже если они запущены в виртуальных машинах на разных компьютерах. Для этого достаточно знать IP-адрес и пароль доступа к запрашиваемой виртуальной машине.
8. Erlang позволяет менять код на лету.
9. Erlang не поддерживает строки напрямую, зато поддерживает массивы. Модель представления массива в памяти - однонаправленный список. Посему в языке определены стандартные операции "добавить в голову массива элемент" и "взять\удалить головной элемент массива"
10. Erlang поддерживает циклы только за счет хвостовой рекурсии. Правда компилятор-интерпретатор умён и если придерживаться определённых правил рекурсия при исполнении всё же будет представлена циклом, но это не меняет впечатления программиста при прочтении исходных кодов.
| Reactions: |
Subscribe to:
Posts (Atom)



