I have spent some free time to port a control from VB.Net to C# and refactor it a little bit. This UI control attaches to RichTextBox and displays line numbers for the text. The control has many settings and re-paints quickly and exactly.
You may get it here: https://github.com/antgraf/C--Numbered-Lines-Control-for-RichTextBox--LineNumbersControlForRichTextBox-
Sunday, October 30, 2011
Sunday, July 24, 2011
Free embedded databases for C# (.Net) performance overview
I have tested several open-source embedded DB engines for .Net to find which one is the best for my purposes.
My choice for testing was:
As for SQLite .Net adapters System.Data.DQLite is faster then sqlite-net for ~ 1.4 times.
Final DB size: 912KB for FireBird, 40KB for SQLite.
I like sqlite-net framework style but current version is slow and does not support blobs & nullable types. I hope it will improve.
If you think I should test something else please comment.
My choice for testing was:
- FireBird 2.5 .Net Provider with patch applied
- sqlite-net r.71 with patch applied
- System.Data.SQLite 1.0.74.0 (3.7.7.1) x86
- Prepare DB: Recreate DB & tables (3 tables, 2 non-PK indexes)
- Create DB: Insert ~500 records to the DB
- Read All: sequentially read 400 records from the only table (no joins)
- Read Random: read random 400 records from the only table (no joins)
- Read / Write All: sequentially read & update 400 records from the only table (no joins)
- Read / Write Random: read & update random 400 records from the only table (no joins)
As for SQLite .Net adapters System.Data.DQLite is faster then sqlite-net for ~ 1.4 times.
Final DB size: 912KB for FireBird, 40KB for SQLite.
I like sqlite-net framework style but current version is slow and does not support blobs & nullable types. I hope it will improve.
If you think I should test something else please comment.
Sunday, July 10, 2011
Skype plugin for easy mute / unmute and PTT
EzMute & EzPTT for Skype 1.0 is released. It creates visual button always on top of windows to mute Skype and allows to configure keyboard keys for mute and push to talk.
Thursday, August 27, 2009
CakePHP: pagination & sorting on deep associated models (for custom behaviors like Linkable or virtual / aggregated fields)
Using in CakePHP custom behavior (like LinkableBehavior) or aggregated fields (sql count, max, min, etc queries) or virtual fields in model breaks sorting with PaginationHelper. Trying to sort on field that does not explicitly defined in the model or directly associated models leads to loosing all sorting information. To fix this you need to correct Controller->paginate() method. To do so create file app/app_controller.php if it doesn't exist and define AppController class there. Add paginate() method to it and copy it's content from the same method from cake/libs/controller/controller.php file. After that replace
with
full code:
$value = $options['order'][$key];
unset($options['order'][$key]);
if (isset($object->{$alias}) && $object->{$alias}->hasField($field)) {
$options['order'][$alias . '.' . $field] = $value;
} elseif ($object->hasField($field)) {
$options['order'][$alias . '.' . $field] = $value;
}
with
$value = $options['order'][$key];
if (isset($object->{$alias}) && $object->{$alias}->hasField($field)) {
unset($options['order'][$key]);
$options['order'][$alias . '.' . $field] = $value;
} elseif ($object->hasField($field)) {
unset($options['order'][$key]);
$options['order'][$alias . '.' . $field] = $value;
}
full code:
class AppController extends Controller {
function paginate($object = null, $scope = array(), $whitelist = array()) {
if (is_array($object)) {
$whitelist = $scope;
$scope = $object;
$object = null;
}
$assoc = null;
if (is_string($object)) {
$assoc = null;
if (strpos($object, '.') !== false) {
list($object, $assoc) = explode('.', $object);
}
if ($assoc && isset($this->{$object}->{$assoc})) {
$object =& $this->{$object}->{$assoc};
} elseif ($assoc && isset($this->{$this->modelClass}) && isset($this->{$this->modelClass}->{$assoc})) {
$object =& $this->{$this->modelClass}->{$assoc};
} elseif (isset($this->{$object})) {
$object =& $this->{$object};
} elseif (isset($this->{$this->modelClass}) && isset($this->{$this->modelClass}->{$object})) {
$object =& $this->{$this->modelClass}->{$object};
}
} elseif (empty($object) || $object === null) {
if (isset($this->{$this->modelClass})) {
$object =& $this->{$this->modelClass};
} else {
$className = null;
$name = $this->uses[0];
if (strpos($this->uses[0], '.') !== false) {
list($name, $className) = explode('.', $this->uses[0]);
}
if ($className) {
$object =& $this->{$className};
} else {
$object =& $this->{$name};
}
}
}
if (!is_object($object)) {
trigger_error(sprintf(__('Controller::paginate() - can\'t find model %1$s in controller %2$sController', true), $object, $this->name), E_USER_WARNING);
return array();
}
$options = array_merge($this->params, $this->params['url'], $this->passedArgs);
if (isset($this->paginate[$object->alias])) {
$defaults = $this->paginate[$object->alias];
} else {
$defaults = $this->paginate;
}
if (isset($options['show'])) {
$options['limit'] = $options['show'];
}
if (isset($options['sort'])) {
$direction = null;
if (isset($options['direction'])) {
$direction = strtolower($options['direction']);
}
if ($direction != 'asc' && $direction != 'desc') {
$direction = 'asc';
}
$options['order'] = array($options['sort'] => $direction);
}
if (!empty($options['order']) && is_array($options['order'])) {
$alias = $object->alias ;
$key = $field = key($options['order']);
if (strpos($key, '.') !== false) {
list($alias, $field) = explode('.', $key);
}
$value = $options['order'][$key];
if (isset($object->{$alias}) && $object->{$alias}->hasField($field)) {
unset($options['order'][$key]);
$options['order'][$alias . '.' . $field] = $value;
} elseif ($object->hasField($field)) {
unset($options['order'][$key]);
$options['order'][$alias . '.' . $field] = $value;
}
}
$vars = array('fields', 'order', 'limit', 'page', 'recursive');
$keys = array_keys($options);
$count = count($keys);
for ($i = 0; $i < $count; $i++) {
if (!in_array($keys[$i], $vars, true)) {
unset($options[$keys[$i]]);
}
if (empty($whitelist) && ($keys[$i] === 'fields' || $keys[$i] === 'recursive')) {
unset($options[$keys[$i]]);
} elseif (!empty($whitelist) && !in_array($keys[$i], $whitelist)) {
unset($options[$keys[$i]]);
}
}
$conditions = $fields = $order = $limit = $page = $recursive = null;
if (!isset($defaults['conditions'])) {
$defaults['conditions'] = array();
}
$type = 'all';
if (isset($defaults[0])) {
$type = $defaults[0];
unset($defaults[0]);
}
extract($options = array_merge(array('page' => 1, 'limit' => 20), $defaults, $options));
if (is_array($scope) && !empty($scope)) {
$conditions = array_merge($conditions, $scope);
} elseif (is_string($scope)) {
$conditions = array($conditions, $scope);
}
if ($recursive === null) {
$recursive = $object->recursive;
}
$extra = array_diff_key($defaults, compact(
'conditions', 'fields', 'order', 'limit', 'page', 'recursive'
));
if ($type !== 'all') {
$extra['type'] = $type;
}
if (method_exists($object, 'paginateCount')) {
$count = $object->paginateCount($conditions, $recursive, $extra);
} else {
$parameters = compact('conditions');
if ($recursive != $object->recursive) {
$parameters['recursive'] = $recursive;
}
$count = $object->find('count', array_merge($parameters, $extra));
}
$pageCount = intval(ceil($count / $limit));
if ($page === 'last' || $page >= $pageCount) {
$options['page'] = $page = $pageCount;
} elseif (intval($page) < 1) {
$options['page'] = $page = 1;
}
$page = $options['page'] = (integer)$page;
if (method_exists($object, 'paginate')) {
$results = $object->paginate($conditions, $fields, $order, $limit, $page, $recursive, $extra);
} else {
$parameters = compact('conditions', 'fields', 'order', 'limit', 'page');
if ($recursive != $object->recursive) {
$parameters['recursive'] = $recursive;
}
$results = $object->find($type, array_merge($parameters, $extra));
}
$paging = array(
'page' => $page,
'current' => count($results),
'count' => $count,
'prevPage' => ($page > 1),
'nextPage' => ($count > ($page * $limit)),
'pageCount' => $pageCount,
'defaults' => array_merge(array('limit' => 20, 'step' => 1), $defaults),
'options' => $options
);
$this->params['paging'][$object->alias] = $paging;
if (!in_array('Paginator', $this->helpers) && !array_key_exists('Paginator', $this->helpers)) {
$this->helpers[] = 'Paginator';
}
return $results;
}
}
?>
Friday, November 28, 2008
Free issue and bug tracking online services review
To fulfill previous post I want to provide my research on free online issue and bug tracking systems available on the Internet. Surprisingly there are very few of them matching my criteria: 5 users minimum, 10000 tickets minimum, closed for public. Here they are:
- The only totally free & unlimited is defectr.com. It has limited functionality and funny UI but has no users nor projects limitations. My choice #1 for not complex projects.
- w3spt.com offers 10000 messages/5 users/100Mb-limited complex integrated project tracking system. It has a lot of custom views and reports such as FAQ, Forum, Feedback zone, Knowledge base. I would recommend it for complex but not huge projects.
- And the last one I want to mention is teamatic.com. It provides simple tracker for 5 persons with 5Mb attachments storage and nice interface. It may be used for small simple projects.
Labels:
free,
freelance,
issue trackers,
management,
programming,
project,
service,
tool
Monday, November 24, 2008
Choose free online software project tools
I spent a lot of time to choose high-quality online software project tools for free. Some of them are not so "free" other ones have a lot of ads or have low quality. Trying different solutions I chose following:
- Instant public chat: there is an options. You may create IRC channel on efnet.org or maintain public chat with Skype (BTW Skype supports up to 150 chat members now).
- Collaborative documents authoring: Google Docs have no competitors in this area.
- FAQ service: personally I prefer bravenet's one.
- Mail list / discussion group: again Google Groups is the best one.
- Project management: unfortunately I was unable to find any wholly satisfactory project management online service. If you know one please let me know.
Labels:
free,
freelance,
management,
programming,
project,
service,
tool
Sunday, November 16, 2008
Configuring TracAdmin for opensvn.csie.org
In previous post I called opensvn.csie.org one of the best free SVN repositories for closed source. Now I want to show how to configure integrated Trac initially.
- First of all go to "Manage Your Project" tab and login.
- Go to "trac" tab and click "interface to trac-admin" link.
- Enter "permission add username TRAC_ADMIN", where "username" is your login, to text field and press "Execute" button.
- After that you may visit your Trac (https://opensvn.csie.org/traccgi/username) and configure it using "Admin" web interface.
Labels:
free,
freelance,
programming,
project,
service,
tool,
Trac,
TracAdmin,
version control
Subscribe to:
Posts (Atom)