понедельник, 15 декабря 2014 г.

Разница между resource vs route в Emberjs

http://blog.trackets.com/2013/02/01/ember-dot-js-router-and-template-naming-convention.html

вторник, 2 декабря 2014 г.

Если истек рутовый сертификат для подписки собственных ключей

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

$ openssl pkcs12 -export -in newcertificate.crt -inkey newcertificate.key -out newcertificate.p12 -name newcertificate -CAfile "VeriSign Class 3 Public Primary Certification Authority - G5.crt"

keytool -importkeystore \
        -srckeystore newcertificate.p12 \
 -srcalias newcertificate \
        -destkeystore my.jks -destalias newcertificate -srcstoretype PKCS12 \
 -destkeypass mypass

"VeriSign Class 3 Public Primary Certification Authority - G5.crt" - это новый рутовый, гарантирующий подлинность выпущенных заказчиком собственных сертификатов и ключей

С этой задачей справиться легко(по опыту), а вот что делать с ключами, которые были подписаны старым истекающим рутом, но самих их время еще не пришло? Тут пришлось добавть этот новый рут отдельным сертификатом в страстстор и тогда все заработало
keytool -import -trustcacerts -alias rootcaverisign -file VeriSign\ Class\ 3\ Public\ Primary\ Certification\ Authority\ -\ G5.crt  -keystore myTrust.jts

Кроме того колега показал, как он справляется с проблемами когда у них не работают какие-то внешние сервисы. Когда удаленный сервис работает с открытым ключем, и нам не нужно от него иметь свой для гарантий своей подлинности, мы можем заполучить его публичный ключ и добавить его в свой трастстор так:
openssl s_client -connect someserviceprovider.com:443 > letssaveinthisfile.cer
openssl обычно подвисает в этом месты мы рвем соединение ^C, но файл сохраняется, проверям если он нормального веса значит все прошло нормально и такой сертификат можно добавлять в трастстор:)


Несменный сайт помошник https://www.sslshopper.com/article-most-common-java-keytool-keystore-commands.html 

суббота, 29 ноября 2014 г.

Как запустить пришедшее в браузер приложение на Backbonejs без дополнительных ajax запросов

var AppointmentApp = new (Backbone.View.extend({
  Collections: {},
  Models: {},
  Views: {},
  events: {
    'click a[data-backbone]': function(e){
      e.preventDefault();
      Backbone.history.navigate(e.target.pathname, { trigger: true });
    }
  },
  start: function(bootstrap){
    this.appointments = new AppointmentApp.Collections.Appointments(bootstrap.appointments);
    var appointmentsView = new AppointmentApp.Views.Appointments({collection: this.appointments});
    $('#app').html(appointmentsView.render().el);
  }
}))({el: document.body});

серевер же старзу вставляет данные-колекцию в страницы и где-нибудь пониже мы вызываем:
var bootstrap = {
  appointments: [
    //сюда выводятся при рендеринге данные на сервере
  ]
}
$(function(){ AppointmentApp.start(bootstrap); })

Как не вязать вью на модель в new Backbone.js

В новом бекбоне появилось встроенное решение отвязки модели от разрешенного дома вьюхи.
Было:

  
var AppointmentView = Backbone.View.extend({
  template: _.template("<%= title %>"),
  initialize: function(){
    this.model.on('change:title', this.changedTitle, this);
  },
  render: function(){
    this.$el.html(this.template(this.model.attributes));
  },
  changedTitle: function(model, value, options){
    this.$('span').html(value);

    if (options.highlight !== false){
      this.$el.effect('highlight', {}, 1000); 
    }
  },
  remove: function() {
    Backbone.View.prototype.remove.apply(this, arguments);
    this.model.off(null, null, this);
  }
});

var appointmentView = new AppointmentView({model: someModel});

appointmentView.remove();


Стало(Added in Backbone 0.9.9):
var AppointmentView = Backbone.View.extend({
  template: _.template("<%= title %>"),
  initialize: function(){
    this.listenTo(this.model, 'change:title', this.changedTitle);
  },
  render: function(){
    this.$el.html(this.template(this.model.attributes));
  },
  changedTitle: function(model, value, options){
    this.$('span').html(value);

    if (options.highlight !== false){
      this.$el.effect('highlight', {}, 1000); 
    }
  }
});


var appointmentView = new AppointmentView({model: someModel});

appointmentView.remove();// автоматически вызовет appointmentView.stopListening();

суббота, 22 ноября 2014 г.

Для адаптив/респонсив/мобайл/флексибл дизайн

http://responsv.com/flexible-math/

четверг, 16 октября 2014 г.

Objective-C основные коцепции

Первоначально Objective-C появился как настройка над C, в виде новых синтаксических конструкций заимствованных у Smalltalk, которые переводились препроцессором в обычные функции C. Кроме того библиотека времени выполнения обрабатывала такие вызовы. Так язык C имея в своем синтаксисе только структуру struct, становился обьектно ориентированным языком.
По сути Objective-C является и сейчас настройкой над C, потому что мы можем написать программу на чистом C, и передать компилятору Objective-C.

"Мир" Objective-C воспринимает как наличие обьектов, которые общаются друг с другом путем передачи сообщений - вызовом методов. Состояние обьектов определяются инвариантами и закрыты от внешнего мира, а поведение методами, которые принимают сообщения и могут измененять в результате состояние обьекта.

Файлы модулей *.m (есть применяется сметь Objective-C и C++, то *.mm)
Файлы заголовков *.h

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

Чтобы узнать какого же типа текущий обьект NSObject  - базовый класс для всех классов - приносит инвариант isa класса Class(позволяет узнавать имена своего и базового класса, а также инварианты класса и какие прототипы методов реализованые этим обьектом  в нем).
Зарезервированные слова Objective-C, отличающиеся от слов C, начинаются с @.


Вывод в стандартный вывод

NSLog(@"Hello, World!");

Префикс NS от OS NeXTSTEP - это вроде образовательная операционная система над которой трудился Стив Джобс, когда его попросили из собственного Apple Computers, именно там развили Objective-C

@ - этим знаком мы создаем обьект, на который будет ссылаться переменная.

Переменный и стандарный классы

Чтобы создать переменную типа строки мы должны использовать тип NSString*, это мы создаем ссылку на созданный обьект:
NSString* firstName = @"World";

Как всегда в С-мире есть плейсхолдеры, 
NSLog(@"Hello there, %@.", firstName);
%@ - это плейсхолдер для любой переменной, которая передается вместе со строкой.

Есть тип числовой:
NSNumber* age = @28;
NSLog(@"%@", age);

Массив, опять же нужно обратить внимание как мы создаем обьекты в памяти с помощью указания символом @, и потом ссылаемся на общую обвертку типом-ссылкой:
NSArray *apps = @[@"AngryFowl", @"Lettertouch", @"Tweetrobot"];
NSLog(@"%@", apps[1]);
Так создаются неизменяемые массивы, но в Objective-C есть всегда изменяемый брат близнец: например NSMutableArray, NSMutableString


Мапа:
NSDictionary *appRatings = @{@"AngryFowl": @3, @"Lettertouch": @5};
NSLog(@"%@", appRatings[@"AngryFowl"]);

пятница, 19 сентября 2014 г.

Backbone - общая структура

Главная концепция - держать данные отдельно от ДОМа страницы, так креши во вью не приводят к потерям данных на странице.

Создание модели

var MyModel = Backbone.Model.extend({});

var myModel = new MyModel({myField: "..."});
myModel.set('myField', 'some value');

Создание вьюхи:

var MyView = Backbone.View.extend({
  render: function(){
   $(this.el).html('<li>' + this.model.get('myField')  + '</li>
');
  }
});

var myView = new MyView({model: myModel});
myView.render();
$('#app').html(myView);

четверг, 18 сентября 2014 г.

Js FE modularity

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

Для это и придумали подход к модульности через неймспейсинг

module1.js:
var MODULE1 = (function(){
   var privateField1={...};
   var privateField2={...};

   var privateMethod1=function{...};
   var privateMethod2=function{...};

   return {
     publicField1: {...},
     publicField2: {...},
     publicMethod1: function(){...},
     publicMethod2: function(){...}
   };
})();

Global Imports

Ну если быть до конца искренним, то глобальные переменные все же нужны, но очень в ограниченном и аргументированном количестве.
Когда мы их испльзуем внутри наших моделей мы сталкиваемся с главными проблемами:
1) Мы можем их случайно изменить.
2) У нас очень много вложенностей-замыканий и это очень неефективно обращаться из них в глобальный скоуп с точки зрения произодительности. Эти проблемы решаются передачей глобальной переменной на этапе создания модуля на странице:

var MODULE1 = (function(neededGlobalInside){
   var privateField1={...};
   var privateField2={...};

   var privateMethod1=function{...};
   var privateMethod2=function{...};

   return {
     publicField1: {...},
     publicField2: {...},
     publicMethod1: function(){...},
     publicMethod2: function(){...}
   };
})(global1);

Эта процедура называется global imports

Augmentation
Процедура, которая помогает нам расширить существующий модуль
augmentation1-for-module1.js:
MODULE1 = function(oldNS){
   var newprivateField1={...};
   
   var newprivateMethod1=function{...};
   oldNS.newpublicMethod1: function(){...};
    
   return oldNS;
}(MODULE1);

Работа с исчислениями

Работа с денежными рассчетами:
int result = parseFloat((0.2 + 0.3).toFixed(1));
С плавающей точкой дают сбив с очень маленькой цифрой за рядом нулей, это фиксится строгим указанием сколько цифр мы хотим видеть после точки, но проблема в том, что тоФиксед возвращает строку, для этого мы парсим ее обратно в число:)
typeof NaN; // -> "number"
console.log(NaN === NaN); // -> false
isNaN("42"); // -> false, потому что строка
parseInt(intStr, radix); //radix -> 10, 8, 16, 2

пятница, 12 сентября 2014 г.

Тестирование производительности в Js

Грубый метод измерения времени выполнения блока кода
console.time("Id");
//блок кода
console.timeEnd("Id");

Более точный:

function SpeedTest(testImplement, testParams, repetitions){
  this.testImplement = testImplement;
  this.testParams = testParams;
  this.repetitions = repetitions || 10000;
  this.average = 0;
}
SpeedTest.prototype = {
  startTest: function(){
    var beginTime, endTime, sumTimes = 0;
    for (var i = 0, x = this.repetitions; i < x; i++){
      beginTime = +new Date();
      this.testImplement( this.testParams );
      endTime = +new Date();
      sumTimes += endTime - beginTime;
    }
    this.average = sumTimes / this.repetitions;
    return console.log("Average execution across " +
                        this.repetitions + ": " +
                        this.average);   
  }
}

четверг, 11 сентября 2014 г.

Полезные Js

http://www.smashingmagazine.com/2009/02/08/50-extremely-useful-javascript-tools/
http://www.javascriptkit.com/cutpastejava.shtml
http://www.scripterlative.com/

Прототипирование в Javascript

valueOf - возвращается сам обьект, на котором вызван данный метод, смысл только для классов, которым мы переопределим этот метод и будем обьект предствлять как простое значение типа хеш.
constructor - что создало обьект. Например для строки: function String(){[native code]}, для обьекта {}: function Object(){[native code]}, или для кастомного класса: function MyClass(a, b){this.a = a; this.b = b;}
toLocaleString - для обьекта класса Date значения результата данного метода будут отличаться в зависимости под какую локаль настроен браузер клиента, а так обычно результат идентичен со следующей вункцией.
toString - функции представляются в виде строки сорцов, для этих обьектов это самое интересное применение.
isPrototypeOftrue если объект на котором вызывают этот метод является прямым прототипом параметра.
propertyIsEnumerable - true возвращает только на свойства определенные именно в этом обьекте, на свойства выше в цепочке прототипов возвращается false, если true - то это поле появится в for..in. Но почему тогда если добавить в прототип Array, то такие поля появятся в for..in?
hasOwnPropertytrue если свойство принадлежит именно самому объекту, а не одному из прототипов по цепочке. Я так понимаю с предыдущим методом есть оличие в том, что некоторые поля прототипов ответятся как тру в предыдущем методе.

Пример использование методом Object

Object.prototype.findOwnerOfProperty = function(propName){
  var currentObject = this;
  while(currentObject !== null) {
    if (currentObject.hasOwnProperty(propName)) {
      return currentObject;
    } else {
      currentObject = currentObject.__proto__;
    }
  }
  return "No property found!";
}

Можно ставить прототипом и не класс, а обьект:
  var shoe = { size: 6, gender: "women", construction: "slipper"};
  
  var magicShoe = Object.create(shoe);
  magicShoe.jewels = "ruby";
  magicShoe.travelAction = "click heels";
  magicShoe.actionRequired = 3;

  shoe.isPrototypeOf(magicShoe);//true
  

Этот новый метод криэйт в последнийх реализациях JS позволил упростить старый добрый метод наследования.
Допустим у нас есть два класса:
function Animal(name) {
    this.name = name
    this.canWalk = true
}
Animal.prototype = {
    live: function(){}
};

function Rabbit(name) {
    this.name = name
}

Старый метод:
function extend(Child, Parent) {
    var F = function() { };
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    Child.prototype.constructor = Child;
    Child.superclass = Parent.prototype;
}

extend(Animal, Rabbit);

Новый метод:

Rabbit.prototype = Object.create(Parent.prototype);

вторник, 9 сентября 2014 г.

Собрать комиты по таске в буфер

git log --author="Andrii Ieremenko" --grep=PDR-520 --pretty=format:"%h" | pbcopy 

среда, 3 сентября 2014 г.

Прикольная статья

https://www.coveros.com/cucumber-jvm-setup/

воскресенье, 17 августа 2014 г.

BDD in JS

http://eamodeorubio.github.io/bdd-with-js
http://custardbelly.com/blog/blog-posts/2014/01/08/bdd-in-js-cucumberjs/
http://www.infoq.com/news/2014/04/cucumberjs-bdd-biezemans

суббота, 16 августа 2014 г.

Cтатьи с терминами и о самих Online Payment Systems

http://sixrevisions.com/tools/online-payment-systems/
http://www.awwwards.com/18-online-payment-services-and-systems.html

http://chineseseoshifu.com/blog/online-payment-methods-china.html
https://www.chinapaymentservices.com/online-payments-china

среда, 13 августа 2014 г.

Работа с радиобаттонами

Впечатлило:)

Say you had radio buttons like these, for example:
 type='radio' name='gender' value='Male'>
 type='radio' name='gender' value='Female'>
And you wanted to check the one with a value of "Male" onload if no radio is checked:
$(function() {
    var $radios = $('input:radio[name=gender]');
    if($radios.is(':checked') === false) {
        $radios.filter('[value=Male]').prop('checked', true);
    }
});

вторник, 12 августа 2014 г.

JVM трастсторы и кисторы: как из полученного вставить куда нужно

Допустим нам прислали поставщик ключей следующие файлы:
-rwxr-xr-x@  1 aieremenko  staff  2616 Aug 12 13:29 portal.gala-coral-prod.ptec.ca.pem
-rwxr-xr-x@  1 aieremenko  staff  1684 Aug 12 13:29 portal.prod.crt.pem
-rwxr-xr-x@  1 aieremenko  staff  1704 Aug 12 13:29 portal.prod.key.pem

У нас есть
javax.net.ssl.keyStore=keystore.jks
javax.net.ssl.trustStore=truststore.jts

Сначала для импорта в кистор мы должны обьединить ключ и сертификат в один p12 кистор. Делаем:
openssl pkcs12 -inkey portal.prod.key.pem -in portal.prod.crt.pem -export -out portal.prod.crt.p12

Вводим пароль от поставщика ключей и впринципе создаемся такой же для нового кистора и есть, теперь добавить из этого кистора в джавовский:
keytool -importkeystore -destkeystore keystore.jks -srckeystore portal.prod.crt.p12 -srcstoretype PKCS12 -srcalias 1 -destalias 'MY_ALIAS' -destkeypass PASSWD_TO_JKS
Вводим пароль к кистору p12 и к джевеемовскому - есть кистор добавлен к нам.

Теперь добавляем сертификат к трастору:
keytool -importcert -file portal.prd.ca.pem -alias MY_ALIAS -trustcacerts -keystore truststore.jts
подтверждаем, что мы доверяем этому сертификату.

Теперь, как отличить по принту(даже короткому) в хранилище ключей лежит то, что представляет нас, или то, чему доверяем мы.
Ключ кому можем доверять мы выглядит так:
$ keytool -list -keystore truststore.jts 

MY_ALIAS, Feb 28, 2018, trustedCertEntry, 
Certificate fingerprint (SHA1): 76:3B:FA:D5:ED:40:6E:DB:B5:49:B8:56:91:08:3D:3C:5C:E1:47:3D

По чем доверяют нам:
$ keytool -list -keystore keystore.jks 

MY_ALIAS, Feb 28, 2018, PrivateKeyEntry, 
Certificate fingerprint (SHA1): 8B:B5:5B:55:62:3E:F1:EB:19:0C:DD:49:D1:71:50:71:B9:9C:E6:61

вторник, 5 августа 2014 г.

Обновление ноды

sudo npm cache clean -f
sudo npm install -g n
sudo n stable

суббота, 26 июля 2014 г.

Хорошая статья про то как узнать апи мобильных приложений

http://timrogers.uk/2014/07/12/discovering-private-apis-with-charles-app/?utm_source=hackernewsletter&utm_medium=email&utm_term=fav


среда, 23 июля 2014 г.

Подебажить MySQL запросы

1. Заходим под рутом в mysql shell
2. Находим где у нас будут писаться логи
mysql> SHOW VARIABLES LIKE "general_log%";

+------------------+----------------------------+
| Variable_name    | Value                      |
+------------------+----------------------------+
| general_log      | OFF                        |
| general_log_file | /var/run/mysqld/mysqld.log |
+------------------+----------------------------+

3. В другой оболочке идем и например начинаем тейлить этот файл лога.
4. Включаем логирование
mysql> SET GLOBAL general_log = 'ON';
5. Наблюдаем за запросами, находим проблему, решаем.
6. Не забываем отключить логирование, чтобы не заполнить себе диск.
mysql> SET GLOBAL general_log = 'OFF';
7. Также будет полезно почистить за собой 
rm /var/run/mysqld/mysqld.log 

четверг, 10 июля 2014 г.

MongoDB Sharding

Мы запускаем шардинг....

Default MongoDB Ports

Default MongoDB Port

The following table lists the default ports used by MongoDB:
Default PortDescription
27017The default port for mongod and mongos instances. You can change this port with port or --port.
27018The default port when running with --shardsvr runtime operation or the shardsvr value for the clusterRolesetting in a configuration file.
27019The default port when running with --configsvr runtime operation or the configsvr value for the clusterRolesetting in a configuration file.
28017The default port for the web status page. The web status page is always accessible at a port number that is 1000 greater than the port determined by port.

MongoDB replication

В контексте MongoDB процедура репликации связана с понятие репликасет. Реплика сет это:
- группа нод, в которых одна является праймери, другие - секондари;
- приложение подключается к праймери, все изменения, которые приходят на праймери, дублицируются на секондари ноды;
- когда праймери падает, репликасет решает какая из секондари нод становится новой праймери, и приложение переподключается на нее, таким образом если быть более точным, то приложение подключается к репликесету, а уже репликасет решает к какой ноде полючить соединение;
- когда упавший праймери подымается, он уже становится одним из секондари и вступает в работу с записи всех изменений, который пришли в репликусет без него;
- минимальное количесвто нод в репликесете 3.


среда, 9 июля 2014 г.

Comparison Matrix



Operation descriptionMongoClient ShellNodeJs DriverJava DriverPython Driver
Подключение к базе
$ mongo dbname
$ mongo 192.169.0.5/dbname
$ mongo 192.169.0.5:9999/dbname

$ mongo
>use dbname
var MongoClient = require('mongodb').MongoClient;

MongoClient.connect('mongodb://localhost:27017/m101'), function(err, db) {
  if(err) throw err;

  db
}
import com.mongodb.DB;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;

final MongoClient client = new MongoClient(new MongoClientURI("mongodb://localhost"));
final DB db = mongoClient.getDB("dbname");

Получение ссылки на коллекцию
>db.collectionName
var MongoClient = require('mongodb').MongoClient;

MongoClient.connect('mongodb://localhost:27017/m101'), function(err, db) {
  if(err) throw err;

  var collection = db.collection('collectionName');
}
import com.mongodb.DB;
import com.mongodb.DBCollection;

final DBCollection collection = db.getCollection("collectionName");

Выборка
>db.students.find({
  $or: [
    { "resume.projects.3.months": {$lte: 3}},
    {currentProjects: {$in: ["Pizza Commerce", "AdvNet"]}}
  ]
})
var MongoClient = require('mongodb').MongoClient;

MongoClient.connect('mongodb://localhost:27017/m101'), function(err, db) {
  if(err) throw err;
  
  /*
  следующий подход для варианта, когда есть вероятность,
  что полей может быть очень много и нам нужно обеспечить
  отпускание потока ноды 
  */
  db.collection('students').find({
    $or: [
      { "resume.projects.3.months": {$lte: 3}},
      {currentProjects: {$in: ["Pizza Commerce", "AdvNet"]}}
    ]
  }).each(function(err, doc){
    console.log(doc);
  });

  /*
  следующий подход для большинства случаев, где мы 
  перестраховываемся лимитированием от чрезмерного
  количества результатов
  */
  db.collection('students').find({
    $or: [
      { "resume.projects.3.months": {$lte: 3}},
      {currentProjects: {$in: ["Pizza Commerce", "AdvNet"]}}
    ]
  }).sort({name: -1}).limit(5).toArray(function(err, items){
    console.log(items);
  });

  
}
import com.mongodb.BasicDBObject;
import com.mongodb.DBCursor;
import java.util.List;

List<DBobject> posts;
BasicDBObject query = new BasicDBObject("tags", tag);

DBCursor cursor = postsCollection.find(query).sort(new BasicDBObject().append("date", -1)).limit(10);
try {
  posts = cursor.toArray();
} finally {
  cursor.close();
}

...OR...

/*Можно также поработать с курсором определенное время*/
while (cursor.hasNext()) {
  posts.add(cursor.next());
}

Изменение конкретной записи
>var j = db.students.findOne()
>j.name = "Tim"
>delete j.surname
>db.students.save(j)
Получение информации о протекании запроса
> db.students.findOne().explain()
var cursor = db.collection('students').findOne({a: 1});
cursor.explain(function(err, explain_output){
  if(err) throw err;

  console.log(explain_output);
});
Явное указание какой именно индекс использовать в запросе
> db.students.findOne({x: 100, y: 200, z: "Some string value"}).hint({x: 1, y:1, z: 1})
var cursor = db.collection('students').find({a: 1}, {}, 
  { 'hint': {$natural: 1}}
);
Подключение к репликасету Запустить несколько процессов в данном случае на одном хосте:
user@localhost$ mkdir -p /data/rs1 /data/rs2 /data/rs3
user@localhost$ mongod --replSet m101 --logpath "1.log" --dbpath /data/rs1 --port 27017 --oplogSize 64 --fork --smallfiles
user@localhost$ mongod --replSet m101 --logpath "2.log" --dbpath /data/rs2 --port 27018 --oplogSize 64 --smallfiles --fork
user@localhost$ mongod --replSet m101 --logpath "3.log" --dbpath /data/rs3 --port 27019 --oplogSize 64 --smallfiles --fork

Теперь соединить всех в одну репликусет через введение данных в процесс, который будет праймери:
$ mongo --port 27018 < echo "config = { _id: "m101", members:[ \
          { _id : 0, host : "localhost:27017", priority:0, slaveDelay:5}, \
          { _id : 1, host : "localhost:27018"},\
          { _id : 2, host : "localhost:27019"} ] \
}; \
rs.initiate(config); \
rs.status(); \
"
Или так:
user@localhost$ mongo --port 27018

> rs.status()
> rs.initiate()
> rs.add("localhost:27017")
> rs.add("localhost:27019")
var MongoClient = require('mongodb').MongoClient;

MongoClient.connect("mongodb://localhost:30001," +
                    "localhost:30002," +
                    "localhost:30003/course", function(err, db) {
  ...
});

воскресенье, 6 июля 2014 г.

Разница между load и get

load(Entity.class, idVal) - кинет исключение, если в базе нет такой сущности с указанным айди.
get(Entity.class, idVal) - вернет налл, если в базе нет такой сущности с указанным айди.

четверг, 3 июля 2014 г.

MongoDB Aggregation

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

Aggregation Pipeline

Collection -> $project -> $match -> $group -> $sort -> Result

$project   - reshape     - 1 : 1
$match    - filter          - n : 1
$group    - aggregate  - n : 1
$sort        - sort           - 1 : 1
$skip       - skips         - n : 1
$limit      - limits         - n : 1
$unwind - normalize  - 1 : n
$out        - output       - 1 : 1  (направить результат в другую колекции из базы)

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

воскресенье, 29 июня 2014 г.

MongoDB Indexes

Table scan in RDBM
Collection scan in MongoDB

Both are a death for performance


Theory of indexing:
We keep our keys sorted.

Indexes in Mongo db are OrderedList of Keys.

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

Типы идексов в Mongo:

Single Field Indexes
A single field index only includes data from a single field of the documents in a collection. MongoDB supports single field indexes on fields at the top level of a document and on fields in sub-documents.
Compound Indexes
A compound index includes more than one field of the documents in a collection.
Multikey Indexes
A multikey index references an array and records a match if a query includes any value in the array.
Geospatial Indexes and Queries
Geospatial indexes support location-based searches on data that is stored as either GeoJSON objects or legacy coordinate pairs.
Text Indexes
Text indexes supports search of string content in documents.
Hashed Index
Hashed indexes maintain entries with hashes of the values of the indexed field.

Эта отсортированная структура сохраняется на диске и по ней мы намного быстрее найдем ссылку в последовательности полных записей колекции на диске.
Например мы создаем ключ|индекс на поля

name, hear_color, age

На диск у нас сохраняется отсортированый список имен, в каждой ячейке имени хранится отсортированный список цвета волос, а в каждой ячейке цвета волос хранятся отсортированные возраста.
А уже на каждой ячейке возраста хранятся ссылки на целые записи всей колекции.

Logging and Profiling

Логирование медленных запросов

Все логи который больше 100 мс считаются медленными и поэтому логируются монго.

Profiler

Пишутся данные в колекцию system.profile
Существуют три уровня/режима
0 -  Off
1 - Log my slow queries
2 - Log all my queries

Можно сразу запустить mongod в указанном режиме
> mongod -dbpath /usr/local/var/mongodb --profile 1 --slowms 2
Мы указали режим и что меделнными мы считаем запросы от 2-х милисекунд

И вот мы выполнили медленный запрос в базу, и так мы его найдем в наших логах:
> db.system.profile.find().pretty()

Обычно там логов много и не редко из разных баз и с разных колекций, чтобы поискать можно воспользоваться следующими командами:
> db.system.profile.find({ns:/interestedDb.interestedColl/}).sort({ts: 1}).pretty()
Так мы ищем только интересующую нас базы и колекцию в ней, и сортируем по времени их создания Или только какие-то очень медленные с любой колекции и базы:
> db.system.profile.find({millis: {$gt: 500}}).sort({ts: 1}).pretty()


Узнать поточный  режим профайлера:

> db.getProfilingLevel()
1
Узнать что у нас логируется и его дополнительный параметр(например у медленных, что считать медленным):
> db.getProfilingStatus()
{"was": 1, "slowms": 2}


Установка в уже запущенном монго:
> db.setProfilingLevel(1, 4)
{"was": 1, "slowms": 4, "ok": 1}

Mongotop

Аналог юниксового top.
При запуске мы указываем параметром с каким диапазоном времени делать просмотр процессов в запащенном монгод.

Mongostat

Аналог юниксового iostat.


суббота, 28 июня 2014 г.

GeoJSON

Json format для карт.
Типы представляют:
Места
Улицы
Регионы

Наборы мест
Наборы улиц
Наборы регионов


пятница, 27 июня 2014 г.

Как добавить сервис к запуску со стартом системы


ln -sfv /usr/local/opt/rabbitmq/homebrew.mxcl.rabbitmq.plist  ~/Library/LaunchAgents

Запустить новосозданную ссылку сейчас:
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.rabbitmq.plist

четверг, 26 июня 2014 г.

Изучение эфективности запросов, занимаемой памати и другое

Изучение того как был обработан запрос

для этого есть метод курсора .explain(), он выводит следующие пункты:

cursor - если поиск прошел без использования индекса мы увидим DefaultCursor, если с индексом, то мы увидим что-нибудь вроде "BtreeCursor indexfield1_1_indexfield2_1_...indexfieldN_1"

isMultyKey - тру, если в ключ входит поле со значением массива.

n - количество документов, которые вернулись в результате запроса.

nscannedObjects - количество просканированных документов для получения результата запроса.

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

indexOnly - может ли запрос быть удовлетворен только идексом

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

millis - время выполнения запроса в милисекундах.


Когда мы запрашиваем компонентный запрос, например выборка и потом сортировка, то в этой ситуации даже если под выборку не попадет индекс, он может пригодиться в сортировке. Например со следующим индексом, следующие запросы будут использовать индекс:
< db.foo.ensureIndex({a:1, b:1, c:1})

< db.foo.find({a:3})
< db.foo.find({c:1}).sort({a:1, b:1})
Но не:
< db.foo.find({b:3, c:4})
< db.foo.find({c:1}).sort({a:-1, b:1})

Как узнать размер

Размер колекции на диске:
< db.collection.stats()

Не нужно стремиться чтобы вся колекция помещалась у нас в оперативной памяти сервера, но неплохо, чтобы в ней полностью помещались индексы колекций базы.
< db.foo.totalIndexSize()

В результате даже если мы не создавали индекс на колекцию, будет размер обязательного индекса, который создается обязательно для _id.



вторник, 10 июня 2014 г.

Динамика состояния DBCollection

Мы получаем колекцию:
final DBCollection grades = db.getCollection("grades");

Это именно состояние колекции, а не курсор по ней. С него мы получаем информацию о состоянии.

То есть если мы получили ссылку на колекцию и посмотрели например к-во документов в ней:
System.out.println(grades.count());
800;

А потом например удалили некие из нее элементы:
grades.remove(new BasicDBObject(
        "_id",
        new BasicDBObject(
            "$in",
            forDeleteList//List
        )
));
То это не означает что нам нужно делать новую ссылку на колекцию, повторное обращение к методу количества даст новый результат:
System.out.println(grades.count());
600;

понедельник, 9 июня 2014 г.

Hibernate Architecture


С курса хибернейт на сайте плюралсайт.ком.

Spring Data JPA

Этот модуль фреймворка Spring помогает избежать шаблонного кода работы с ЭнтитиМенеджера.

И так Spring Data JPA:
- A wrapper for JPA
  - Need to know JPA before you can use Spring Data JPA
- Replaces our Repository Tier
- Extremely powerful and eliminates boiler plate code
- Can be extended for additional functionality

воскресенье, 8 июня 2014 г.

NamedQueries

- Cleaner than adhoc JPQL
- Not required, but focuses on the domain
- Named parameters


@NamedQueries({ @NamedQuery(name=Goal.FIND_GOAL_REPORTS,
  query="Select new com.domain.model.GoalReport(g.minutes, e.minutes, e.activity) " +
   "from Goal g, Exercise e where g.id = e.goal.id"
)})

Projection

- Great way to present objects to the UI
- Objects added using JPQL syntax
- Projection Objects can be JPA Entities
- Need a constructor for the projection

String jpql="Select new com.domain.model.GoalReport(g.minutes, e.minutes, e.activity) " +
  "from Goal g, Exercise e where g.id = e.goal.id";

Самая распространенная ошибка в приложениях SpringMVC-Hibernate/JPA

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

Проблема решается вот таким веб-фильтром OpenEntityManagerInViewFilter, который обеспечивает жизнь сессии ЭнтитиМенеджера на все время обработки веб-запроса:
<filter>
  <filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
  <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>

<filter-mapping>
  <filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

Join Types and Fetch Type

4 join types:
  - @OneToOne
  - @OneToMany
  - @ManyToOne
  - @ManyToMany

Can be used in various configurations:
  - Unidirectional
  - Bidirectional
  - Cascade


Fetch Types:
  - Lazy - Queries the database when that property is called
  - Eager - Queries the database when the object is originally created
Хибернейт имеет ограничение - он позвояет иметь только две колекции на объект, которые могут быть "нетерпеливо" выбраны в объект.

@OneToMany(mappedBy="goal", cascade=CascadeType.ALL, fetch=FetchType.LAZY)
private List exercise = new ArrayList<>();



суббота, 7 июня 2014 г.

Fat Arrow

Этот способ позволяет нам ссылаться на this из класса а не контекста более глубокого.
Например:

class Coffee
  constructor: (@name, @strength=1, @inventory=0) ->

  pourClick: ->
    $("#pour-#{@name}").click (event) ->
      if @inventory isnt 0
        @inventory -= 1
        alert "Poured a cup of #{name}"
В даном примере мы хотим внутри хендлера клика обратиться к @inventory (this.inventory) именно инстанции класса, но в данном контексе this будет представлять кнопку.
Именно для такого случая придумали Fat Arrow(=>) чтобы указать, что нас интересует контекст инстанции класса.
class Coffee
  constructor: (@name, @strength=1, @inventory=0) ->

  pourClick: ->
    $("#pour-#{@name}").click (event) =>
      if @inventory isnt 0
        @inventory -= 1
        alert "Poured a cup of #{name}"

пятница, 6 июня 2014 г.

Splat Arguments

Фишка из Ruby, которая помогает в работе с переменным количеством аргументов.
loadTruck = (firstDibs, secondDibs, tooSlow...) ->
    truck:
        driversSeat: firstDibs
        passengerSeat: secondDibs
        trunkBed: tooSlow

loadTruck("Amanda", "Joel")
# => { truck: { driversSeat: "Amanda", passengerSeat: "Joel", trunkBed: [] } }

loadTruck("Amanda", "Joel", "Bob", "Mary", "Phillip")
# => { truck: { driversSeat: "Amanda", passengerSeat: "Joel", trunkBed: ["Bob", "Mary", "Phillip"] } }

With a trailing argument:
loadTruck = (firstDibs, secondDibs, tooSlow..., leftAtHome) ->
    truck:
        driversSeat: firstDibs
        passengerSeat: secondDibs
        trunkBed: tooSlow
    taxi:
        passengerSeat: leftAtHome

loadTruck("Amanda", "Joel", "Bob", "Mary", "Phillip", "Austin")
# => { truck: { driversSeat: 'Amanda', passengerSeat: 'Joel', trunkBed: [ 'Bob', 'Mary', 'Phillip' ] }, taxi: { passengerSeat: 'Austin' } }

loadTruck("Amanda")
# => { truck: { driversSeat: "Amanda", passengerSeat: undefined, trunkBed: [] }, taxi: undefined }

среда, 4 июня 2014 г.

MongoDB mongoimport tool

Утилита для импорта документов в виде джейсона в указанную базу и колекцию.
Формат команды:
mongoimport -d <DATABASE> -c <COLLECTION> < FILE.js

Нужно обратить внимание, что формат файла не json - внутри не массив обьектов, а строки обьектов - можно понять что каждаю строка какбы инсертится в колекцию. 

Подключение Java движка шаблонов Freemarker в приложение


import freemarker.template.Configuration;
import freemarker.template.Template;

public class MyApp {
  public static void main(String[] args) throws Exception {
    Configuration cfg = new Configuration();
    cfg.setClassForTemplateLoading(MyApp.class, "/");//где искать шаблоны фримаркера, мы указываем что искать в корне класспаза

    Template helloTmplt = cfg.getTemplate("hello.ftl");
    StringWriter writer = new StringWriter();

    Map helloMap = new HashMap();
    helloMap.put("name", "Freemarker");

    helloTmplt.process(helloMap, writer);

    System.out.println(writer);
  }
}

А где-то в recources/hello.ftl:
<html>
<head>
  <title>Welcome!</title>
</head>
<body>
  <h1>Hello ${name}</h1>
</body>
</html>

MongoDB. What is it?

Is:
- NoSQL;
- Document Store (Document Database - key/value pairs, lists are also able to be used);
- Schemaless Database (has dynamic schema);

No:
- joins;
- transactions;
- sql.

Basic usage of mongo client tool:

> db //  посмотреть имя выбраной поточной базы данных
> show dbs // показать имена доступных баз данных
> use mydbname // выбрать базу данных
> show collections // показать доступный коллекции документов в поточной базе данных


mongorestore path/to/dir/with/dumps ## залить в работающую монгу дампы из директории

понедельник, 2 июня 2014 г.

jQuery Promises

$.ajax возвращает промис обьект, этот патерн делает код более читабельным.
var promise = $.ajax('/url',{...});//опции без колбеков success&error
promise.done(function(args){});//callback on success
promise.fail(function(args){});//callback on error

Кроме того, если объект который приходит с удаленки сложной структуры, а нам из нее необходима только некая часть, мы можем руками создать обьект промиса и запонить его в колбеках аякса только нужными частями ответа, так мы можем написать максимально простой обработчик в промисе, но приэтом по закону мировоздания более сложными будут опции аякса:)
var promise = $.Deferred();
$.ajax('/weather', {
    data: {q: location},
    success: function(result){
      promise.resolve(result.weather);
    },
    error: function(){
      var error = 'invalid location';
      promise.reject(error);
    }
});
promise.done(function(args){});//callback on success
promise.fail(function(args){});//callback on error



ajax запросы заканчиваются в разное время, бывают моменты, когда процессинг ответов на разные запросы нужно произвести в одно и тоже время. Для этого ипользуются $.when & $.then





$.when(
     Weather.today(loc),
     City.find(loc)
   ).then(function(weatherResult, cityResult){
     resultsDiv.append(cityResult);
     resultsDiv.append(weatherResult);

jQuery прояснение моментов

Axaj

$.ajax('/url/to/server/script', {
  ...
  dataType: 'json', // сразу попытаться распарсить ответ как json(по умолчанию jQuery делает анализ)
  contentType: 'application/json', //jQuery устанавливает соответствующий хттп заголовок, на основании которого сервер может принимать решение в каком формате отвечать
  context: someWidgetEl, //в колбеках this будет ссылаться на указанный обьект 
  data: $('form').serialize(), //так мы собираем значение полей с формы в джейсон
  
});

четверг, 29 мая 2014 г.

Способ ручного мониторинга логов

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

Вот что получилось:
tail -f logs/app.log \
| egrep -A3 "^(DEBUG|INFO|WARN|ERROR)"

Ну а где-то выключение все же полезно:
tail -f ums.log \
| egrep -v "^INFO.*NotifyBalanceChange" \
| egrep -v "^INFO.*Ping"
Вместо egrep можно пользоваться grep -E

среда, 28 мая 2014 г.

Подключение JPA настроек в приложении Spring Web MVC

Для этого нам нужно в web.xml подключить лисенер и предоставить для него context-param с именем contextConfigLocation, в нем должен находится путь к файлу настрое контекста, вринципе любого, но в нашем даном конкретном случае JPA
<context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:jpaContext.xml</param-value>
    </context-param>
    
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
Разберемся за что отвечает jpaContext.xml, который мы используем всместо persistence.xml. Его имя не обязно быть таким как мы его определили в web.xml - оно будет таким как мы его определим, но по смыслу оно таково как мы его сейчас назвали.

Этот файл содержит:
- EntityManagerFactory;
  - JPA Vendor;
  - JPA Properties;
- Transaction Manager;
- Annotation configuration;
- Datasource configuration or lookup.

EntityManagerFactory представлен в spring классом LocalContainerEntityManagerFactoryBean:
  - класс находится в spring-orm.jar;
  - представляет собой наш персистенс модуль;
  - впрыскивает датасорс, если такой не определен в нашем персистенс модуле;
  - поставляет специфические JPA свойства


Еще такой прикол в SpringMVC-Hibernate приложении. Чтобы у нас все работало гладко и с транзакциями, мы должны сканировать пакеты репозиториев, моделей и сервисов в  jpaContext.xml. Потому что аннотация @Transactional, которой помечаются методы сервисов, должна именно обрабатываться бинами из контекста  jpaContext.xml. Хоть на сервисы есть ссылки и с контроллеров, но как показывает практитка указав для сканирования только пакет с контроллерами в servlet-context.xml все работает - контейнер предоставляет сервисы из контекста  jpaContext.xml, но вот наоборот не работает.



persistence.xml

persistence.xml - в этом файле настраивается фреймворк JPA, определяются следующие настройки:
 - Datasource;
 - Allowed Operations;
 - Caching;
 - Etc.

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

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


вторник, 27 мая 2014 г.

Блин! Нафиг я делал этот мердж? - Отмена мерджа с конфликтами.

После версии включительно 1.7.4
git merge --abort

До версии 1.7.4:
git reset --merge

До версии 1.6.2. Оно по сути делает то же самое, что и команда выше:
git reset --hard



Теперь ты понимаешь что пулиться нудно было так, что ты и делаешь:
git pull -Xtheirs


Если же мерджим локальные бранчи то:
git merge --strategy-option theirs branch_name


понедельник, 26 мая 2014 г.

Mac OS X. Создать симлинку с /home на /Users

EDITOR=nano sudo -e /etc/auto_master
# add a "#" at the start of the line beginning with /home
# save changes
sudo automount -cv
sudo ln -s /Users /home

mac os git by homebrew

Andriis-MacBook-Pro-2:~ aieremenko$ brew install git
==> Downloading https://downloads.sf.net/project/machomebrew/Bottles/git-1.9.3.mavericks.bottle.1.tar.gz
######################################################################## 100.0%
==> Pouring git-1.9.3.mavericks.bottle.1.tar.gz
==> Caveats
The OS X keychain credential helper has been installed to:
  /usr/local/bin/git-credential-osxkeychain

The 'contrib' directory has been installed to:
  /usr/local/share/git-core/contrib

Bash completion has been installed to:
  /usr/local/etc/bash_completion.d

zsh completion has been installed to:
  /usr/local/share/zsh/site-functions
==> Summary

🍺  /usr/local/Cellar/git/1.9.3: 1325 files, 31M

пятница, 23 мая 2014 г.

Angularjs - общий конспект

  • Directives - HTML annotations that trigger Javascript behaviors
  • Modules - Where our application components live
  • Controllers - Where we add application behavior
  • Expressions - ow values get displayed within the page

среда, 7 мая 2014 г.

liquibase, сброс чексумм

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

Чтобы обнулить чексуммы, чтобы изменения уже в примененных "изменениях базы" были восприняты, как тоже самое, но с улученным форматированием (то есть без повторного вызова указанных ченджсетов), нужно подправить записи в таблице логирования liquibase:
update DATABASECHANGELOG set MD5SUM=null;

четверг, 24 апреля 2014 г.

Ant. запустить скрипт в зависимости от операционки

<target name="prepare-project">
    <if>
      <os family="unix" />
      <then>
        <echo>is unix........</echo>
        <exec dir="./scripts" executable="/bin/sh">
          <arg line="-c ./prepare-project.sh"/>
        </exec>
      </then>
      <elseif>
        <os family="windows" />
        <then>
          <echo>is windows........</echo>
          <exec dir="./scripts" executable="/bin/sh">
            <arg line="-c ./prepare-project.sh"/>
          </exec>
        </then>
      </elseif>
    </if>
  </target>