LINUX.ORG.RU

Подскажите ЯП.


1

3

Есть желание познакомится с новым языком программирования. Цель использования — программирование «для себя». Что хочу — максимум синтаксического сахара, ООП, лёгкие биндинги С либ, мультипарадигменность желательна, есс-но свободный и есс-но с компиляторами, очень желательно и с IDE тоже, под онтопик.

★★★★★

Ответ на: комментарий от anonymous

Расскажите об этом по-подробнее, пожалуйста.

harm
()
Ответ на: комментарий от anonymous

Я поверил, однако весь открытый софт на лиспе, код которого я видел, в первую очередь, это код емакса — представляет собой такое же нечитабельное, по сравнению с кодом на скала/руби, нагромождение.

(defun describe-buffer-case-table ()
  "Describe the case table of the current buffer."
  (interactive)
  (let ((description (make-char-table 'case-table)))
    (map-char-table
     (function (lambda (key value)
		 (if (not (natnump value))
		     (if (consp key)
			 (set-char-table-range description key "case-invariant")
		       (aset description key "case-invariant"))
		   (let (from to)
		     (if (consp key)
			 (setq from (car key) to (cdr key))
		       (setq from (setq to key)))
		     (while (<= from to)
		       (aset
			description from
			(cond ((/= from (downcase from))
			       (concat "uppercase, matches "
				       (char-to-string (downcase from))))
			      ((/= from (upcase from))
			       (concat "lowercase, matches "
				       (char-to-string (upcase from))))
			      (t "case-invariant")))
		       (setq from (1+ from)))))))
     (current-case-table))
    (save-excursion
     (with-output-to-temp-buffer "*Help*"
       (set-buffer standard-output)
       (describe-vector description)
       (help-mode)))))

(defun get-upcase-table (case-table)
  "Return the upcase table of CASE-TABLE."
  (or (char-table-extra-slot case-table 0)
      ;; Setup all extra slots of CASE-TABLE by temporarily selecting
      ;; it as the standard case table.
      (let ((old (standard-case-table)))
	(unwind-protect
	    (progn
	      (set-standard-case-table case-table)
	      (char-table-extra-slot case-table 0))
	  (or (eq case-table old)
	      (set-standard-case-table old))))))

(defun copy-case-table (case-table)
  (let ((copy (copy-sequence case-table))
	(up (char-table-extra-slot case-table 0)))
    ;; Clear out the extra slots (except for upcase table) so that
    ;; they will be recomputed from the main (downcase) table.
    (if up
	(set-char-table-extra-slot copy 0 (copy-sequence up)))
    (set-char-table-extra-slot copy 1 nil)
    (set-char-table-extra-slot copy 2 nil)
    copy))

(defun set-case-syntax-delims (l r table)
  "Make characters L and R a matching pair of non-case-converting delimiters.
This sets the entries for L and R in TABLE, which is a string
that will be used as the downcase part of a case table.
It also modifies `standard-syntax-table' to
indicate left and right delimiters."
  (aset table l l)
  (aset table r r)
  (let ((up (get-upcase-table table)))
    (aset up l l)
    (aset up r r))
  ;; Clear out the extra slots so that they will be
  ;; recomputed from the main (downcase) table and upcase table.
  (set-char-table-extra-slot table 1 nil)
  (set-char-table-extra-slot table 2 nil)
  (modify-syntax-entry l (concat "(" (char-to-string r) "  ")
		       (standard-syntax-table))
  (modify-syntax-entry r (concat ")" (char-to-string l) "  ")
		       (standard-syntax-table)))

(defun set-case-syntax-pair (uc lc table)
  "Make characters UC and LC a pair of inter-case-converting letters.
This sets the entries for characters UC and LC in TABLE, which is a string
that will be used as the downcase part of a case table.
It also modifies `standard-syntax-table' to give them the syntax of
word constituents."
  (aset table uc lc)
  (aset table lc lc)
  (let ((up (get-upcase-table table)))
    (aset up uc uc)
    (aset up lc uc))
  ;; Clear out the extra slots so that they will be
  ;; recomputed from the main (downcase) table and upcase table.
  (set-char-table-extra-slot table 1 nil)
  (set-char-table-extra-slot table 2 nil)
  (modify-syntax-entry lc "w   " (standard-syntax-table))
  (modify-syntax-entry uc "w   " (standard-syntax-table)))

(defun set-upcase-syntax (uc lc table)
  "Make character UC an upcase of character LC.
It also modifies `standard-syntax-table' to give them the syntax of
word constituents."
  (aset table lc lc)
  (let ((up (get-upcase-table table)))
    (aset up uc uc)
    (aset up lc uc))
  ;; Clear out the extra slots so that they will be
  ;; recomputed from the main (downcase) table and upcase table.
  (set-char-table-extra-slot table 1 nil)
  (set-char-table-extra-slot table 2 nil)
  (modify-syntax-entry lc "w   " (standard-syntax-table))
  (modify-syntax-entry uc "w   " (standard-syntax-table)))

(defun set-downcase-syntax (uc lc table)
  "Make character LC a downcase of character UC.
It also modifies `standard-syntax-table' to give them the syntax of
word constituents."
  (aset table uc lc)
  (aset table lc lc)
  (let ((up (get-upcase-table table)))
    (aset up uc uc))
  ;; Clear out the extra slots so that they will be
  ;; recomputed from the main (downcase) table and upcase table.
  (set-char-table-extra-slot table 1 nil)
  (set-char-table-extra-slot table 2 nil)
  (modify-syntax-entry lc "w   " (standard-syntax-table))
  (modify-syntax-entry uc "w   " (standard-syntax-table)))

(defun set-case-syntax (c syntax table)
  "Make character C case-invariant with syntax SYNTAX.
This sets the entry for character C in TABLE, which is a string
that will be used as the downcase part of a case table.
It also modifies `standard-syntax-table'.
SYNTAX should be \" \", \"w\", \".\" or \"_\"."
  (aset table c c)
  (let ((up (get-upcase-table table)))
    (aset up c c))
  ;; Clear out the extra slots so that they will be
  ;; recomputed from the main (downcase) table and upcase table.
  (set-char-table-extra-slot table 1 nil)
  (set-char-table-extra-slot table 2 nil)
  (modify-syntax-entry c syntax (standard-syntax-table)))

(provide 'case-table)

Вы скажете — ну да, код емакса — хлам, к тому же, там наполовину сишка, не надо судь о лиспе по исходникам в этой помойке. Вы безусловно будете правы, но других живых нехеллоуворлдных разработок на лиспе попросту не существует. Есть ещё парочка известных приложений со встроенным лиспом, но там везде такой же ужас.

next_time ★★★★★
() автор топика
Ответ на: комментарий от next_time

Я поверил, однако весь открытый софт на лиспе, код которого я видел, в первую очередь, это код емакса — представляет собой такое же нечитабельное, по сравнению с кодом на скала/руби, нагромождение.

Я посмотрел на японские/китайские иероглифы - это вообще ппц какой-то, это же невозможно читать! Просто столбики каких-то жутких каракуль!

Заверни уже неосиляторское хлебало - ЛОР и без тебя успешно скатывается в СГ

yyk ★★★★★
()
Ответ на: комментарий от next_time

Я поверил, однако весь открытый софт на лиспе, код которого я видел, в первую очередь, это код емакса — представляет собой такое же нечитабельное, по сравнению с кодом на скала/руби, нагромождение.

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

anonymous
()
Ответ на: комментарий от next_time

Вы скажете — ну да, код емакса — хлам, к тому же, там наполовину сишка, не надо судь о лиспе по исходникам в этой помойке.

не надо по одному лиспу судить о других лиспах. Так же как не надо судить о скале по сишке. Скала и сишка гораздо ближе друг к другу, чем елисп и схема, например.

anonymous
()
Ответ на: комментарий от anonymous

не надо по одному лиспу судить о других лиспах.

тогда такая просьба: приведите рабочий код на любом диалекте/прямом производном лиспе, который не менее красив, чем вот этот код:

http://benchmarksgame.alioth.debian.org/u32/program.php?test=knucleotide&...

Только 3 условия: 1) приведённый вами код может быть взят из любого рабочего проекта/хеллоуворлда написанный вами код тоже считается 2)программа, из которой взят код должна компилироваться без ошибок 3) в программе из которой взят код как минимум 1/3 кода должна быть не менее красива

next_time ★★★★★
() автор топика
Ответ на: комментарий от next_time

Не осилите это, приведите пример хотябы одной хоть более-менее серьёзной програмы, дожившей до наших дней, написанной на любом диалекте/прямом производном лиспа.

Емакс, разумеется, не в счёт, ибо написан на С.

next_time ★★★★★
() автор топика
Ответ на: комментарий от next_time

но других живых нехеллоуворлдных разработок на лиспе попросту не существует

maxima же

yoghurt ★★★★★
()
Ответ на: комментарий от next_time

Ну естественно это тот же самый алгоритм. А ты чего ожидал?

Я привел тебе код, который очевидно значительно красивее, чем то, что было в скале, требование выполнено. Какие проблемы?

anonymous
()
Ответ на: комментарий от next_time

рассуждения о «красивости» кода
пример на скале

anonymous
()
Ответ на: комментарий от anonymous

А ты чего ожидал?

ожидал более красивый код

Я привел тебе код, который очевидно значительно красивее

отнюдь. возможно, у нас просто разные представления о читабельности кода, в таком случае и обсуждать нечего — лиспопроизводные просто не для меня

next_time ★★★★★
() автор топика
Ответ на: комментарий от Deleted

Причины скобочкохейта со стороны сишника непонятны.

А причины, на самом деле, очень просты:

  • Обычные языки, вроде сишечки и прочих фортранов — читаются естественным путём, хотя разбор для машины не совсем тривиален.
  • Конкатенативные языки, forth — читаются и выполняются слева-направо. Ад, когда дело касается математики, в остальном вполне удобно.
  • APL и J — выполняются справа-налево, но читаются, внезапно, слева-направо. Простой разбор и относительно легко воспринимаются человеком.
  • ЛNСП — читается и выполняется так, как скобки лягут. Практически абстрактное синтаксическое дерево, записанное скобочками.

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

quantum-troll ★★★★★
()
Последнее исправление: quantum-troll (всего исправлений: 1)
Ответ на: комментарий от next_time

ожидал более красивый код

Я и привел более красивый код. Причем _значительно_ более красивый.

отнюдь.

Ну то есть ты просто не понимаешь кода на незнакомо языке. Это вполне логично, нет? Чтобы сравнивать, надо знать и лисп и джаву (потому что то, что ты дал, это на самом деле почти чистая джава, а не скала, на скале такой код будет выглядеть совершенно иначе).

anonymous
()
Ответ на: комментарий от quantum-troll

Обычные языки, вроде сишечки и прочих фортранов — читаются естественным путём, хотя разбор для машины не совсем тривиален.

Точно так же читается и лисп.

Лиспы заставляют выполнять работу, предназначенную компиляторам — генерировать и обрабатывать синтаксическое дерево.

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

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

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

anonymous
()
Ответ на: комментарий от anonymous

Да ладно, инфиксные операторы не сложнее твоих скобок для понимания. А так-то quantum-troll - балбес, конечно.

anonymous
()
Ответ на: комментарий от anonymous

Да ладно, инфиксные операторы не сложнее твоих скобок для понимания.

Да конечно не сложнее - только надо сперва выучить приоритеты, а потом распарсить выражение и расставить скобки в уме. Когда это обычная инфиксная арифметика, то тут обычно проблем нету, да, т.к. парсинг в голове происходит практически мгновенно - все уже в подкорку вбито.

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

anonymous
()
Ответ на: комментарий от anonymous

парсить выражение и составлять в уме аст

Воистину лиспомышление.

Да конечно не сложнее - только надо сперва выучить приоритеты

Взгляни на J и APL — там приоритетов операций нет.

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

Просто у лисперов не принято, взгляни, например, на haskell, там многие вещи, которые обычно пишут инфиксно, делают префиксно.

quantum-troll ★★★★★
()
Ответ на: комментарий от quantum-troll

Взгляни на J и APL — там приоритетов операций нет.

Ну да, нету, там есть скобки. А без скобок оно менее читабельно, чем форт.

Воистину лиспомышление.

Да ты чо? Скажешь мне, что такое x1 op1 x2 op1 x3 op2 x4 op3 x5 op1 x6, не заглядывая в таблицу приоритетов/ассоциативности для op1,op2,op3?

Просто у лисперов не принято

Что не принято?

взгляни, например, на haskell, там многие вещи, которые обычно пишут инфиксно, делают префиксно.

Ну о чем и речь - используют префиксную запись вместо инфиксной, как в лиспе. Потому что с большим количеством операторов (а в хаскеле их реально много, да еще и карринг) инфиксная запись совершенно нечитабельна и ее используют только упоротые фанаты хаски-арта в стиле (.).(.) и (_|_).

anonymous
()
Ответ на: комментарий от anonymous

Ну о чем и речь - используют префиксную запись вместо инфиксной, как в лиспе.

Стоп, я действительно это написал? Конечно же я имел в виду «там многие вещи, которые обычно пишут префиксно, делают инфиксно».

Что не принято?

Не принято что-либо, отличное от префиксной нотации.

Ну да, нету, там есть скобки.

Которые нужно куда меньше, так как J умеет в неявное программирование.

не заглядывая в таблицу приоритетов/ассоциативности для op1,op2,op3?

Приоритеты для неарифмитических операций — зло, никто не спорит.

quantum-troll ★★★★★
()
Ответ на: комментарий от next_time

я видел емакс
видел

Тогда жирнющие жабаидэе и пихтон — твой удел. Голую женщину ты тоже только с монитора видел?

Deleted
()
Ответ на: комментарий от quantum-troll

Стоп, я действительно это написал? Конечно же я имел в виду «там многие вещи, которые обычно пишут префиксно, делают инфиксно».

Ну да, если фанаты хаскиарта ходят запутать код - именно так они и делают, пишут в инфиксе.

Не принято что-либо, отличное от префиксной нотации.

Ну да, именно из-за того, что инфиксная нотация неудобна - и непринято.

Которые нужно куда меньше

Если скобки не расставить получается совершенно нечитабельное говно. Ну как и с инфиксом, собственно говоря.

Приоритеты для неарифмитических операций — зло, никто не спорит.

И почему ты ратуешь за то, чтобы этого зла было как можно больше?

anonymous
()
Ответ на: комментарий от anonymous

Ну о чем и речь - используют префиксную запись вместо инфиксной, как в лиспе.

Неправда. Все используют . и >>=, например, вместо изобретения их префиксных аналогов.

anonymous
()
Ответ на: комментарий от anonymous

Чтобы сравнивать, надо знать и лисп и джаву

дело в том, что и то и другое я знаю примерно в одинаковой степени, код писал и на том и на другом, и примерно столь же давно

  val table = Array.tabulate[Byte](256) {
    case 'a' | 'A' => 0
    case 't' | 'T' => 1
    case 'g' | 'G' => 2
    case 'c' | 'C' => 3
    case '\n' => -3
    case '>' => -2
    case _ => -1
  }

Вот это - не ява. и здесь всё ясно.

    (fprintf port "~a ~a\n"
             (car a)
             (real->decimal-string (fl* 100. (fl/ (fx->fl (cdr a)) total)) 3))))
а вот здесь ничего не ясно: «функция печать функции порт, создать машину а, настояще-десятичная строка что-то умножить что-то разделить, создать диск только для чтения а, всего 3»

ппц, «красивый код»

next_time ★★★★★
() автор топика
Ответ на: комментарий от Deleted

Тогда жирнющие жабаидэе и пихтон — твой удел.

как будто что-то плохое

Голую женщину ты тоже только с монитора видел?

эммм, вы намекаете на то, что с емаксом тоже нужно заниматься сексом? нет, простите, секс я приемлю IRL only

next_time ★★★★★
() автор топика
Ответ на: комментарий от next_time

как будто что-то плохое

Как будто ты работал за чем-то кроме них и однокнопочных редакторов типа gedit.

Deleted
()
Ответ на: комментарий от Deleted

пытался в емакс кодить на С++ — в емаксе ничего нет, ни нормального интерфейса, ни подсветки синтаксиса

next_time ★★★★★
() автор топика
Ответ на: комментарий от next_time

Выглядит так, будто это вообще можно написать как

(_3 _2, (],]) 0 1 2 3) (10, 3&u: '>atgcATGC') } 256 $ _1

quantum-troll ★★★★★
()
Ответ на: комментарий от next_time

дело в том, что и то и другое я знаю примерно в одинаковой степени

Это не правда. Лиспа ты не знаешь.

Вот это - не ява. и здесь всё ясно.
а вот здесь ничего не ясно:

Непонятно, почему сравнивается разный код? Вариант на скале в racket будет выглядеть так (при наличии функции tabulate, что не является языковой характеристикой):

(define table
  (tabulate array 256
            (match-lambda
              [(or #\a #\A) 0]
              [(or #\t #\T) 1]
              [(or #\g #\G) 2]
              [(or #\c #\C) 3]
              [#\newline -3]
              [#\> -2]
              [_ -1])))
а второй код на скале будет выглядеть как
val str = (100 * a._1 / total).toDecimalString(3)
port.fprintf("~s ~s\n", a._2.toString, str)

создать машину а

И ты еще что-то кукарекаешь на счет «писал на лиспе»? Ну это даже не смешно.

anonymous
()
Ответ на: комментарий от next_time

А, ну и чтобы совсем все было ясно, racket:

(define (write-freqs table port)
  (define content (hash-map table cons))
  (define total (exact->inexact (apply + (map cdr content))))
  (for ([a (sort content > #:key cdr)])
    (fprintf port "~a ~a\n"
             (car a)
             (real->decimal-string (fl* 100. (fl/ (fx->fl (cdr a)) total)) 3))))
scala (та же самая функция):
    def printSorted {
      val factor = 100.0/counts.sum
      (counts.map(_*factor) zip keys.map(l2s(_,z))).filter(_._1 > 0).sortWith((a,b) =>
        a._1 > b._1 || (a._1 == b._1 && a._2 < b._2)
      ).foreach{ case (freq, label) => printf("%s %.3f\n",label,freq) }
      println
    }
а ты давай дальше кукарекай, кукаретик

anonymous
()
Ответ на: комментарий от anonymous

писал на лиспе

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

Вариант на скале в racket будет выглядеть так
а второй код на скале будет выглядеть как

ну и? скала красивее и понятнее

next_time ★★★★★
() автор топика
Ответ на: комментарий от anonymous

а ты давай дальше кукарекай, кукаретик

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

next_time ★★★★★
() автор топика
Ответ на: комментарий от anonymous

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

next_time ★★★★★
() автор топика

Есть желание познакомится с новым языком программирования. Цель использования — программирование «для себя». Что хочу — максимум синтаксического сахара, ООП, лёгкие биндинги С либ, мультипарадигменность желательна, есс-но свободный и есс-но с компиляторами, очень желательно и с IDE тоже, под онтопик.

Tcl/Tk уже предлагали?

есс-но с компиляторами, очень желательно и с IDE тоже

а это зачем?

anonymous
()
Ответ на: комментарий от next_time

я такого не говорил, я сказал что несколько лет назад на лиспе я пару учебных программ написал и всё

То есть лиспа ты не знаешь. Значит и оценивать синтаксис его не можешь. Потому что ты его не понимаешь не из-за того что синтаксис языка плохо понятен - а из-за того, что ты просто не умеешь его читать.

ну и? скала красивее и понятнее

Да? И чем же «case 'a' | 'A' => 0» красивее и понятнее, чем «[(or #\a #\A) 0]»?

anonymous
()
Ответ на: комментарий от next_time

Ты всерьез утверждаешь, что вот эта жуткая портянка, за которую в культурном обществе руки отрывают:

(counts.map(_*factor) zip keys.map(l2s(_,z))).filter(_._1 > 0).sortWith((a,b) =>
        a._1 > b._1 || (a._1 == b._1 && a._2 < b._2)
      ).foreach{ case (freq, label) => printf("%s %.3f\n",label,freq) }
      println
пример красивого, читабельного кода?

anonymous
()
Ответ на: комментарий от next_time

но кнопки

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

и автодополнение из коробки не появляется

Ты не способен поставить два плагина? Это занимает не больше пяти минут.

anonymous
()
Ответ на: комментарий от next_time

да

Т.е. ты готов посвятить больше времени изучению языка, чем программированию? Странно в сочетании с целью «для себя»

annulen ★★★★★
()
Ответ на: комментарий от annulen

Как раз, совсем не странно. А самое главное — особо-то много сахара в ЯП, как выясняется, нет нигде.

next_time ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Откуда у тебя в емаксе взялись кнопки?

Из коробки.

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

Программа должна поставять всё необходимое из коробки. Всё ненужное должно быть выключено, всё нужное включено. Если этого не сделано — значит, программа - говно.

Ты не способен поставить два плагина? Это занимает не больше пяти минут.

Не хочу.

next_time ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Но всё равно, она лучше, чем аналогичный код на racket, вами же приведённый.

Если это

жуткая портянка, за которую в культурном обществе руки отрывают

то как можно описать код на racket я и представить боюсь

next_time ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Да? И чем же «case 'a' | 'A' => 0» красивее и понятнее, чем «[(or #\a #\A) 0]»?

Это у вас тонкий английскию юмор такой?

То есть лиспа ты не знаешь. Значит и оценивать синтаксис его не можешь. Потому что ты его не понимаешь не из-за того что синтаксис языка плохо понятен - а из-за того, что ты просто не умеешь его читать.

Знаете, когда я впервые открыл исходники программки на питоне, я почти всё сразу понял, несмотря на то, что питон до этого не то, что не учил, но и в глаза не видел. Зато через 2 года после изучения лиспа даже близко не могу догадаться что значит «автомобиль» и «сиди диск одноразовой записи» на лиспоязыках. Вообще никаких идей.

next_time ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.