суббота, 10 января 2009 г.

Читаем Flash Shared Object средствами Java

Здравствуйте, уважаемые.

Возникла потребность в считывании файлов, которые хранят данные при работе с Flash приложениями. В сети нашел лишь редактор этих файлов SolVE - Flash Shared Object editor, даже написал создателю письмо с просьбой поделиться исходниками.
Но не дождавшись ответа решил самолично засесть и написать, в конце концов, эту Java библиотеку - парсер Flash файлов.
Итак, вашему вниманию библиотека SolReader. Единственное ее предназначение читать файл Flash формата и строить дерево объектов.
Для некоммерческого использования лицензия GPL
Для коммерческого - придется скинуть 5-10 евро на электронный кошелек с упоминанием проекта, в котором планируется использовать библиотеку.

SolReader-v0.0.1

суббота, 11 октября 2008 г.

Google Code Jam 2008 EMEA: Разбор задачи Painting a Fence

Здравствуйте, уважаемые.

Зашел сегодня посмотреть, как там соревнования Гугла проходят, заодно попрактиковаться на прошедших соревнованиях. Условия задачи Scaled Triangle я так и не понял, поэтому взялся за вторую задачу Painting a Fence. Порадовало то, что мозг шевелится, есть идеи. Решение сразу встало перед глазами -
первое) надо построить ориентированный нецикличный граф ^_^ + зачем-то мне взбрело в голову, добавить в граф вершину начала и вершину конца (это поможет мне совсем забыть о диапазонах, буду работать только с графом), переформулировав задачу, найти минимальное число вершин чтобы дойти от вершины начала до вершины конца.
второе) поиск в глубину должен учитывать количество цветов на каждой ветке: при переходе на следующий уровень - добавлять цвет, при возврате - убавлять.

2 несложных пункта средствами Java реализовать крайне легко:

import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class PaintingFence {

private String[] colors;

private boolean[][] g;

private int N;
// Удобная штука Map в ней ключ - имя цвета, значение - количество художников, использующих этот цвет
private Map<String, Integer> colorMap = new HashMap<String, Integer>();

public int getMinimumPainters(String[] colors, int[] start, int[] finish) {
this.colors = colors;
N = colors.length;
// мы создаем матрицу достижимости (ориентированный граф) и добавляем в нее 2 узла - начало и конец
g = new boolean[N + 2][N + 2];
/*
* попарно проверяем возможность перехода
* критерий один - если из отрезка i можно увеличить сплошной отрезок с помощью отрезка j,
* то считаем, что из узла i можно перейти в узел j
*/
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++)
g[i][j] = finish[j] > finish[i] && start[j] <= finish[i] + 1;
// проверяем, можно ли войти в этот узел, другими словами, предлагает ли художник рисовать с начала полотна
g[N][i] = start[i] == 1;
// проверяем, может ли художник закончить полотно
// далее точка N + 1 будет означать, что мы смогли полностью закрасить полотно
g[i][N + 1] = finish[i] == 10000;
}
int res = Integer.MAX_VALUE;
for (int i = 0; i < N; i++)
// начинаем с точек входа, которые мы определили на прошлом шаге
if (g[N][i]) {
// резервируем цвет
colorMap.put(colors[i], 1);
res = Math.
min(doIt(i), res);
colorMap.clear();
}
return res == Integer.MAX_VALUE ? -1 : res;
}

private int doIt(int c) {
// если художник может завершить полотно, то нам достаточно его одного
if (g[c][N + 1]) return 1;
int res = Integer.MAX_VALUE;
for (int i = 0; i < N; i++) {
if (g[c][i]) {
String currentColor =
colors[i];
// если количество цветов, задействованных не превышает 3, или цвет рассматриваемого художника уже используется
if (colorMap.size() < 3 || colorMap.containsKey(currentColor)) {
// учитываем цвет, которым рисует художник
if (colorMap.containsKey(currentColor))
colorMap.put(currentColor, colorMap.get(currentColor) + 1);
else
colorMap.put(currentColor, 1);
// продвигаемся вглубь
int cur = doIt(i);
// если решение найдено
if (cur != Integer.MAX_VALUE)
res = Math.min(res, cur + 1);
// цвет, которым рисует художник учесть учли, теперь еще раз учитываем, только в обратную сторону
colorMap.put(colors[i], colorMap.get(currentColor) - 1);
// если цвет больше никем не используется, то удаляем его из списка
if (colorMap.get(currentColor) == 0)
colorMap.remove(currentColor);
}
}
}
// возвращаем минимальное число художников, которые могут нарисовать полотно
return res;
}

public static void main(String[] args) throws FileNotFoundException {
Scanner sc =
new Scanner(System.in);
int N = sc.nextInt();
for (int i = 1; i <= N; i++) {
int n = sc.nextInt();
String[] colors =
new String[n];
int[] start = new int[n];
int[] finish = new int[n];
sc.nextLine();
for (int j = 0; j < n; j++) {
String[]t = sc.nextLine().split(
" ");
colors[j] = t[
0];
start[j] = Integer.
valueOf(t[1]);
finish[j] = Integer.
valueOf(t[2]);
}
int res = new PaintingFence().getMinimumPainters(colors, start, finish);
System.
out.println("Case #" + i + ": " + (res == -1? "IMPOSSIBLE" : String.valueOf(res)));
}
}
}

пятница, 8 августа 2008 г.

Как определить позиции сайта? Вашему вниманию SESpider

Здравствуйте, уважаемые.

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


SESpider v0.6.12 (3 МБ)
или обновление
SESpider v0.6.12u (300 КБ)

Лог изменения

Официальный сайт программы для определения позиций сайта http://sespider.ru

Только представьте себе! Чтобы определить позиции сайта вам необходимо пролистать около дюжины страниц каждой поисковой системы и по уйме ключевых фраз. Фактически, для определения позиций сайта, находящегося в пределах с первой по 10 страницу (100 первых позиций), по десяти ключевым фразам в пяти поисковых системах, вам придется просмотреть около пятисот страниц. Да, не велика ли цена для простой операции определения позиций вашего сайта? Сколько времени и сил уйдет на то, чтобы заняться по-настоящему серьезными делами? И здесь на сцене появился герой, SESpider - программа для определения позиций сайта! Переложите все заботы по проверке позиций на него и ваш сайт будет найден среди сотен других в поисковой выдаче самых известных поисковиков. Теперь определить позиции сайта сможет даже младенец! Чем вы хуже? Дерзайте!

Восьмиминутный ролик, охватывающий основные возможности программы.

вторник, 8 июля 2008 г.

Минимализм: Толстушки меня не привлекают

Здравствуйте, уважаемые.
Будучи известным минималистом, не желая работать ни с RMI, ни с SOAP, ни с Cobra, выбрав голый байтовый протокол, вооружился я средством от Apache, именуемым MINA.

Будучи известным минималистом, не желая работать ни со Spring, ни со Struts, ни с Tribune, вооружился я средством от Apache, именуемым Velocity и набросал свой мини фреймворк.

Будучи известным минималистом, не желая работать ни с FormLayout, ни с чем-нибудь еще, ни с чем-нибудь еще, вооружился я GridBagLayout и набросал свой мини класс

Будучи известным минималистом, не желая работать ни с Hibernate, ни с TopLink, ни с прочим JPA, вооружился я средством от Apache, именуемым dbcp и набросал свой мини фреймворк.

Он не настолько крут, как Hibernate, но для работы с перзистивным слоем вполне пригоден ^_^
Итак, в этот раз я хочу представить вашему вниманию свои наброски по работе с данными перзистивного слоя.

Из-за его простоты и отсутствия работы с рефлексией, необходимо четко представлять структуру таблиц баз данных, а также брать всю работу ORM на себя + отсутствие HQL запросов, который при всей моей нелюбви к большим вещам, вызывает у меня большую симпатию.

Если желание еще не пропало, начинаем.
Классический пример. Пользователь и его заказы.

package ru.vingrad.platon.perst.test;

import ru.vingrad.platon.perst.DAORequestException;

import java.util.List;

public class User {
private long id;
private String login;
private String password;
private int rating;

private static final UserOrderManager ORDER_MANAGER = new UserOrderManager();

public User(long id, String login, String password, int rating) {
this.id = id;
this.login = login;
this.password = password;
this.rating = rating;
}

public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}

public String getLogin() {
return login;
}

public void setLogin(String login) {
this.login = login;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public int getRating() {
return rating;
}

public void setRating(int rating) {
this.rating = rating;
}

// Разбираемся с ORM

private List<UserOrder> orders;

public List<UserOrder> getOrders() {
if (orders == null)
try {
orders = ORDER_MANAGER.getUserOrders(this);
}
catch (DAORequestException e) {
e.printStackTrace();
}
return orders;
}

public void setOrders(List<UserOrder> orders) {
this.orders = orders;
}
}


package ru.vingrad.platon.perst.test;

import ru.vingrad.platon.perst.jdbc.DAOManagerJDBC;
import ru.vingrad.platon.perst.jdbc.SQLFactory;
import ru.vingrad.platon.perst.jdbc.SqlData;
import ru.vingrad.platon.perst.jdbc.SqlVariant;
import ru.vingrad.platon.perst.DAORequestException;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;

public class UserItemManager extends DAOManagerJDBC<User> {

private static final SQLFactory<User> factory = new SQLFactory<User>() {
public User build(ResultSet rec) throws SQLException {
return new User(rec.getLong("record_id"), rec.getString("login"), rec.getString("password"), rec.getInt("rating"));
}

public List<SqlData> insertPart(User item) {
List<SqlData> m = updatePart(item);
m.add(
new SqlData("login", item.getLogin()));
return m;
}

public List<SqlData> updatePart(User item) {
return Arrays.asList(
new SqlData("password", item.getPassword()),
new SqlData("rating", item.getRating())
);
}

public List<SqlData> primaryPart(User item) {
return Arrays.asList(new SqlData("record_id", item.getId()));
}
};

public UserItemManager() {
super("users", "record_id", factory);
}

public User get(String login) throws DAORequestException {
return get("login = ?", Arrays.asList(new SqlVariant(login)));
}

public User get(String login, String password) throws DAORequestException {
return get("login = ? AND password = ?", new SqlVariant[]{new SqlVariant(login), new SqlVariant(password)});
}
}


package ru.vingrad.platon.perst.test;

public class UserOrder {
private long id;
private String description;
private long userId;

public UserOrder(long id, String description, long userId) {
this.id = id;
this.description = description;
this.userId = userId;
}

public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public long getUserId() {
return userId;
}

public void setUserId(long userId) {
this.userId = userId;
}

// Разбираемся с ORM

private User user;

public User getUser() {
if (user == null)
user = new UserItemManager().get(userId);
return user;
}

public void setUser(User user) {
this.user = user;
userId = user.getId();
}
}


package ru.vingrad.platon.perst.test;

import ru.vingrad.platon.perst.jdbc.*;
import ru.vingrad.platon.perst.DAORequestException;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;

public class UserOrderManager extends DAOManagerJDBC<UserOrder> {

private static final SQLFactory<UserOrder> factory = new SQLFactory<UserOrder>() {
public UserOrder build(ResultSet rec) throws SQLException {
return new UserOrder(rec.getLong("order_id"), rec.getString("description"), rec.getLong("user_id"));
}

public List<SqlData> insertPart(UserOrder item) {
return updatePart(item);
}

public List<SqlData> updatePart(UserOrder item) {
return Arrays.asList(
new SqlData("description", item.getDescription()),
new SqlData("user_id", item.getId())
);
}

public List<SqlData> primaryPart(UserOrder item) {
return Arrays.asList(new SqlData("order_id", item.getId()));
}
};

public UserOrderManager() {
super("user_order", "order_id", factory);
}

public List<UserOrder> getUserOrders(User user) throws DAORequestException {
return getList("user_id = ?", Arrays.asList(new SqlVariant(user.getId())));
}
}



SQLFactory представляет здесь для нас новизну. Состоит из 4-х методов
build(ResultSet) восстанавливает из записи объект Java
insertPart(T item) возвращает список полей таблицы и их значений, которые необходимо вставлять в запрос при добавлении записи в таблицу базы данных
updatePart(T item) возвращает список полей таблицы и их значений, которые необходимо вставлять в запрос при обновлении записи в таблице базы данных
primaryPart(T item) возвращает список полей таблицы и их значений, которые являются первичным ключем

Perst (0.1.1)

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

Маленькие классы: GBC писать куда проще, чем GridBagConstraints

Здравствуйте, уважаемые.

Решил выложить здесь свои наработки по работе с весьма тяжелым менеджером выравнивания - GridBagLayout. Тяжелым не потому, что он запутанный, а потому что писать надо много а выхлоп маленький. К решению меня подтолкнула тема обсуждения лучшего менеджера выравнивания в Java

w1nd, конечно же, меня переоценил, предположив, что я решил сделать сплав из FormLayout и GridBagLayout. С другой стороны, FormLayout повлиял на результат модификации GridBagLayout.

3 цели, которые я преследовал:
1. Писать сокращенную форму GridBagConstraints
2. Т.к. ячейки в столбце, как правило, имеют одни и те же параметры, необходим механизм "Задать параметры 1 раз и распространить на все ячейки столбца"
3. Цепочечный стиль, описанный уважаемым Се ля ви

И вот они классы:

package ru.vingrad.platon.swing;

import java.awt.*;

public class GBC extends GridBagConstraints {
public GBC() {
}

public GBC(int gridx, int gridy, int gridwidth, int gridheight, double weightx, double weighty, int anchor, int fill, Insets insets, int ipadx, int ipady) {
super(gridx, gridy, gridwidth, gridheight, weightx, weighty, anchor, fill, insets, ipadx, ipady);
}

public GBC(int gridx, int gridy) {
this.gridx = gridx;
this.gridy = gridy;
}

public GBC(int gridx, int gridy, int gridwidth, int gridheight) {
this.gridx = gridx;
this.gridy = gridy;
this.gridwidth = gridwidth;
this.gridheight = gridheight;
}

public GBC gridX(int gridx) {
this.gridx = gridx;
return this;
}

public GBC gridY(int gridy) {
this.gridy = gridy;
return this;
}

public GBC gridWidth(int gridwidth) {
this.gridwidth = gridwidth;
return this;
}

public GBC gridHeight(int gridheight) {
this.gridheight = gridheight;
return this;
}

public GBC weightX(double weightx) {
this.weightx = weightx;
return this;
}

public GBC weightY(double weighty) {
this.weighty = weighty;
return this;
}

public GBC anchor(int anchor) {
this.anchor = anchor;
return this;
}

public GBC fill(int fill) {
this.fill = fill;
return this;
}

public GBC ipadX(int ipadx) {
this.ipadx = ipadx;
return this;
}

public GBC ipadY(int ipady) {
this.ipady = ipady;
return this;
}

public GBC insets(Insets insets) {
this.insets = insets;
return this;
}
}


package ru.vingrad.platon.swing;

import javax.swing.*;
import java.awt.*;

public class GBCUtil {
public int defaultGridX;
public int defaultGridY;
public int defaultGridWidth = 1;
public int defaultGridHeight = 1;
public double defaultWeightX;
public double defaultWeightY;
public int defaultAnchor = GBC.CENTER;
public int defaultFill = GBC.NONE;
public Insets defaultInsets = new Insets(2, 2, 2, 2);
public int defaultPadX;
public int defaultPadY;

public GBCUtil() {
}

public GBCUtil(int defaultGridX, int defaultGridY, int defaultGridWidth, int defaultGridHeight, double defaultWeightX, double defaultWeightY, int defaultAnchor, int defaultFill, Insets defaultInsets, int defaultPadX, int defaultPadY) {
this.defaultGridX = defaultGridX;
this.defaultGridY = defaultGridY;
this.defaultGridWidth = defaultGridWidth;
this.defaultGridHeight = defaultGridHeight;
this.defaultWeightX = defaultWeightX;
this.defaultWeightY = defaultWeightY;
this.defaultAnchor = defaultAnchor;
this.defaultFill = defaultFill;
this.defaultInsets = defaultInsets;
this.defaultPadX = defaultPadX;
this.defaultPadY = defaultPadY;
}

public GBC buildGBC() {
return new GBC(defaultGridX, defaultGridY, defaultGridWidth, defaultGridHeight, defaultWeightX, defaultWeightY,
defaultAnchor, defaultFill, defaultInsets, defaultPadX, defaultPadY);
}

public GBC buildGBC(int gridx, int gridy, int gridwidth, int gridheight, double weightx, double weighty, int anchor,
int fill, Insets insets, int ipadx, int ipady) {
return new GBC(gridx, gridy, gridwidth, gridheight, weightx, weighty, anchor, fill, insets, ipadx, ipady);
}

public GBC buildGBC(int gridx, int gridy) {
return new GBC(gridx, gridy, defaultGridWidth, defaultGridHeight, defaultWeightX, defaultWeightY,
defaultAnchor, defaultFill, defaultInsets, defaultPadX, defaultPadY);
}

public GBC buildGBC(int gridx, int gridy, int gridwidth, int gridheight) {
return new GBC(gridx, gridy, gridwidth, gridheight, defaultWeightX, defaultWeightY,
defaultAnchor, defaultFill, defaultInsets, defaultPadX, defaultPadY);
}

public GBCUtil gridX(int gridX) {
defaultGridX = gridX;
return this;
}

public GBCUtil gridY(int gridY) {
defaultGridY = gridY;
return this;
}

public GBCUtil gridWidth(int defaultGridWidth) {
this.defaultGridWidth = defaultGridWidth;
return this;
}

public GBCUtil gridHeight(int defaultGridHeight) {
this.defaultGridHeight = defaultGridHeight;
return this;
}

public GBCUtil weightX(double defaultWeightX) {
this.defaultWeightX = defaultWeightX;
return this;
}

public GBCUtil weightY(double defaultWeightY) {
this.defaultWeightY = defaultWeightY;
return this;
}

public GBCUtil anchor(int defaultAnchor) {
this.defaultAnchor = defaultAnchor;
return this;
}

public GBCUtil fill(int defaultFill) {
this.defaultFill = defaultFill;
return this;
}

public GBCUtil insets(Insets defaultInsets) {
this.defaultInsets = defaultInsets;
return this;
}

public GBCUtil padX(int defaultPadX) {
this.defaultPadX = defaultPadX;
return this;
}

public GBCUtil padY(int defaultPadY) {
this.defaultPadY = defaultPadY;
return this;
}

}


Пример использования:

  JPanel panel = new JPanel(new GridBagLayout());
GBCUtil util =
new GBCUtil().anchor(GBC.WEST).insets(new Insets(2, 2, 2, 2));
panel.add(
new JLabel("Label1"), util.buildGBC(0, 0));
panel.add(
new JLabel("Label2"), util.buildGBC(0, 1));
panel.add(
new JLabel("Label3"), util.buildGBC(0, 2));
panel.add(
new JButton("..."), util.buildGBC(2, 2));
util.weightX(
1).anchor(GBC.CENTER).fill(GBC.HORIZONTAL);
panel.add(
new JTextField(), util.buildGBC(1, 0, 2, 1));
panel.add(
new JTextField(), util.buildGBC(1, 1));
panel.add(
new JTextField(), util.buildGBC(1, 2));