// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
// 
//   http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

PACKAGE uima.ruta.example;

// learnt using TextRulerExample\data\single

SCRIPT uima.ruta.example.Features;
Document{-> CALL(Features)};
FirstToken{->MARKONCE(Author, 1, 2)} # LParen;  // p=20; n=0
LParen{->MARKONCE(Date, 1, 4)} YearInd RParen PeriodSep;    // p=20; n=0
NUM{->MARKONCE(Pages, 1, 4)} SPECIAL NUM LastToken; // p=15; n=0
CW{REGEXP("University")->MARKONCE(Publisher, 1, 5)} EnglishStopWord CW CW CommaSep; // p=1; n=0
PublisherInd{->MARKONCE(Publisher, 1, 2)} CommaSep; // p=1; n=0
CW{REGEXP("Department")->MARKONCE(Institution, 1, 3)} # PeriodSep;  // p=1; n=0
NUM{->MARKONCE(Volume, 1, 4)} # RParen CommaSep;    // p=6; n=0
NUM{REGEXP("1")->MARKONCE(Volume, 1, 2)} CommaSep;  // p=1; n=0
CW{->MARKONCE(Title, 1, 6)} SW SW SW # PeriodSep;   // p=13; n=0
CW{REGEXP("Markov")->MARKONCE(Title, 1, 3)} # PERIOD CW;    // p=1; n=0
CW{->MARKONCE(Title, 1, 6)} SW EnglishStopWord SW # PeriodSep;  // p=5; n=0
CW{REGEXP("Introducing")->MARKONCE(Title, 1, 3)} # PeriodSep;   // p=1; n=0
CW{REGEXP("Backtrack")->MARKONCE(Title, 1, 2)} # CW;    // p=1; n=0
CW{REGEXP("Verbal")->MARKONCE(Title, 1, 3)} # PeriodSep;    // p=1; n=0
CW{REGEXP("Causation")->MARKONCE(Title, 1, 3)} # PeriodSep; // p=1; n=0
CW{REGEXP("Projection")->MARKONCE(Title, 1, 2)} # CW;   // p=1; n=0
CW{REGEXP("Proceedings")->MARKONCE(Booktitle, 1, 3)} # CommaSep;    // p=1; n=0
CW{REGEXP("Fundamenta")->MARKONCE(Journal, 1, 3)} CW CommaSep;  // p=1; n=0
CW{->MARKONCE(Journal, 1, 5)} EnglishStopWord EnglishStopWord CAP CommaSep; // p=1; n=0
FirstNameInitial{->MARKONCE(Journal, 1, 3)} CAP CommaSep;   // p=1; n=0
CW{->MARKONCE(Journal, 1, 5)} EnglishStopWord CW # NameLinker NUM CommaSep; // p=2; n=0
CW{REGEXP("Nucleic")->MARKONCE(Journal, 1, 4)} CW CW CommaSep;  // p=1; n=0
CW{REGEXP("Journal")->MARKONCE(Journal, 1, 5)} EnglishStopWord CW CW CommaSep;  // p=1; n=0
CW{REGEXP("Artificial")->MARKONCE(Journal, 1, 3)} CW CommaSep;  // p=2; n=0
CW{REGEXP("Pattern")->MARKONCE(Journal, 1, 4)} CW CW CommaSep;  // p=1; n=0
CW{REGEXP("Econometrica")->MARKONCE(Journal, 1, 2)} CommaSep;   // p=1; n=0
CW{REGEXP("Journal")->MARKONCE(Journal, 1, 3)} # NameLinker;    // p=5; n=0
CW{REGEXP("Evolutionary")->MARKONCE(Journal, 1, 3)} CW CommaSep;    // p=1; n=0
CW{->MARKONCE(Location, 1, 3)} FirstName LastToken; // p=2; n=0
FirstName{->MARKONCE(Location, 1, 4)} CommaSep CW LastToken;    // p=1; n=0
CW{->MARKONCE(Tech, 1, 5)} PeriodSep SW PeriodSep CommaSep; // p=1; n=0
