\PassOptionsToPackage{mw, RCS}{gmutils}
\documentclass[english, wide, mwbk, 11pt, golden,
fleqn]{pmlectionis}



\usepackage{polski}
\usepackage{xcolor}


\usepackage{gmutils}
\XeTeXthree

\WPheadings

\PassOptionsToPackage{lckeywords}{gmsql}
\usepackage[tt]{gmrhtml, gmsql}

\let\rb\ruby

\defaultfontfeatures{Mapping=tex-text, Numbers=OldStyle }

\setromanfont[% Mapping=tex-text, 
Scale=0.9]{TeX Gyre Bonum}%

%\setmainfont{Garamond Premier Pro}

\setsansfont[% Mapping=tex-text,
Scale=MatchLowercase]{TeX Gyre
  Adventor}%{LMSans10}

\setmonofont[Scale=%
0.8%
% MatchLowercase% 
  ]{LucidaTypeCE}
  % \setmonofont[Scale=MatchLowercase]{Andale Mono}
  % ^^A  \setmonofont[Scale=MatchLowercase]{LMTypewriter10}%
  % ^^A~kiedy ustawiałem, składało się Latin Modernem, czy to w~kodowaniu
  % ^^A~T1, czy to bez niego.

\let\rbfont\ttfamily

\def\linenumfont{\rm\scriptsize\addfontfeature{Numbers=Monospaced}}






\def\ka#1 #2: #3\par{%
  \section*{#2}%
  \markboth{#2}{#2}%
  \def\curdir{/home/natror/anotatornia/#2/}%
  \csname iter#1input\endcsname #3 \par}



\def\iterxinput#1#2 #3\par{%
  \unlesstilde#2~\nil{%
    \subsection*{#2}\markright{#2}%
    \csname r#1inputnolicense\endcsname{\curdir#2}%
  }%
  \ifx\relax#3\relax\else\afterfi{%
    \iterxinput#1#3\par}\fi}

\def\iterbinput{\iterxinput b}
\def\iterhinput{\iterxinput h}


\def\unlesstilde#1~#2\nil#3{%
  \ifx\unlesstilde#2\unlesstilde
  \ifx\unlesstilde#1\unlesstilde\else#3\fi\fi}

\GMverbatimspecials

\fooatletter{%
  \foone{%
    \verbatim@specials
    \pp@setcatcodes
    \makeatletter
    \catcode`€=14
    \catcode`§=6 }}«€
⁄def⁄rb@swallow@license§1 #
 # This file is part§2 # PURPOSE.
 #
§3«§1




















§3»€
⁄def⁄rh@swallow@license§1 # PURPOSE.
%>
§2«





















§2»€
» % «
  

\MakeShortVerb\|

\overfullrule=0sp



\twocoltoc

\pagestyle{myheadings}


\title{% Dokumentacja techniczna serwisu Anotatornia
  Technical Remarks Concerning\\ the Anotatornia Service\\
{\smallerr  The \ac{NKJP} Version 
v.\eRCSVersion $Id: anotatornia_NK.tex,v 1.180 2010/07/02 01:32:59 zrogezrg Exp $}}
\date{\today}
\author{Grzegorz Murzynowski}


\let\class\sfname
\let\tabela\sfname

% \show\square
% \show\uparrow
% \show\downarrow
%\show\sqrtsign
%\show\uparrow
%\show\downarrow

\gmath\garamath
\gmathscripts

\errorcontextlines=100

\setcounter{tocdepth}{3}

\fooatletter{%
  \addtomacro\sql@scanthook{\RubyHash}}

\let\di\discret

\urladdstar

\begin{document}
\catcode`§=6
\RubyHash

\exhyphenpenalty=\hyphenpenalty

%\show\rbformatloner

\maketitle


%\rbinput{t2.rb} %/home/natror/anotatornia/app/models/rola.rb 

%\newpage
%\rhinput{/home/natror/anotatornia/app/views/layouts/_sidebar1.rhtml}

\catcode`_=12

\tableofcontents


\StoreMacros{\thesection \thesubsection}

\def\thesection{\arabic{section}}
\def\thesubsection{\arabic{section}.\arabic{subsection}}


%&&&&&&&&&&&&&&&&&&&&&&&&&&

\cleardoublepage


\chapter*{Introduction}

This is Anotatornia, a Ruby on Rails-based application for manual
multi-level annotation of texts.

The Anotatornia program, i.e.~the contents of directories \file{app/}, \file{db/}
and files contained in the main directory, are released under the \ac{GNU}
Public License version~3.

A compatible copy of the Ruby on Rails framework, 
i.e.\ the contents of the \file{vendor/rails/} directory, is provided
under the \ac{MIT} license. 

For the texts of those licenses see file \ac{COPYING}.

However, if you don't want to read these licenses, please note at
least that both of them claim that 

{\noindent\bfseries This software is provided free of charge and free
  to be used in almost any manner but{\largerr\space AS IS, i.e.\
    WITHOUT ANY GUARANTEE OF ANY KIND }(such as: that it works, won't
  destroy your data and so on).

}



\section{Installation and deployment}

Anotatornia has been installed only on Linux machines (Ubuntu and Red
Hat Enterprise).

To make Anotatornia work you'll need:

\medskip
\begin{tabular}{@{}>{•\enspace}ll@{}}
    Ruby	&		v.>=1.8,\\
    SQLite3 & 		v.>=3.3.6\\
    sqlite3-ruby &	v.>=1.2.4\\
    mongrel &		v.>=1.1.5\\[\medskipamount]

\multicolumn{2}{@{}>{•\enspace}l}{Rails v==1.2.4 (provided in this package)}\\
\end{tabular}

\medskip
As you are reading this file, let's assume you have unpacked the
contents of the archive to a directory \file{~/anotatornia} (and you want it
to stay there). To start, you should
\begin{verbatim}
sqlite3 <database-name>.db
.read schema_20106005.sql
⁄<C-d (quit SQLite3)>
\end{verbatim}

This creates the database file and gives it Anotatornia's
structure. Since in the \ac{NKJP} project there were a couple of linguistic
databases with the same set of users, the users' database is contained
in another file. Create it:
\begin{verbatim}
sqlite3 ⁄<users_db>.db
.read schema_u.sql
⁄<C-d (quit SQLite3)>
\end{verbatim}

Now configure the Rails code: add a stanza for your database to the
\file{config/database.yml} file and define an environment file for it (named
the same as the stanza in \file{config/database.yml}).

To be sure the database is most up-to-date run also
\begin{verbatim}
RAILS_ENV=⁄<your env.⁄ name>  rake db:migrate
\end{verbatim}


Then you can probably input linguistic data. The morphosyntactic
tagset is in the file \file{gramdata/tagset.cfg} and will be
automatically loaded to the table \tabela{tagset} at the first startup
of the application.

\medskip

Because of historical reasons (word-sense disambiguation was deployed
after deployment of the first three levels) input of the sense
dictionary is not automatic. 


The senses dictionary is contained in the file
\file{nkjp_wsd_si/NKJP_WSI.xml}.

To input it you should change the datetime in line 46 in the Ruby
script \file{isens.rb} (contained in the main directory) to some
future value (it's a sentinel not to destroy the senses once
input). Then you launch the script in the proper environment, which is
done by typing in a terminal:
\begin{verbatim}
script/console nk8005
load 'isens.rb'
\end{verbatim}
You can replace the senses dictionary until word-sense disambiguation
started only.

\medskip

You can add new users via the admin interface. During the very first
launch of a new Anotatornia a default admin is created with login
'QueenOfSpades' and password '15 mars 1615 Paris'. It is strongly
advisable that you delete this user after creating your own admin(s)
or at least change her password.

\medskip

The texts should be in \ac{NKJP} \ac{XML} format. Then they can be
input with the \file{danowlew} shell script:
\begin{verbatim}
danowlew  ⁄<envir.>  ⁄<path to texts>
\end{verbatim}
% Wówczas skrypt Rubinowy \file{im.rb} wlewa do odpowiedniej bazy dane
% z~katalogów w~nim wpisanych oraz inicjalizuje bazę, tj. tworzy
% \emph{akapity transzy}, czyli instancje akapitów przeznaczone dla
% poszczególnych Anotatorek, oraz transze, czyli grupy akapitów
% przeznaczone do jednorazowego przydzielenia:
That script launches \file{im.rb} which in turn inputs the data into
the proper database and initializes it, i.e.\ creates \emph{akapit
  transzy}'s—‘a bulk's paragraphs’, i.e.\ groups of Akapit's
(paragraphs) destined to be attributed at once (together), explained
in the next section.


\medskip

To make your Anotatornia available from outside you should open some
port (in \ac{NKJP} project it was 8003) and write it down in the
\file{anotatornia-mongrels} script. Then run
\begin{verbatim}
./anotatornia-mongrels start
\end{verbatim}
for single launch (during tests etc.) or		    
\begin{verbatim}
./anotatornia-keeprunning
\end{verbatim}
for full deployment. The latter script launches \pk{mongrel} server(s)
as set in the file \file{anotatornia-mongrels} and every 10~seconds
checks whether are they running.



% =======================================
% ANNOTATION
% =======================================

% Too complicated to describe it here. See Instrukcja anotacji...



%&&&&&&&&&&&&&&&&&&&&&&&&&&



\subsection{The Transza's—creation and allocation}
% (Jednostką tekstu do zatwierdzenia  jest akapit. Każdy akapit ma
% zostać zaanotowany przez dwoje Anotatorów. Akapity mają być
% przydzielane w~taki sposób, by w~miarę możliwości utrudnić tworzenie
% się tandemów anotatorskich.)

A unit of text to be worked on is Akapit, a paragraph that is. Each
Akapit should be annotated by two Annotators. Akapits have to be
allocated in such a manner that co-learning of the Annotators is
minimised.

Akapit's are allocated to the Annotators in Transza's (‘bulks’). The
number of Akapit's in a Transza is determined by
#{AnoVersion.rozmiar_transzy} (defined in
\file{config/environments/⁄<env. file>}) and for the deployment
in \ac{NKJP} was 10. 

To make a Transza consisting of 10 Akapits every next 20 of Akapits is
divided in fives and those fives are paired in different ways to
allocate them to four different Annotators. Let's consider Akapit's 1–20:
% Każdą dwudziestkę akapitów dzieli na  piątki, i~piątki te łączy w~pary
% po 10 akapitów zwane \emph{transzami} na różne sposoby, by
% przydzielić czterem różnym Anotatorkom. Dla ustalenia uwagi rozważmy
% akapity 1–20:
\begin{verse}
  Transza 1:\enspace Akapit's 1–5, 6–10 (fives 1 \& 2);
  Transza 2:\enspace Akapit's 1–5, 11–15 (fives 1 \& 3);
  Transza 3:\enspace Akapit's 11–15, 16–20 (fives 3 \& 4);
  Transza 4:\enspace Akapit's 6–10, 16–20 (fives 2 \& 4).
\end{verse}
% Każda Anotatorka może z~danej czwórki tak przecinających się transz
% dostać co najwyżej jedną, dlatego też do działania Anotatorni
% koniecznie potrzeba co najmniej czworo Anotatorów.  Transze będą
% przydzielane (na życzenie Anotatorki) w~kolejności ich utworzenia,
% która jest zgodna z~kolejnością wczytania tekstu do bazy danych, czyli
% z~kolejnością akapitów, z~zastrzeżeniem, że dany Anotator może z~danej
% czwórtranszy dostać co najwyżej jedną (nie ma jednak programowych
% przeszkód, by Anotatorka X otrzymała np. transze 1, 8, 9, 14, 17).
From such a four of intersecting Transza's any Annotator can get at
most one (therefore the minimum number of Annotators required in
Anotatornia is 4).

The Transza's are allocated at Annotator's request in the order of
creation, which is according to the order of inputting of the data
into the database, which in particular is according with the order of
Akapit's.

Note that it is perfectly consistent with the above conditions that
Annotator $X$ gets the Transza's 1, 8, 9, 14, 17.

% Nie może się zdarzyć, że jedna Anotatorka zaanotuje wszystko, nie
% zostawiając nic dla innych: żadna Anotatorka nie może zaanotować
% więcej niż \df1/4 transz.
% % Nie oznacza to zaanotowania połowy tekstu, gdyż do zaanotowania
% % jakiegokolwiek tekstu konieczne są co najmniej dwie anotatorki.
%  W~przypadku liczby Anotatorów większej niż 5
% możliwe jest oczywiście, że ktoś zaanotuje więcej niż inni.


\section{Multi-level annotation}

Anotatornia provides four levels of annotation:
\begin{itemize}
\item word-level segmentation,
\item sentence-level segmentation,
\item morphosyntactic annotation,
\item word-sense disambiguation.
\end{itemize}

Since the sentence limits cannot be determined before determining the
limits of words and so on, the levels constitute a partial order that
can be described with a following diagram:
% Poziomy anotacji zadane są następującym grafem zależności:

\begin{center}

\small

  \DeclareCommand\blubrus{%
    o% (1) options of node
    >iQ{at} c% (2) coordinate
    c% (3) name
    m% (4) text
    >iT{;}} {%
    % \typeout{\unexpanded{#4}}%
    % \settowidth\blubrak{#4}%
    \IfValueTF{§1}{%
      \node at (§2) [§1, }%}
    {\node at (§2) [ }% }
    % text width=\blubrak,
    text centered, inner sep=5pt] (§3)
    {\lv\vphantom{gl}\ignorespaces§4};%
  }


  \DeclareCommand\krawóndź{ A{2} % wysokość kontrolki wychodz.
    >is A{2} % wysokość kontrolki wchodz.
    m % nazwa wych.
    m % nazwa wchodz.
  }{%
    \draw (§3.south) .. controls +(down:§1) and +(up:§2)
    .. (§4.north);}


  \begin{tikzpicture}[x=1\baselineskip,y=1\baselineskip]
  
    \blubrus at (0,0) (segm) {word-level segmentation};

    \blubrus at (-7, -6) (sent) {sentence-level segmentation};
    
    \blubrus at (7, -6) (ms) {morphosyntactic annotation};

    \blubrus at (0, -12) (wsd) {word-sense disambiguation};

    \krawóndź {segm}{sent}
    \krawóndź {segm}{ms}
    \krawóndź {sent}{wsd}
    \krawóndź {ms}{wsd}
    
  \end{tikzpicture}
  
\end{center}
which is also encoded in the model file \file{poziomy_anotacji.rb}.
Annotation at level $x$ is possible (status 0, see next section), if
\[\Bigl( \forall_{y\in \text{Levels}}\bigl(\hbox{succ}(y)\mathbin= x \rightarrow
\text{Verified}(y)\bigr)\Bigr) \wedger \neg\text{Closed}(x)\]
It is clear that at the minimal level (word-level segmentation)
the first part of the conjunction is empty-satisfied.

% Jak widać, na poziomach minimalnych, tj. na poziomach segmentacji
% i~granic zdania, pierwszy człon koniunkcji jest pusto spełniony.

\passage
%  Kiedy Anotator wchodzi w~anotację akapitu, wyświetlają mu się
% dostępne poziomy anotacji oraz poziomy bezpośrednio niższe. Dla akapitu
% „świeżego” będzie to anotacja morfosyntaktyczna lub ewentualnie
% ujednoznacznienie segmentacji. Anotator może wybrać, które poziomy
% wyświetlać. Odpowiednio do tego pojawiają się przyciski „Zatwierdź
% \<poziom>” a~także, jeśli jest więcej niż jeden poziom dostępny do
% anotacji, „Zatwierdź wszystkie”. 
If there is no word-level segmentation ambiguity in an Akapit, it is
automatically “empty-verified” at this level.

When an Annotator enters the annotation of an Akapit, they is shown
available levels and their immediate precedents. For a “fresh” Akapit
it usually will be the sentence-level segmentation and
morphosyntactic annotation level (word-level segmentation ambiguities
are rather rare). The Annotator can choose which levels should be
displayed. According to this the buttons “Zatwierdź \<level>”
(‘Commit~…’) are displayed and, if there are more than one levels,
“Zatwierdź wszystkie” (‘Commit all’).

% Naciśnięcie przycisku „Zatwierdź …” powoduje odpalenie procedury
% sprawdzającej poprawność anotacji na tym poziomie i, w~razie
% pozytywnego wyniku testu, zmianę statusu akapitu na 8
% \ruby{:zatwierdzone} lub, jeśli partner też je zaanotował, na 16
% \ruby{:zweryfikowane}
% bądź 10 \ruby{:do_poprawki}.
Clicking a “Zatwierdź~\<level>” button launches a subroutine checking
correctness of annotation at this level and, if the test turns true,
change of the Akapit's status to 8, #{:zatwierdzone} (‘ratified’), or,
if the counter-Annotator has annotated it too, to 16,
#{:zweryfikowane} (‘verified’) or 10 #{:do_poprawki} (‘to be fixed’).

% W~tym drugim przypadku akapit zostaje zwrócony Anotatorowi do
% powtórnego przejrzenia z~zaznaczeniem miejsca niezgodności z~anotacją
% partnera, ale bez pokazania, jak partner zaanotował. Po ponownym
% zatwierdzeniu akapitu zostaje on poddany weryfikacji i, w~przypadku
% zgodności anotacji, oznaczony jako zweryfikowany, a~w~przypadku
% niezgodności — oznaczony „do osądzenia” (status 14).
% (W~razie niewprowadzenia poprawki przez partnera akapit otrzymuje
% status 12 „po poprawce”, a~powyższa procedura zostanie zastosowana do
% „poprawczego” zatwierdzenia przez partnera.) (Zgodnie z~mailem AP
% z~5~stycznia~2009 godz. 13.10, „Re: Streszczenie na \ac{PALC}”.)



In the latter case the Akapit is returned to the Annotator to be
looked at again. The points of Annotator's' disagreement are
highlighted but annotation of the counter-Annotator is not shown.

After another commitment of the Akapit it is checked again and, if the
annotations fully agree, it's marked as verified (status 16),
otherwise it's marked #{:do_osądzenia} (‘to be judged’) (status 14).

(In case the counter-Annotator didn't re-annotate the Akapit, it gets
status 12, #{:po_poprawce} (‘after the fix’) and the above routine
will be applied to the “fixing” commitment of the Akapit by the
counter-Annotator.)

% Akapity o~statusie co najmniej 14 \ruby{:do_osadzenia} mogą być
% anotowane tylko przez Arbitra. Wraz z~wprowadzeniem przez Arbitra
% pierwszej zmiany (która może być na dowolnym poziomie nie wyższym niż
% makswyższy dopuszczalny) następuje zmiana statusu akapitu na tym
% poziomie na 15 \ruby{:osadzane}, a~na wszystkich poziomach wyższych —
% na $-1$ \ruby{:nie_dopuszczone}

The Akapit's with status $\ge 14$ (#{:do_osądzenia}) can be annotated
only by a Super-Annotator. With making any slightest change by a
Super-Annotator (which may occur at any level not higher than than
maximal allowed) the Akapit's status at this level changes into 15,
#{:osądzane} (‘under judgment’), and at all the levels higher into
$-1$, #{:nie_dopuszczone} (‘not allowed’).


\passage

% Anotator może zmieniać anotację akapitu na dostępnym poziomie, na
% którym akapit nie został zweryfikowany. Wprowadzenie zmiany w~akapicie
% zatwierdzonym powoduje obniżenie jego statusu na tym poziomie do 0
% \ruby{:dopuszczone}, jeśli zmieniający jest Anotatorem, lub 10
% \ruby{:osadzane}, jeśli zmieniającym jest Superanotator.

An annotating user can change the Akapit's annotation at any available
level, at which the Akapit is not yet verified. Making a change in a ‘committed’
Akapit results with degrading its status (at this level) to 0,
#{:dopuszczony} (‘allowed’), if the user is an Annotator, or 14,
#{:osądzany}, if the user is a Super-Annotator.

% W~związku z~tym mamy w~klasie \ruby{Statusy} metodę
% \ruby{zabron_wyzszych} i, niezupełnie symetrycznie, metodę
% \ruby{dopusc_nastepniki}. Niezupełnie symetrycznie, bo
% \ruby{zabron_wyzszych} blokuje \emph{wszystkie} poziomy powyżej
% danego, zaś \ruby{dopuść_następniki} — dopuszcza anotację tylko na
% poziomach będących bezpośrednimi następnikami danego. Będzie z~tym
% zapewne dużo zabawy: jeśli Superanotator coś zmieni na poziomie
% morfosyntaktycznym, to nawet, jeśli nie ma to de facto wpływu na żaden
% z~trzech wyższych poziomów — Anotatorzy będą musieli ponownie
% zatwierdzić je wszystkie (lub zrobi to sam Superanotator).


\subsection{Statuses}

Since we divide annotation into levels, we assign a level-status to
each Akapit Transzy (‘paragraph of a bulk’), i.e.\ a pair

% Ponieważ koncepcyjnie wyróżniamy poziomy anotacji, akapitowi,
% a~dokładniej: akapitowi transzy, tj. parze
$\langle\hbox{akapit},\hbox{anotator}\rangle$:% , przypisujemy status na
% każdym poziomie:
\begin{itemize}
\item [\numlabel -1] % (wartość domyślna) a.t. nie jest na tym poziomie
  % zaanotowany ani dopuszczony do anotacji;
  (the default) Akapit Transzy is nor annotated neither allowed to be
  annotated at  this level;

\item [\numlabel 0] A.T.\ % jest na tym poziomie dopuszczony do anotacji
  is allowed to be annotated at this level;
\item [\numlabel 8] A.T.\ %   został zaanotowany (i~jest gotowy do konfrontacji
  % z~a.t. bliźniaczym)
has been annotated and is ready for confrontation with its twin;

\item  [\numlabel 10] to be fixed: verifying subroutine was launched
  at this Akapit for the first time and found disagreement(s), the
  Akapit is returned to Annotators.

\item [\numlabel 16] A.T.\ % został zweryfikowany (to, czy został zatwierdzony
  % czy odrzucony, wiemy z~pola Boolowskiego \sql{odrzucony})
has been verified;
\item [\numlabel 14] to be judged: % procedura weryfikacji na tym poziomie
  % stwierdziła niezgodność, akapit zostaje przekazany Arbitrowi
the verifying subroutine found disagreement(s), the Akapit is passed
to Super-Annotators;
\item [\numlabel 15] under judgement: % Superanotator zmienił anotację akapitu na tym
  % poziomie, ale jeszcze go nie zatwierdził
a Super-Annotator made some change to the annotation but has it not
yet commited;
\item [\numlabel 18] judged: the Akapit has been annotated by a Super-Annotator.
\end{itemize}

% W~modelu \file{zdania_transzy.rb} zdefiniowaliśmy (w~klauzuli 
% \ruby{if DlaEli.nk}) metody statusowe odwołujące się do rekordu tabeli
% \tabela{statusy} związanego z~danym akapitem transzy.
In the model file \file{akapit_transzy.rb} there are defined (in the
clause #{if DlaEli.nk}) status methods referring to the record of the
table \tabela{statusy} connected with given Akapit Transzy.

% Z~powodu sześciu poziomów anotacji odpowiedź na pytanie „Ile jest akapitów
% zaanotowanych?” staje się wielowymiarowa. Wahamy się, czy informację
% o~liczbie zaanotowanych akapitów przechowywać w~bazie danych (w~tabeli
% \tabela{ile_zaanotowanych}) czy każdorazowo wyliczać. W~każdym
% z~trzech wariantów (dane przechowywane w~bazie, osobne zapytanie dla
% każdego poziomu anotacji, wspólne zapytanie dla wszystkich poziomów)
% odpowiedź jest natychmiastowa (w~badaniu na oko).

Because of four levels of annotation the answer to the question “How
many Akapit's have been annotated” becomes a vector and so it
appears at the main site after logging in, next to bulks in a list and
so on.

% Wariant z~cache'owaniem wymagałby podopisywania update'ów
% w~procedurach zmiany statusu, które i~tak muszą zostać napisane od
% nowa w~paradygmacie wielopoziomowym.

% That  information is stored in the table  \tabela{ile_zaanotowanych}
% (‘how many annotated’).
% \passage Definicja tabeli \tabela{ile_zaanotowanych} jest generowana
% iteracyjnie — nie jest wypisana jawnie — w~pliku migracji 046.


\passage
% Kiedy należy na danym poziomie podnieść status akapitu transzy, wołana
% jest metoda \ruby{anotacja_controller.podnies_status}, która patrzy na
% hasz \ruby{STATI_podnies} twardo wpisany w~modelu
% \file{zdania_transzy}, który koduje graf podnoszenia poziomów. Te
% poziomy, które zostaną podniesione niezależnie od werdyktu
% weryfikacji, są w~tym haszu po prostu (sauté). Te, których
% podniesienie jest zależne od werdyktu — jako tablica  
% \ruby{[\<status>, \<werdykt>]}.
When a status at a given level should be increased, the method
\ruby{anAnotacjaController.podnies_status} (‘increase status’) is
called. It looks at the hash #{STATI_podnies} hardcoded in the model
\file{akapit_transzy.rb}, in which the graph of status increasing is
encoded. The stati that will be increased independent of the
verification result, appear in that hash sauté. Those whose increasing
depends of the verification result are encoded as an array
\ruby{[\<status>, \<werdykt>]}.

% Zakładamy, że nie będzie weryfikacji (obiektu
% \ruby{session[:weryfikacja]} dla tych statusów, które nie muszą być
% weryfikowane. 

An assumption is made that there will not be a verification (the object
\ruby{session[:weryfikacja]}) for those stati that don't need to be
verified.

% Zdefiniowałem metodę \ruby{statusy.setpoziom} dla krótkości tego, co
% już robiłem w~dwóch miejscach, mianowicie dla posłania obiektowi klasy
% \ruby{Statusy} metody \ruby{\<poziom>=}.
A method is defined \ruby{aStatusy.setpoziom} as a shorthand for a
thing I did in two places, i.e.\ passing to an object of the class
#{Statusy} the method \ruby{\<poziom>=}.

% Każdy poziom anotacji ma w~tabeli \tabela{statusy} kolumnę na \ac{ID}
% użytkownika, który zatwierdził ten poziom. Zakładamy, że zazwyczaj
% będzie to Anotator, w~którego transzy znajduje się akapit, ale może
% też być Superanotator, a~w~przypadku segmentacji — także administrator,
% czyli ja.

Each level of annotation has in the table \tabela{statusy} the column
#{\<level name>_uzid} for the user who committed that level. We assume
that they usally are an Anotator, in whose bulk (Transza) this Akapit
is present. But they also can be a Super-Anotator, and in case of
word-level segmentation also an Admin (who changes something “by
hand”). 

\passage
% W~widokach \file{anotuj.rhtml}, \file{_token_disamb.rhtml},
% \file{_token_sens.rhtml}, \file{_token_fra.rhtml}
% (i~\file{_walencja.rhtml}, którym jednak w~ramach projektu \ac{NKJP}
% się nie zajmujemy) używana jest metoda pomocnicza (helper's method)
% \ruby{zt_edytowalne?}, zdefiniowana w~pomagaczu
% \file{anotacja_helper.rb}. Metoda ta w~poprzednich wersjach Anotatorni
% sprawdzała, czy akapit jest dostępny do edycji przez danego
% użytkownika przy danym statusie. W~projekcie \ac{NKJP}, gdzie
% rozróżniamy poziomy anotacji, metoda musi brać pod uwagę także te
% poziomy, tj. sprawdzać dostępność akapitu transzy do edycji przez
% danego użytkownika na danym poziomie przy danym statusie na tym
% poziomie. Jeszcze inną rzeczą jest kwestia, czy dany poziom anotacji
% ma być wyświetlany. Wydaje się jednak sensowne, by metoda
% \ruby{zt_edytowalne?}  dla poziomów aktualnie ukrytych zwracała
% \ruby{false}, by wprowadzenie zmian w~anotacji na poziomach ukrytych
% było blokowane także przez nią.

In the views \file{anotuj.rhtml}, \file{_token_disamb.rhtml},
\file{_token_sens.rhtml}, \file{_token_fra.rhtml} (and
\file{_walencja.rhtml}, not used in the \ac{NKJP} version)
a helper's method is used \ruby{zt_edytowalne?},defined in the helper 
 \file{anotacja_helper.rb}. This method in the previous version of
 Anotatornia checked whether an Akapit is available for editing by the
 given user at the given status. In the \ac{NKJP} project, where we
 distinguish annotation levels, this  method has to take into account
 also them, i.e.\ to check availability with three respects: user,
 level and status.

Another thing is the question whether the given annotation level
should be displayed. It seems however reasonable to make the method
\ruby{zt_edytowalne?} return #{false} for the levels hidden at the
moment, so that making changes to the annotation at the hidden levels
would be forbidden.

% Metoda ta oczywiście musi zostać dla \ac{NKJP} napisana od nowa,
% z~dwoma argumentami, nie z~jednym,
% dlatego też celowe wydaje się utworzenie osobnych wersji wymienionych
% widoków dla Projektu, by wpisać \ruby{zt_edytowalne?} z~właściwą
% arnością w~każdej z~nich.

This method for \ac{NKJP} has to be completely rewritten, two-argument
not one-. Therefore it seems reasonable to create separate versions of
those views for the Project, to write  \ruby{zt_edytowalne?} with
proper arity in each version.

% \ruby{zt_edytowalne?} w~wersji \ac{NKJP} jest dwuwariantowa: jeśli
% wołana z~jednym argumentem, którym wówczas musi być id użytkownika, to
% sprawdza dostępność akapitu do \emph{jakiejkolwiek} edycji (anotacji):
% czy użytkownik ma uprawnienia do anotacji i~czy akapit ma choć jeden
% poziom anotacji nie zakończony a~dopuszczony do anotacji. Jeśli będzie
% wywołana z~dwoma argumentami, wówczas musi to być para $\langle
% \<poziom>, \<id użytkownika>\rangle$ — metoda sprawdzi dostępność
% akapitu do anotacji na tym konkretnie poziomie.

So, the method \ruby{zt_edytowalne?} in the \ac{NKJP} version is
two-variant: if called with one argument, which in such case has to be
a user \ac{ID}, then it checks availability of given Akapit for
\emph{any} editing (annotation): whether the user is permitted to
annotate and whether the Akapit has an unfinished level and allowed
for annotation.  If called with two arguments, which have to be
$\langle \<level>, \<user \ac{ID}>\rangle$, the method checks
editability at this given level.

% Oprócz statusu dla każdego poziomu anotacji (w~tabeli
% \tabela{statusy}) będziemy używali „dużego” statusu: pola \sql{status}
% tabeli \tabela{zdania_transzy}, które zmieni się tylko gdy zmieni się
% minimalny status któregoś z~poziomów maksymalnych. W~związku z~tym
% w~modelu \file{poziomy_anotacji.rb} dodaliśmy metodę
% \ruby{self.maksymalne}.  

Besides the level-stati (stored in the table \tabela{statusy}) we also
use the “grand” status: the column #{status} of the table
\tabela{akapit_transzy} which changes iff the minimal status of a
maximal level gets changed. To handle this a method is added
 \ruby{self.maksymalne} in the model \file{poziomy_anotacji.rb}.

% Odrzucenie  akapitu będzie składowane (bazowane ;-) w~tabeli
% \tabela{zdania_transzy} w~polu \sql{odrzucone}, ale także w~tabeli
% \tabela{statusy} w~polu \sql{\<poziom>_odrzucone}.

% \subsubsection{% Weryfikacja a~zatwierdzenie akapitu
% Verification and committing of an Akapit
% }



% \ruby{niegotowe?( zdziw_sie )}

% a~\ruby{weryfikacja} już nie przewiduje zdziwienia, tylko werdykt.


\subsection{Reports}

% Wystąpienie rozbieżności w~równoległych anotacjach tego samego akapitu
% jest odnotowywane w~bazie w~tabelach \tabela{protokol},
% \tabela{punkt_protokolu} i~tabelach \tabela{\<poziom>_rozbieznosc}.
% Protokołowane jest także uzgodnienie decyzji segmentacyjnej, w~tabeli
% \tabela{segmentation_protokol}, o~czym więcej na
% s.~\pageref{prot_dec_segm}.  Tabela \tabela{punkt_protokolu} jest
% powiązana polimorficznie z~tabelami \tabela{segmentation_protokol}
% i~\tabela{\<poziom>_rozbieznosc}, którego obsługa jest wbudowana
% w~Rails.

Occurrence of a disagreement between the two annotations of a given
Akapit is recorded in the tables \tabela{protokol} (‘report’),
\tabela{punkt_protokolu} (‘report's item’) and
\tabela{\<level>_rozbieznosc} (‘disagreement’). Also agreeing upon a
word-level segmentation disambiguation is reported, in the table 
\tabela{segmentation_protokol}% , what is described further on the page
% \pageref{prot_dec_segm}  (w części skreślonej)
. The table \tabela{punkt_protokolu} is
polymorphically associated with  \tabela{segmentation_protokol} and with
the tables \tabela{\<poziom>_rozbieznosc}. Handling of such an
association is provided by Rails themselves.

\subsection{Editability}

% Filtr \ruby{\<application>.check_edytowalne} — patrzy na Status akapitu
% (kolumnę \sql{status} w~tabeli \tabela{zdania_transzy}) i~czy
% w~parametrach żądania jest \ruby{:poziom}, wówczas sprawdza
% edytowalność na tym poziomie.

The filter \ruby{anApplication.check_edytowalne} (‘check the
editables’) looks at the grand status of the given Akapit Transzy (the
field \sql{status} of the table \tabela{akapit_transzy}) and whether
the parameters require  #{:poziom}, and checks editability at that
level if so.

\ruby{AkapitTranszy.editable_par_annoteur?}

\ruby{anAkapitTranszy.edytowalne_przez_anotatora?( poziom )}

\ruby{anAnotacjaHelper.zt_edytowalne?( *args )}, where \ruby{*args}
are \ruby{[ \<user \ac{ID}> ]} or \ruby{[ \<user \ac{ID}>, :\<level>]}

% Sprawdzamy edytowalność dwukrotnie: raz przy renderowaniu widoku, żeby
% nie wyświetlić linków do niedostępnych akcji, i~drugi raz przed
% wykonaniem akcji, w~filtrze \ruby{check_edytowalne}, by akcja była
% rzeczywiście niedostępna.

We check editability twice: first time while rendering a view, to hide
the links to the unavailable actions, and second time before executing
an action, in the filter  \ruby{check_edytowalne}, so that the action
be really unavailable.
 

\subsection{Handling of word-level segmentation ambiguities}

% \begin{skreślone}[skreślone]

% Segmentacja jest minimalnym (a~nawet najniższym) przewidzianym
% poziomem anotacji. Zgodnie z~przyjętą zasadą akapit musi przejść przez
% ujednoznacznienie segmentacji, by mógł być dalej anotowany. % W~bazie
% % danych możemy więc przechowywać tylko segmentację po
% % ujednoznacznieniu. Dzięki temu nie musimy tworzyć struktury bazy
% % danych od podstaw, ze specjalnymi tabelami dla segmentacji, ale możemy
% % skorzystać z~paradygmatu token\dy zdanie\dy zdanie_transzy:
% Moglibyśmy więc przechowywać tylko segmentację ujednoznacznioną,
% tj. pozostać w~paradygmacie \ruby{token}\dy \ruby{akapit}\dy
% \ruby{akapit_transzy}, gdyby nie to, że do momentu ujednoznacznienia
% trzeba przechować dwa, być może niezgodne, warianty rozstrzygnięcia
% segmentacji — tak, jak je zrobił każdy z~pary Anotatorów.

% I~oczywiście wyświetlać połączone tokeny tylko dla tego Anotatora,
% który je postanowił połączyć. W~tym celu w~tabeli \tabela{token}
% wprowadzamy kolumnę \sql{razem_z_nast}, która posłuży do wyświetlania
% tokenów połączonych w~naszym mniemaniu łatwiej, niż kolumna
% \sql{ns_poprzedza}: dla zrenderowania widoku tokeny są przeglądane
% w~porządku prostym, a~nie odwrotnym, łatwiej jest renderować brak
% spacji (połączenie tokenów) kiedy się o~nim wie zawczasu.

% \sql{razem_z_nast} ma być \ruby{true} gdy tokeny należy zdaniem
% Anotatora połączyć i~\ruby{false} gdy tokeny mają pozostać
% rozdzielone. Wartość w~polu \sql{ns_nastepuje} rekordu \sql{token}
% zmieni się tylko w~razie połączenia (na \ruby{false}), bo przecież nie
% będzie już przed czym miało być braku spacji.

% \ruby{\<token>.ns_poprzedza?} jest używana wyłącznie
% w~\ruby{\<zdanie>.tresc} i, gdyby jej nadmiarowość zaczęła
% przeszkadzać, łatwo się jej pozbyć.


% Niejednoznaczności segmentacji spodziewamy się co najwyżej w~miejscach
% braku spacji między tokenami, czyli tam, gdzie pole \sql{ns_poprzedza}
% ma wartość \ruby{true} — ewentualna niejednoznaczność polega na tym,
% czy mają to być dwa tokeny rozdzielone brakiem spacji, czy też jeden
% token. Informację, że w~tym miejscu należy przeprowadzić
% ujednoznacznienie segmentacji, umieścimy w~Boolowskiej kolumnie
% \sql{czy_segm}, zawierającej domyślnie \ruby{false}, a~\ruby{true}
% tylko dla miejsc wymagających ujednoznacznienia segmentacji.


% \passage
% Konieczność ujednoznacznienia segmentacji wystąpi, jak się
% spodziewamy, w~niewielu przypadkach, dlatego też obliczenie
% statusów\discret/dopuszczeń na poziomie segmentacji i~a.\
% morfosyntaktycznej zawrzemy w~programie wlewającym dane do bazy.

% Procedurę inicjalnego przejrzenia wszystkich akapitów i~nadania tym co
% trzeba statusu \ruby{:zweryfikowane} na poziomie segmentacji, \ruby{odsegmentuj},
% umieszczamy w~modelu \file{zdanie.rb}.

% \passage Kiedy\label{prot_dec_segm} segmentacja danego akapitu zostanie
% zatwierdzona przez drugiego anotatora i~przejdzie weryfikację,
% tj. decyzje segmentacyjne obu Anotatorów okażą się zgodne (lub Superanotator
% rozstrzygnie arbitralnie), tokeny zostaną połączone, a~stan sprzed
% połączenia zostanie zapisany w~tabeli \tabela{segmentation_protokol}:
% wszystkie atrybuty encji \sql{token} w~odpowiednich kolumnach tabeli
% oraz jej tagi (instancje encji \sql{interpretacja}) w~postaci
% zserializowanej w~kolumnie \sql{interpretacje}. (Przypomnijmy, że
% obsługa serializacji obiektów Ruby'ego jest wbudowana w~Rails,
% a~uruchamia się ją deklaracją \ruby{serialize :\<kolumna>} w~klasie
% modelu. 

% Najodpowiedniejszym miejscem dla wywołania metody protokołującej
% stan sprzed zatwierdzenia segmetacyj,
% \ruby{Protokol.protokoluj_przed_segm}, i~metody zatwierdzającej
% segmentacje, \ruby{\<zdanie>.commit_segmentations}, wydaje się być
% zakończenie metody \ruby{\<anotacja_controller>.zweryfikuj_zdanie},
% w~klauzuli \ruby{ if poziomy.include?( :segmentation )}.

% \passage
% # :segmentation jest takim poziomem trochę szemranym,
% bo jak się ją raz zatwierdzi, to kłopot z~odkręceniem, więc przyjmuję,
% żeby nie kodować za dużo w~sprawie tego niewartej, iż Superanotator
% podejmuje decyzje segmentacyjne tylko raz dla danego akapitu i~że po
% podjęciu takiej decyzji nie ma „naturalnej” możliwości ponownego
% decydowania o~segmentacji: segmentacje zostały zaprotokołowane
%  i~zatwierdzone, być może jakieś tokeny usunięto z~bazy…


% \subsection{Segmentacja domówiona}

% \the\everypar

% \end{skreślone}

% Anotatornia ma dostawać wynik działania Morfeusza, niejednoznaczności
% segmentacji nie będą więc w~postaci dwóch tokenów być może ze znakiem
% »do połączenia«, tylko w~postaci alternatywy: dwa tokeny—jeden token
% połączony, i~każda z~tych alternatyw ma swój zestaw proponowanych
% interpretacyj. 

The source corpus data for Anotatornia were output of
Morfeusz. Therefore the word-level segmentation ambiguities were given
as a disjunction: two tokens—one token (concatenated), and each part
of this disjunction has its own set of morphosyntactic interpretations
(possible tags).

% Wobec tego kolumna \sql{czy_segm} ma służyć do wyświetlenia faktu
% istnienia alternatywy segmentacyjnej.

% Żeby nie mnożyć kolumn Boolowskich w~tabeli \tabela{token}, po
% uzgodnieniu decyzji segmentacyjnych tokeny odrzucone będą usuwane
% z~tabeli. To sprawia, że poprzednia sekcja nie usuwa się w~niebyt,
% a~jedynie wymaga nieznacznej modyfikacji.

% Therefore let the column  \sql{czy_segm} (‘whether segm[entation
% ambiguity]’) of the table \tabela{token} serve as a trigger to inform
% the user about existence of more than one alternate word-level
% segmentations.

% To avoid making too many of Boolean columns in the table
% \tabela{token}, after the Annotators agree upon one of such
% a segmentation variant, the 

% Tworzymy tabelę \tabela{segmentation}, która ma 

% \passage
% Na poziomie segmentacji Anotatorzy oznaczają także granice
% zdań w~akapicie. Informację o~tym, czy granice zdań zostały oznaczone, jak
% również czy ujednoznaczniono segmentację, zawiera statusek zdania
% transzy, tj. wartość pola \sql{segmentation} w~tabeli \tabela{statusy}
% w~rekordzie powiązanym z~danym \sql{zdaniem_transzy}: jeśli jest on
% $\ge8$ to znaczy, że dokonano.

With a huge amount  of work % (about 50–80\% of this version of
% Anotatornia)
also a possibility of adding new word-level 
segmentations was implemented, still not perfect since the
pathological possibilities are endless.


\subsection{% Anotacja morfosyntaktyczna
Morphosyntactic annotation
}

% Na potrzeby \acro{NKJP} implementujemy, oprócz możliwości
% wybierania dezambiguacji spośród tagów przypisanych tokenowi
% automatycznie, obecnych w~tabeli \tabela{interpretacja}, także
% możliwość tworzenia tagów przez Anotatora. 

For each token (word segment) there is a list of possible
morphosyntactic tags computed by Morfeusz and input as a part of the
source data.

Due to the \ac{NKJP} project needs there is also implemented a
possibility of creating (by the Annotators) new morphosyntactic tags
for the tokens. Such a new tag is checked against the tagset input
at each startup of Anotatornia from the file
\file{gramdata/tagset.cfg} (in the Poliqarp format).

The \tabela{tagset} table is polymorphic in a sense: the \file
{tagset.cfg} file consists of a couple of parts (attributes,
grammatical classes etc.) and the table stores them as serialised Ruby
objects, which, thanks to buil-in Rails methods,  makes access to them
seamless: the lists of attributes are serialised as arrays, attribute
values as Regexps (disjunctional) etc.


% W~związku z~tym tworzymy tabelę \tabela{tagset} i~wczytujemy do niej
% tagset \acro{IPI} w~formacie Poliqarpa. Tabela \tabela{tagset} 
% jest poniekąd polimorficzna, z~uwagi na to, że plik \file{tagset.cfg}
% składa się z~kilku części, opisujących atrybuty, klasy gramatyczne
% itd. Tabela \tabela{tagset} przechowuje te dane w~postaci
% serializowanych obiektów języka Ruby, dzięki czemu, dzięki wbudowanym
% we framework metodom dostępu do takiego typu pól, dostęp do danych
% jest w~aplikacji „bezbolesny”: listy atrybutów są serializowane jako
% tablice, wartości poszczególnych atrybutów — jako wyrażenia regularne
% (alternatywne) itd.

% W~klasie \ruby{Tagset}, stanowiącej Railsową obudowę tabeli
% \tabela{tagset}, definiujemy metodę 
% \ruby{Tagset.check_tag( tag_string )}, która zwraca \ruby{[true]} gdy podany tag jest poprawny z~punktu
% widzenia tagsetu, bądź \ruby{[false, "wskazanie co jest źle"]}, gdy
% tag nie spełnia reguł.

In the class #{Tagset}, being a Rails frame for the \tabela{tagset}
table, a method is defined \ruby{Tagset.check_tag( tag_string )},
which returns #{[true]} if #{tag_string} is a correct tag or else
 #{[false,  \<what's wrong with it>]}.

% Na stronie anotacji (\file{anotuj.rhtml}, \file{_token_wszi.rhtml},
% \file{_token_disamb.rhtml}) implementujemy pole listy do wyboru tagu
% spośród oznaczonych automatycznie oraz pole tekstowe do
% wprowadzania tagu przez Anotatora. To ostatnie jest wyposażone
% w~mechanizm autouzupełniania, który ma pomóc w~konstrukcji poprawnego
% tagu przez podpowiadanie kolejnych jego atrybutów. 

At the annotation page  (\file{anotuj.rhtml}, \file{_token_wszi.rhtml},
\file{_token_disamb.rhtml}) we implement a list field for choosing the
tag from those computed by Morfeusz and a text field for adding a new
tag by Anotator. The latter  is equipped with auto-completion which
should help to create a correct tag (anyway it'll be checked when
committed).

% Wyświetlenie tego
% pola następuje po kliknięciu w~link „twórz”, pojawiający się przy
% tagu proponowanym automatycznie. Wyświetlenie pola jest warunkowane
% wartością (typu Boolowskiego) zmiennej \ruby{zmieniaj_dyzamb}, która
% zależnie od …
% w~linii \ref{zmien dyzamb} na s.~\pageref{zmien dyzamb}.

 % This field is displayed after clicking the “twórz” (‘create’) link,
 % appearing next to a tag from the “original” list. Displaying of the
 % field depends on a Boolean variable  \ruby{zmieniaj_dyzamb} (‘change
 % disambiguation’)


\section{Export of annotated data}

You export the annotated data with the \file{sowa} shell script (it uses \file{exml.rb}):
\begin{verbatim}
./sowa  ⁄arg[argument]
\end{verbatim}
The \<argument>s accepted by \pk{sowa} are intended to
narrow the set of data to export and are described in the
script. They include Ruby's number interval (for interval of Akapit's)
and a Ruby's (almost Perl's) Regexp to specify the Corpus path(s).

If no argument is provided then all the annotated Akapit's are
exported.


You should modify that script to make it copy and export \emph{your}
database.

\section{Path and Transza's finder}

Because of the need of easy finding the Corpus path or the Transza of
a given Akapit a view is provided \file{debug/elektroforeza}.



\section{See also}

The \file{zip} archive you got (as we assume since you read this file)
contains a Dia file \file{anotatornia.dia} containg a diagram of the
database.

\medskip
For the (linguistic) details of annotation see also
\file{instrukcja_NK.pdf} (in Polish).

There's also a presentation (in le{.pdf}) \ty{Manual annotation of the
  National Corpus of Polish with Anotatornia} by Adam Przepiórkowski
and me (Grzegorz Murzynowski) at
\url{nlp.ipipan.waw.pl/Anotatornia/anotatornia.pdf}\\

and an article of the same title and authors in Proceedings of the
\ac{PALC} 2009 Conference, published by Peter Lang, Frankfurt am Main,
ed.\ by Stanisław Goźdź-Roszkowski.


\section{Contact}

% For possibilities of another terms of use of this software please
% contact Institute of Computer Science,
% Polish Academy of Sciences, \url{ipi@ipipan.waw.pl}\,.

% in the below meta-symbols at \& dot the letters »a« and »o« are not
% \ac{ASCII} but \ac{UTF-8} Cyrillic.

About technical (implementation) matters of Anotatornia please contact
Grzegorz Murzynowski, \url*{natror⁄metaat:o2⁄metadot:pl}\,.


About other matters concerning Anotatornia and the \ac{NKJP} project
please contact Adam Przepiórkowski, Ph.D., Associate Professor,
\url*{Adam.Przepiorkowski⁄metaat:ipipan⁄metadot:waw⁄metadot:pl}\,.


% $ ala miała aligatora gozaimashta, 1673:\alpha := {{}:{}={}}17$


% \[  ala × miała +\infty \uparrow\left<\sqrt[7]{\frac{12}{13}}
% \downarrow\langle>\right>aligatora\leftarrow gozaimashta, 1673\]


\chapter*{The tables' definitions}
\markboth{The tables' definitions}{The tables' definitions}


\sqlinput{../schema_20100605.sql}

\chapter*{The Ruby and \ac{RHTML} code}


\input ls-R5



\end{document}

 
anotatornia$    ls -R app > doc/ls-R5
anotatornia$    ls -R db/migrate >> doc/ls-R5
% and add  \ka at the beginning of each directory-stanza by hand.

%%% Local Variables: 
%%% mode: latex
%%% TeX-master: t
%%% End: 
