OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Четверг, 16 Август, 2018 13:02

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 46 ]  На страницу Пред.  1, 2, 3  След.
Автор Сообщение
СообщениеДобавлено: Суббота, 09 Февраль, 2013 00:38 
Аватара пользователя

Зарегистрирован: Пятница, 11 Май, 2007 21:57
Сообщения: 975
Откуда: Украина, Киев
В той-же Delphi, это всё сделано в виде довольно лаконичной и наглядной библиотечки, код которой можно смотреть-изучать.
Ну, естественно, в языке дополнительным смыслом нагрузили "<" и ">".
Я что-то подобное конструировал http://sage.com.ua/ru.shtml?e1l5
И когда делал это, не покидало чувство, что приходится изголяться, что-бы реализовать такую простую вобщем-то идею... И то что получается всё-равно ещё не совсем то что нужно.

viewtopic.php?f=22&t=3863


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Суббота, 09 Февраль, 2013 14:58 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2516
Откуда: Россия, Ярославль
Ярослав Романченко писал(а):
Я что-то подобное конструировал http://sage.com.ua/ru.shtml?e1l5
А, понятно, у меня тоже часто возникали подобные структуры над списками из Lists, получается, вроде, решение для "сочетания" своего и чужого, то, о чём инфо21 сказал, что это мол, сложно.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Суббота, 09 Февраль, 2013 15:23 
Аватара пользователя

Зарегистрирован: Пятница, 11 Май, 2007 21:57
Сообщения: 975
Откуда: Украина, Киев
Хм, а что сложного-то? Наоборот, повышение уровня абстракции.
Или повсюду в коде должны просматриваться кишки в виде операций по манипуляции указателями и приведению типов?
Вполне читабельный код получается :)
Код:
   PROCEDURE SubsetConstruct*(nfa: RegExpNFA.NFA): RegExpDFA.DFA;
   VAR
      dfa: RegExpDFA.DFA;
      trans: RegExpMaps.Transition;
      lstlstMarked, lstlstUnmarked: Lists.LongintListList;
      mapDFAStateNum: RegExpMaps.DFAStateNumMap;
      lstNFAInitial, lstFirst, lstAState, lstNext: Lists.LongintList;
      iNewState, iInput, i: LONGINT;
      
      PROCEDURE gen_new_state(): LONGINT;
      BEGIN
         INC(iNewState);
         RETURN iNewState
      END gen_new_state;
      
   BEGIN
      NEW(dfa);
      NEW(lstNFAInitial, {});
      NEW(lstlstMarked, {Lists.LIST_SORTED, Lists.LIST_NO_DUPLICATES});
      NEW(lstlstUnmarked, {Lists.LIST_SORTED, Lists.LIST_NO_DUPLICATES});
      NEW(mapDFAStateNum);
      iNewState := 0;
      lstNFAInitial.Add(nfa.iInitial);
      lstFirst := EpsClosure(nfa, lstNFAInitial);
      lstlstUnmarked.Add(lstFirst);
      dfa.iInitial := gen_new_state();
      mapDFAStateNum.Add(lstFirst, dfa.iInitial);
      WHILE ~lstlstUnmarked.IsEmpty() DO
         lstAState := lstlstUnmarked.GetItem(0);
         lstlstUnmarked.Remove(0);
         lstlstMarked.Add(lstAState);
         IF lstAState.IndexOf(nfa.iFinal) # -1 THEN
            i := mapDFAStateNum.IndexOf(lstAState);
            IF i # -1 THEN
               dfa.lstFinal.Add(mapDFAStateNum.GetItem(i).iState)
            END
         END;
         FOR iInput := 0 TO nfa.lstInputs.GetCount() - 1 DO
            lstNext := EpsClosure(nfa,
               Move(nfa, lstAState, nfa.lstInputs.GetItem(iInput)));
            IF (lstlstUnmarked.IndexOf(lstNext) = -1) &
               (lstlstMarked.IndexOf(lstNext) = -1)
            THEN
               lstlstUnmarked.Add(lstNext);
               mapDFAStateNum.Add(lstNext, gen_new_state())
            END;
            i := mapDFAStateNum.IndexOf(lstAState);
            IF i # -1 THEN
               trans := RegExpMaps.NewTransition(
                  mapDFAStateNum.GetItem(i).iState,
                  nfa.lstInputs.GetItem(iInput));
               i := mapDFAStateNum.IndexOf(lstNext);
               IF (i # -1) & (dfa.mapTransition.IndexOf(trans) = -1) THEN
                  dfa.mapTransition.Add(trans,
                     mapDFAStateNum.GetItem(i).iState)
               END
            END
         END
      END;
      dfa.nStates := mapDFAStateNum.GetCount();
      RETURN dfa
   END SubsetConstruct;

То-же на C++:
Код:
DFA subset_construct(NFA nfa)
{
   DFA dfa;

   // state_rep: a set of NFA states which is represented by some DFA state
   //
   typedef set<state> state_rep;
   set<state_rep> marked_states;
   set<state_rep> unmarked_states;
   
   // gives a number to each state in the DFA
   //
   map<state_rep, state> dfa_state_num;
   
   set<state> nfa_initial;
   nfa_initial.insert(nfa.initial);
      
   // initially, eps-closure(nfa.initial) is the only state in the DFAs states
   // and it's unmarked
   //
   state_rep first(build_eps_closure(nfa, nfa_initial));
   unmarked_states.insert(first);
   
   // the initial dfa state
   //
   state dfa_initial = gen_new_state();
   dfa_state_num[first] = dfa_initial;
   dfa.start = dfa_initial;
   
   while (!unmarked_states.empty())
   {
      // Take out one unmarked state and mark it (remove from the unmarked set,
      // insert into the marked set)
      //
      state_rep a_state = *(unmarked_states.begin());
      unmarked_states.erase(unmarked_states.begin());
      marked_states.insert(a_state);
      
      // If this state contains the NFA's final state, add it to the DFA's set
      // of final states
      //
      if (a_state.find(nfa.final) != a_state.end())
         dfa.final.insert(dfa_state_num[a_state]);
      
      // for each input symbol the nfa knows
      //
      for (set<input>::const_iterator inp_i = nfa.inputs.begin(); inp_i != nfa.inputs.end(); ++inp_i)
      {
         // next state
         //
         state_rep next = build_eps_closure(nfa, nfa.move(a_state, *inp_i));
         
         // if we haven't examined this state before, add it to the unmarked
         // states, and make up a new number for it
         //
         if (unmarked_states.find(next) == unmarked_states.end() &&
            marked_states.find(next) == marked_states.end())
         {
            unmarked_states.insert(next);
            dfa_state_num[next] = gen_new_state();
         }
         
         dfa.trans_table[make_pair(dfa_state_num[a_state], *inp_i)] = dfa_state_num[next];
      }
   }
   
   return dfa;
}


PS.
http://svn.assembla.com/svn/oberonru/tr ... /Lists.Mod
http://svn.assembla.com/svn/oberonru/tr ... es/RegExp/


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Суббота, 09 Февраль, 2013 16:08 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2516
Откуда: Россия, Ярославль
Ну да, я тоже к этому пришёл не сразу, но из обычных средств, доступных в КП, это достаточно удобный вариант, плюс такую обёртку можно наращивать всякими важными в контексте проекта, штуками.
А вообще, раз уж мы не можем уйти от определения сущностей для списка в своём проекте, вот ещё вариант, определяем сразу контейнер для выполнения той или иной операции.
Код:
MODULE ListsOp;

   IMPORT
      Meta,
      Kernel, SYSTEM;
   
   CONST
      dataName* = 'data';
      
   TYPE
      List* = POINTER TO LIMITED RECORD
         root, last: Item;
      END;
      
      Item = POINTER TO RECORD
         data: ANYPTR;
         next: Item;
      END;
      
      AddOp* = ABSTRACT RECORD END;
      
      Host = RECORD END;
      
      MyData = POINTER TO RECORD END;
      
      MyAddOp* = RECORD (AddOp)
         data*: MyData;
      END;
      
   VAR
      host: Host;
   
   PROCEDURE (VAR h: Host) Lookup (VAR r: ANYREC; OUT i: Meta.Item), NEW;
      VAR type: Kernel.Type; mod: Kernel.Module; attr: Kernel.ItemAttr;
   BEGIN   (* create a meta item for a global variable passed as VAR parameter *)
      attr.obj := Meta.varObj;
      attr.typ := Meta.recTyp;
      attr.vis := Meta.exported;
      attr.adr := SYSTEM.ADR(r);
      attr.mod := NIL;
      attr.desc := SYSTEM.VAL(Kernel.Type, SYSTEM.TYP(r));
      attr.ptr := NIL;
      attr.ext := NIL;
      attr.mod := NIL;
      Meta.GetThisItem(attr, i)
   END Lookup;   
      
   PROCEDURE GetData(VAR rec: ANYREC): ANYPTR;
      VAR sc: Meta.Scanner; i: Meta.Item; vs: Meta.Name; data: ANYPTR;
   BEGIN
      host.Lookup(rec, i);
      sc.ConnectTo(i);
      WHILE ~sc.eos & (data=NIL) DO
         sc.Scan; sc.GetObjName(vs);
         IF (sc.this.obj#Meta.undef) & (vs$=dataName) THEN
            data:=sc.this.PtrVal();
         END
      END;
   RETURN data
   END GetData;
   
   PROCEDURE (l: List) Add(x: ANYPTR), NEW;
      VAR i: Item;
   BEGIN
      NEW(i); i.data:=x;
      IF l.last=NIL THEN l.root:=i; l.last:=i
      ELSE l.last.next:=i; l.last:=i END;
   END Add;
   
   PROCEDURE (l: List) Do (VAR op: ANYREC), NEW;
      VAR data: ANYPTR;
   BEGIN
      WITH op: AddOp DO
         data:=GetData(op);
         ASSERT(data#NIL, 40);
         l.Add(data)
      ELSE HALT(100) END;
   END Do;
      
   PROCEDURE New*(): List;
      VAR l: List;
   BEGIN
      NEW(l);
   RETURN l
   END New;
   
   PROCEDURE Test*;
      VAR i: INTEGER; ao: MyAddOp; l: List;
   BEGIN
      l:=New();
      i:=0;
      WHILE i<10 DO
         NEW(ao.data);
         l.Do(ao);
         INC(i);
      END;
      HALT(0);
   END Test;
   
BEGIN

END ListsOp.

(!)ListsOp.Test


На хост-часть можно не смотреть :D
Ну и, если таким же способом определить остальные операции, то мета поможет нам установить данные нашего типа в наш контейнер-операцию.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 10 Февраль, 2013 19:20 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2516
Откуда: Россия, Ярославль
Пётр Кушнир писал(а):
определяем сразу контейнер для выполнения той или иной операции. <...>
Ну и, если таким же способом определить остальные операции, то мета поможет нам установить данные нашего типа в наш контейнер-операцию.

В общем, реализовал такой способ, в виде полноценного линейного списка, ничего страшного нет в нём, даже, некоторое однообразие привнесено.
Ещё раз поясню, первая идея была в том, чтобы в модуле Списка был определён специальный контейнер для расширения в клиентских модулях и агрегирования в контейнер поля нужного типа. А потом я понял, что в итоге все методы списка будут работать с этим контейнером, а при наличии WITH что методы, что хэндлер, всё едино. В итоге, получилось даже веселее, например, операция сортировки опирается на сравнение, соответственно, компаратор должен принимать два объекта из списка, так вот, оказалось, что можно эти два поля записать через Meta в поля расширения.
Скорее всего, конечно, упадёт производительность, ну да он и не для того был придуман, чтобы в гонках участвовать, а уж по сравнению с каким-нибудь Си на неуправляемой памяти, любой список в ББ врятли блеснёт скоростью.


Вложения:
Op.odc [12.58 КБ]
Скачиваний: 125
Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 11 Февраль, 2013 09:27 
Модератор
Аватара пользователя

Зарегистрирован: Среда, 16 Ноябрь, 2005 00:53
Сообщения: 4485
Откуда: Россия, Орёл
Пётр Кушнир писал(а):
...модуле Списка ... получилось даже веселее, например, операция сортировки опирается на сравнение, соответственно, компаратор должен принимать два объекта из списка, так вот, оказалось, что можно эти два поля записать через Meta в поля расширения.
Скорее всего, конечно, упадёт производительность, ну да он и не для того был придуман, чтобы в гонках участвовать, а уж по сравнению с каким-нибудь Си на неуправляемой памяти, любой список в ББ врятли блеснёт скоростью.
1) Если делать по-простому, как в Си (где нету Meta), то и в константе (на работу через Meta) разницы не будет.
2) Метод управления памятью влияет только на время создания нового элемента. Вычислительная сложность при работе со списками от этого дела зависит константно; на сортировку же вообще не влияет, если использовать соотв. алгоритм.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 11 Февраль, 2013 09:51 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2516
Откуда: Россия, Ярославль
ну, в ListsLinear используется алгоритм Горячева из динамических строк, насколько я помню этот метод выделения памяти дал максимум производительности на ББ, там внутри есть NEW, это очевидно.

А сортировка не относилась к абзацу про скорость работы.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 28 Февраль, 2013 14:34 
Аватара пользователя

Зарегистрирован: Пятница, 11 Май, 2007 21:57
Сообщения: 975
Откуда: Украина, Киев
Внёс некоторые новшества и улучшения в свою библиотеку контейнеров.
List переименовал в Vector, поскольку, если рассуждать логически, это именно вектор на базе динамического массива. Настоящий List ещё необходимо будет реализовать на базе двухсвязного списка.
Реализовал Dictionary на базе хеш-таблицы. Хеш-таблица простейшая на базе динамического массива с простым механизмом разрешения коллизий и возможностью роста. Все возможные размеры таблицы заранее заданы табличкой простых чисел. При росте хеш-таблицы, позиции элементов пересчитываются с новым модулем, при этом хеш-коды элементов берутся из кэша, так-как операция взятия хеш-кода может быть достаточно медленной.
На базе Dictionary можно строить контейнеры типа Set и типа Map. В контейнере Set как-правило хранятся только ключи, и они-же являются и данными. В контейнере Map хранятся пары ключ:значение.
Реализовал двоичную кучу BinaryHeap.
Конейнер под любой тип данных описывается очень быстро, в библиотеке в качестве примера реализованы: вектор целых (LongintVector), вектор векторов целых (LongintVectorVector), вектор строк (StringVector), множество целых (LongintSet), множество множеств целых (LongintSetSet), куча целых (LongintHeap).
Dictionary получился достаточно быстрым. Добавление в LongintSetSet 100000 множеств LongintSet, содержащих в свою очередь до 21 случайного целого, с предварительной проверкой на вхождение в множество выполняется чуть менее чем за секунду. Для сравнения, заполнение LongintSet 100000 случайных целых с предварительной проверкой занимает порядка 70 мс. Без предварительной проверки будет просто останов по ASSERTу, поскольку Dictionary предполагает хранение лишь уникальных ключей.
http://svn.assembla.com/svn/oberonru/tr ... ainers.Mod


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 28 Февраль, 2013 14:52 
Аватара пользователя

Зарегистрирован: Пятница, 11 Май, 2007 21:57
Сообщения: 975
Откуда: Украина, Киев
Код:
MODULE ContainersTest; (** AUTHOR ""; PURPOSE ""; *)

IMPORT
   Commands, Containers, Random, PreciseTimer;

PROCEDURE HashTest*(context: Commands.Context);
CONST
   SETS = 100000;
   TRIES = 20;
VAR
   r: Random.Generator;
   set: Containers.LongintSet;
   setset1, setset2: Containers.LongintSetSet;
   i, j, n, iTry: LONGINT;
   t: HUGEINT;
BEGIN
   context.out.Ln;

   NEW(r);

   t := PreciseTimer.GetTicks();
   
   FOR iTry := 0 TO TRIES - 1 DO
      NEW(set);
      FOR i := 0 TO SETS - 1 DO
         n := r.Dice(MAX(LONGINT));
         IF ~set.Contains(n) THEN
            set.Add(n)
         END
      END
   END;
   
   t := PreciseTimer.GetTicks() - t;
   
   context.out.String("Count: ");
   context.out.Int(set.GetCount(), 0);
   context.out.Ln;
   context.out.String("Collisions: ");
   context.out.Int(set.dictionary.nCollisions, 0);
   context.out.Ln;
   context.out.String("Time: ");
   context.out.Float(PreciseTimer.GetTime(t) / TRIES, 15);
   context.out.Ln;
   context.out.Update;
   
   NEW(setset1);
   FOR i := 0 TO SETS - 1 DO
      NEW(set);
      FOR j := 0 TO 20 DO
         n := r.Dice(MAX(LONGINT));
         IF ~set.Contains(n) THEN
            set.Add(n)
         END
      END;
      IF ~setset1.Contains(set) THEN
         setset1.Add(set)
      END
   END;
   
   context.out.String("Sets generated");
   context.out.Ln;
   context.out.Update;
   
   t := PreciseTimer.GetTicks();
   
   FOR iTry := 0 TO TRIES - 1 DO
      NEW(setset2);
      setset1.Reset;
      WHILE setset1.HasNext() DO
         set := setset1.GetNext();
         IF ~setset2.Contains(set) THEN
            setset2.Add(set)
         END
      END
   END;

   t := PreciseTimer.GetTicks() - t;

   context.out.String("Count: ");
   context.out.Int(setset2.GetCount(), 0);
   context.out.Ln;
   context.out.String("Collisions: ");
   context.out.Int(setset2.dictionary.nCollisions, 0);
   context.out.Ln;
   context.out.String("Time: ");
   context.out.Float(PreciseTimer.GetTime(t) / TRIES, 15);
   context.out.Ln;
   
END HashTest;

BEGIN
END ContainersTest.

ContainersTest.Test ~
ContainersTest.HashTest ~
SystemTools.Free ContainersTest Containers ~

Count: 99997
Collisions: 232111
Time:   7.291155E-002
Sets generated
Count: 100000
Collisions: 255930
Time:   9.049281E-001


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 11 Март, 2014 20:27 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2516
Откуда: Россия, Ярославль
Реализовывал ли кто-нибудь структуру хранения произвольных данных (рекордов с полями примитивных типов) в Stores.Store (ну или просто в массиве байтов) с интерфейсом, подобным дин.массиву?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 11 Март, 2014 23:33 
Аватара пользователя

Зарегистрирован: Пятница, 25 Сентябрь, 2009 13:10
Сообщения: 1158
Откуда: Tel-Aviv
Пётр Кушнир писал(а):
Реализовывал ли кто-нибудь структуру хранения произвольных данных (рекордов с полями примитивных типов) в Stores.Store (ну или просто в массиве байтов) с интерфейсом, подобным дин.массиву?
Нет, лично не пробовал. И смысла не вижу. Изобретаем свою БД?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 11 Март, 2014 23:38 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2516
Откуда: Россия, Ярославль
Ну почему сразу БД, может быть изобретаем контейнер для IPC.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 11 Март, 2014 23:44 
Аватара пользователя

Зарегистрирован: Пятница, 25 Сентябрь, 2009 13:10
Сообщения: 1158
Откуда: Tel-Aviv
Пётр Кушнир писал(а):
Ну почему сразу БД, может быть изобретаем контейнер для IPC.
Насколько мне известно, Stores работает на файловой основе, что возможно излишне для выполнения сетевых операций (сокет, к примеру).


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 11 Март, 2014 23:50 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2516
Откуда: Россия, Ярославль
Для этого есть memory mapped files (ну, реализованы уже в ББ). В этом плане еще интересно попробовать что-то типа lock-free структур, даже в наивной реализации, имеющимися средствами.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 11 Март, 2014 23:56 
Аватара пользователя

Зарегистрирован: Пятница, 25 Сентябрь, 2009 13:10
Сообщения: 1158
Откуда: Tel-Aviv
Допустим так. Неясно как тогда происходит отправка сообщения. Ведь приёмник должен постоянно считывать файл.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 11 Март, 2014 23:58 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2516
Откуда: Россия, Ярославль
Не, суть именно в том, что это структура типа массива. Нужно хранение в массиве всяких структур. Допустим оно будет.
А далее интересно, как там должно быть, например, с обработкой массива, который того и гляди изменится.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Среда, 12 Март, 2014 00:03 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2516
Откуда: Россия, Ярославль
Но пока интересно только запилить типа "массив".
Профит в том, что память у двух ББ общая. А значит запись-чтение будет происходить один раз, как будто этот список у нас в памяти.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Среда, 12 Март, 2014 00:06 
Аватара пользователя

Зарегистрирован: Пятница, 25 Сентябрь, 2009 13:10
Сообщения: 1158
Откуда: Tel-Aviv
Пётр Кушнир писал(а):
Не, суть именно в том, что это структура типа массива. Нужно хранение в массиве всяких структур. Допустим оно будет.
А далее интересно, как там должно быть, например, с обработкой массива, который того и гляди изменится.

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

Допускается ли применение вложенных структур?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Среда, 12 Март, 2014 00:10 
Аватара пользователя

Зарегистрирован: Пятница, 25 Сентябрь, 2009 13:10
Сообщения: 1158
Откуда: Tel-Aviv
Причём, размер структуры перед самими данными отправлять не нужно. Это можно сделать в виде маркера окончания приёма данных.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Среда, 12 Март, 2014 00:12 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 8970
Откуда: Россия, Орёл
Я когда-то делал тупо "двоичный дамп" записи в Files.File.
Где-то даже публиковал на форуме, но не ищется!!
Что несложно сделать через Kernel и Type.size.

Процедуры ReadRec/WriteRec, ReadTagged/WriteTagged.
Последние отличались тем, что до собственно данных записи клали 64-бит фингепринт типа.
При чтении проверялось соответствие фингерприта типу RECORD-а, в который пытаемся считывать.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 46 ]  На страницу Пред.  1, 2, 3  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2018, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB