Извините, ничего не найдено.

Не расстраивайся! Лучше выпей чайку!
Регистрация
Справка
Календарь

Вернуться   forum.boolean.name > Веб-программирование > JavaScript / HTML

JavaScript / HTML Создание динамической разметки страниц

Ответ
 
Опции темы
Старый 01.09.2013, 16:45   #1
pax
Unity/C# кодер
 
Аватар для pax
 
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,568
Написано 3,006 полезных сообщений
(для 5,323 пользователей)
Node.JS + MongoDB

Посоветуйте пожалуйста чтиво по этому поводу.

Из основных вопросов: Пока не понял как правильно работать с открытием соединения к базе, хочу использовать модуль mongodb и думаю никакие mongoose не надо. Цель - создать REST API для начала.
__________________
Blitz3d to Unity Wiki
(Offline)
 
Ответить с цитированием
Старый 01.09.2013, 22:00   #2
moka
.
 
Регистрация: 05.08.2006
Сообщений: 10,429
Написано 3,454 полезных сообщений
(для 6,863 пользователей)
Ответ: Node.JS + MongoDB

Не нужно книжек и чтивы. Если работал с mongo то там всё проактически идентично официальным докам (в случае с mongoose это не так).
Я юзал mongoose и потом перешёл на mongo-native от самих 10gen - и не жалею вовсе. Мне эти schemas - нафиг не сдались. Суть mongo - в её динамике, и нефиг пытаться прикручивать правила и структуру к collection'ам подобно это SQL бд.

Офф дока - очень полезна, т.к. как уже говорил почти идентична к mongo-native в использовании.
По факту - коммандная строка для mongo тоже на JavaScript'е

Про соединение, сперва тебе нужно создать объект куда коннектиться:
var mongodb = require('mongodb');
var 
access = new mongodb.Server('127.0.0.1'27017, { auto_reconnecttrue });

new 
mongodb.Db('database'access, { safetrue }).open((function (errdb) {
  if (
err) throw err;
  
// db - хендл для бд (client)
}); 
Далее тебе нужно будет получить сами collection'ы, я это делаю один раз при коннекте в самом каллбеке (точнее я создаю евент и слущаю его, таким образом разные модули получают свои collection'ы:
var users db.collection('users'); 
Как только у тебя есть collection можешь уже работать с данными:
users.insert({ name'test' });

users.find({ }).toArray(function(errdata) {
  if (
err) throw err;

  
console.log(data);
}); 
Вот тут исчерпывающие примеры:
https://github.com/mongodb/node-mong...aster/examples

Есть пару тонкостей:
  • Реконнект при обрыве с бд, я не тестировал, но может даже collection хэндлы нужно будет переполучать (а может и нет). В общем тестируй если такие сценарии бывают.
  • _id - по стандарту mongo держит ObjectID - это своего рода просто string и в консоль по факту будет выводиться просто как string что пиздецки сбивает порой. Так что не забывай что каждый раз если имеешь ID например с REST запроса, нужно создать ObjectID объект из string'и.
  • Если хочешь просто номер для _id (не рекомендуется если предполагается шардинг или репликация бд). То у меня был очень простой выход: заводим collection 'ids' и имеем _id - имя collection и inc - число инкремента. Затем если хотим создать объект в бд делаем:
    ids.findAndModify({ _id'users' }, { }, { $inc: { inc} }, { new: true }, function(errid) {
      if (
    err) throw err;

      
    // id == твой новый id
    }); 
  • find получает список, и в mongo-native модуле это не callback (это единственный метод с таким исключением). Так что юзаем спец модуль "toArray":
    users.find({ }).toArray(function(errdata) {
      
    }); 
  • Для REST советую использовать express.js т.к. роутинг будет очень простым и удобным.
  • Валидация - важно. Типы данных бывают разные (если это POST).
  • Middleware - в express есть отличная тема с middeware, так можно написать модуль с парсингом пагинации и юзать его везде. Пример: заводим файл pagination.js и его содержимое:
    exports.middleware = function(data) {
      return function(
    reqresnext) { // возвращаем middleware функцию
        
    var limit data.limit data.limit 0// limit по стандарту 0
        
    var skip 0// skip тоже нуль

        
    if (req.query.limit) { // если в запросе есть limit
          
    var tmp parseInt(req.query.limit); // парсим
          
    if (tmp != NaN && tmp 0) { // если хорошее число
            
    limit tmp;
          }
        }
        if (
    req.query.skip) { // если в запросе есть skip
          
    var tmp parseInt(req.query.skip); // парсим
          
    if (tmp != NaN && tmp 0) { // если хоршее число
            
    skip tmp;
          }
        }

        if (
    data.max) { // если указан максимальное число на страницу
          
    limit Math.min(limitdata.max); // ограничиваем limit
        
    }
        if (
    data.min) { // если указано минимальное число на страницу
          
    limit Math.max(limitdata.min); // ограничиваем limit
        
    }

        
    req.paginator = { // создаём объект с limit и skip данными в объекте запроса
          
    limitlimit,
          
    skipskip
        
    };
        
    next(); // продолжаем цепочку middleware
      
    }
    }; 
    Далее в коде:
    var paginator = require('./paginator.js').middleware// получаем handle middleware пагинатора
    app.get('/users'paginator({
      
    limit8,
      
    min4,
      
    max64
    }), function(reqresnext) { // устанавливаем get запрос с пагинатором
      
    users.find({ }, { skipreq.paginator.skiplimitreq.paginator.limit }).toArray(function(errdata) { // ищем в бд с данными из пагинатора
        
    if (errnext(err); // если ошибка, бежим в express хэндлер ошибок
        
    res.json(data); // или шлём данные с бд джонсоном
      
    });
    }); 

Если есть конкретные вопросы - задавай.
Я пишу по работе RESTful API с mongo-native и express'ом ну и другими всякими плюшками.
(Offline)
 
Ответить с цитированием
Эти 3 пользователя(ей) сказали Спасибо moka за это полезное сообщение:
Lestar (05.09.2013), pax (02.09.2013), SpiritSound (28.11.2015)
Старый 01.09.2013, 22:49   #3
pax
Unity/C# кодер
 
Аватар для pax
 
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,568
Написано 3,006 полезных сообщений
(для 5,323 пользователей)
Ответ: Node.JS + MongoDB

Правильно ли я понимаю, что для каждого REST запроса надо создавать свое подключение? Мне сначала подумалось создать одно подключение к базе на старте приложения и потом его использовать. Потом я посмотрел некоторые рест библиотеки для монго и там для каждого запроса создается свой экземпляр Db. Такой подход верный?

Еще один вопрос - есть у nodejs возможность запускаться в многопроцессном режиме, это не стоит использовать для REST API?
__________________
Blitz3d to Unity Wiki
(Offline)
 
Ответить с цитированием
Старый 01.09.2013, 23:44   #4
moka
.
 
Регистрация: 05.08.2006
Сообщений: 10,429
Написано 3,454 полезных сообщений
(для 6,863 пользователей)
Ответ: Node.JS + MongoDB

Не нужно для каждого запроса свой db хэндлер - это оверкил.
Там блокировка на уровне бд будет а не на уровне node, следственно иметь более одного хэндла - смысла нету, только замедляет процесс.
Возможно mongo-native кеширует коннекты и будет выдавать уже подконекченный - но это снова лишние телодвижения.

Относительно мультипоточности - ты говоришь о cluster?
Мы используем - 4 worker'а. Всё работает как полагается, естественно если у тебя есть сессия, то её нужно хранить вне процесса, мы используем connect-mongo, тем самым не важно в какой worker идёт запрос.

По опыту пришёл к такому выводу - если у тебя есть CMS и write'ы очень редкие, и обслуживаются определённой группой людей, следственно таскать с собой функционал для CMS в основном API не оправдано.
Для этого я сделал отдельные запросы для PUSH'ей, это немного идёт против логики REST'а, т.к. /url будет отличаться (я сделал субдомейн для этого, а руты были те же), но зато когда нужно обновить основной API, не нужно было перегружать CMS и т.п.

Но это зависит от ситуации.

cluster'ы - реально помогают, их количество обычно параллельно количеству ядер. Мы на ec2 xlarge (4 CPU) 4 worker'а запускаем - и всё ок.
(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
pax (02.09.2013)
Старый 03.09.2013, 10:46   #5
pax
Unity/C# кодер
 
Аватар для pax
 
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,568
Написано 3,006 полезных сообщений
(для 5,323 пользователей)
Ответ: Node.JS + MongoDB

Еще пара вопросов:

1. Как правильно обрабатывать ошибки, чтобы при их происхождении не падал весь процесс. Можно конкретно для express и mongodb.

2. Я так понимаю что кластер можно использовать как защиту от падения процесса, т.е. кластер при падении одного воркера может запустить нового воркера? И если надо будет перезапустить сервер, то просто необходимо будет перезапустить кластер да?

3. Какой модуль лучше использовать для логирования? Особенно если используется кластер и несколько воркеров.
__________________
Blitz3d to Unity Wiki
(Offline)
 
Ответить с цитированием
Старый 03.09.2013, 13:53   #6
moka
.
 
Регистрация: 05.08.2006
Сообщений: 10,429
Написано 3,454 полезных сообщений
(для 6,863 пользователей)
Ответ: Node.JS + MongoDB

Сообщение от pax Посмотреть сообщение
1. Как правильно обрабатывать ошибки, чтобы при их происхождении не падал весь процесс. Можно конкретно для express и mongodb.
В примерах я делал 'throw', обычно я так не делаю.
Важно понимать что ошибки - это важно, и их не должно быть.
Если в тестировании ошибок в запросах к бд небыло, а потом есть, значит твой query слишком динамичен и нужно его немного нормализировать (это 90% случаев).
Я у себя в коде так делаю:

Ранее при настройке express'а:
app.configure(function() {
  
app.use(express.errorHandler());
  ...
}); 
app.get('/users', ..., function(reqresnext) {
  
users.find({ }, { skipreq.paginator.skiplimitreq.paginator.limit }).toArray(function(errdata) {
     if (!
err) {
       
res.json(data);
     } else {
       
next(err);
     }
  });
}); 
Далее где-то в коде самый последний middleware будет для ловли ошибок:

app.use(function(errreqresnext) {
  var 
obj = {
    
errortrue,
    
messageerr.message
  
};
  if (
development) {
    
obj.stackerr.stack;
  }
  
res.json(obj);
}); 


Сообщение от pax Посмотреть сообщение
2. Я так понимаю что кластер можно использовать как защиту от падения процесса, т.е. кластер при падении одного воркера может запустить нового воркера? И если надо будет перезапустить сервер, то просто необходимо будет перезапустить кластер да?
Да. Но нужно следить точно когда что-то падает или нет.
Вообще есть "защито" от падения процесса. Есть event который ловит не словленные exception'ы. Но естественно если что-то жесть как пошло не так, то нужно и реагировать соответственно, а не тупо игнорировать.
Но всё равно:

process.on('uncaughtException', function(err) {
  
console.log('Caught exception: ' errerr.stack);
}); 


Сообщение от pax Посмотреть сообщение
3. Какой модуль лучше использовать для логирования? Особенно если используется кластер и несколько воркеров.
Я пока настраивал node.js как сервис в linux, тупо выводил консоль в файл, естественно это не супер решение. И исследовал этот вопрос. Лидер тут конкретный: winston https://github.com/flatiron/winston , отлично поддерживается.
Суть у него в том что он имеет основу для логгирования, но логит в транспорты, которые могут быть что угодно: консоль, файл, бд, MQ, redis, socket, amazon alerts, email, и т.п.
Есть стандартный набор транспортов которых обычно хватает с головой.

Я лично юзать буду файл + бд (с индексом просрочивания неделю), и ZeroMQ в мелкий процесс который через socket.io будет слать логи от разных процессов мне на мелкую страничку мониторинга. Таким образом если что-то случиться, я сразу могу вычислить с кем, где и т.п.
(Offline)
 
Ответить с цитированием
Эти 2 пользователя(ей) сказали Спасибо moka за это полезное сообщение:
pax (03.09.2013), SpiritSound (28.11.2015)
Старый 03.09.2013, 15:10   #7
pax
Unity/C# кодер
 
Аватар для pax
 
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,568
Написано 3,006 полезных сообщений
(для 5,323 пользователей)
Ответ: Node.JS + MongoDB

Хочу часть логики сделать на хранимом js в MongoDB, это лучше чем делать логику в NodeJS?

Upd: кстати как правильно вызывать хранимые функции?

Upd2: Получилось примерно так:
db.getUser = function (user_idcallback) {
        
db.eval(new Code('return user_get(user_id);', {'user_id'user_id}), {nolocktrue}, callback);
    } 
сама функция


Это нормально или я что-то не так делаю?
__________________
Blitz3d to Unity Wiki
(Offline)
 
Ответить с цитированием
Старый 03.09.2013, 16:58   #8
moka
.
 
Регистрация: 05.08.2006
Сообщений: 10,429
Написано 3,454 полезных сообщений
(для 6,863 пользователей)
Ответ: Node.JS + MongoDB

Я предпочитаю ничего не хранить в DB. Можно лишь мелкие туулзы или функции утилит, но не относящиеся к логике твоего приложения - это ответственность твоего API.
Да и сразу по твоей функции - ты доверяешь назначение user_id кому? БД, или логике приложения?
Я пытался сделать подобное - вставлять если нету, но потом пришёл к выводу - нефиг! Есть куча сценариев где тебе нужно получить юзверя - но он может и не быть там, следственно и вставлять его не нужно.
Так что лучше разделить эту логику.

Да и если ты 100% вставляешь, то не используй 'save', а используй 'insert'.
save - весьма опасен, тем что если будешь обновлять что-то (ожидая update), а документа такого не будет, а обновление будет partial (только пару полей), то вставиться "не полный" документ, что твоя логика приложения не будет ожидать.

И мелкая заметка, в node, для даты проще писать так:
Date.now() - получает timestamp.
(Offline)
 
Ответить с цитированием
Эти 2 пользователя(ей) сказали Спасибо moka за это полезное сообщение:
pax (03.09.2013), SpiritSound (28.11.2015)
Старый 03.09.2013, 18:21   #9
pax
Unity/C# кодер
 
Аватар для pax
 
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,568
Написано 3,006 полезных сообщений
(для 5,323 пользователей)
Ответ: Node.JS + MongoDB

У меня это авторегистрация такая. id это id пользователя в соц сети. На счет insert спасибо, буду иметь ввиду. И я уже решил делать логику в ноде, а не в БД, а то получается какая-то фигня (не нравится мне такой код) с вызовами.
__________________
Blitz3d to Unity Wiki
(Offline)
 
Ответить с цитированием
Старый 03.09.2013, 19:27   #10
moka
.
 
Регистрация: 05.08.2006
Сообщений: 10,429
Написано 3,454 полезных сообщений
(для 6,863 пользователей)
Ответ: Node.JS + MongoDB

Я тут щас aggregation и mapReduce изучаю. Заодно открыл для себя $where.
$where - позволяет стрингой передать сроку кода, например:

Пример player'а:
{
  
_id42,
  
prizes: [
    { 
created123type'foo' },
    { 
created234type'bar' }
  ]

И вот такой query:
players.count({ $where'this.prizes.length >= 20' }, function(errcount) {
  if(!
err) {
    
// count - сколько игроков имеет призов больше чем 20
  
} else {
    ...
  }
}); 
Если в бд вбить:
db.players.find({ $where'this.prizes.length >= 20' }).explain() 
То выдаст факт того что тут ничего естественно не индексируется, индекс тоже игнорируется.
Следственно например для collection'а с 2800 записями, у меня затрачивается 72мс (на простом Mac'е), что ужасно долго для таких запросов.
Следственно в реальном мире лучше кешировать длину массива рядом с массивом.

Но всё же, если у тебя например запрос на 32 записи (например), то такой код - вполне приемлем. Нужно исследовать как там с блоком всего процесса (блокирует ли другие запросы и т.п.).


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

players.collection().aggregate([
  {
    
$match: {
      
favourite: { $existstrue // ищем всех игроков у которых указан 'favourite'
    
}
  }, {
    
$group: { // групируем все записи
      
_id"$favourite"// по favourite полю
      
total: { $sum// и прибавляем 1 к total
    
}
  }, {
    
$sort: { // потом сортируем по убыванию total
      
total: -1
    
}
  }
], function(
errdata) {
  if (!
err) {
    
//
  
} else {
    ...
  }
}); 
favourite - это id команды простое число.
Всего там 20 команд.
В результате получу массив с до 20 записями такого вида:
{
  
_id 685,
  
total 813

Для сборов статистики - самое то. Естетсвенно это не супер шустро такие статистически сборы делать. Но в aggregate есть не мало разных операторов, которые используют индексацию, что ускоряет весьма не плохо. Для не больших запросов (до 64 записей), это весьма приемлемый подход. Естественно всегда можно закешить результаты.


mapReduce - это ещё следующий шаг. Когда aggregation предоставляет операторы, и там важна их поочерёдность и т.п., то mapReduce принимает лишь 2 функции и query фильтр.
Первая функция обрабатывает каждый документ (удовлетворяющий query) и если нужно вызывает emit, что передаёт уже обработанные данные (можно и не обработанные) в reduce функцию, где уже дальше мы имеем дело с групированными данными.
Примеров много можно привезти, в моём случае, нужно было узнать сколько призов в среднем выйграл каждый игрок. Есть 2800 записей. И нужно получить общее арифметическое колличества призов:

players.collection().mapReduce(function() {
  
emit('stats'this.prizes.length); // map - для всех запускаем reduce с групированием (_id будет 'stats')
}, function(keyvalues) { // reduce
  
var total 0// всего призов
  
var values.length;
  while(
i--) { // для каждой длины массива призов
    
total += values[i]; // складываем
  
}
  return 
total values.length// и делим на количество значений
}, {
  
query: { confirmedtrue }, // только игрокам кто подтвердил свой аккаунт
  
out: { inline}
}, function(
errdata) {
  if (!
err) {
    
// data[0].value - общее арифметическое длин массива призов у каждого игрока
  
} else {
    ...
  }
}); 
На самом деле это можно было сделать и aggregator'ом, но я хотел попробовать mapReduce.
Снова, для тысячей записей - это не шустро, но для статистики - самое то.
(Offline)
 
Ответить с цитированием
Эти 2 пользователя(ей) сказали Спасибо moka за это полезное сообщение:
pax (04.09.2013), SpiritSound (28.11.2015)
Старый 04.09.2013, 12:21   #11
pax
Unity/C# кодер
 
Аватар для pax
 
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,568
Написано 3,006 полезных сообщений
(для 5,323 пользователей)
Ответ: Node.JS + MongoDB

Заметил что таймштамп в ноде в миллисекундах, а не в секундах как это в php. Поделил все на 1000)
__________________
Blitz3d to Unity Wiki
(Offline)
 
Ответить с цитированием
Старый 04.09.2013, 16:34   #12
moka
.
 
Регистрация: 05.08.2006
Сообщений: 10,429
Написано 3,454 полезных сообщений
(для 6,863 пользователей)
Ответ: Node.JS + MongoDB

Сообщение от pax Посмотреть сообщение
Заметил что таймштамп в ноде в миллисекундах, а не в секундах как это в php. Поделил все на 1000)
Дык держи в миллисекундах, их и так достаточно, и не вижу бенефита в секундах
Тем более что если захочешь перевезти timestamp в дату то:
var date = new Date(timestamp); 
Иначе прийдётся ещё и на 1000 умножать..
(Offline)
 
Ответить с цитированием
Старый 04.09.2013, 18:08   #13
pax
Unity/C# кодер
 
Аватар для pax
 
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,568
Написано 3,006 полезных сообщений
(для 5,323 пользователей)
Ответ: Node.JS + MongoDB

Бенефит: в базе либо Int32 если секунды, либо double если миллисекунды.

PS: начинаю втягиваться, на первый взгляд сложнее чем на php, потому что надо писать асинхронный код, с другой стороны вроде как и интереснее получается.
__________________
Blitz3d to Unity Wiki
(Offline)
 
Ответить с цитированием
Старый 04.09.2013, 18:32   #14
moka
.
 
Регистрация: 05.08.2006
Сообщений: 10,429
Написано 3,454 полезных сообщений
(для 6,863 пользователей)
Ответ: Node.JS + MongoDB

Сообщение от pax Посмотреть сообщение
Бенефит: в базе либо Int32 если секунды, либо double если миллисекунды.
Исходя из того как бд хранит данные и создаёт файлы с зазорами - это не даст практически никакой разницы, если конечно у тебя документы не просто _id и timestamp.
http://stackoverflow.com/questions/6...tes-in-mongodb

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

Правда появяться некоторые "трудности", например запустить сразу 3 асинхронных функции, и потом финальную функцию, или сделать очередь асинхронных функций. Есть promise и async.js, но я как обычно юзаю свой вариант решения простой задачи:

function jobsQueue(jobs) {
  if (
jobs && jobs instanceof Array && jobs.length 0) {
    var 
count jobs.length;
    var 
= -1;
    var 
next = function() {
      if (++
count) {
        
jobs[i](next);
      }
    }
    
next();
  }
}

function 
jobsQueueAsync(jobscomplete) {
  if (
jobs && jobs instanceof Array && jobs.length 0) {
    var 
count jobs.length;
    var 
done = function() {
      if (--
count == && complete) {
        
complete();
      }
    }
    for(var 
0len jobs.lengthlen; ++i) {
      
jobs[i](done)
    }
  }

Первая запускает поочерёдно функции.
Вторая запускает все асинхронно и финальную когда все закончили.

Пользоваться так:
jobsQueue([
  function(
next) {
    ...
    
next();
  }, function() {
    ...
  }
]);

jobsQueueAsync([
  function(
next) {
    ...
    
next();
  },
  function(
next) {
    ...
    
next();
  }
], function() {
  ... 
done
}); 
Ну и тесты:
jobsQueue([
  function(
next) {
    
console.log('1');
    
next();
  },
  function(
next) {
    
console.log('2a')
    
setTimeout(function() {
      
console.log('2b');
      
next();
    }, 
400);
  },
  function(
next) {
    
console.log('3a');
    
setTimeout(function() {
      
console.log('3b');
      
next();
    }, 
100);
  },
  function() {
    
console.log('4');
  }
]); 
Выдаст: 1 2a 2b 3a 3b 4
Как видишь он даже не начинает выполнение следующей функции до выполнения прошлой.

jobsQueueAsync([
  function(
next) {
    
console.log('1');
    
next();
  },
  function(
next) {
    
console.log('2a')
    
setTimeout(function() {
      
console.log('2b');
      
next();
    }, 
400);
  },
  function(
next) {
    
console.log('3a');
    
setTimeout(function() {
      
console.log('3b');
      
next();
    }, 
100);
  } ],
  function() {
    
console.log('4');
  }
); 
Выдаст: 1 2a 3a 3b 2b 4
И тут видно что он запускает все сразу, но финальную только когда каждая функция запустит next() по завершению (асинхронно или нет).
(Offline)
 
Ответить с цитированием
Эти 2 пользователя(ей) сказали Спасибо moka за это полезное сообщение:
pax (05.09.2013), SpiritSound (28.11.2015)
Старый 04.09.2013, 18:36   #15
moka
.
 
Регистрация: 05.08.2006
Сообщений: 10,429
Написано 3,454 полезных сообщений
(для 6,863 пользователей)
Ответ: Node.JS + MongoDB

В тему асинхронного кода, юмор:

var result = fs.readFile(‘data.json’, function () {})
(Offline)
 
Ответить с цитированием
Эти 2 пользователя(ей) сказали Спасибо moka за это полезное сообщение:
pax (05.09.2013), SpiritSound (28.11.2015)
Ответ


Опции темы

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


Часовой пояс GMT +4, время: 13:33.


vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot
Style crйe par Allan - vBulletin-Ressources.com