├── .babelrc ├── .dockerignore ├── .eslintrc ├── .gitignore ├── .jscsrc ├── .jshintrc ├── Dockerfile ├── README.md ├── circle.yml ├── controllers ├── declensions.js ├── sentence.js ├── suggestions.js └── summary.js ├── corrections ├── is.aff ├── is.dic └── spelling.js ├── data └── verbs.conf ├── database ├── build-database.js ├── create-index.js ├── database.js ├── get-by.js ├── populate.js ├── query.js └── simple-populate.js ├── deploy.sh ├── error.js ├── filters ├── adjectives.js ├── prepositions.js └── verbs.js ├── formatters ├── adjective.js ├── preposition.js ├── summary.js └── word.js ├── grammar ├── parsed.js └── parser.js ├── index.js ├── middleware └── response-time.js ├── models.json ├── models ├── concat-stream-promise.js ├── icenlp.js └── static.js ├── npm-shrinkwrap.json ├── package.json ├── routes ├── declensions.js ├── index.js ├── sentence.js └── suggestions.js ├── rules ├── helpers.js ├── index.js ├── preposition.js ├── verb.js └── verbObject.js ├── server.js ├── test ├── adjectives.js.skip ├── corrections │ ├── spelling.js │ ├── verb.js │ └── verbObject.js ├── grammar │ └── parsed.js ├── model │ ├── icenlp.js │ └── static.js ├── parsed.js ├── parser │ ├── adjective.js │ └── nouns.js ├── prepositions.js └── verb.js ├── translate ├── _grammar-tag-parser.js ├── _mapTags.js ├── _tags.js ├── _translate.js ├── translate.js └── translate.json └── uninstall.sh /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["node5", "stage-0"], 3 | "plugins": ["transform-runtime"] 4 | } 5 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | data 3 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | --- 2 | parser: babel-eslint 3 | 4 | env: 5 | node: true 6 | es6: true 7 | mocha: true 8 | 9 | plugins: 10 | - babel 11 | 12 | extends: "airbnb/base" 13 | 14 | rules: 15 | semi: 16 | - 2 17 | - "never" 18 | prefer-const: 0 19 | no-undef: 2 20 | func-names: 0 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 27 | node_modules 28 | 29 | # Debug log from npm 30 | npm-debug.log 31 | 32 | *.csv 33 | 34 | db 35 | data 36 | -------------------------------------------------------------------------------- /.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "preset": "google", 3 | "esnext": true, 4 | "excludeFiles": ["node_modules/**"], 5 | "maximumLineLength": 120 6 | } 7 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "asi": true 5 | } 6 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nodesource/node:5 2 | 3 | WORKDIR /code 4 | 5 | ADD package.json /code/package.json 6 | 7 | RUN npm config set production && npm install 8 | 9 | ADD . /code 10 | 11 | EXPOSE 8000 12 | 13 | CMD [ "npm", "start" ] 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Icelandic declension API 2 | ### [api.tala.is](http://api.tala.is) 3 | 4 | An API for icelandic declensions. Uses data from [Beygingarlýsing íslensks nútímamáls](http://bin.arnastofnun.is/DMII/) 5 | 6 | `api.tala.is/find/hestur?lang=en` 7 | 8 | ```js 9 | [ 10 | { 11 | headWord: "Hestur", 12 | binId: 259304, 13 | wordClass: "Noun (masculine)", 14 | section: "örn", 15 | forms: [ 16 | { 17 | form: "Hestur", 18 | grammarTag: "NFET", 19 | tags: { 20 | grammarCase: "nominative", 21 | number: "singular", 22 | article: "indefinite", 23 | gender: "masculine" 24 | } 25 | }, 26 | { 27 | form: "Hest", 28 | grammarTag: "ÞFET", 29 | tags: { 30 | grammarCase: "accusative", 31 | number: "singular", 32 | article: "indefinite", 33 | gender: "masculine" 34 | } 35 | ... 36 | } 37 | ] 38 | ``` 39 | 40 | ## Declensions api 41 | 42 | Search is case-insensitive (hestur returns results for hestur and Hestur). Add a `lang` query parameter to translate tags (supported languages: `en`, `is`) 43 | 44 | ### `/id/:id` 45 | 46 | Finds a word by bin id 47 | 48 | ### `/find/:word` 49 | 50 | Finds all words that match exactly 51 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | services: 3 | - docker 4 | environment: 5 | TAG: davidblurton/tala-api 6 | 7 | dependencies: 8 | cache_directories: 9 | - "~/docker" 10 | 11 | override: 12 | - docker info 13 | - if [[ -e ~/docker/image.tar ]]; then docker load -i ~/docker/image.tar; fi 14 | - docker build -t $TAG . 15 | - mkdir -p ~/docker; docker save $TAG > ~/docker/image.tar 16 | 17 | test: 18 | override: 19 | - echo "run tests" 20 | 21 | deployment: 22 | hub: 23 | branch: master 24 | commands: 25 | - docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS 26 | - docker push $TAG 27 | 28 | -------------------------------------------------------------------------------- /controllers/declensions.js: -------------------------------------------------------------------------------- 1 | import { words } from '../database/database' 2 | import getBy from '../database/get-by' 3 | 4 | /** 5 | * Find a word by id. 6 | * @param {string} id 7 | * @return {Array} 8 | */ 9 | export function findById(id) { 10 | return new Promise((resolve, reject) => { 11 | words.get(id, function(err, results) { 12 | if (err) return reject(err) 13 | resolve(results) 14 | }) 15 | }) 16 | } 17 | 18 | /** 19 | * Find all words from the same headword. 20 | * @param {string} word 21 | * @return {Array} 22 | */ 23 | export function find(word) { 24 | return new Promise((resolve, reject) => { 25 | getBy('form', word.toLowerCase(), function(err, results) { 26 | if (err) return reject(err) 27 | resolve(results) 28 | }) 29 | }).then(ids => { 30 | return Promise.all(ids.map(id => findById(id))) 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /controllers/sentence.js: -------------------------------------------------------------------------------- 1 | import icenlp from '../models/icenlp' 2 | import {structure} from '../grammar/parsed' 3 | import correctionRules from '../rules' 4 | 5 | async function getParse(query) { 6 | let parsedQuery = await icenlp(query) 7 | let {tokenized, parsed, tagged} = parsedQuery 8 | let parts = structure(parsed) 9 | 10 | return {tokenized, parts, parsed, tagged} 11 | } 12 | 13 | function isRecognized(taggedWord) { 14 | return !taggedWord.endsWith('*') 15 | } 16 | 17 | async function getRules({tokenized, parts, parsed, tagged}) { 18 | let recognized = tagged.map(isRecognized) 19 | let rules = [] 20 | let error 21 | 22 | try { 23 | rules = Promise.all([ 24 | correctionRules.verb(tokenized, parts), 25 | correctionRules.verbObject(tokenized, parts), 26 | correctionRules.preposition(tokenized, parts, tagged), 27 | ]) 28 | } catch (err) { 29 | // TODO: log error 30 | console.log(err, err.stack) 31 | error = err 32 | } 33 | 34 | rules = rules.filter(x => x) 35 | 36 | return { 37 | tokenized, 38 | parsed, 39 | rules, 40 | tagged, 41 | recognized, 42 | error, 43 | parts, 44 | } 45 | } 46 | 47 | function applyRules({rules, tokenized}) { 48 | let suggestions = [...tokenized] 49 | 50 | rules.forEach(rule => { 51 | let replacement = rule.replacements[0] 52 | suggestions[rule.index] = replacement 53 | }) 54 | 55 | return [suggestions.join(' ')] 56 | } 57 | 58 | async function sentence(query) { 59 | let {tokenized, parts, parsed, tagged} = await getParse(query) 60 | let rules = await getRules({tokenized, parts, parsed, tagged}) 61 | let suggestions = applyRules(rules) 62 | 63 | return { 64 | ...rules, 65 | suggestions, 66 | } 67 | } 68 | 69 | export default {sentence} 70 | -------------------------------------------------------------------------------- /controllers/suggestions.js: -------------------------------------------------------------------------------- 1 | import { getSuggestions } from '../corrections/spelling' 2 | 3 | export function suggestions(word) { 4 | return new Promise((resolve, reject) => { 5 | getSuggestions(word, (err, results) => { 6 | if (err) reject(err) 7 | resolve(results) 8 | }) 9 | }) 10 | } 11 | -------------------------------------------------------------------------------- /controllers/summary.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | import database from '../models/database' 3 | import getPrepositionFilters from '../filters/prepositions' 4 | import getVerbFilters from '../filters/verbs' 5 | 6 | function uniqueWords(words) { 7 | return _.uniq(words, w => w.binId) 8 | } 9 | 10 | // Generates a list of autocompletion suggestions. 11 | function suggestions(prefix, limit) { 12 | return database.search(prefix) 13 | .then(results => results.filter(x => x.headWord === x.wordForm)) // this should be a filter 14 | .then(results => results.map(x => x.wordForm)) 15 | .then(_.unique) 16 | .then(results => results.slice(0, limit)) 17 | } 18 | 19 | // Find all words from the same headword. 20 | async function related(word) { 21 | let words = await database.lookup(word) 22 | 23 | let ids = _.chain(words).pluck('binId').unique().value() 24 | let results = Promise.all(ids.map(database.lookup)) 25 | 26 | return _.flatten(results) 27 | } 28 | 29 | async function preposition(modifier, word) { 30 | let nouns = uniqueWords(await database.lookup(word)) 31 | let results = await this.related(word) 32 | 33 | let filters = await getPrepositionFilters(modifier, nouns) 34 | 35 | return filters.map(filter => { 36 | let {grammarTag} = filter 37 | return _.mapValues(grammarTag, tag => results.filter(x => x.binId === filter.binId && x.grammarTag === tag)[0]) 38 | }) 39 | } 40 | 41 | async function verb(modifier, word) { 42 | let results = await this.related(word) 43 | 44 | let {grammarTag} = getVerbFilters(modifier) 45 | 46 | return _.mapValues(grammarTag, tag => results.filter(x => x.grammarTag === tag)[0]) 47 | } 48 | 49 | export default {suggestions, related, preposition, verb} 50 | -------------------------------------------------------------------------------- /corrections/is.aff: -------------------------------------------------------------------------------- 1 | SET UTF-8 2 | 3 | #Letter frequency based on all Icelandic text from www.snerpa.is/net 4 | TRY arniesutðglmkofhvþádíójbúyöæépÞHSEGýBAVKNOFMJDLRÍÁTÓxIÉUzPÖcÚÆYÐCqXwÝQWZ 5 | WORDCHARS "-./= 6 | KEY qwertyuiopð|asdfghjklæ|zxcvbnm,.þ 7 | 8 | #Splitted suggestions are most likely compound words 9 | NOSPLITSUGS 10 | 11 | # rules from http://www2.hu-berlin.de/bragi/b5/b5framburdarreglur.htm 12 | REP 57 13 | REP a á 14 | REP e é 15 | REP i é 16 | REP o ó 17 | REP o ö 18 | REP u ú 19 | REP y ý 20 | REP ae æ 21 | REP d ð 22 | REP p þ 23 | REP i y 24 | REP y i 25 | REP í ý 26 | REP ý í 27 | REP áng ang 28 | REP eing eng 29 | REP eyng eng 30 | REP íng ing 31 | REP ýng ing 32 | REP úng ung 33 | REP íng yng 34 | REP ýng yng 35 | REP aung öng 36 | REP ánk ank 37 | REP eink enk 38 | REP eynk enk 39 | REP ínk ink 40 | REP ýnk ink 41 | REP únk unk 42 | REP ínk ynk 43 | REP ýnk ynk 44 | REP aunk önk 45 | REP ægi agi 46 | REP eigi egi 47 | REP eygi egi 48 | REP ígi igi 49 | REP ýgi igi 50 | REP oji ogi 51 | REP uji ugi 52 | REP yji ygi 53 | REP augi ögi 54 | REP v f 55 | REP kv hv 56 | REP dl ll 57 | REP dn nn 58 | REP md fnd 59 | REP mt fnd 60 | REP bl fl 61 | REP bn fn 62 | REP rdl rl 63 | REP rdn rn 64 | REP sdl sl 65 | REP sdn sn 66 | REP gt t 67 | REP kt t 68 | REP ói ófi 69 | REP óa ófa 70 | REP úa úfa 71 | REP ngl nl 72 | REP lgd gld 73 | REP nd rnd 74 | REP st rst 75 | REP ð þ 76 | REP gs x 77 | REP ks x 78 | REP x gs 79 | REP x ks 80 | 81 | FLAG num 82 | 83 | #kk et agr 84 | SFX 1 N 21 85 | SFX 1 ur 0 86 | SFX 1 n 0 nn 87 | SFX 1 l 0 ll 88 | SFX 1 ur i 89 | SFX 1 n i einn 90 | SFX 1 n i ónn 91 | SFX 1 inn ni [^e]inn 92 | SFX 1 unn ni 93 | SFX 1 ill li 94 | SFX 1 all li 95 | SFX 1 ull li 96 | SFX 1 0 i u[^r] 97 | SFX 1 0 i n[^n] 98 | SFX 1 0 i [^unl][^l] 99 | SFX 1 0 i [^l]l 100 | SFX 1 ur s 101 | SFX 1 n s nn 102 | SFX 1 l s ll 103 | SFX 1 0 s u[^r] 104 | SFX 1 0 s n[^n] 105 | SFX 1 0 s [^un]. 106 | 107 | #kk et gr 108 | SFX 2 N 22 109 | SFX 2 0 inn 110 | SFX 2 ur inn 111 | SFX 2 n inn nn 112 | SFX 2 l inn ll 113 | SFX 2 ur inum 114 | SFX 2 n inum einn 115 | SFX 2 n inum ónn 116 | SFX 2 inn ninum [^e]inn 117 | SFX 2 unn ninum 118 | SFX 2 ill linum 119 | SFX 2 all linum 120 | SFX 2 ull linum 121 | SFX 2 0 inum u[^r] 122 | SFX 2 0 inum n[^n] 123 | SFX 2 0 inum [^unl][^l] 124 | SFX 2 0 inum [^l]l 125 | SFX 2 ur sins 126 | SFX 2 n sins nn 127 | SFX 2 l sins ll 128 | SFX 2 0 sins u[^r] 129 | SFX 2 0 sins n[^n] 130 | SFX 2 0 sins [^un]. 131 | 132 | #kk et agr -s 133 | SFX 3 N 7 134 | SFX 3 ur 0 ur 135 | SFX 3 n 0 nn 136 | SFX 3 ur i ur 137 | SFX 3 n i nn 138 | SFX 3 0 i u[^r] 139 | SFX 3 0 i n[^n] 140 | SFX 3 0 i [^un]. 141 | 142 | #kk et gr -s 143 | SFX 4 N 13 144 | SFX 4 0 inn 145 | SFX 4 ur inn ur 146 | SFX 4 n inn nn 147 | SFX 4 ur inum ur 148 | SFX 4 n inum nn 149 | SFX 4 0 inum u[^r] 150 | SFX 4 0 inum n[^n] 151 | SFX 4 0 inum [^un]. 152 | SFX 4 ur ins ur 153 | SFX 4 n ins nn 154 | SFX 4 0 ins u[^r] 155 | SFX 4 0 ins n[^n] 156 | SFX 4 0 ins [^un]. 157 | 158 | #kk sb/vb ft agr 159 | SFX 5 N 4 160 | SFX 5 r 0 161 | SFX 5 ar um 162 | SFX 5 ir um 163 | SFX 5 ir a 164 | 165 | #kk sb/vb ft gr 166 | SFX 6 N 6 167 | SFX 6 0 nir 168 | SFX 6 r na 169 | SFX 6 ar unum 170 | SFX 6 ir unum 171 | SFX 6 ar anna 172 | SFX 6 ir anna 173 | 174 | #kk sb/vb ft agr 175 | SFX 7 N 1 176 | SFX 7 r 0 177 | 178 | #kk sb/vb ft gr 179 | SFX 8 N 3 180 | SFX 8 0 nir 181 | SFX 8 r na 182 | SFX 8 r nna 183 | 184 | #kk sb et agr a 185 | SFX 11 N 7 186 | SFX 11 ur 0 [^a]ur 187 | SFX 11 l 0 ll 188 | SFX 11 ur s [^a]ur 189 | SFX 11 0 s aur 190 | SFX 11 0 s [^rl] 191 | SFX 11 0 s [^ul]. 192 | SFX 11 l s ll 193 | 194 | #kk et gr b 195 | SFX 12 N 13 196 | SFX 12 0 inn 197 | SFX 12 ur inn [^a]ur 198 | SFX 12 l inn ll 199 | SFX 12 ur num [^a]ur 200 | SFX 12 0 num aur 201 | SFX 12 l num ll 202 | SFX 12 0 num [^rl] 203 | SFX 12 0 num [^ul]. 204 | SFX 12 ur sins [^a]ur 205 | SFX 12 0 sins aur 206 | SFX 12 0 sins [^rl] 207 | SFX 12 0 sins [^ul]. 208 | SFX 12 l sins ll 209 | 210 | #kk vb et agr 211 | SFX 22 N 1 212 | SFX 22 i a 213 | 214 | #kk vb et gr 215 | SFX 23 N 4 216 | SFX 23 0 nn 217 | SFX 23 i ann 218 | SFX 23 i anum 219 | SFX 23 i ans 220 | 221 | #son/dóttir 222 | SFX 26 N 11 223 | SFX 26 0 son 224 | SFX 26 0 syni 225 | SFX 26 0 sonar 226 | SFX 26 0 synir 227 | SFX 26 0 sonum 228 | SFX 26 0 sona 229 | SFX 26 0 dóttir 230 | SFX 26 0 dóttur 231 | SFX 26 0 dætur 232 | SFX 26 0 dætrum 233 | SFX 26 0 dætra 234 | 235 | #kvk et agr i 236 | SFX 13 N 6 237 | SFX 13 ur i ur 238 | SFX 13 0 i u[^r] 239 | SFX 13 0 i [^u]. 240 | SFX 13 ur ar ur 241 | SFX 13 0 ar u[^r] 242 | SFX 13 0 ar [^u]. 243 | 244 | #kvk vb et agr 245 | SFX 14 N 1 246 | SFX 14 a u 247 | 248 | #kvk vb et gr 249 | SFX 15 N 4 250 | SFX 15 0 n 251 | SFX 15 a una 252 | SFX 15 a unni 253 | SFX 15 a unnar 254 | 255 | #kvk vb ft agr 256 | SFX 16 N 2 257 | SFX 16 r m 258 | SFX 16 ur a 259 | 260 | #kvk vb ft gr 261 | SFX 17 N 3 262 | SFX 17 0 nar 263 | SFX 17 r num 264 | SFX 17 ur anna 265 | 266 | #kvk sb et agr 267 | SFX 18 N 1 268 | SFX 18 0 ar 269 | 270 | #kvk sb et gr 271 | SFX 19 N 4 272 | SFX 19 0 in 273 | SFX 19 0 ina 274 | SFX 19 0 inni 275 | SFX 19 0 arinnar 276 | 277 | #kvk sb ft agr 278 | SFX 20 N 6 279 | SFX 20 ir um [^a]nir 280 | SFX 20 ir um [^n]ir 281 | SFX 20 anir unum 282 | SFX 20 ar um 283 | SFX 20 ir a 284 | SFX 20 ar a 285 | 286 | #kvk sb ft gr 287 | SFX 21 N 7 288 | SFX 21 0 nar 289 | SFX 21 ir unum [^a]nir 290 | SFX 21 ir unum [^n]ir 291 | SFX 21 anir ununum 292 | SFX 21 ar unum 293 | SFX 21 ir anna 294 | SFX 21 ar anna 295 | 296 | #kvk vb ft agr 297 | SFX 24 N 2 298 | SFX 24 r m 299 | SFX 24 ur na 300 | 301 | #kvk vb ft gr 302 | SFX 25 N 3 303 | SFX 25 0 nar 304 | SFX 25 r num 305 | SFX 25 ur nanna 306 | 307 | #kvk sb et agr u 308 | SFX 31 N 2 309 | SFX 31 0 ar 310 | SFX 31 0 u 311 | 312 | #kvk sb et gr u 313 | SFX 32 N 4 314 | SFX 32 0 in 315 | SFX 32 0 una 316 | SFX 32 0 unni 317 | SFX 32 0 arinnar 318 | 319 | #lo frumstig 1 320 | SFX 400 N 13 321 | SFX 400 0 an 322 | SFX 400 0 um 323 | SFX 400 0 s 324 | SFX 400 0 a 325 | SFX 400 0 ri 326 | SFX 400 0 rar 327 | SFX 400 0 t 328 | SFX 400 0 u 329 | SFX 400 0 ir 330 | SFX 400 0 ra 331 | SFX 400 0 ar 332 | SFX 400 0 i 333 | SFX 400 0 u 334 | 335 | #lo miðstig 1 336 | SFX 401 N 2 337 | SFX 401 0 ari 338 | SFX 401 0 ara 339 | 340 | #lo frumstig 3 341 | SFX 402 N 16 342 | SFX 402 0 an 343 | SFX 402 0 um 344 | SFX 402 0 s 345 | SFX 402 0 a 346 | SFX 402 0 ni n 347 | SFX 402 0 li l 348 | SFX 402 0 nar n 349 | SFX 402 0 lar l 350 | SFX 402 0 t 351 | SFX 402 0 u 352 | SFX 402 0 ir 353 | SFX 402 0 na n 354 | SFX 402 0 la l 355 | SFX 402 0 ar 356 | SFX 402 0 i 357 | SFX 402 0 u 358 | 359 | #lo miðstig 3 360 | SFX 403 N 2 361 | SFX 403 0 i 362 | SFX 403 0 a 363 | 364 | #lo efsta stig 365 | SFX 404 N 14 366 | SFX 404 0 astur 367 | SFX 404 0 astan 368 | SFX 404 0 ustum 369 | SFX 404 0 asts 370 | SFX 404 0 ust 371 | SFX 404 0 asta 372 | SFX 404 0 astri 373 | SFX 404 0 astrar 374 | SFX 404 0 ast 375 | SFX 404 0 ustu 376 | SFX 404 0 astir 377 | SFX 404 0 astra 378 | SFX 404 0 astar 379 | SFX 404 0 asti 380 | 381 | #hk et agr 382 | SFX 70 N 2 383 | SFX 70 0 i [^i] 384 | SFX 70 0 s . 385 | 386 | #hk et gr 387 | SFX 71 N 5 388 | SFX 71 0 ið [^i] 389 | SFX 71 0 ð i 390 | SFX 71 0 inu [^i] 391 | SFX 71 0 nu i 392 | SFX 71 0 sins . 393 | 394 | #hk ft agr 395 | SFX 72 N 4 396 | SFX 72 0 um [^i] 397 | SFX 72 i um i 398 | SFX 72 0 a [^i] 399 | SFX 72 i a i 400 | 401 | #hk ft gr 402 | SFX 73 N 6 403 | SFX 73 0 in [^i] 404 | SFX 73 0 n i 405 | SFX 73 0 unum [^i] 406 | SFX 73 i unum i 407 | SFX 73 0 anna [^i] 408 | SFX 73 i anna i 409 | 410 | #hk ft agr 411 | SFX 74 N 2 412 | SFX 74 0 jum 413 | SFX 74 0 ja 414 | 415 | #hk ft gr 416 | SFX 75 N 3 417 | SFX 75 0 in 418 | SFX 75 0 junum 419 | SFX 75 0 janna 420 | 421 | #hk ft agr þf þgf 422 | SFX 76 N 1 423 | SFX 76 0 um 424 | 425 | #hk ft gr þf þgf 426 | SFX 77 N 2 427 | SFX 77 0 in 428 | SFX 77 0 unum 429 | 430 | #Fallbeyging hk sb 01 431 | SFX 405 N 1 432 | SFX 405 0 0/70,71,72,73 . 433 | #Fallbeyging hk sb 01 et 434 | SFX 406 N 1 435 | SFX 406 0 0/70,71 . 436 | #Fallbeyging hk sb 01 ft 437 | SFX 407 N 1 438 | SFX 407 0 0/72,73 . 439 | #Fallbeyging hk sb 01 j 440 | SFX 408 N 1 441 | SFX 408 0 0/70,71,74,75 . 442 | #Fallbeyging hk sb 01 ö 443 | SFX 409 N 3 444 | SFX 409 0 0/70,71 445 | SFX 409 0 a 446 | SFX 409 0 anna 447 | 448 | #Fallbeyging hk sb 03 449 | SFX 410 N 1 450 | SFX 410 0 0/70,71,72,73 . 451 | 452 | #Fallbeyging hk sb 03 et 453 | SFX 411 N 1 454 | SFX 411 0 0/70,71 . 455 | 456 | #Fallbeyging hk sb örnefni 02 457 | SFX 412 N 1 458 | SFX 412 0 s 459 | 460 | #Fallbeyging karlmannsnafn 01 461 | SFX 413 N 6 462 | SFX 413 0 0/1 . 463 | SFX 413 ur s/26 ur 464 | SFX 413 n s/26 nn 465 | SFX 413 0 s/26 u[^r] 466 | SFX 413 0 s/26 n[^n] 467 | SFX 413 0 s/26 [^un]. 468 | 469 | #Fallbeyging karlmannsnafn 01a 470 | SFX 414 N 5 471 | SFX 414 0 s/26 [^u]r 472 | SFX 414 0 s/26 [^u][^r] 473 | SFX 414 0 s/26 u[^r] 474 | SFX 414 ur s/26 ur 475 | SFX 414 ur 0 ur 476 | 477 | #Fallbeyging karlmannsnafn 01 n 478 | SFX 415 N 3 479 | SFX 415 0 0/1 480 | SFX 415 n s/26 nn 481 | SFX 415 l s/26 ll 482 | 483 | #Fallbeyging karlmannsnafn 04 484 | SFX 416 N 2 485 | SFX 416 r 0 486 | SFX 416 r s/26 487 | 488 | #Fallbeyging kk sb 01 489 | SFX 417 N 6 490 | SFX 417 0 0/1,2 491 | SFX 417 ur ar/5,6 ur 492 | SFX 417 n ar/5,6 nn 493 | SFX 417 0 ar/5,6 u[^r] 494 | SFX 417 0 ar/5,6 n[^n] 495 | SFX 417 0 ar/5,6 [^un]. 496 | 497 | #Fallbeyging kk sb 01a 498 | SFX 418 N 7 499 | SFX 418 0 0/11,12 500 | SFX 418 ur ar/5,6 [^a]ur 501 | SFX 418 l ar/5,6 l 502 | SFX 418 0 ar/5,6 u[^r] 503 | SFX 418 0 ar/5,6 l[^l] 504 | SFX 418 0 ar/5,6 [^ul]. 505 | SFX 418 0 ar/5,6 aur 506 | 507 | #Fallbeyging kk sb 01b 508 | SFX 419 N 6 509 | SFX 419 0 0/1,12 510 | SFX 419 ur ar/5,6 ur 511 | SFX 419 n ar/5,6 nn 512 | SFX 419 0 ar/5,6 u[^r] 513 | SFX 419 0 ar/5,6 n[^n] 514 | SFX 419 0 ar/5,6 [^un]. 515 | 516 | #Fallbeyging kk sb 01 et 517 | SFX 420 N 1 518 | SFX 420 0 0/1,2 . 519 | 520 | #Fallbeyging kk sb 01 ft 521 | SFX 421 N 1 522 | SFX 421 0 0/5,6 . 523 | 524 | #Fallbeyging kk sb 01 n 525 | SFX 422 N 8 526 | SFX 422 0 0/1,2 527 | SFX 422 ur ar/5,6 528 | SFX 422 n ar/5,6 nn 529 | SFX 422 ill lar/5,6 530 | SFX 422 all lar/5,6 531 | SFX 422 ull lar/5,6 532 | SFX 422 unn nar/5,6 533 | SFX 422 inn nar/5,6 534 | 535 | #Fallbeyging kk sb 01 n et 536 | SFX 423 N 1 537 | SFX 423 0 0/1,2 538 | 539 | #Fallbeyging kk sb 01 ö 540 | SFX 424 N 6 541 | SFX 424 0 0/1,2 542 | SFX 424 ur ar/7,8 ur 543 | SFX 424 n ar/7,8 nn 544 | SFX 424 0 ar/7,8 u[^r] 545 | SFX 424 0 ar/7,8 n[^n] 546 | SFX 424 0 ar/7,8 [^un]. 547 | 548 | #Fallbeyging kk sb 01 -s 549 | SFX 425 N 6 550 | SFX 425 0 0/3,4 . 551 | SFX 425 ur ar/5,6 ur 552 | SFX 425 n ar/5,6 nn 553 | SFX 425 0 ar/5,6 u[^r] 554 | SFX 425 0 ar/5,6 n[^n] 555 | SFX 425 0 ar/5,6 [^un]. 556 | 557 | #Fallbeyging kk sb 02 558 | SFX 426 N 4 559 | SFX 426 0 0/1,2 560 | SFX 426 ur ir/5,6 ur 561 | SFX 426 0 ir/5,6 u[^r] 562 | SFX 426 0 ir/5,6 [^u]. 563 | 564 | #Fallbeyging kk sb 03 565 | SFX 427 N 8 566 | SFX 427 ur 0 567 | SFX 427 ur i 568 | SFX 427 ur ar 569 | SFX 427 0 inn 570 | SFX 427 ur inn 571 | SFX 427 ur inum 572 | SFX 427 ur arins 573 | SFX 427 ur ir/5,6 574 | 575 | #Fallbeyging kk vb 01 576 | SFX 428 N 2 577 | SFX 428 0 0/22,23 578 | SFX 428 i ar/5,6 579 | 580 | #Fallbeyging kk vb 01 et 581 | SFX 429 N 1 582 | SFX 429 0 0/22,23 583 | 584 | #Fallbeyging kk vb 01 ft 585 | SFX 430 N 1 586 | SFX 430 0 0/5,6 587 | 588 | #Fallbeyging kk vb 01 ö 589 | SFX 431 N 2 590 | SFX 431 0 0/22,23 591 | SFX 431 i ar/7,8 592 | 593 | #Fallbeyging kk vb 01 u 594 | SFX 432 N 2 595 | SFX 432 0 0/22,23 596 | SFX 432 i ar/7,8 597 | 598 | #Fallbeyging kvenmannsnafn 01 599 | SFX 433 N 1 600 | SFX 433 0 0/18 . 601 | 602 | #Fallbeyging kvenmannsnafn 01 i 603 | SFX 434 N 1 604 | SFX 434 0 0/13 . 605 | 606 | #Fallbeyging kvenmannsnafn 01 vb 607 | SFX 435 N 1 608 | SFX 435 0 0/14 609 | 610 | #Fallbeyging kvk sb 01 611 | SFX 436 N 2 612 | SFX 436 0 0/18,19 . 613 | SFX 436 0 ir/20,21 . 614 | #Fallbeyging kvk sb 01 et 615 | SFX 437 N 1 616 | SFX 437 0 0/18,19 . 617 | #Fallbeyging kvk sb 01 ft 618 | SFX 438 N 1 619 | SFX 438 0 0/20,21 . 620 | #Fallbeyging kvk sb 01 un 621 | SFX 439 N 2 622 | SFX 439 0 0/18,19 . 623 | SFX 439 un anir/20,21 . 624 | #Fallbeyging kvk sb 02 625 | SFX 440 N 2 626 | SFX 440 0 0/18,19 . 627 | SFX 440 0 ar/20,21 . 628 | #Fallbeyging kvk sb 02 u 629 | SFX 441 N 2 630 | SFX 441 0 0/31,32 . 631 | SFX 441 0 ar/20,21 . 632 | 633 | #Fallbeyging kvk sb 08 et 634 | SFX 442 N 4 635 | SFX 442 0 n 636 | SFX 442 0 na 637 | SFX 442 0 nni 638 | SFX 442 0 nnar 639 | 640 | #Fallbeyging kvk vb 01 641 | SFX 443 N 2 642 | SFX 443 0 0/14,15 643 | SFX 443 a ur/16,17 644 | 645 | #Fallbeyging kvk vb 01a 646 | SFX 444 N 2 647 | SFX 444 0 0/14,15 648 | SFX 444 a ur/24,25 649 | 650 | #Fallbeyging kvk vb 01 et 651 | SFX 445 N 1 652 | SFX 445 0 0/14,15 653 | 654 | #Fallbeyging kvk vb 01 ft 655 | SFX 446 N 1 656 | SFX 446 0 0/16,17 657 | 658 | #Fallbeyging kvk vb 01 og 01a 659 | SFX 447 N 2 660 | SFX 447 0 0/14,15 661 | SFX 447 a ur/17,24,25 662 | 663 | #Fallbeyging kvk vb örnefni 664 | SFX 448 N 1 665 | SFX 448 0 0/14 666 | 667 | #Lýsingarorðsbeyging 01 668 | SFX 450 N 3 669 | SFX 450 ur 0/400,401,404 ur 670 | SFX 450 0 0/400,401,404 u[^r] 671 | SFX 450 0 0/400,401,404 [^u]. 672 | 673 | #Lýsingarorðsbeyging 01a 674 | SFX 451 N 1 675 | SFX 451 0 0/400,401,404 676 | 677 | #Lýsingarorðsbeyging 01 -legur 678 | SFX 452 N 1 679 | SFX 452 ur 0/400,401,404 ur 680 | 681 | #Lýsingarorðsbeyging 03 682 | SFX 453 N 3 683 | SFX 453 n 0/402,404 n 684 | SFX 453 l 0/402,404 l 685 | SFX 453 0 0/403 686 | 687 | #Sagnbeyging 01 vb -aði 688 | SFX 456 N 16 689 | SFX 456 0 r . 690 | SFX 456 a um a 691 | SFX 456 a ið a 692 | SFX 456 0 ði . 693 | SFX 456 0 ðir . 694 | SFX 456 a uðum a 695 | SFX 456 a uðuð a 696 | SFX 456 a uðu a 697 | SFX 456 a i a 698 | SFX 456 a ir a 699 | SFX 456 0 st . 700 | SFX 456 a umst a 701 | SFX 456 a ist a 702 | SFX 456 0 ðist a 703 | SFX 456 a uðumst a 704 | SFX 456 a uðust a 705 | 706 | -------------------------------------------------------------------------------- /corrections/spelling.js: -------------------------------------------------------------------------------- 1 | const Nodehun = require('nodehun') 2 | const fs = require('fs') 3 | const path = require('path') 4 | 5 | const affbuf = fs.readFileSync(path.join(__dirname, 'is.aff')) 6 | const dictbuf = fs.readFileSync(path.join(__dirname, 'is.dic')) 7 | 8 | const dict = new Nodehun(affbuf, dictbuf) 9 | 10 | export function getSuggestions(word, cb) { 11 | dict.spellSuggestions(word, function(err, correct, suggestion, origWord) { 12 | cb(err, suggestion) 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /data/verbs.conf: -------------------------------------------------------------------------------- 1 | # 2 | # Verbs.conf 3 | # 4 | # List of Icelandic verbs and their associated cases, 5 | # objects and subjects 6 | # 7 | 8 | aðstoða 9 | aðstoða þf 10 | afgreiða 11 | afgreiða þf 12 | afhenda þf 13 | afhenda þgf þf 14 | afsala þgf 15 | afsala þgf þf 16 | afskrifa þf 17 | anna þgf # !!! Ath. 'að annast Pál' 18 | athuga þf 19 | auka þf 20 | auka þgf þf # 'að auka mér leti' 21 | ábyrgjast þf 22 | ákveða þf 23 | ásaka þf 24 | átta þf 25 | ávaxta þf 26 | auka þf 27 | auka þgf þf # 'auktu mér leti og sæktu kaffið' 28 | banka 29 | banka þf 30 | banna þf 31 | banna þgf þf 32 | batna 33 | batna nf # 'að batna sóttin' 34 | beiða ef 35 | beiða þf ef # 'að beiða einhvern einhvers' 36 | beina þgf þf 37 | beita þgf 38 | beita þf þgf # 'að beita Pál viðskiptaþvingunum' 39 | benda 40 | benda þgf 41 | bera # 'ærnar eru að bera' 42 | bera þf 43 | bera þgf # 'á morgun ber Páli að svara til saka' 44 | berja 45 | berja þf 46 | berja þgf # 'listaverkið var barið augum í gær' 47 | biðja 48 | biðja þf 49 | biðja ef # 'að biðja konunnar' 50 | birta þf 51 | bíða 52 | bíða ef # 'að bíða þess að niðurstöður verið birtar' 53 | blaða 54 | blása 55 | blogga 56 | bjarga þgf 57 | bjóða 58 | bjóða þf 59 | bjóða þgf þf 60 | blöskra nf 61 | bora 62 | bora þf 63 | borða 64 | borða þf 65 | borga 66 | borga þf 67 | borga þgf þf 68 | bókfæra þf 69 | bóna 70 | bóna þf 71 | braggast 72 | bregða 73 | bregða þgf 74 | brenna 75 | brenna þf 76 | bresta 77 | bresta nf 78 | breyta 79 | breyta þgf 80 | brosa 81 | búa 82 | búa þf # 'að búa barnið undir skólann' 83 | búa þgf þf # 'að búa barninu gott heimili' 84 | byggja þf 85 | byrja 86 | byrja þf 87 | býsna 88 | bæta þf 89 | danska þf 90 | dáma nf 91 | deila 92 | deila þgf 93 | detta 94 | detta nf # 'að detta eitthvað í hug' 95 | deyja 96 | deyja þgf # 'að deyja drottni sínum' 97 | draga 98 | draga þf 99 | drepa þf 100 | dreyma 101 | dreyma nf 102 | drjúpa 103 | drúpa þgf # 'að drúpa höfði' 104 | duga 105 | duga nf # 'að duga góð skæri' 106 | duga þgf # 'vitnisburðurinn dugði Páli' 107 | efa þf 108 | efla þf 109 | eiga # 'Jóna er búin að eiga' 110 | eiga þf 111 | eiga þgf þf # 'ég á mér draum' 112 | eigna þgf þf 113 | eignfæra þf 114 | einangra þf 115 | einkenna þf 116 | einsetja þgf 117 | elna nf # 'að elna sóttin' 118 | elta 119 | elta þf 120 | # Elda án viðfangs er "að verða eldri", sbr. 'ég eldist', eða 'ég er að elda' 121 | elda 122 | # Elda með viðfangi er "að elda mat" 123 | elda þf 124 | elska 125 | elska þf 126 | endurheimta þf 127 | endurnýja 128 | endurnýja þf 129 | endurraða 130 | endurraða þgf 131 | endursemja 132 | endursemja þf 133 | endurskoða þf 134 | eyða þgf 135 | faðma þf 136 | falla 137 | falla nf # 'að falla eitthvað í geð' 138 | falla þgf # 'fellur Páli vel' 139 | falsa þf 140 | fara 141 | fara þf # 'ég fer Hvalfjörðinn' 142 | fá þf 143 | fá þgf þf 144 | fara 145 | fara þgf # 'skyrtan fer Páli vel' 146 | fara þf # 'að fara veginn' 147 | fasta 148 | feita þf 149 | fela þf 150 | fela þgf þf 151 | fella þf 152 | finna þf 153 | finna þgf þf 154 | fjalla 155 | fjármagna þf 156 | fjölga 157 | fjölga þgf # 'við vildum fjölga konum á þingi' 158 | fleygja þgf 159 | fljúga 160 | fljúga þgf 161 | flokka þf 162 | flytja 163 | flytja þf 164 | flytja þgf þf # 'að flytja Páli fréttirnar' 165 | forma þf 166 | frama þf 167 | framfæra þf 168 | framkvæma 169 | framkvæma þf 170 | freista ef 171 | fresta þgf 172 | frétta 173 | frétta þf 174 | fullyrða 175 | fullyrða þf 176 | funda 177 | fylgja 178 | fylgja þgf 179 | fyrirskipa þgf 180 | fækka 181 | fækka þgf 182 | færa þf 183 | færa þgf þf 184 | gagnrýna 185 | gagnrýna þf 186 | gamla þf 187 | ganga 188 | ganga þf # 'ég geng Laugaveginn' 189 | ganga þgf # 'ég geng skrefinu lengra' 190 | gáta þf 191 | gefa þf 192 | gefa þgf þf 193 | gegna 194 | gegna þgf 195 | gera 196 | gera þf 197 | geta þf 198 | geta þgf þf # 'að geta Önnu barn' 199 | geta ef # 'að geta þess í framhjáhlaupi' 200 | gleyma 201 | gleyma þgf 202 | glugga 203 | gjalda # 'þú munt gjalda fyrir þetta' 204 | gjalda þgf þf # 'að gjalda líku líkt' 205 | greina 206 | greina þf 207 | grilla 208 | grilla þf 209 | grilla þgf þf 210 | grípa 211 | grípa þf 212 | gruna þf 213 | gufa 214 | gæða þf þgf 215 | gæta ef 216 | hafa 217 | hafa þf 218 | haga þgf 219 | halda 220 | halda þgf # 'að halda dyrunum' 221 | halda þf # 'að halda fund' 222 | harðna 223 | hefða þf 224 | heilsa 225 | heilsa þgf 226 | heita 227 | heita nf 228 | heita þgf 229 | heita þgf þf 230 | hefja þf 231 | helta þf 232 | henta 233 | henta þgf 234 | hlaupa 235 | hlaupa þf 236 | hlusta 237 | hlusta þf 238 | hluta þf 239 | hlýna 240 | hnigna 241 | horfa 242 | hraka 243 | hringa þf 244 | hringja 245 | hringja þgf 246 | hrjósa nf 247 | hrylla 248 | hrylla þf 249 | hrynja 250 | huga 251 | hugsa 252 | hugsa þf 253 | hugsa þgf þf # 'að hugsa Páli þegjandi þörfina' 254 | hungra 255 | hæfa þf 256 | hægja þgf 257 | hækka 258 | hækka þf 259 | hætta 260 | hætta þgf 261 | iðka þf 262 | ilma 263 | innheimta þf 264 | íslenska þf 265 | kalla 266 | kalla þf þgf # 'að kalla Pál öllum illum nöfnum' 267 | kalla þf þf # 'að kalla kött Kött' 268 | kanna þf 269 | kaupa þf 270 | kaupa þgf þf 271 | keyra 272 | keyra þf 273 | kitla 274 | kitla þf 275 | kjarna þf 276 | kjósa 277 | kjósa þf 278 | klífa þf 279 | klígja 280 | klóra þf 281 | klóra þgf 282 | klæja 283 | knýja þf 284 | # knýja þgf 285 | koma 286 | koma þf # 'ég kem sjóleiðina' 287 | koma þgf # 'að koma öllum fyrir á hóteli' 288 | koma þgf þf # 'ég kem bréfinu landleiðina' 289 | kosta þf 290 | kosta þf þf # 'að kosta Pál skildinginn' 291 | kólna 292 | krakka 293 | krakka þf 294 | krefja ef # 'að krefjast þess' 295 | krefja þf ef # 'að krefja Pál reikningsskapar' 296 | kreppa þf 297 | kunna þf 298 | kunna þgf þf # 'að kunna Páli litlar þakkir fyrir' 299 | kvikmynda 300 | kvikmynda þf 301 | kyngja 302 | kyngja þgf 303 | kynna þf 304 | kynna þgf þf 305 | kyssa þf 306 | kyssa þf þgf # 'að kyssa Pál rembingskossi' 307 | laga þf 308 | lagða þf 309 | landa þgf 310 | langa þf 311 | launa þgf þf 312 | lána þf 313 | lána þgf þf 314 | láta þf 315 | leggja 316 | leggja þf 317 | leggja þgf þf # 'að leggja Páli lífsreglurnar' 318 | leiða 319 | leiða þf 320 | leiðast 321 | leiðast nf # 'mér leiðist Páll' 322 | leka 323 | leka þgf 324 | lenda 325 | lenda þgf # 'að lenda flugvélinni' 326 | leika þf 327 | leika þgf 328 | lengja þf 329 | lesa 330 | lesa þf 331 | lesa þgf þf # 'að lesa Páli pistilinn' 332 | leysa þf 333 | létta þf # 'ég létti bílinn' 334 | létta þgf þf # 'snjallsíminn létti Páli gönguna' 335 | liða 336 | liða þf 337 | lifa 338 | lifa þf 339 | lifa þgf 340 | liggja 341 | linna þgf 342 | líða 343 | líða þf # 'ég líð Pál ekki í mínum húsum' 344 | líka nf 345 | ljúka þgf 346 | ljósta þgf # 'þá laust því í huga Páls' 347 | lofta 348 | lofta þf 349 | lofta þgf # 'ég lofta ekki þessum lóðum' 350 | loga 351 | loka þgf 352 | lóga þgf 353 | lúka þgf 354 | lyfta þgf 355 | lykta 356 | lykta þgf # 'með því lyktaði fundinum' 357 | lynda 358 | lysta 359 | lýsa þf 360 | lýsa þgf 361 | lýta þf 362 | lægja 363 | lægja þf 364 | læka 365 | læka þf 366 | lækka 367 | lækka þf 368 | læra 369 | læra þf 370 | nauðga 371 | nauðga þgf 372 | ná 373 | ná þgf 374 | náða þf 375 | nefna þf 376 | neita 377 | neita þgf 378 | nema þf 379 | nema þgf # 'hallinn nemur 347 milljörðum' 380 | nota þf 381 | njóta ef 382 | núa þgf 383 | nýja þf 384 | næða 385 | nægja 386 | nægja nf 387 | manna þf 388 | margfalda þf 389 | marka þf 390 | marka þgf þf 391 | mislíka nf 392 | má þf # 'að má áletrunina', 'áletrunin máðist' 393 | mála 394 | mála þf 395 | mega 396 | meina 397 | meina þf 398 | meina þgf þf 399 | merkja þf 400 | merkja þgf þf 401 | meta þf 402 | meta þgf þf # 'að meta Páli það til tekna' 403 | miðla þgf 404 | mikla þf 405 | millilenda 406 | millilenda þgf 407 | minna þf 408 | minna ef # 'að minnast Páls' 409 | misminna þf 410 | misskilja þf 411 | morgna 412 | mótmæla 413 | mótmæla þgf 414 | muna 415 | muna þf 416 | munu 417 | mylja þf 418 | mynda þf 419 | myrða þf 420 | ofbjóða 421 | ofbjóða nf 422 | opinbera 423 | opinbera þf 424 | opinbera þgf þf # 'að opinbera hópnum skýrsluna' 425 | orða þf 426 | óma 427 | óska 428 | óska ef 429 | óska þgf ef 430 | óttast þf 431 | panta þf 432 | panta þgf þf 433 | pissa 434 | pissa þgf 435 | plata 436 | plata þf 437 | raða þgf 438 | rannsaka þf 439 | raska þgf 440 | rassskella þf 441 | ráða 442 | ráða þf # 'að ráða Pál til vinnu" 443 | ráða þgf # 'ég ræð þessari ákvörðun' 444 | reka 445 | reka þf 446 | renna 447 | renna nf # 'Páli rann reiðin' 448 | reyna 449 | reyna þf 450 | réna nf # 'síðdegis rénaði rigningin' 451 | rétta þf 452 | rétta þgf þf 453 | rigna 454 | rigna þgf # 'það rigndi hundum og köttum' 455 | ríða 456 | ríða þgf 457 | ríða þf # 'að ríða netið' 458 | rífa þf 459 | ríkja 460 | rísa 461 | rísa nf # 'þar reis byggingin' 462 | ropa 463 | ropa þgf # 'að ropa þessu upp úr sér' 464 | rússa 465 | ryksuga þf 466 | rýma þf 467 | rýrna 468 | ræða þf 469 | rækja þf 470 | ræna þgf 471 | ræna þf þgf 472 | ræskja þf 473 | safna þgf 474 | saka þf 475 | sama þf 476 | samræma þf # 'ég samræmi þetta við það sem þú skrifaðir' 477 | samræma þf þgf # 'að samræma mig því sem þú segir' 478 | samsama þgf # 'ég samsama þessu' 479 | samsama þf þgf # 'að samsama mig því sem þú segir' 480 | samþykkja 481 | samþykkja þf 482 | sá þgf # 'að sá korninu' 483 | sárna nf 484 | segja þf 485 | segja þgf þf 486 | segla þf 487 | seinka þgf 488 | selja þf 489 | selja þgf þf 490 | semja 491 | semja þf 492 | senda þf 493 | senda þgf þf 494 | setja þgf þf # 'að setja okkur nýja stjórnarskrá' 495 | setja þf # 'að setja hamarinn á hilluna' 496 | sigra 497 | sigra þf 498 | sinna þgf 499 | sitja 500 | sitja þf # 'að sitja fundinn' 501 | síma 502 | sjatna 503 | sjá 504 | sjá þf 505 | sjá þgf # 'að sjá börnunum fyrir nauðþurftum' 506 | sjónvarpa þgf 507 | skafa þf 508 | skapa 509 | skapa þf 510 | skána 511 | skeika þgf 512 | skila þgf 513 | skila þgf þgf # 'að skila Páli bílnum' 514 | skilja 515 | skilja þf 516 | skipa þf # 'að skipa formann nefndarinnar' 517 | skipa þgf # 'að skipa Páli að fara út' 518 | skipta þgf 519 | skjalfesta þf 520 | skola þf 521 | skorta þf 522 | skóla þf 523 | skulda þf 524 | skulda þgf þf 525 | skuldfæra þf 526 | skulu 527 | skrásetja þf 528 | skrifa þf # 'að skrifa eitthvað' 529 | skrifa þgf # 'að skrifa einhverjum' 530 | skrifa þgf þf # 'að skrifa einhverjum bréf' 531 | skrika 532 | skrika nf # 'þér skrikaði fótur' 533 | skuldbinda þf 534 | skylda þf 535 | sleppa þgf 536 | slaka þgf 537 | sleikja þf 538 | slóra 539 | sóma þgf 540 | snúa þgf 541 | snúa þf # 'að snúa Pál af sér' 542 | snæða 543 | snæða þf 544 | sortna 545 | spá 546 | spá þgf 547 | spá þgf þgf 548 | spjalla 549 | spjalla þf # 'að spjalla stúlkuna' 550 | sprengja 551 | sprengja þf 552 | springa 553 | spyrja 554 | spyrja þf # 'að spyrja einhvern' 555 | spyrja ef # 'að spyrja einhvers' 556 | spyrja þf ef # 'að spyrja Pál einhvers' 557 | staðfesta þf 558 | stafa þf 559 | stafa þgf 560 | standa 561 | standa þf # 'Jón stóð vaktina' 562 | standa þgf # 'að standa styrkum fótum' 563 | starfa 564 | stefna þf # 'að stefna áfram veginn' 565 | stefna þgf # 'að stefna Páli fyrir dóm' 566 | stika 567 | stika þf 568 | stinga þf 569 | stinga þgf # 'að stinga því að Páli' 570 | stíga 571 | stíga þf # 'Jón stóð ölduna' 572 | stoða þf 573 | strauja 574 | strauja þf 575 | strika þf 576 | stríða 577 | stríða þgf 578 | strjúka 579 | strjúka þf 580 | strjúka þgf 581 | styðja þf 582 | styrkja þf 583 | stýra 584 | stýra þgf 585 | stökkva 586 | suma 587 | sundla 588 | súrna 589 | svara 590 | svara þgf 591 | sveifla þgf 592 | svengja 593 | svima 594 | svindla 595 | svipa 596 | svipta þgf þf 597 | svíða 598 | svíða nf 599 | syfja 600 | sýna þf 601 | sýna þgf þf 602 | sækja þf 603 | sækja þgf þf # 'ég sæki mér kaffi' 604 | sæma þgf # 'Titillinn sæmir Páli' 605 | taka þf 606 | taka þgf þf # 'að taka einhverjum blóð' 607 | tala 608 | tala þgf # 'að tala máli Páls' 609 | tapa 610 | tapa þgf 611 | telja 612 | telja þf # 'að telja peningana' 613 | telja þgf # 'að telja Páli trú um' 614 | tengsla # væntanlega 'að tengsla' = 'að kúpla'? 615 | tilbúa þf 616 | tilkynna 617 | tilkynna þf 618 | tilkynna þgf 619 | tilkynna þgf þf 620 | tryggja þf # 'að tryggja bílinn' 621 | tryggja þgf þf # 'að tryggja okkur betri kjör' 622 | una þgf 623 | unda þf 624 | undra þf 625 | undirgangast þf 626 | undirrita 627 | undirrita þf 628 | unga þgf 629 | unna þgf 630 | unna þgf ef # 'að unna Páli þess að vera fallegur' 631 | uppfylla þf 632 | upplýsa 633 | upplýsa þf 634 | útbúa þf 635 | útfæra þf 636 | úthluta þgf 637 | úthluta þgf þgf # 'að úthluta Páli peningum' 638 | útskýra 639 | útskýra þf 640 | vaða þf 641 | vakna 642 | valda þf # 'Riddarinn valdaði hrókinn' 643 | valda þgf 644 | valda þgf þgf # 'að valda Páli óþægindum' 645 | vanda þf 646 | vanda þgf þf 647 | vanta þf 648 | vara þf 649 | varða þf 650 | varna þgf þf 651 | vatna þgf # 'Páll vatnaði músum' 652 | vefa 653 | vefa þf # 'ég er að vefa klæði' 654 | vefja þf # 'ég er að vefja vindling' 655 | vefja þgf # 'ég vef fisknum inn í dagblað' 656 | vega þf 657 | vegna # 'vegna' er einnig forsetning sem stýrir eignarfalli 658 | vegna þgf 659 | veiða 660 | veiða þf 661 | veita 662 | veita þf # 'að veita lánið' 663 | veita þgf # 'að veita einhverju [burt, út]' 664 | veita þgf þf # 'að veita Páli lánið' 665 | velja þf 666 | velja þgf þf 667 | velta 668 | velta þgf 669 | venja þf 670 | vera nf 671 | vera þgf nf # 'Þetta er Páli tilefni til aðgerða' 672 | vera ef # 'Hún er þeirrar náttúru að elska börn' 673 | verða nf 674 | verða þgf nf 675 | verða ef 676 | verja þf 677 | verja þgf 678 | verka þf 679 | verkja 680 | verpa 681 | verpa þgf 682 | versna 683 | viðkoma þgf # 'málið viðkemur þér' 684 | viðurkenna þf 685 | viðvíkja þgf # 'málið víðvíkur þér' 686 | vilja 687 | vilja þf 688 | vilja þgf þf 689 | vinda þf 690 | vinda þgf # 'Páll vindur sér í þetta' 691 | virða 692 | virða þf # 'að virða Pál' 693 | virða þgf # 'að virða Páli það til málsbóta' 694 | virka 695 | virkja 696 | virkja þf 697 | víkja 698 | víkja þgf 699 | vísa þgf 700 | vísa þgf þf # 'að vísa einhverjum leiðina' 701 | volgna 702 | vopna þf 703 | vænta ef 704 | vökna 705 | yfirbuga þf 706 | yfirgefa þf 707 | ylna 708 | yrða 709 | yrja þf 710 | yrkja þf 711 | yrkja þgf þf 712 | þakka 713 | þakka nf 714 | þakka þgf 715 | þakka þgf þf 716 | þekkja þf 717 | þjarma 718 | þoka þgf 719 | þrjóta 720 | þrjóta þf 721 | þrýsta 722 | þrýsta þgf 723 | þurfa 724 | þurfa þf 725 | þurrka þf 726 | þverra 727 | þverra nf # 'Jóni þvarr máttur' 728 | þvertaka þf 729 | þvo 730 | þvo þf 731 | þætta þf 732 | þykja 733 | þykja nf 734 | þyrma þgf 735 | þyrsta 736 | þýða 737 | þýða þf 738 | þýska þf 739 | æla 740 | æta þf # 'sýran ætir steininn' 741 | ætla 742 | ætla þf # 'ég ætla Vatnaleiðina í sumar' 743 | ætla þgf þf # 'ég ætla Páli ekkert illt' 744 | ævintýra 745 | örva þf 746 | 747 | aflétta þgf 748 | afplána þf 749 | barna þf 750 | blómstra 751 | brjóta þf 752 | dæma þf 753 | dæma þgf þf 754 | eina þf 755 | enda þf 756 | fangelsa þf 757 | fordæma þf 758 | fóðra þf 759 | frelsa þf 760 | fremja þf 761 | fylla þf 762 | fyrirtaka þf 763 | fyrtast 764 | gilda þf 765 | greiða þf 766 | greiða þgf þf 767 | heyra 768 | heyra þf 769 | hleypa þf 770 | hleypa þgf 771 | hneyksla þf 772 | höggva þf 773 | innlima þf 774 | leita þgf ef 775 | leita ef 776 | lofa 777 | lofa þf 778 | lofa þgf þgf 779 | móðga þf 780 | nýta þf 781 | pósta þgf 782 | rata 783 | rata þf 784 | sannfæra þf 785 | skoða þf 786 | skora 787 | skora þf 788 | skrá þf 789 | smella þgf # 'ég smellti lásnum' 790 | spara 791 | spara þf 792 | spara þgf þf 793 | staðsetja þf 794 | stynja 795 | stynja þgf 796 | útgefa þf 797 | verðtryggja þf 798 | vinna 799 | vinna þf 800 | vinna þgf þf # 'að vinna landi sínu allt' 801 | vægja 802 | vægja þgf 803 | væna þf 804 | þora 805 | þora þgf 806 | þora þf 807 | 808 | álykta þf 809 | álykta 810 | ára þf 811 | baka þf 812 | besta þf 813 | beygja 814 | beygja þf 815 | blasa 816 | boða þf 817 | boða þgf þf 818 | brota þf 819 | býta þgf 820 | einblína 821 | einblína þf 822 | eitra 823 | eitra þf 824 | endurspegla þf 825 | ferðast 826 | flæða 827 | flæða þf 828 | freka 829 | gumma 830 | hafna þgf 831 | hagna 832 | halla 833 | halla þgf 834 | heimila þf 835 | heimila þgf þf 836 | heimta þf 837 | heimta þgf þf 838 | hliða þf 839 | hrinda þgf 840 | hvika 841 | höfða 842 | höfða þf 843 | jafna 844 | jafna þf 845 | kana þf 846 | magna þf 847 | magna þgf þf 848 | mata þf 849 | minnka 850 | minnka þf 851 | mæla 852 | mæla þf 853 | mæla þgf þf 854 | nálægja þgf 855 | reiða þf 856 | réttlæta þf 857 | rýra þf 858 | saga þf 859 | skatta þf 860 | skella þgf 861 | skilyrða þf 862 | spila 863 | spila þf # 'að spila uppáhaldslagið' 864 | spila þgf # 'að spila hjartaásnum' 865 | stunda þf 866 | stytta þf 867 | stytta þgf þf 868 | synda 869 | synda þf # 'að synda 50 metrana' 870 | tíma þgf 871 | tjóna þf 872 | treysta þgf 873 | umreikna þf 874 | varpa þgf 875 | varpa þgf þf # 'að varpa kúlunni langleiðina' 876 | veðja 877 | veðja þgf 878 | viðhalda þgf 879 | vika þgf 880 | vina þf 881 | vita þf 882 | víkka þf 883 | þinglýsa þgf 884 | þrefalda þf 885 | þróa þf 886 | öskra 887 | öskra þf # 'Páll öskraði sig hásan' 888 | 889 | aðlaga þf 890 | aðskilja þf 891 | afla ef 892 | afla þgf ef 893 | afmarka þf 894 | aka 895 | aka þf # 'ég ek veginn' 896 | aka þgf # 'ég ek bílnum' 897 | ala þf 898 | ala þgf þf 899 | aldra 900 | aldra þf 901 | anda 902 | anda þgf 903 | annála 904 | annála þf 905 | apa þf 906 | axla þf 907 | áfrýja 908 | áfrýja þgf 909 | ákæra 910 | ákæra þf 911 | ása 912 | ása þf 913 | áætla 914 | áætla þf 915 | áætla þgf # 'ég áætla Páli ávinning' 916 | bakka 917 | bakka þgf 918 | bana þgf 919 | banda þgf 920 | bergja 921 | betra þf 922 | binda þf 923 | binda þf þgf # 'við bindum þetta fastmælum' 924 | bíla þf 925 | blasta þf 926 | blasta þgf 927 | blessa þf 928 | bolta þf 929 | boxa þf 930 | breiða þf 931 | brotna 932 | brúa þf 933 | brynja þf 934 | bursta þf 935 | bylta þgf 936 | dafna 937 | daga 938 | dansa 939 | dansa þf 940 | demba þgf 941 | demba þgf þf # 'ég ákvað að demba mér Vatnaleiðina' 942 | dimma 943 | dimma þf 944 | djöfla 945 | dolla 946 | dóta þf 947 | dreifa þgf 948 | dressa þgf 949 | dvelja 950 | dvelja þf 951 | efna þf 952 | einbeita þgf 953 | endurnýta þf 954 | enduróma þf 955 | endurreisa þf 956 | endurskapa þf 957 | endurvekja þf 958 | enska þf 959 | erfa þf 960 | erfa þgf þf # 'ég erfði honum það ekki' 961 | erfiða 962 | erfiða þf # 'ég erfiðaði allan daginn' 963 | erinda 964 | erta þf 965 | exa 966 | eyðileggja þf 967 | fagna þgf 968 | fala þf 969 | fala þgf þf 970 | fatta 971 | fatta þf 972 | fána þf 973 | fegra þf 974 | fiska 975 | fiska þf 976 | fita þf 977 | fía þf 978 | fífla þf 979 | fjórðunga þf 980 | fjölmenna 981 | flaka þf 982 | flakka 983 | flengja þf 984 | fletja þf 985 | flétta þf 986 | flykkjast 987 | flykkjast þf 988 | flækja þf 989 | forða þgf 990 | forvitna 991 | framleiða þf 992 | framlengja þf 993 | friðhelga þf 994 | friðhelga þgf þf 995 | friðmælast 996 | frumflytja þf 997 | frumsýna 998 | frumsýna þf 999 | fræða þf 1000 | fullkomna þf 1001 | fyrirhuga þf 1002 | gangsetja þf 1003 | gasa þf 1004 | gerja þf 1005 | geyma þf 1006 | gifta þf 1007 | gifta þgf þf 1008 | gjörbreyta þgf 1009 | gleypa þf 1010 | glíma 1011 | gosa þf 1012 | góma þf 1013 | granda þgf 1014 | gráta 1015 | gráta þf 1016 | græða 1017 | græða þf 1018 | græða þgf þf 1019 | hamla þgf 1020 | handtaka þf 1021 | hanna þf 1022 | hata þf 1023 | hausa þf 1024 | hefa 1025 | hefa þf 1026 | hefna ef 1027 | hefta þf 1028 | heilla þf 1029 | heimsækja þf 1030 | helga þf 1031 | helga þgf þf 1032 | helminga þf 1033 | henda þgf 1034 | herða þf 1035 | herma 1036 | heyja þf 1037 | hita þf 1038 | hita þgf þf 1039 | hitta þf 1040 | hjálpa 1041 | hjálpa þgf 1042 | hlakka 1043 | hljóða 1044 | hljóðrita þf 1045 | hljóta þf 1046 | hlýða 1047 | hlýða þgf 1048 | hlæja 1049 | hoppa 1050 | hoppa þf 1051 | hóta þgf 1052 | hreinsa 1053 | hreinsa þf 1054 | hreyfa þf 1055 | hreyfa þgf # 'hann hreyfði málinu við mig' 1056 | hræða þf 1057 | hrökklast 1058 | húsa þf 1059 | hverfa 1060 | hverfa þf # 'hann hvarf neðri leiðina' 1061 | hvetja þf 1062 | hvíla þf 1063 | hyggja 1064 | hæla þgf 1065 | höndla þf 1066 | inna þf 1067 | innkalla þf 1068 | íhuga þf 1069 | jafngilda þgf 1070 | jarða þf 1071 | kafa 1072 | kafna 1073 | kalda þf 1074 | kata þf 1075 | kenna 1076 | kenna þf 1077 | kenna þgf þf 1078 | kerfa þf 1079 | klára þf 1080 | klemma þf 1081 | klæða þf 1082 | kokka 1083 | kokka þf 1084 | kopa 1085 | kópa 1086 | krabba þf 1087 | krauma 1088 | kúka 1089 | kúka þgf 1090 | kveða 1091 | kveða þf 1092 | kveða þgf þf 1093 | kvika 1094 | kvíða þgf 1095 | kvölda 1096 | kæra þf 1097 | labba 1098 | labba þf 1099 | lama þf 1100 | lágmarka þf 1101 | lesta þf 1102 | letja þf 1103 | leyfa þf 1104 | leyna þf þgf 1105 | leyna þgf 1106 | lita 1107 | lita þf 1108 | líkja þgf 1109 | líta 1110 | líta þf 1111 | lokna 1112 | losa þf 1113 | lúta þgf 1114 | lækna þf 1115 | malbika 1116 | malbika þf 1117 | mennta þf 1118 | miða 1119 | miða þf # 'að miða símtækið út' 1120 | missa þf 1121 | móta þf 1122 | mæta 1123 | mæta þgf 1124 | nálgast 1125 | nálgast þf 1126 | nenna 1127 | nenna þgf 1128 | niðra þf 1129 | næla þgf 1130 | ofmeta þf 1131 | opna 1132 | opna þf 1133 | opna þgf þf # 'hann opnaði mér nýjan heim' 1134 | orsaka þf 1135 | ógna þgf 1136 | para þf 1137 | passa þf 1138 | prenta 1139 | prenta þf 1140 | prýða þf 1141 | radda 1142 | radda þf 1143 | raka 1144 | raka þf 1145 | raka þgf # 'að raka inn peningunum' 1146 | rása 1147 | rása þf 1148 | regla þf 1149 | reiðast 1150 | reiðast þgf 1151 | rekja þf 1152 | riðla þgf 1153 | rifja 1154 | rista þf 1155 | rita þf 1156 | rita þgf þf # 'ég rita þér bréf' 1157 | rokka 1158 | rokka þf # 'að rokka feitt' 1159 | rýna 1160 | rýna þf 1161 | rækta þf 1162 | rækta þgf þf # 'ég rækta mér grænmeti' 1163 | ræta 1164 | ræta þf 1165 | rölta 1166 | rölta þf 1167 | sameina þf 1168 | sameina þf þgf 1169 | sela 1170 | sigla 1171 | sigla þf 1172 | skaða þf 1173 | skaffa 1174 | skaffa þf 1175 | skaffa þgf þf 1176 | skamma þf 1177 | skara 1178 | skara þf 1179 | skála 1180 | skelfa þf 1181 | skemma 1182 | skemma þf 1183 | skera 1184 | skera þf 1185 | skera þgf þf # 'ég skar mér sneið' 1186 | skilgreina þf 1187 | skipuleggja þf 1188 | skjóta 1189 | skjóta þf 1190 | skokka 1191 | skokka þf 1192 | skrefa þf 1193 | skreyta 1194 | skreyta þf 1195 | skyggna þf 1196 | skýra þf 1197 | slaga 1198 | slaga þf 1199 | slasa þf 1200 | slá 1201 | slá þf 1202 | slá þgf # 'að slá þessu upp í kæruleysi' 1203 | slitna 1204 | slökkva 1205 | slökkva þf 1206 | smá þf 1207 | smita 1208 | smita þf 1209 | smíða þf 1210 | smíða þgf þf # 'ég smíðaði mér skó' 1211 | snarlækka 1212 | snarlækka þf 1213 | snerta þf 1214 | snjalla þf 1215 | sofa 1216 | sofa þf # 'að sofa nóttina' 1217 | spenna þf 1218 | spinna 1219 | spinna þf 1220 | sprella 1221 | spretta 1222 | spretta þgf 1223 | staldra 1224 | starfrækja þf 1225 | stela 1226 | stela þgf 1227 | stela þgf þgf # 'að stela sér köku' 1228 | stirna 1229 | stjórna 1230 | stjórna þgf 1231 | stofna þf 1232 | stórauka þf 1233 | stráka 1234 | stráka þf 1235 | stressa þf 1236 | streyma 1237 | streyma þf 1238 | streyma þgf # 'að streyma tónlistinni yfir netið' 1239 | stuða þf 1240 | stækka 1241 | stækka þf 1242 | stöðva 1243 | stöðva þf 1244 | sverja 1245 | sverja þf 1246 | sverja þgf þf # 'að sverja föðurlandinu eið' 1247 | svíkja 1248 | svíkja þf 1249 | syngja 1250 | syngja þf 1251 | syngja þgf þf # 'að syngja henni lofsöngva' 1252 | særa þf 1253 | sæta þgf 1254 | sætta þf 1255 | takmarka þf 1256 | tengja 1257 | tengja þf 1258 | texta 1259 | texta þf 1260 | texta þgf þf # 'ég textaði henni skilaboðin' 1261 | tilnefna þf 1262 | tjalda 1263 | tjalda þgf 1264 | tolla þf 1265 | tóna 1266 | tóna þf 1267 | troðfylla þf 1268 | trufla 1269 | trufla þf 1270 | trúa 1271 | trúa þgf 1272 | túlka 1273 | túlka þf 1274 | týna þgf 1275 | tæpa 1276 | töfra þf 1277 | töfra þgf þf # 'hann töfraði sér kanínu' 1278 | umbreyta þgf 1279 | umfaðma þf 1280 | undirbúa þf 1281 | undirstrika þf 1282 | uppfæra 1283 | uppfæra þf 1284 | útbreiða þf 1285 | útiloka þf 1286 | útrýma þgf 1287 | útskrifa þf 1288 | útvarpa þgf 1289 | vakta þf 1290 | vanmeta þf 1291 | vanvirða þf 1292 | vaxa 1293 | vaxa þgf # 'það vex mér í augum' 1294 | vekja þf 1295 | vekja þgf þf # 'það vakti Páli kenndir' 1296 | verðskrá 1297 | véla 1298 | véla þf 1299 | villa 1300 | vissa 1301 | vista þf 1302 | vígja þf 1303 | vígja þgf þf 1304 | víta þf 1305 | ýta þgf 1306 | ýta þgf þf 1307 | þéna 1308 | þjá þf 1309 | þola þf 1310 | þola þgf þf 1311 | þroska þf 1312 | þruma 1313 | þruma þgf # 'hann þrumaði boltanum í markið' 1314 | þula þf 1315 | þyngja þf 1316 | æfa þf 1317 | öðlast þf 1318 | 1319 | aðgreina þf 1320 | afhöfða þf 1321 | aga þf 1322 | ama þf 1323 | ata þf 1324 | auga þf 1325 | áforma þf 1326 | ála þf 1327 | áreita þf 1328 | birgja þf 1329 | bita þf 1330 | bíta 1331 | bíta þf 1332 | bjalla 1333 | blanda þf 1334 | blanda þgf 1335 | bláma þf 1336 | blotna 1337 | boga þf 1338 | bretta 1339 | bretta þf 1340 | brjála þf 1341 | búsetja þf 1342 | dagsetja þf 1343 | dikta þf 1344 | drekka 1345 | drekka þf 1346 | drekka þgf þf # 'að drekka brúðhjónunum skál' 1347 | dropa 1348 | dúkka 1349 | eðla þf 1350 | eggja þf 1351 | ekta þf 1352 | endurhlaða þf 1353 | endurnæra þf 1354 | erla þf 1355 | eta þf 1356 | etja þgf 1357 | etja þgf þf 1358 | éta 1359 | éta þf 1360 | faxa þf 1361 | faxa þgf þf 1362 | festa þf 1363 | festa þgf þf 1364 | fetta þf 1365 | fima þf 1366 | fjara 1367 | fjárfesta 1368 | fjárfesta þgf 1369 | flagga 1370 | flagga þgf 1371 | fletta þgf 1372 | fleyga þf 1373 | flippa 1374 | flippa þgf 1375 | flota þf 1376 | flýja 1377 | flýja þf 1378 | flýta þgf 1379 | forrita 1380 | forrita þf 1381 | frysta 1382 | frysta þf 1383 | frægja þf 1384 | fugla þf 1385 | fullskipa þf 1386 | fyrirlíta þf 1387 | fæða 1388 | fæða þf 1389 | fæða þgf þf 1390 | gala 1391 | gala þf 1392 | garða þf 1393 | gauta 1394 | geysa 1395 | gína 1396 | gjósa 1397 | gjósa þgf 1398 | glaða þf 1399 | gleðja þf 1400 | glymja 1401 | gólfa þf 1402 | grafa 1403 | grafa þf 1404 | grafa þgf þf # 'að grafa sér gröf' 1405 | grána 1406 | grunda þf 1407 | grundvalla þf 1408 | grýta þf 1409 | grýta þgf 1410 | grýta þgf þf 1411 | gylla þf 1412 | gæsa þf 1413 | hagræða 1414 | hagræða þgf 1415 | hala þf 1416 | hala þgf 1417 | hamast 1418 | harðbanna þf 1419 | harðbanna þgf 1420 | harðbanna þgf þf 1421 | harma þf 1422 | hasla þf 1423 | hasla þgf þf # 'að hasla sér völl' 1424 | hára þf 1425 | heila 1426 | heila þf 1427 | hekla þf 1428 | hekla þgf þf # 'að hekla mér peysu' 1429 | hella þgf 1430 | hernema þf 1431 | herra þf 1432 | hesta þf 1433 | hissa þf 1434 | hjóla 1435 | hjóla þf 1436 | hlaða þf 1437 | hlaða þgf 1438 | hníga 1439 | hóla 1440 | hraða þgf 1441 | hríðfalla 1442 | hríðlækka 1443 | hríðlækka þf 1444 | hrossa þf 1445 | hugga þf 1446 | hvíta þf 1447 | hvolfa 1448 | hvolfa þgf 1449 | hvolpa þf 1450 | hýsa þf 1451 | hæða þf 1452 | ítreka 1453 | ítreka þf 1454 | jafnvægja þf 1455 | jakka þf 1456 | jóla þf 1457 | kappa þf 1458 | keppa 1459 | kíkja 1460 | kjóa þf 1461 | klína þgf 1462 | klúðra 1463 | klúðra þgf 1464 | kolla þf 1465 | kóróna þf 1466 | kría þf 1467 | krossa þf 1468 | krumma þf 1469 | krydda 1470 | krydda þf 1471 | krýna þf 1472 | kveðja 1473 | kveðja þf 1474 | kveikja 1475 | kveikja þf 1476 | kveikja þgf þf # 'að kveikja Páli eldmóð í brjósti" 1477 | kvikna 1478 | kvænast 1479 | kvænast þgf 1480 | kýla 1481 | kýla þf 1482 | lappa 1483 | lappa þf 1484 | látra þf 1485 | leigja 1486 | leigja þgf 1487 | leigja þgf þf 1488 | lista þf 1489 | líkama þf 1490 | ljóma 1491 | ljósprenta þf 1492 | ljúga 1493 | ljúga þf # 'að ljúga Pál fullan' 1494 | ljúga þgf # 'að ljúga einhverju' 1495 | lóa 1496 | lóða 1497 | lunda 1498 | lúðra þf 1499 | lúna þf 1500 | lyfja þf 1501 | lýja þf 1502 | mala 1503 | mala þf 1504 | máta 1505 | máta þf 1506 | menna 1507 | merja þf 1508 | metra þf 1509 | misnota þf 1510 | mosa 1511 | nasa 1512 | náttúra þf 1513 | nostra 1514 | næra þf 1515 | olla 1516 | orka þgf # 'ég orka ekki Fjóni' ('jeg orker ikke Fyn', slagorð Mols-ferjunnar) 1517 | óna 1518 | palla 1519 | pilla þf 1520 | prjóna 1521 | prjóna þf 1522 | prjóna þgf þf 1523 | prófa þf 1524 | punkta þf 1525 | pústa 1526 | pústa þgf 1527 | pynta þf 1528 | rafmagna þf 1529 | ramma þf 1530 | reikna 1531 | reikna þf 1532 | reykja 1533 | reykja þf 1534 | ritstýra þgf 1535 | rjóða þf 1536 | roða þf 1537 | róa þf # 'ég reyndi að róa Pál' 1538 | róa þgf # 'Páll réri bátnum' 1539 | róa þgf þf # 'við ætlum að róa strandleiðina' 1540 | róla 1541 | rústa þgf 1542 | sakna ef 1543 | samanstanda 1544 | samsvara þgf 1545 | sanda þf 1546 | sekta þf 1547 | selta þf 1548 | sérhæfa þf 1549 | sérsmíða þf 1550 | siga þgf 1551 | sía þf 1552 | síga 1553 | síga þf 1554 | sjóða þf 1555 | sjóða þgf þf # 'ég ætla að sjóða mér fiskibollur' 1556 | skalla þf 1557 | skauta 1558 | skauta þf 1559 | skeiða 1560 | skeiða þf 1561 | skemmta 1562 | skemmta þgf 1563 | skeyta þgf 1564 | skota þf 1565 | skóa þf 1566 | skugga þf 1567 | skýja þf 1568 | slapa 1569 | slappa 1570 | slappa þf 1571 | slétta þf 1572 | slæma þgf 1573 | smala 1574 | smala þgf 1575 | smala þgf þf 1576 | smyrja 1577 | smyrja þf 1578 | smyrja þgf 1579 | sniða þf 1580 | sníða þf 1581 | sníða þgf þf # 'að sníða sér stakk eftir vexti' 1582 | sofna 1583 | sopa þf 1584 | sorga þf 1585 | sóla 1586 | sóla þf 1587 | sparka 1588 | sparka þgf 1589 | sparka þgf þf 1590 | spegla þf 1591 | sperra þf 1592 | spræna 1593 | spræna þgf 1594 | staðreyna þf 1595 | stara 1596 | starra þf 1597 | státa 1598 | steina þf 1599 | stella þf 1600 | stilla þf 1601 | stíla þf 1602 | stjóra þgf # ??? 1603 | stokka 1604 | stokka þf 1605 | storka þgf 1606 | stranda 1607 | stranda þgf 1608 | strá þgf 1609 | stuðla 1610 | stuðla þf 1611 | sulla 1612 | sulla þgf 1613 | svarta þf 1614 | svella 1615 | svífa 1616 | sökkva 1617 | sökkva þgf 1618 | sölva þf 1619 | tefja 1620 | tefja þf 1621 | teipa þf 1622 | tifa 1623 | tileinka þgf 1624 | tileinka þgf þf 1625 | tilheyra 1626 | tilheyra þgf 1627 | titla þf 1628 | tjá þf 1629 | tjá þgf þf 1630 | toga 1631 | toga þf 1632 | toppa þf 1633 | trilla þgf 1634 | troða þf # 'ég treð magann fullan af mat' 1635 | troða þgf # 'ég treð tvisti í gatið' 1636 | trylla þf 1637 | túra 1638 | túra þf 1639 | tvímenna 1640 | tvímenna þf 1641 | tvöfalda 1642 | tvöfalda þf 1643 | ulla 1644 | umbera þf 1645 | umbera þgf þf # 'ég umbar honum vitleysuna' 1646 | umbjóða þf 1647 | upplifa 1648 | upplifa þf 1649 | uppskera 1650 | uppskera þf 1651 | útvega þf 1652 | útvega þgf þf 1653 | vaka 1654 | vaka þf # 'við vöktum alla nóttina' 1655 | vella 1656 | verðmeta 1657 | verðmeta þf 1658 | vernda þf 1659 | versla 1660 | versla þf 1661 | versla þgf þf # '?ég verslaði mér reiðhjól' 1662 | vetra 1663 | viðra þf 1664 | vigta þf 1665 | vigta þgf þf # 'ég vigtaði mér nautahakk' 1666 | vikna 1667 | vitna 1668 | vona 1669 | vona þf 1670 | væta 1671 | væta þf 1672 | vökva þf 1673 | yfirlýsa þgf 1674 | þanga 1675 | þarfa þf 1676 | þekja 1677 | þekja þf 1678 | þeyta þf # 'að þeyta rjómann' 1679 | þeyta þgf # 'að þeyta þessu út í hafsauga' 1680 | þrá þf 1681 | þreyta þf 1682 | æða þf 1683 | æja 1684 | 1685 | -------------------------------------------------------------------------------- /database/build-database.js: -------------------------------------------------------------------------------- 1 | var series = require('run-series'); 2 | var populate = require('./populate'); 3 | var simplePopulate = require('./simple-populate'); 4 | var createIndex = require('./create-index'); 5 | 6 | var words = require('./database').words; 7 | 8 | function wordMapper(split) { 9 | var headWord = split[0]; 10 | var binId = split[1]; 11 | var wordClass = split[2]; 12 | var section = split[3]; 13 | var form = split[4]; 14 | var grammarTag = split[5]; 15 | 16 | return { 17 | headWord, 18 | binId: parseInt(binId, 10), 19 | wordClass, 20 | section, 21 | form, 22 | grammarTag, 23 | } 24 | } 25 | 26 | function lemmaMapper(line) { 27 | return wordMapper(line.split(';')); 28 | } 29 | 30 | function getForm(data) { 31 | var forms = data.value.forms ? data.value.forms.map(x => x.form) : [data.value.headWord] 32 | return forms.map(form => form.toLowerCase()) 33 | } 34 | 35 | function uninflectableMapper(line) { 36 | var split = line.split(' ') 37 | var form = split[0] 38 | var wordClasses = split.slice(1) 39 | 40 | return wordClasses.map(wordClass => ({ 41 | headWord: form, 42 | binId: form + '~' + wordClass, 43 | wordClass: wordClass, 44 | section: 'obeyg' 45 | })) 46 | } 47 | 48 | series([ 49 | (cb) => simplePopulate('data/obeyg.smaord.txt', uninflectableMapper, cb), 50 | (cb) => populate('data/spurnarmyndir.csv', lemmaMapper, cb), 51 | (cb) => populate('data/plastur.csv', lemmaMapper, cb), 52 | (cb) => populate('data/SHsnid.csv', lemmaMapper, cb), 53 | (cb) => createIndex(words, 'form', getForm, cb) 54 | ], function(err, results) { 55 | if (err) console.log(err) 56 | }) 57 | -------------------------------------------------------------------------------- /database/create-index.js: -------------------------------------------------------------------------------- 1 | var index = require('./database').index 2 | var separator = '|' 3 | 4 | function createIndex(db, indexName, fn, cb) { 5 | console.log('creating indexes...') 6 | 7 | db.createReadStream() 8 | .on('data', function(data) { 9 | var keys = fn(data).map(value => [indexName, value, data.key].join(separator)) 10 | 11 | index.batch(keys.map(key => ({ type: 'put', key: key})), function(err) { 12 | if (err) cb(err) 13 | }) 14 | }) 15 | .on('error', function(err) { 16 | cb(err) 17 | }) 18 | .on('end', function() { 19 | cb() 20 | }) 21 | } 22 | 23 | module.exports = createIndex 24 | -------------------------------------------------------------------------------- /database/database.js: -------------------------------------------------------------------------------- 1 | var levelup = require('levelup'); 2 | var path = require('path'); 3 | var sublevel = require('level-sublevel'); 4 | 5 | var db = sublevel(levelup(path.join(__dirname, '../db'), { 6 | valueEncoding: 'json', 7 | })) 8 | 9 | module.exports = { 10 | index: db.sublevel('index'), 11 | words: db.sublevel('words'), 12 | } 13 | -------------------------------------------------------------------------------- /database/get-by.js: -------------------------------------------------------------------------------- 1 | var index = require('./database').index; 2 | var _ = require('lodash'); 3 | 4 | var separator = '|'; 5 | 6 | function getBy(indexName, value, cb) { 7 | var gt = [indexName, value, ''].join(separator) 8 | var lt = [indexName, value, '\xff'].join(separator) 9 | 10 | var results = []; 11 | 12 | index.createReadStream({ 13 | gt, 14 | lt, 15 | values: false, 16 | fillCache: true, 17 | }) 18 | .on('data', function (data) { 19 | results.push(data.split(separator).slice(-1)[0]) 20 | }) 21 | .on('error', function (err) { 22 | cb(err) 23 | }) 24 | .on('end', function () { 25 | cb(null, _.uniq(results)) 26 | }) 27 | } 28 | 29 | module.exports = getBy; 30 | -------------------------------------------------------------------------------- /database/populate.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var LineByLineReader = require('line-by-line'); 3 | var words = require('./database').words; 4 | 5 | var wordBuffer = []; 6 | var batchBuffer = []; 7 | 8 | var currentId; 9 | var total = 286286; 10 | var batchSize = 1000; 11 | var count = 0; 12 | 13 | function collect(words) { 14 | var first = words[0] 15 | 16 | return { 17 | headWord: first.headWord, 18 | binId: first.binId, 19 | wordClass: first.wordClass, 20 | section: first.section, 21 | forms: words.map(x => ({form: x.form, grammarTag: x.grammarTag})) 22 | } 23 | } 24 | 25 | function populate(path, mapper, cb) { 26 | var input = new LineByLineReader(path); 27 | 28 | input.on('line', function(data) { 29 | var word = mapper(data); 30 | 31 | if (!currentId) { 32 | currentId = word.binId 33 | } 34 | 35 | if (word.binId === currentId) { 36 | wordBuffer.push(word) 37 | } else { 38 | var entry = collect(wordBuffer); 39 | batchBuffer.push({ 40 | type: 'put', 41 | key: entry.binId, 42 | value: entry 43 | }) 44 | 45 | if (batchBuffer.length > batchSize) { 46 | input.pause(); 47 | words.batch(batchBuffer, function(err) { 48 | if (err) cb(err) 49 | count += batchBuffer.length 50 | console.log(`${count}/${total} = ${Math.round(count/total*100)}%`) 51 | batchBuffer = []; 52 | input.resume(); 53 | }) 54 | } 55 | 56 | wordBuffer = []; 57 | wordBuffer.push(word); 58 | currentId = word.binId; 59 | } 60 | }); 61 | 62 | input.on('error', function(err) { 63 | cb(err) 64 | }); 65 | 66 | input.on('end', function() { 67 | var entry = collect(wordBuffer); 68 | batchBuffer.push({ 69 | type: 'put', 70 | key: entry.binId, 71 | value: entry 72 | }) 73 | 74 | words.batch(batchBuffer, function(err) { 75 | cb(err) 76 | }) 77 | }); 78 | } 79 | 80 | module.exports = populate; 81 | -------------------------------------------------------------------------------- /database/query.js: -------------------------------------------------------------------------------- 1 | var words = require('./database').words; 2 | var getBy = require('./get-by'); 3 | 4 | var query = process.argv[2] 5 | 6 | getBy('form', query, function(err, result) { 7 | result.forEach(result => { 8 | words.get(result, console.log) 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /database/simple-populate.js: -------------------------------------------------------------------------------- 1 | var LineByLineReader = require('line-by-line'); 2 | var _ = require('lodash'); 3 | var words = require('./database').words; 4 | 5 | function populate(path, mapper, cb) { 6 | var input = new LineByLineReader(path, { 7 | skipEmptyLines: true, 8 | start: 39 9 | }); 10 | 11 | var buffer = [] 12 | 13 | input.on('line', function(data) { 14 | buffer.push(mapper(data)) 15 | }); 16 | 17 | input.on('error', function(err) { 18 | cb(err); 19 | }); 20 | 21 | input.on('end', function() { 22 | var all = _.flatten(buffer).map(entry => ({ 23 | type: 'put', 24 | key: entry.binId, 25 | value: entry 26 | })); 27 | 28 | words.batch(all, function(err) { 29 | cb(err); 30 | }); 31 | }); 32 | } 33 | 34 | module.exports = populate; 35 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | docker build -t davidblurton/tala-api . && docker push davidblurton/tala-api 2 | -------------------------------------------------------------------------------- /error.js: -------------------------------------------------------------------------------- 1 | export default function errorHandler(err, req, res, next) { 2 | req.log.debug(err) 3 | res.status(500).json({ error: err }) 4 | } 5 | -------------------------------------------------------------------------------- /filters/adjectives.js: -------------------------------------------------------------------------------- 1 | import {parse} from '../grammar/parser' 2 | 3 | function isNoun(word) { 4 | return ['hk', 'kvk', 'kk'].includes(word.wordClass) 5 | } 6 | 7 | function isAdjective(word) { 8 | return word.wordClass === 'lo' 9 | } 10 | 11 | function getTags(nouns, degree) { 12 | 13 | let results = { 14 | 'F': getTags(nouns, 'F'), 15 | 'MST': getTags(nouns, 'MST'), 16 | } 17 | 18 | 19 | 20 | //'E': getTags(nouns, 'E') 21 | 22 | return nouns.map(noun => { 23 | let parsed = parse(noun.wordClass, noun.grammarTag) 24 | let definite 25 | 26 | if (degree.length === 1) { 27 | definite = degree + (parsed.article ? 'VB' : 'SB') 28 | } else { 29 | definite = degree 30 | } 31 | 32 | return `${definite}-${noun.wordClass.toUpperCase()}-${parsed.grammarCase}${parsed.number}` 33 | }) 34 | } 35 | 36 | function getDeterminerTags(nouns) { 37 | return { 38 | 'determiner': nouns.map(noun => { 39 | let parsed = parse(noun.wordClass, noun.grammarTag) 40 | return `${noun.wordClass.toUpperCase()}-${parsed.grammarCase}${parsed.number}` 41 | }) 42 | } 43 | } 44 | 45 | export default (words, hasDegree) => { 46 | let nouns = words.filter(isNoun) 47 | 48 | if (hasDegree) { 49 | return { 50 | wordClass: 'lo', 51 | grammarTag: { 52 | 'F': getTags(nouns, 'F'), 53 | 'MST': getTags(nouns, 'MST'), 54 | 'E': getTags(nouns, 'E') 55 | } 56 | } 57 | } else { 58 | return { 59 | wordClass: 'lo', 60 | grammarTag: { 61 | 'determiner': getDeterminerTags(nouns) 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /filters/prepositions.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | import {parse, toString} from '../grammar/parser' 3 | import {findVerbs} from '../controllers/declensions' 4 | import lookupVerb from '../models/static' 5 | 6 | const supportedClasses = ['hk', 'kk', 'kvk', 'to', 'pfn'] 7 | 8 | const prepositions = { 9 | // Accusative 10 | 'fyrir ofan': 'ÞF', 11 | 'gegnum': 'ÞF', 12 | 'kringum': 'ÞF', 13 | 'um': 'ÞF', 14 | 'umfram': 'ÞF', 15 | 'umhverfis': 'ÞF', 16 | 17 | // Dative 18 | 'að': 'ÞGF', 19 | 'af': 'ÞGF', 20 | 'andspænis': 'ÞGF', 21 | 'ásamt': 'ÞGF', 22 | 'frá': 'ÞGF', 23 | 'gagn': 'ÞGF', 24 | 'gagnvart': 'ÞGF', 25 | 'gegnt': 'ÞGF', 26 | 'handa': 'ÞGF', 27 | 'hjá': 'ÞGF', 28 | 'meðfram': 'ÞGF', 29 | 'mót': 'ÞGF', 30 | 'móti': 'ÞGF', 31 | 'nálægt': 'ÞGF', 32 | 'undan': 'ÞGF', 33 | 'úr': 'ÞGF', 34 | 35 | // Genitive 36 | 'án': 'EF', 37 | 'auk': 'EF', 38 | 'austan': 'EF', 39 | 'innan': 'EF', 40 | 'í staö': 'EF', 41 | 'meðal': 'EF', 42 | 'megin': 'EF', 43 | 'milli': 'EF', 44 | 'millum': 'EF', 45 | 'neðan': 'EF', 46 | 'norðan': 'EF', 47 | 'ofan': 'EF', 48 | 'sakir': 'EF', 49 | 'sunnan': 'EF', 50 | 'sökum': 'EF', 51 | 'til': 'EF', 52 | 'utan': 'EF', 53 | 'vegna': 'EF', 54 | 'vestan': 'EF', 55 | 56 | // Accusative or dative 57 | 'á': ['ÞF', 'ÞGF'], 58 | 'eftir': ['ÞF', 'ÞGF'], 59 | 'fyrir': ['ÞF', 'ÞGF'], 60 | 'í': ['ÞF', 'ÞGF'], 61 | 'með': ['ÞF', 'ÞGF'], 62 | 'undir': ['ÞF', 'ÞGF'], 63 | 'við': ['ÞF', 'ÞGF'], 64 | 'yfir': ['ÞF', 'ÞGF'], 65 | } 66 | 67 | function getCombinations(queries, words) { 68 | return _(queries).map(query => words.map(word => [query, word])).flatten().value() 69 | } 70 | 71 | function fixGrammar({modifier, cases}, word) { 72 | if (!Array.isArray(cases)) { 73 | cases = [cases] 74 | } 75 | 76 | let parsed = parse(word.wordClass, word.grammarTag) 77 | 78 | return cases.map(grammarCase => { 79 | let res = {} 80 | 81 | res.wordClass = word.wordClass 82 | res.binId = word.binId 83 | res.grammarTag = {} 84 | 85 | parsed.grammarCase = grammarCase 86 | res.grammarTag[grammarCase] = toString(word.wordClass, parsed) 87 | return res 88 | }) 89 | } 90 | 91 | export default async function(query, words) { 92 | let queries = [] 93 | 94 | if (prepositions[query]) { 95 | queries.push({modifier: query, cases: prepositions[query]}) 96 | } 97 | 98 | let verbs = await findVerbs(query) 99 | let verbCases = Promise.all(verbs.map(lookupVerb)) 100 | queries.push(... _.zip(verbs, verbCases).filter(([, cases]) => cases).map(([verb, cases]) => { 101 | return {modifier: verb, cases: cases} 102 | })) 103 | 104 | words = words.filter(word => supportedClasses.includes(word.wordClass)) 105 | 106 | const combinations = getCombinations(queries, words) 107 | 108 | return _.flatten(combinations.map(combination => fixGrammar(...combination))) 109 | } 110 | -------------------------------------------------------------------------------- /filters/verbs.js: -------------------------------------------------------------------------------- 1 | const filters = { 2 | 'ég': { 3 | wordClass: 'so', 4 | grammarTag: { 5 | 'NT': 'GM-FH-NT-1P-ET', 6 | 'ÞT': 'GM-FH-ÞT-1P-ET', 7 | } 8 | }, 9 | 'þú': { 10 | wordClass: 'so', 11 | grammarTag: { 12 | 'NT': 'GM-FH-NT-2P-ET', 13 | 'ÞT': 'GM-FH-ÞT-2P-ET', 14 | } 15 | }, 16 | 'hann': { 17 | wordClass: 'so', 18 | grammarTag: { 19 | 'NT': 'GM-FH-NT-3P-ET', 20 | 'ÞT': 'GM-FH-ÞT-3P-ET', 21 | } 22 | }, 23 | 'hún': { 24 | wordClass: 'so', 25 | grammarTag: { 26 | 'NT': 'GM-FH-NT-3P-ET', 27 | 'ÞT': 'GM-FH-ÞT-3P-ET' 28 | } 29 | }, 30 | 'það': { 31 | wordClass: 'so', 32 | grammarTag: { 33 | 'NT': 'GM-FH-NT-3P-ET', 34 | 'ÞT': 'GM-FH-ÞT-3P-ET' 35 | } 36 | }, 37 | 'við': { 38 | wordClass: 'so', 39 | grammarTag: { 40 | 'NT': 'GM-FH-NT-1P-FT', 41 | 'ÞT': 'GM-FH-ÞT-1P-FT' 42 | 43 | } 44 | }, 45 | 'þið': { 46 | wordClass: 'so', 47 | grammarTag: { 48 | 'NT': 'GM-FH-NT-2P-FT', 49 | 'ÞT': 'GM-FH-ÞT-2P-FT' 50 | } 51 | }, 52 | 'þeir': { 53 | wordClass: 'so', 54 | grammarTag: { 55 | 'NT': 'GM-FH-NT-3P-FT', 56 | 'ÞT': 'GM-FH-ÞT-3P-FT' 57 | } 58 | }, 59 | 'þær': { 60 | wordClass: 'so', 61 | grammarTag: { 62 | 'NT': 'GM-FH-NT-3P-FT', 63 | 'ÞT': 'GM-FH-ÞT-3P-FT' 64 | } 65 | }, 66 | 'þau': { 67 | wordClass: 'so', 68 | grammarTag: { 69 | 'NT': 'GM-FH-NT-3P-FT', 70 | 'ÞT': 'GM-FH-ÞT-3P-FT' 71 | } 72 | }, 73 | } 74 | 75 | let getFilters = query => { 76 | return filters[query.toLowerCase()] 77 | } 78 | 79 | export default getFilters 80 | -------------------------------------------------------------------------------- /formatters/adjective.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | import translate from '../translate/translate' 3 | 4 | export default (results, query, lang) => { 5 | let formattedResults = _.mapValues(results, x => `${x.wordForm} ${query}`) 6 | 7 | return { 8 | query: query, 9 | results: lang ? translate(formattedResults, lang) : formattedResults, 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /formatters/preposition.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | 3 | export default (results, keyword) => { 4 | return _.chain(results) 5 | .sortBy('grammarTag') 6 | .filter(x => x.wordForm) 7 | .map(x => `${keyword} ${x.wordForm}`) 8 | .value() 9 | } 10 | -------------------------------------------------------------------------------- /formatters/summary.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | import translate from '../translate/translate' 3 | 4 | export default (results, query, lang) => { 5 | if (!Array.isArray(results)) { 6 | results = [results] 7 | } 8 | 9 | let formattedResults = results.map(result => _.mapValues(result, x => `${query} ${x.wordForm}`)) 10 | 11 | return { 12 | query: query, 13 | results: lang ? translate(formattedResults, lang) : formattedResults, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /formatters/word.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | import {parse} from '../grammar/parser' 3 | import lookup from '../translate/translate.json' 4 | 5 | function sort(result) { 6 | return _.sortBy(result.forms, x => { 7 | let caseRank = { 8 | NF: 1, 9 | ÞF: 2, 10 | ÞGF: 3, 11 | EF: 4, 12 | } 13 | 14 | let personRank = { 15 | '1P-ET': 1, 16 | '2P-ET': 2, 17 | '3P-ET': 3, 18 | '1P-FT': 4, 19 | '2P-FT': 5, 20 | '3P-FT': 6, 21 | } 22 | 23 | let numberRank = { 24 | 'ET': 1, 25 | 'FT': 2, 26 | } 27 | 28 | return caseRank[x.tags && x.tags.grammarCase] || 29 | personRank[Object.keys(personRank).filter(person => x.grammarTag.includes(person))[0]] || 30 | numberRank[x.tags && x.tags.number] 31 | }) 32 | } 33 | 34 | function translateTags(tags, language) { 35 | return _.mapValues(tags, tag => lookup[language].grammarTag[tag] || tag) 36 | } 37 | 38 | function translateWordClass(wordClass, language) { 39 | return lookup[language].wordClass[wordClass] 40 | } 41 | 42 | function translate(result, lang) { 43 | result.forms && result.forms.forEach(form => { 44 | form.tags = lang ? translateTags(form.tags, lang) : form.tags 45 | }) 46 | 47 | result.wordClass = lang ? translateWordClass(result.wordClass, lang) : result.wordClass 48 | return result 49 | } 50 | 51 | function tag(result) { 52 | if (!result.forms) { 53 | return result 54 | } 55 | 56 | result.forms.forEach(form => { 57 | try { 58 | form.tags = parse(result.wordClass, form.grammarTag) 59 | } catch (e) { 60 | console.log(e) 61 | form.tags = {} 62 | } 63 | }) 64 | 65 | result.forms = sort(result) 66 | return result 67 | } 68 | 69 | export default function(results, lang) { 70 | if (!Array.isArray(results)) { 71 | results = [results] 72 | } 73 | 74 | return results 75 | .map(result => tag(result)) 76 | .map(result => translate(result, lang)) 77 | } 78 | 79 | -------------------------------------------------------------------------------- /grammar/parsed.js: -------------------------------------------------------------------------------- 1 | import traverse from 'traverse' 2 | 3 | function parseJson(s) { 4 | if (s.indexOf('"{*SUBJ"') !== s.lastIndexOf('"{*SUBJ"')) { 5 | let pos = s.lastIndexOf('"{*SUBJ"') + 7 6 | s = s.substring(0, pos) + '2' + s.substring(pos) 7 | } 8 | 9 | try { 10 | return JSON.parse(s) 11 | } catch (e) { 12 | console.log('Failed to parse', s) 13 | return JSON.parse(s) 14 | } 15 | } 16 | 17 | function formatWords(words) { 18 | return { 19 | word: Object.keys(words)[0], 20 | tag: Object.values(words)[0], 21 | } 22 | } 23 | 24 | function getWord(part) { 25 | if (!part) return null 26 | 27 | let result 28 | 29 | traverse(part).forEach(function(value) { 30 | if (this.key === 'WORDS') { 31 | result = value[0] 32 | } 33 | }) 34 | 35 | return formatWords(result) 36 | } 37 | 38 | function getWords(part) { 39 | if (!part) return null 40 | 41 | let results = [] 42 | 43 | traverse(part).forEach(function(value) { 44 | if (this.key === 'WORDS') { 45 | results.push(value) 46 | } 47 | }) 48 | 49 | return results.map(word => formatWords(word[0])) 50 | } 51 | 52 | export function structure(jsonString) { 53 | let parsed = parseJson(jsonString) 54 | 55 | let sentence = parsed['Parsed Text']['Sentence'] 56 | let subject = getWord(sentence['{*SUBJ>'] || sentence['{*SUBJ']) 57 | let verb = getWord(sentence['[VPi'] || sentence['[VP'] || sentence['[VP?Vn?']) 58 | let object = getWord(sentence['{*OBJ<'] || sentence['{*SUBJ2'] || sentence['[AP']) 59 | 60 | let prepositionPhrase = getWords(sentence['[PP'] || sentence['[PP?Pca?'] || sentence['[AdvP']) 61 | 62 | let preposition = prepositionPhrase && prepositionPhrase[0] 63 | let prepositionObject = prepositionPhrase && prepositionPhrase[1] || getWord(sentence['{*SUBJ']) 64 | 65 | return {subject, verb, object, preposition, prepositionObject} 66 | } 67 | 68 | export function headwordFromTagged(tokenized, tagged, word) { 69 | let index = tokenized.indexOf(word) 70 | let headwordMatch = /\((.*)\)/.exec(tagged[index]) 71 | return headwordMatch && headwordMatch[1] 72 | } 73 | -------------------------------------------------------------------------------- /grammar/parser.js: -------------------------------------------------------------------------------- 1 | function isNoun(wordClass) { 2 | return wordClass === 'hk' || 3 | wordClass === 'kk' || 4 | wordClass === 'kvk' 5 | } 6 | 7 | const featuresMap = { 8 | // Nouns 9 | 'hk': ['grammarCase', 'number', 'article', 'gender'], 10 | 'kk': ['grammarCase', 'number', 'article', 'gender'], 11 | 'kvk': ['grammarCase', 'number', 'article', 'gender'], 12 | // Numeral 13 | 'to': ['grammarCase', 'gender', 'number'], 14 | // Pronoun 15 | 'pfn': ['grammarCase', 'gender', 'number'], 16 | // Adjective 17 | 'lo': ['grammarCase', 'gender', 'number', 'degree', 'article'], 18 | // Verb 19 | 'so': ['person', 'number', 'tense', 'voice', 'mood', 'impersonal', 'pronoun'], 20 | // Other pronoun 21 | 'fn': ['grammarCase', 'gender', 'number'], 22 | // Adverb 23 | 'ao': ['degree'], 24 | } 25 | 26 | const parser = { 27 | grammarCase(tag) { 28 | return ['NF', 'ÞF', 'ÞGF', 'EF'].filter(x => tag.includes(x))[0] 29 | }, 30 | 31 | gender(tag, wordClass) { 32 | if (isNoun(wordClass)) { 33 | return wordClass.toUpperCase() 34 | } 35 | 36 | return ['KK', 'KVK', 'HK'].filter(x => tag.includes(x))[0] 37 | }, 38 | 39 | number(tag) { 40 | return ['ET', 'FT'].filter(x => tag.includes(x))[0] 41 | }, 42 | 43 | definite(tag) { 44 | return ['ESB', 'EVB', 'FSB', 'FVB', 'MST'].filter(x => tag.includes(x))[0] 45 | }, 46 | 47 | article(tag, wordClass) { 48 | if (isNoun(wordClass)) { 49 | if (tag.includes('gr')) { 50 | return 'gr' 51 | } else { 52 | return '' 53 | } 54 | } else { 55 | if (['EVB', 'FVB'].filter(x => tag.includes(x)).length) { 56 | return 'gr' 57 | } else if (['ESB', 'FSB'].filter(x => tag.includes(x)).length) { 58 | return '' 59 | } else { 60 | return null 61 | } 62 | } 63 | }, 64 | 65 | person(tag) { 66 | return ['1P', '2P', '3P'].filter(x => tag.includes(x))[0] 67 | }, 68 | 69 | tense(tag) { 70 | return ['NT', 'ÞT'].filter(x => tag.includes(x))[0] 71 | }, 72 | 73 | voice(tag) { 74 | return ['GM', 'MM', 'OP'].filter(x => tag.includes(x))[0] 75 | }, 76 | 77 | mood(tag) { 78 | return ['FH', 'VH'].filter(x => tag.includes(x))[0] 79 | }, 80 | 81 | impersonal(tag) { 82 | return ['OP'].filter(x => tag.includes(x))[0] 83 | }, 84 | 85 | pronoun(tag) { 86 | return ['FN'].filter(x => tag.includes(x))[0] 87 | }, 88 | 89 | degree(tag) { 90 | return ['FST', 'FSB', 'FVB', 'MST', 'EST', 'ESB', 'EVB'].filter(x => tag.includes(x))[0] 91 | }, 92 | } 93 | 94 | export function toString(wordClass, tags) { 95 | if (isNoun(wordClass)) { 96 | let {grammarCase, number, article} = tags 97 | return grammarCase + number + article 98 | } 99 | 100 | if (wordClass === 'to') { 101 | let {gender, grammarCase, number} = tags 102 | return `${gender}_${grammarCase}${number}` 103 | } 104 | 105 | if (wordClass === 'pfn') { 106 | let {grammarCase, number} = tags 107 | return grammarCase + number 108 | } 109 | 110 | if (wordClass === 'lo') { 111 | let {degree, gender, grammarCase, number} = tags 112 | return `${degree}-${gender}-${grammarCase}${number}` 113 | } 114 | } 115 | 116 | export function parse(wordClass, grammarTag) { 117 | let features = featuresMap[wordClass] 118 | 119 | if (!features) { 120 | throw new Error(`Unsupported word class: ${wordClass}`) 121 | } 122 | 123 | var result = {} 124 | 125 | features.forEach(x => { 126 | result[x] = parser[x].call(null, grammarTag, wordClass) 127 | }) 128 | 129 | return result 130 | } 131 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | require('babel-register') 2 | require('./server') 3 | -------------------------------------------------------------------------------- /middleware/response-time.js: -------------------------------------------------------------------------------- 1 | import responseTime from 'response-time' 2 | import StatsD from 'node-statsd' 3 | 4 | // let stats = new StatsD({ 5 | // host: 'stats.tala.is', 6 | // }) 7 | 8 | export default responseTime((req, res, time) => { 9 | try { 10 | let stat = (req.method + req.route.path).toLowerCase() 11 | .replace(/[:\.]/g, '') 12 | .replace(/\//g, '_') 13 | // stats.timing(stat, time) 14 | } catch (err) { 15 | console.log(err) 16 | } 17 | }) 18 | -------------------------------------------------------------------------------- /models.json: -------------------------------------------------------------------------------- 1 | // result 2 | { 3 | tokenized: [] 4 | parsed: [] 5 | tagged: [] 6 | corrections: [] 7 | suggestions: [] 8 | } 9 | 10 | // correction 11 | 12 | { 13 | rule: 14 | index: 15 | replacements: 16 | modifier: 17 | modified: [] 18 | } 19 | 20 | // filter 21 | { 22 | wordClass: [] 23 | grammarTags: [] 24 | } 25 | 26 | // structure 27 | // Entry for each rule with modifier and targets 28 | { 29 | subjectVerbAgreement: { 30 | modifier: subject 31 | targets: [verb] 32 | } 33 | verbObjectAgreement: { 34 | modifier: verb 35 | targets: 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /models/concat-stream-promise.js: -------------------------------------------------------------------------------- 1 | import concat from 'concat-stream' 2 | 3 | export default stream => new Promise((resolve, reject) => { 4 | stream.on('error', reject) 5 | stream.pipe(concat({ 6 | encoding: 'object' 7 | }, resolve)) 8 | }) 9 | -------------------------------------------------------------------------------- /models/icenlp.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | let lookup = async function(query) { 4 | let res = await axios({ 5 | url: 'http://nlp.cs.ru.is/IceNLPWebService/', 6 | method: 'get', 7 | params: { 8 | mode: 'icenlp', 9 | parsing: true, 10 | tokenize: true, 11 | query: query, 12 | lemma: true, 13 | output: 'json', 14 | errors: true, 15 | functions: true, 16 | agreement: true, 17 | mergelabels: false, 18 | markunknown: true, 19 | inputtokenize: 2, 20 | tagging: true, 21 | tagger: 'hmmicehmm', 22 | }, 23 | }) 24 | 25 | let lines = res.data.split(/^\s*$[\n\r]{1,}/gm) 26 | 27 | let tokenized = lines[0].trim().split(' ') 28 | let tagged = lines[1].trim().split(/\n/) 29 | let parsed = lines[2].trim() 30 | 31 | return {tokenized, tagged, parsed} 32 | } 33 | 34 | export default lookup 35 | -------------------------------------------------------------------------------- /models/static.js: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs' 2 | import Promise from 'prfun' 3 | 4 | const readFile = Promise.promisify(fs.readFile) 5 | 6 | async function parseStatic() { 7 | const data = await readFile('data/verbs.conf', 'utf8') 8 | const results = {} 9 | 10 | for (let line of data.split(/[\r\n]+/)) { 11 | line = line.replace(/\s*(#.*)?$/, '') 12 | const [verb, ...cases] = line.split(/\s+/) 13 | 14 | // Only support simple verb>noun sentances for now. 15 | if (cases.length !== 1) { 16 | continue 17 | } 18 | 19 | if (!results[verb]) { 20 | results[verb] = [] 21 | } 22 | // Verb controls cases 23 | results[verb].push(cases[0].toUpperCase()) 24 | } 25 | 26 | return results 27 | } 28 | 29 | const DATA_PROMISE = parseStatic() 30 | 31 | async function lookup(verb) { 32 | const data = await DATA_PROMISE 33 | return data[verb] 34 | } 35 | 36 | export default lookup 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "icelandic-api", 3 | "version": "0.0.1", 4 | "description": "An api for exploring icelandic grammar", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "forever --minUptime 1000 --spinSleepTime 1000 index.js", 8 | "test": "mocha --require babel-core/register --require babel-polyfill --recursive ./test/parser -s 10", 9 | "lint": "jshint --exclude ./node_modules . || true && eslint .", 10 | "style": "eslint .", 11 | "deploy": "./deploy.sh", 12 | "build-database": "rm -rf db && node ./database/build-database" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/davidblurton/icelandic-api" 17 | }, 18 | "author": "David Blurton", 19 | "license": "ISC", 20 | "dependencies": { 21 | "axios": "^0.5.4", 22 | "babel-plugin-transform-regenerator": "^6.4.4", 23 | "babel-plugin-transform-runtime": "^6.4.3", 24 | "babel-polyfill": "^6.3.14", 25 | "babel-preset-node5": "^10.5.0", 26 | "babel-preset-stage-0": "^6.3.13", 27 | "compression": "^1.6.1", 28 | "concat-stream": "^1.5.0", 29 | "cors": "^2.7.1", 30 | "express": "^4.13.1", 31 | "express-bunyan-logger": "^1.1.1", 32 | "forever": "^0.15.1", 33 | "level-sublevel": "^6.5.4", 34 | "leveldown": "^1.4.4", 35 | "levelup": "^1.3.1", 36 | "line-by-line": "^0.1.4", 37 | "lodash": "^4.5.0", 38 | "node-statsd": "^0.1.1", 39 | "nodehun": "^2.0.8", 40 | "prfun": "^2.1.1", 41 | "response-time": "^2.3.1", 42 | "run-series": "^1.1.4", 43 | "traverse": "^0.6.6" 44 | }, 45 | "devDependencies": { 46 | "babel-core": "^6.4.5", 47 | "babel-eslint": "^4.1.3", 48 | "babel-register": "^6.4.3", 49 | "eslint": "^1.5.0", 50 | "eslint-config-airbnb": "0.0.8", 51 | "eslint-plugin-babel": "^2.1.1", 52 | "jscs": "^1.13.1", 53 | "mocha": "^2.2.5" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /routes/declensions.js: -------------------------------------------------------------------------------- 1 | import { Router } from 'express' 2 | import { find, findById } from '../controllers/declensions' 3 | import format from '../formatters/word' 4 | 5 | let router = new Router() 6 | 7 | router.get('/find/:word', (req, res, next) => { 8 | find(req.params.word) 9 | .then(results => format(results, req.query.lang)) 10 | .then(results => res.send(results)) 11 | .catch(next) 12 | }) 13 | 14 | router.get('/id/:id', (req, res, next) => { 15 | findById(req.params.id) 16 | .then(results => format(results, req.query.lang)) 17 | .then(results => res.send(results)) 18 | .catch(next) 19 | }) 20 | 21 | export default router 22 | -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | import Router from 'express' 2 | let router = new Router() 3 | 4 | router.get('/', (req, res) => res.send('tala api running')) 5 | 6 | router.get('/loaderio-f7ba020fa41e103dcd582cda31797ceb', (req, res) => res.send('loaderio-f7ba020fa41e103dcd582cda31797ceb')) 7 | 8 | export default router 9 | -------------------------------------------------------------------------------- /routes/sentence.js: -------------------------------------------------------------------------------- 1 | import { Router } from 'express' 2 | import controller from '../controllers/sentence' 3 | 4 | let router = new Router() 5 | 6 | router.get('/sentence', (req, res, next) => { 7 | let sentence = req.query.q 8 | 9 | if (!sentence) { 10 | res.sendStatus(400, 'You should send a sentence with the query parameter q') 11 | } 12 | 13 | controller.sentence(sentence).then(results => { 14 | if (process.env.NODE_ENV === 'production') { 15 | req.log.info(results) 16 | } 17 | 18 | res.json(results) 19 | }, next) 20 | }) 21 | 22 | export default router 23 | -------------------------------------------------------------------------------- /routes/suggestions.js: -------------------------------------------------------------------------------- 1 | import { Router } from 'express' 2 | import { suggestions } from '../controllers/suggestions' 3 | 4 | let router = new Router() 5 | 6 | router.get('/suggestions/:word', (req, res, next) => { 7 | suggestions(req.params.word) 8 | .then(results => res.json(results), next) 9 | }) 10 | 11 | export default router 12 | -------------------------------------------------------------------------------- /rules/helpers.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | 3 | function uniqueWords(words) { 4 | return _.uniq(words, w => w.binId) 5 | } 6 | 7 | function getDirectedCase(results) { 8 | let caseTags = results.map(r => Object.keys(r)) 9 | 10 | let cases = { 11 | 'NF': 'nominative', 12 | 'ÞF': 'accusative', 13 | 'ÞGF': 'dative', 14 | 'EF': 'genitive', 15 | } 16 | 17 | return caseTags.map(caseTag => cases[caseTag]).join(' or ') 18 | } 19 | 20 | export default {uniqueWords, getDirectedCase} 21 | -------------------------------------------------------------------------------- /rules/index.js: -------------------------------------------------------------------------------- 1 | export {preposition} from './preposition' 2 | export {verbObject} from './verbObject' 3 | export {verb} from './verb' 4 | -------------------------------------------------------------------------------- /rules/preposition.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | import declensions from '../controllers/declensions' 3 | import {headwordFromTagged} from '../grammar/parsed' 4 | import getPrepositionFilters from '../filters/prepositions' 5 | import {uniqueWords, getDirectedCase} from './helpers' 6 | 7 | export default async function (tokenized, parts, tagged) { 8 | if (!parts.preposition || !parts.prepositionObject) { 9 | return false 10 | } 11 | 12 | let preposition = parts.preposition.word 13 | let object = parts.prepositionObject.word 14 | 15 | let headWord = headwordFromTagged(tokenized, tagged, object) 16 | let nouns = uniqueWords(await declensions.find(object)).filter(x => x.headWord === headWord) 17 | let results = await declensions.related(object) 18 | let filters = await getPrepositionFilters(preposition, nouns) 19 | 20 | let res = filters.map(filter => { 21 | let {grammarTag} = filter 22 | return _.mapValues(grammarTag, tag => results.filter(x => x.binId === filter.binId && x.grammarTag === tag)[0]) 23 | }) 24 | 25 | let replacements = _(res.map(word => Object.values(word).map(x => x.wordForm))).flatten().unique().value() 26 | 27 | return { 28 | rule: 'object should agree with preposition', 29 | explanation: `${preposition} directs the ${getDirectedCase(res)} case`, 30 | modifierIndex: tokenized.indexOf(preposition), 31 | targetIndex: tokenized.indexOf(object), 32 | replacements, 33 | isCorrect: replacements.includes(object), 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /rules/verb.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | import declensions from '../controllers/declensions' 3 | import getVerbFilters from '../filters/verbs' 4 | 5 | export async function verb(tokenized, parts) { 6 | if (!parts.subject || !parts.verb) { 7 | return false 8 | } 9 | 10 | let modifier = parts.subject.word 11 | let verb = parts.verb.word 12 | 13 | let results = await declensions.related(verb) 14 | 15 | let {grammarTag} = getVerbFilters(modifier) 16 | 17 | let corrected = _.mapValues(grammarTag, tag => results.filter(x => x.grammarTag === tag)[0]) 18 | 19 | let replacements = Object.values(_.mapValues(corrected, x => x.form)) 20 | let isCorrect = replacements.includes(verb) 21 | 22 | return { 23 | rule: `verb ${isCorrect ? 'agrees' : 'should agree'} with subject`, 24 | modifierIndex: tokenized.indexOf(modifier), 25 | targetIndex: tokenized.indexOf(verb), 26 | replacements, 27 | isCorrect, 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /rules/verbObject.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | import declensions from '../controllers/declensions' 3 | import getPrepositionFilters from '../filters/prepositions' 4 | import {uniqueWords, getDirectedCase} from './helpers' 5 | 6 | export default async function (tokenized, parts) { 7 | if (!parts.object || !parts.verb) { 8 | return false 9 | } 10 | 11 | let verb = parts.verb.word 12 | let object = parts.object.word 13 | 14 | let nouns = uniqueWords(await declensions.find(object)) 15 | let results = await declensions.related(object) 16 | let filters = await getPrepositionFilters(verb, nouns) 17 | 18 | let res = filters.map(filter => { 19 | let {grammarTag} = filter 20 | return _.mapValues(grammarTag, tag => results.filter(x => x.binId === filter.binId && x.grammarTag === tag)[0]) 21 | }) 22 | 23 | let replacements = [] 24 | 25 | if (res[0]) { 26 | replacements = Object.values(res[0]).map(x => x.wordForm) 27 | } 28 | 29 | let isCorrect = replacements.includes(object) 30 | 31 | return { 32 | rule: `object ${isCorrect ? 'agrees' : 'should agree'} with verb`, 33 | explanation: `${verb} directs the ${getDirectedCase(res)} case`, 34 | modifierIndex: tokenized.indexOf(verb), 35 | targetIndex: tokenized.indexOf(object), 36 | replacements, 37 | isCorrect, 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | import express from 'express' 2 | import cors from 'cors' 3 | import logger from 'express-bunyan-logger' 4 | import compression from 'compression' 5 | 6 | import declensions from './routes/declensions' 7 | import index from './routes/index' 8 | import sentence from './routes/sentence' 9 | import suggestions from './routes/suggestions' 10 | // import error from './error' 11 | 12 | import responseTime from './middleware/response-time' 13 | 14 | let app = express() 15 | 16 | // app.use(logger({ 17 | // name: 'request', 18 | // streams: [{ 19 | // level: 'debug', 20 | // stream: process.stdout, 21 | // }], 22 | // format: ':remote-address :incoming :method :url :status-code - :user-agent[family] :user-agent[major].:user-agent[minor] :user-agent[os] - :response-time ms', 23 | // excludes: ['*'], 24 | // })) 25 | app.use(cors()) 26 | app.use(responseTime) 27 | app.use(compression()) 28 | 29 | app.use('/', index) 30 | app.use('/', declensions) 31 | app.use('/', sentence) 32 | app.use('/', suggestions) 33 | 34 | // app.use(logger.errorLogger()) 35 | // app.use(error) 36 | 37 | let server = app.listen(8000, () => { 38 | let host = server.address().address 39 | let port = server.address().port 40 | 41 | console.log(`app running at http://${host}:${port}`) 42 | }) 43 | -------------------------------------------------------------------------------- /test/adjectives.js.skip: -------------------------------------------------------------------------------- 1 | import assert from 'assert' 2 | import summary from '../controllers/summary'; 3 | import adjectiveFormatter from '../formatters/adjective' 4 | 5 | describe('Adjectives', () => { 6 | 7 | it('should not return superlative for indefinite nouns', async function() { 8 | let results = await summary.adjective('góða', 'veður') 9 | let formatted = adjectiveFormatter(results, 'veður') 10 | 11 | assert.deepEqual(formatted.results, { 12 | "F": "góður veður", 13 | "MST": "betri veður" 14 | }) 15 | }) 16 | 17 | it('should return adjectives that match noun', async function() { 18 | let results = await summary.adjective('stór', 'hesturinn') 19 | let formatted = adjectiveFormatter(results, 'hesturinn') 20 | 21 | assert.deepEqual(formatted.results, { 22 | "F": "stóri hesturinn", 23 | "MST": "stærri hesturinn", 24 | "E": "stærsti hesturinn", 25 | }) 26 | }) 27 | 28 | it('should work for determiners', async function() { 29 | let results = await summary.adjective('annar', 'gaffal') 30 | let formatted = adjectiveFormatter(results, 'gaffal') 31 | 32 | assert.deepEqual(formatted.results, { 33 | "determiner": "annan gaffal", 34 | }) 35 | }) 36 | }) 37 | -------------------------------------------------------------------------------- /test/corrections/spelling.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert' 2 | import {generateSuggestions, filterSuggestions} from '../../corrections/spelling' 3 | 4 | describe('Generates suggestions by replacing lettes', () => { 5 | it('suggests a single letter replacements', () => { 6 | let results = generateSuggestions('eg') 7 | assert.deepEqual(['ég'], results) 8 | }) 9 | 10 | it('suggests multiple replacements for many replacable letters', () => { 11 | let results = generateSuggestions('utland') 12 | assert.deepEqual(['utlánd', 'útland', 'utlanð'], results) 13 | }) 14 | 15 | it('suggests replacements for double letter pairs', () => { 16 | let results = generateSuggestions('Baering') 17 | assert.deepEqual(['Báering', 'Baéring', 'Baeríng', 'Bæring'], results) 18 | }) 19 | }) 20 | 21 | describe('Filters suggestions to words that exist in the database', () => { 22 | it('suggests a single replacement', () => { 23 | return filterSuggestions(['ég']).then(results => { 24 | assert.deepEqual(['ég'], results) 25 | }) 26 | }) 27 | 28 | it('picks the correct suggestion from a list with one correct suggestion', () => { 29 | return filterSuggestions(['utlánd', 'útland', 'utlanð']).then(results => { 30 | assert.deepEqual(['útland'], results) 31 | }) 32 | }) 33 | 34 | it('picks the correct suggestion from a list with one correct suggestion 2', () => { 35 | return filterSuggestions(['Báering', 'Baéring', 'Baeríng', 'Bæring']).then(results => { 36 | assert.deepEqual(['Bæring'], results) 37 | }) 38 | }) 39 | }) 40 | 41 | describe('Corrects the spelling of mispelled words', function() { 42 | it('corrects eg to ég') 43 | it('corrects utland to útland') 44 | it('corrects Baering to Bæring') 45 | it('corrects Thor to Þór') 46 | it('corrects thad to það') 47 | }) 48 | -------------------------------------------------------------------------------- /test/corrections/verb.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert' 2 | import {verb} from '../../rules' 3 | import {structure} from '../../grammar/parsed' 4 | 5 | describe('Corrects subject verb agreement', function() { 6 | it('should find the correct verb for a pronoun subject', async function() { 7 | let tokenized = ['hann', 'tala', 'íslensku'] 8 | let parsedQuery = '{"Parsed Text":{"Sentence":{"{*SUBJ":{"[NP":{"WORDS":[{"hann":"fpken"}]}},"[VPi":{"WORDS":[{"tala":"sng"}]},"{*OBJ<":{"[NP":{"WORDS":[{"íslensku":"nveo"}]}}}}}' 9 | 10 | let parts = structure(parsedQuery) 11 | let result = await verb(tokenized, parts) 12 | 13 | assert.deepEqual(result.modifierIndex, 0) 14 | assert.deepEqual(result.targetIndex, 1) 15 | assert.deepEqual(result.replacements, ['talar', 'talaði']) 16 | }) 17 | 18 | it('should find the correct verb when the verb comes first') 19 | it('should find the correct verb for a noun subject') 20 | }) 21 | -------------------------------------------------------------------------------- /test/corrections/verbObject.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert' 2 | import {verbObject} from '../../rules' 3 | import {structure} from '../../grammar/parsed' 4 | 5 | describe('Corrects verb object agreement', function() { 6 | it.skip('it should change the case of objects to match verbs', async function() { 7 | let tokenized = ['ég', 'tala', 'íslenska'] 8 | let parsedQuery = '{"Parsed Text":{"Sentence":{"{*SUBJ>":{"[NP":{"WORDS":[{"ég":"fp1en"}]}},"[VP":{"WORDS":[{"tala":"sfg1en"}]},"{*OBJ<":{"[AP":{"WORDS":[{"íslenska":"lkfosf"}]}}}}}' 9 | 10 | let parts = structure(parsedQuery) 11 | let result = await verbObject(tokenized, parts) 12 | assert.deepEqual(result.replacements, ['íslensku']) 13 | }) 14 | }) 15 | -------------------------------------------------------------------------------- /test/grammar/parsed.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert' 2 | import {structure} from '../../grammar/parsed' 3 | 4 | describe('Parses parts of a sentence', () => { 5 | it('it detects SVO', () => { 6 | let parsedQuery = '{"Parsed Text":{"Sentence":{"{*SUBJ":{"[NP":{"WORDS":[{"hann":"fpken"}]}},"[VPi":{"WORDS":[{"tala":"sng"}]},"{*OBJ<":{"[NP":{"WORDS":[{"íslensku":"nveo"}]}}}}}' 7 | let result = structure(parsedQuery) 8 | 9 | assert.equal(result.subject.word, 'hann') 10 | assert.equal(result.verb.word, 'tala') 11 | assert.equal(result.object.word, 'íslensku') 12 | }) 13 | 14 | it('detect the second subject as the object', () => { 15 | let parsedQuery = '{"Parsed Text":{"Sentence":{"{*SUBJ":{"[NP":{"WORDS":[{"hann":"fpken"}]}},"[VPi":{"WORDS":[{"gleyma":"sng"}]},"{*SUBJ":{"[NP":{"WORDS":[{"lykillinn":"nkeng"}]}}}}}' 16 | let result = structure(parsedQuery) 17 | 18 | assert.equal(result.subject.word, 'hann') 19 | assert.equal(result.object.word, 'lykillinn') 20 | }) 21 | 22 | it('detects the second noun as the object', () => { 23 | let parsedQuery = '{"Parsed Text":{"Sentence":{"{*SUBJ>":{"[NP":{"WORDS":[{"hann":"fpken"}]}},"[VP":{"WORDS":[{"talar":"sfg3en"}]},"[AP":{"WORDS":[{"íslenska":"lvenvf"}]}}}}' 24 | let result = structure(parsedQuery) 25 | 26 | assert.equal(result.subject.word, 'hann') 27 | assert.equal(result.object.word, 'íslenska') 28 | }) 29 | 30 | it('filters out adverbs from object', () => { 31 | let parsedQuery = '{"Parsed Text":{"Sentence":{"{*SUBJ>":{"[NP":{"WORDS":[{"hann":"fpken"}]}},"[VP":{"WORDS":[{"talar":"sfg3en"}]},"[AP":{"[AdvP":{"WORDS":[{"ekki":"aa"}]},"WORDS":[{"íslenska":"lvenvf"}]}}}}' 32 | let result = structure(parsedQuery) 33 | 34 | assert.equal(result.object.word, 'íslenska') 35 | }) 36 | 37 | it('detects a preposition and matching object', () => { 38 | let parsedQuery = '{"Parsed Text":{"Sentence":{"{*SUBJ>":{"[NP":{"WORDS":[{"ég":"fp1en"}]}},"[VP":{"WORDS":[{"fer":"sfg1en"}]},"[PP":{"WORDS":[{"í":"ao"}],"[NP":{"WORDS":[{"búðina":"nveog"}]}}}}}' 39 | let result = structure(parsedQuery) 40 | 41 | assert.equal(result.preposition.word, 'í') 42 | assert.equal(result.prepositionObject.word, 'búðina') 43 | }) 44 | 45 | it('matches the object with the preposition and not the verb', () => { 46 | let parsedQuery = '{"Parsed Text":{"Sentence":{"{*SUBJ>":{"[NP":{"WORDS":[{"ég":"fp1en"}]}},"[VP":{"WORDS":[{"tala":"sfg1en"}]},"[AdvP":{"WORDS":[{"við":"aa"}]},"{*SUBJ":{"[NP":{"WORDS":[{"hún":"fpven"}]}}}}}' 47 | let result = structure(parsedQuery) 48 | 49 | assert.equal(result.preposition.word, 'við') 50 | assert.equal(result.prepositionObject.word, 'hún') 51 | }) 52 | 53 | it.skip('matches the object with verbs in the infinitive', () => { 54 | let parsedQuery = '{"Parsed Text":{"Sentence":{"{*SUBJ>":{"[NP":{"WORDS":[{"ég":"fp1en"}]}},"[VPb":{"WORDS":[{"er":"sfg1en"}]},"[VPi":{"WORDS":[{"að":"cn","læra":"sng"}]},"{*OBJ<":{"[AP":{"WORDS":[{"íslenska":"lveosf"}]}}}}}' 55 | let result = structure(parsedQuery) 56 | 57 | assert.equal(result.verb.word, 'læra') 58 | assert.equal(result.object.word, 'íslenska') 59 | }) 60 | }) 61 | -------------------------------------------------------------------------------- /test/model/icenlp.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert' 2 | import lookup from '../../models/icenlp' 3 | 4 | const query = 'Ég bý með íslenskri konu' 5 | 6 | const expected = { 7 | tokenized: ['Ég', 'bý', 'með', 'íslenskri', 'konu'], 8 | tagged: [ 9 | 'Ég fp1en (Ég)', 10 | 'bý sfg1en (búa)', 11 | 'með aþ (með)', 12 | 'íslenskri lveþsf (íslenskur)', 13 | 'konu nveþ (kona)' 14 | ], 15 | } 16 | 17 | describe('Lookup data from icenlp', () => { 18 | it(`get results`, async function() { 19 | let result = await lookup(query) 20 | assert.deepEqual(result.tokenized, expected.tokenized) 21 | assert.deepEqual(result.tagged, expected.tagged) 22 | }) 23 | }) 24 | -------------------------------------------------------------------------------- /test/model/static.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert' 2 | import lookupVerb from '../../models/static' 3 | 4 | const testCases = { 5 | 'tefja': ['ÞF'], 6 | 'vernda': ['ÞF'] 7 | } 8 | 9 | describe('Lookup static verb rules', () => { 10 | it(`should not include asdf`, async function() { 11 | let result = await lookupVerb('asdf') 12 | assert.deepEqual(result, null) 13 | }) 14 | 15 | Object.keys(testCases).forEach(input => { 16 | it(`should include ${input}`, async function() { 17 | let result = await lookupVerb(input) 18 | let expected = testCases[input] 19 | 20 | assert.deepEqual(result, expected) 21 | }) 22 | }) 23 | }) 24 | -------------------------------------------------------------------------------- /test/parsed.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert' 2 | import {structure, wordFromPart} from '../grammar/parsed' 3 | 4 | // Convert examples to json format :( 5 | describe.skip('Understands parsed output from icenlp', () => { 6 | it(`identifies subject and verb`, () => { 7 | const parsed = '{*SUBJ> [NP Ég fp1en ] } [VP sá sfg1eþ ] {*OBJ< [NP [AP veiku lveovf ] konuna nveog ] } ' 8 | const expected = { 9 | subject: 'NP Ég fp1en', 10 | verb: 'VP sá sfg1eþ', 11 | object: 'NP [AP veiku lveovf ] konuna nveog' 12 | } 13 | 14 | let result = structure(parsed) 15 | assert.deepEqual(result, expected) 16 | }) 17 | 18 | it(`identifies subject in a sentence where the subject and verb don't match`, () => { 19 | const parsed = '{*SUBJ [NP Hann fpken ] } [VPi tala sng ] {*OBJ< [NP íslensku nveo ] } ' 20 | const expected = { 21 | subject: 'NP Hann fpken', 22 | verb: 'VPi tala sng', 23 | object: 'NP íslensku nveo' 24 | } 25 | 26 | let result = structure(parsed) 27 | assert.deepEqual(result, expected) 28 | }) 29 | 30 | it(`identifies verb in a sentence where the subject and verb don't match`, () => { 31 | const parsed = '{*SUBJ> [NP við fp1fn ] } [VP?VnVp? talar sfg3en ] {*OBJ< [NP íslensku nveþ ] } ' 32 | const expected = { 33 | subject: 'NP við fp1fn', 34 | verb: 'VP?VnVp? talar sfg3en', 35 | object: 'NP íslensku nveþ' 36 | } 37 | 38 | let result = structure(parsed) 39 | assert.deepEqual(result, expected) 40 | }) 41 | 42 | it(`identifies verb in a sentence with more than one verb`, () => { 43 | const parsed = '{*SUBJ> [NP ég fp1en ] } [VPb er sfg1en ] [VPi að cn tala sng ] {*OBJ< [NP íslensku nveo ] } ' 44 | const expected = { 45 | subject: 'NP ég fp1en', 46 | verb: 'VPb er sfg1en', 47 | object: 'NP íslensku nveo' 48 | } 49 | 50 | let result = structure(parsed) 51 | assert.deepEqual(result, expected) 52 | }) 53 | 54 | it(`identifies object in a sentence`, () => { 55 | const parsed = '{*SUBJ> [NP Ég fp1en ] } [VP sakna sfg1en ] {*OBJ< [NP?Aca? þig fp2eo ] } ' 56 | const expected = { 57 | subject: 'NP Ég fp1en', 58 | verb: 'VP sakna sfg1en', 59 | object: 'NP?Aca? þig fp2eo' 60 | } 61 | 62 | let result = structure(parsed) 63 | assert.deepEqual(result, expected) 64 | }) 65 | 66 | it('extracts the word from a part', () => { 67 | const subject = 'NP Ég fp1en' 68 | 69 | let result = wordFromPart(subject) 70 | assert.equal(result, 'Ég') 71 | }) 72 | }) 73 | -------------------------------------------------------------------------------- /test/parser/adjective.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert' 2 | import {parse, toString} from '../../grammar/parser' 3 | 4 | const testCases = { 5 | 'FVB-KK-NFET': {degree: 'FVB', gender: 'KK', grammarCase: 'NF', number: 'ET'}, 6 | 'FVB-KVK-NFET': {degree: 'FVB', gender: 'KVK', grammarCase: 'NF', number: 'ET'}, 7 | 'FSB-KVK-NFET': {degree: 'FSB', gender: 'KVK', grammarCase: 'NF', number: 'ET'}, 8 | 'MST-KK-NFET': {degree: 'MST', gender: 'KK', grammarCase: 'NF', number: 'ET'}, 9 | 'EVB-KK-NFET': {degree: 'EVB', gender: 'KK', grammarCase: 'NF', number: 'ET'}, 10 | } 11 | 12 | describe('Parse adjectives', () => { 13 | const wordClass = 'lo' 14 | 15 | Object.keys(testCases).forEach(input => { 16 | it(`should parse ${input}`, () => { 17 | let parsed = parse(wordClass, input) 18 | let expected = testCases[input] 19 | 20 | assert.deepEqual(parsed, expected) 21 | assert.equal(toString(wordClass, parsed), input) 22 | }) 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /test/parser/nouns.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert' 2 | import {parse, toString} from '../../grammar/parser' 3 | 4 | const testCases = { 5 | 'NFET': {grammarCase: 'NF', number: 'ET', article: ''}, 6 | 'NFETgr': {grammarCase: 'NF', number: 'ET', article: 'gr'}, 7 | 'NFFT': {grammarCase: 'NF', number: 'FT', article: ''}, 8 | 'NFFTgr': {grammarCase: 'NF', number: 'FT', article: 'gr'}, 9 | 'ÞFET': {grammarCase: 'ÞF', number: 'ET', article: ''}, 10 | 'ÞFETgr': {grammarCase: 'ÞF', number: 'ET', article: 'gr'}, 11 | 'ÞFFT': {grammarCase: 'ÞF', number: 'FT', article: ''}, 12 | 'ÞFFTgr': {grammarCase: 'ÞF', number: 'FT', article: 'gr'}, 13 | 'ÞGFET': {grammarCase: 'ÞGF', number: 'ET', article: ''}, 14 | 'ÞGFETgr': {grammarCase: 'ÞGF', number: 'ET', article: 'gr'}, 15 | 'ÞGFFT': {grammarCase: 'ÞGF', number: 'FT', article: ''}, 16 | 'ÞGFFTgr': {grammarCase: 'ÞGF', number: 'FT', article: 'gr'}, 17 | 'EFET': {grammarCase: 'EF', number: 'ET', article: ''}, 18 | 'EFETgr': {grammarCase: 'EF', number: 'ET', article: 'gr'}, 19 | 'EFFT': {grammarCase: 'EF', number: 'FT', article: ''}, 20 | 'EFFTgr': {grammarCase: 'EF', number: 'FT', article: 'gr'}, 21 | } 22 | 23 | describe('Parse nouns', () => { 24 | const wordClass = 'hk' 25 | 26 | Object.keys(testCases).forEach(input => { 27 | it(`should parse ${input}`, () => { 28 | let parsed = parse(wordClass, input) 29 | let expected = testCases[input] 30 | expected.gender = wordClass.toUpperCase() 31 | 32 | assert.deepEqual(parsed, expected) 33 | assert.equal(toString(wordClass, parsed), input) 34 | }) 35 | }) 36 | }) 37 | -------------------------------------------------------------------------------- /test/prepositions.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert' 2 | import summary from '../controllers/summary' 3 | import summaryFormatter from '../formatters/summary' 4 | 5 | describe.skip('Prepositions', () => { 6 | 7 | it('should return definite noun for definite noun input', async function() { 8 | let results = await summary.preposition('um', 'dagurinn') 9 | let formatted = summaryFormatter(results, 'um') 10 | 11 | assert.deepEqual(formatted.results, [{ 'ÞF': 'um daginn' }]) 12 | }) 13 | 14 | it('should return multiple results for prepositions that have multiple cases', async function() { 15 | let results = await summary.preposition('í', 'búðin') 16 | let formatted = summaryFormatter(results, 'í') 17 | 18 | assert.deepEqual(formatted.results, [ 19 | { 20 | 'ÞF': 'í búðina', 21 | }, 22 | { 23 | 'ÞGF': 'í búðinni' 24 | }]) 25 | }) 26 | 27 | it('should return matching proper nouns', async function() { 28 | let results = await summary.preposition('til', 'Ægir') 29 | let formatted = summaryFormatter(results, 'til') 30 | 31 | assert.deepEqual(formatted.results, [{ 'EF': 'til Ægis' }]) 32 | }) 33 | 34 | it('should match verbs', async function() { 35 | let results = await summary.preposition('tala', 'íslenska') 36 | let formatted = summaryFormatter(results, 'tala') 37 | 38 | assert.deepEqual(formatted.results, [{ 'ÞGF': 'tala íslensku' }]) 39 | }) 40 | 41 | it('should match complex verbs', async function() { 42 | let results = await summary.preposition('opna', 'gluggi') 43 | let formatted = summaryFormatter(results, 'opna') 44 | 45 | assert.deepEqual(formatted.results, [{ 'ÞF': 'opna glugga' }, { 'ÞF': 'opna glugg' }]) 46 | }) 47 | 48 | it('should match "á"', async function() { 49 | let results = await summary.preposition('á', 'hesturinn') 50 | let formatted = summaryFormatter(results, 'á') 51 | 52 | assert.deepEqual(formatted.results, [{ 'ÞF': 'á hestinn' }, { 'ÞGF': 'á hestinum' }, { 'ÞF': 'á hestinn' }]) 53 | }) 54 | 55 | it('should return matching pronouns', async function() { 56 | let results = await summary.preposition('frá', 'hann') 57 | let formatted = summaryFormatter(results, 'frá') 58 | 59 | assert.deepEqual(formatted.results, [{ 'ÞGF': 'frá honum' }]) 60 | }) 61 | }) 62 | -------------------------------------------------------------------------------- /test/verb.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert' 2 | import summary from '../controllers/summary' 3 | import summaryFormatter from '../formatters/summary' 4 | 5 | describe.skip('Verbs', () => { 6 | 7 | it('should return past and present verbs with correct person', async function() { 8 | let results = await summary.verb('ég', 'fara') 9 | let formatted = summaryFormatter(results, 'ég') 10 | 11 | assert.deepEqual(formatted.results, [{ 12 | 'NT': 'ég fer', 13 | 'ÞT': 'ég fór', 14 | }]) 15 | }) 16 | }) 17 | -------------------------------------------------------------------------------- /translate/_grammar-tag-parser.js: -------------------------------------------------------------------------------- 1 | import lookup from './translate.json' 2 | 3 | let endsWith = (str, suffix) => 4 | str.indexOf(suffix, str.length - suffix.length) !== -1 5 | 6 | export default (word, language) => { 7 | let tags = word.grammarTag.split('-') 8 | 9 | // Definite article doesn't have a separator 10 | if (endsWith(word.grammarTag, 'gr')) { 11 | tags = [] 12 | tags.push(word.grammarTag.replace('gr', '')) 13 | tags.push('gr') 14 | } 15 | 16 | // Other pronouns use _ as a separator 17 | if (word.wordClass === 'fn' || word.wordClass === 'ao') { 18 | tags = word.grammarTag.split('_') 19 | } 20 | 21 | if (language) { 22 | return tags.map(tag => lookup[language].grammarTag[tag] || tag) 23 | } else { 24 | return tags 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /translate/_mapTags.js: -------------------------------------------------------------------------------- 1 | import matchers from './tags' 2 | 3 | let lookup = { 4 | // Nouns 5 | 'kk': ['case', 'number', 'article'], 6 | 'kvk': ['case', 'number', 'article'], 7 | 'hk': ['case', 'number', 'article'], 8 | 9 | // Verb 10 | 'so': ['voice', 'mood', 'tense', 'person', 'number'], 11 | 12 | // Pronoun 13 | 'pfn': ['case', 'number'], 14 | 15 | // Adjective 16 | 'lo': ['degree', 'gender', 'case', 'number'], 17 | 18 | // Reflexive pronoun 19 | 'abfn': ['case'], 20 | 21 | // Other pronoun 22 | 'fn': ['gender', 'case', 'number'], 23 | 24 | // Numeral 25 | 'to': ['gender', 'case', 'number'] 26 | } 27 | 28 | export default (grammarTag, wordClass) => { 29 | let tags = { 30 | case: { 31 | NF: matchers.isNominative(grammarTag), 32 | ÞF: matchers.isAccusative(grammarTag), 33 | ÞGF: matchers.isDative(grammarTag), 34 | EF: matchers.isGenitive(grammarTag) 35 | }, 36 | number: { 37 | ET: matchers.isSingular(grammarTag), 38 | FT: matchers.isPlural(grammarTag) 39 | }, 40 | article: { 41 | '': matchers.isIndefinite(grammarTag, wordClass), 42 | 'gr': matchers.isDefinite(grammarTag) 43 | }, 44 | gender: { 45 | KK: matchers.isMasculine(grammarTag, wordClass), 46 | KVK: matchers.isFeminine(grammarTag, wordClass), 47 | HK: matchers.isNeuter(grammarTag, wordClass) 48 | }, 49 | person: { 50 | '1P': matchers.isFirstPerson(grammarTag), 51 | '2P': matchers.isSecondPerson(grammarTag), 52 | '3P': matchers.isThirdPerson(grammarTag) 53 | }, 54 | tense: { 55 | 'NT': matchers.matchesTags(grammarTag, 'NT'), 56 | 'ÞT': matchers.matchesTags(grammarTag, 'ÞT') 57 | }, 58 | mood: { 59 | 'FH': matchers.matchesTags(grammarTag, 'FH'), 60 | 'VH': matchers.matchesTags(grammarTag, 'VH') 61 | }, 62 | degree: { 63 | 'FSB': matchers.isPositive(grammarTag), 64 | 'FVB': matchers.matchesTags(grammarTag, 'FVB'), 65 | 'MST': matchers.isComparative(grammarTag), 66 | 'ESB': matchers.isSuperlative(grammarTag), 67 | 'EVB': matchers.matchesTags(grammarTag, 'EVB') 68 | }, 69 | voice: { 70 | 'GM': matchers.matchesTags(grammarTag, 'GM') 71 | } 72 | } 73 | 74 | let results = {} 75 | 76 | if (lookup[wordClass]) { 77 | lookup[wordClass].forEach(prop => results[prop] = tags[prop]) 78 | } 79 | 80 | return results 81 | } 82 | -------------------------------------------------------------------------------- /translate/_tags.js: -------------------------------------------------------------------------------- 1 | let isNoun = wordClass => 2 | wordClass === 'kk' || 3 | wordClass === 'kvk' || 4 | wordClass === 'hk' 5 | 6 | export default { 7 | isSingular: (tags) => tags.includes('ET'), 8 | 9 | isPlural: (tags) => tags.includes('FT'), 10 | 11 | isIndefinite: (tags, wordClass) => (isNoun(wordClass) && !tags.includes('gr')) || tags.includes('SB'), 12 | 13 | isDefinite: (tags) => tags.includes('gr') || tags.includes('VB'), 14 | 15 | isMasculine: (tags) => tags.includes('KK'), 16 | 17 | isFeminine: (tags) => tags.includes('KVK'), 18 | 19 | isNeuter: (tags) => tags.includes('HK'), 20 | 21 | isNominative: (tags) => tags.includes('NF'), 22 | 23 | isAccusative: (tags) => tags.includes('ÞF'), 24 | 25 | isGenitive: (tags) => tags.includes('EF'), 26 | 27 | isDative: (tags) => tags.includes('ÞG'), 28 | 29 | isFirstPerson: (tags) => tags.includes('1p') || tags.includes('1P'), 30 | 31 | isSecondPerson: (tags) => tags.includes('2p') || tags.includes('2P'), 32 | 33 | isThirdPerson: (tags) => tags.includes('3p') || tags.includes('3P'), 34 | 35 | isPositive: (tags) => tags.includes('FSB'), 36 | 37 | isSuperlative: (tags) => tags.includes('ESB'), 38 | 39 | isComparative: (tags) => tags.includes('MST'), 40 | 41 | matchesTags: (tags, val) => tags.includes(val) 42 | } 43 | -------------------------------------------------------------------------------- /translate/_translate.js: -------------------------------------------------------------------------------- 1 | import mapTags from './mapTags' 2 | 3 | export default (word, lang) => { 4 | word.tags = mapTags(word.grammarTag, word.wordClass, lang) 5 | return word 6 | } 7 | -------------------------------------------------------------------------------- /translate/translate.js: -------------------------------------------------------------------------------- 1 | import lookup from './translate.json' 2 | import _ from 'lodash' 3 | 4 | export default (results, language) => { 5 | if (language) { 6 | return results.map(result => _.mapKeys(result, (value, tag) => lookup[language].grammarTag[tag] || tag)) 7 | } 8 | 9 | return results 10 | } 11 | -------------------------------------------------------------------------------- /translate/translate.json: -------------------------------------------------------------------------------- 1 | { 2 | "en" : { 3 | "wordClass": { 4 | "hk": "Noun (neuter)", 5 | "kk": "Noun (masculine)", 6 | "kvk": "Noun (feminine)", 7 | "lo": "Adjective", 8 | "so": "Verb", 9 | "ao": "Adverb", 10 | "to": "Numeral", 11 | "pfn": "Personal pronoun", 12 | "abfn": "Reflexive pronoun", 13 | "fn": "Other pronoun", 14 | "gr": "Definite article", 15 | "ao": "Adverb", 16 | "fs": "Preposition", 17 | "nhm": "Infinitive particle", 18 | "st": "Conjunction", 19 | "töl": "Numeral", 20 | "uh": "Exclamation" 21 | }, 22 | 23 | "grammarTag": { 24 | "1p": "1st person", 25 | "1P": "1st person", 26 | "2p": "2nd person", 27 | "2P": "2nd person", 28 | "3p": "3rd person", 29 | "3P": "3rd person", 30 | "ao": "adverb", 31 | "BH": "imperative", 32 | "EF": "genitive", 33 | "EFET": "genitive singular", 34 | "EFFT": "genitive plural", 35 | "ESB": "superlative, indefinite", 36 | "EST": "superlative", 37 | "ET": "singular", 38 | "EVB": "superlative, definite", 39 | "FH": "indicative", 40 | "FN": "pronoun (excluding personal and possessive pronouns)", 41 | "FSB": "positive degree, indefinite", 42 | "FST": "positive degree", 43 | "FT": "plural", 44 | "FVB": "positive degree, definite", 45 | "GM": "active voice", 46 | "gr": "definite", 47 | "HK": "neuter", 48 | "KK": "masculine", 49 | "KVK": "feminine", 50 | "LHNT": "past participle", 51 | "lo": "adjective", 52 | "MM": "mediopassive", 53 | "MST": "comparative", 54 | "NF": "nominative", 55 | "NFET": "nominative singular", 56 | "NFFT": "nominative plural", 57 | "NH": "infinitive", 58 | "no": "noun (--> gender)", 59 | "NT": "present tense", 60 | "OP": "impersonal construction", 61 | "pfn": "personal pronoun", 62 | "sagnb": "?supine", 63 | "so": "verb", 64 | "to": "numeral", 65 | "VH": "subjunctive", 66 | "ÞF": "accusative", 67 | "ÞFET": "accusative singular", 68 | "ÞFFT": "accusative plural", 69 | "ÞGF": "dative", 70 | "ÞGFET": "dative singular", 71 | "ÞGFFT": "dative plural", 72 | "ÞT": "past tense", 73 | "F": "positive degree", 74 | "E": "superlative", 75 | "": "indefinite" 76 | } 77 | }, 78 | 79 | "is" : { 80 | "wordClass": { 81 | "hk": "hvorugkyn", 82 | "kk": "karlkyn", 83 | "kvk": "kvenkyn", 84 | "lo": "lýsingarorð", 85 | "so": "sagnorð", 86 | "ao": "atviksorð", 87 | "to": "töluorð", 88 | "pfn": "persónufornafn", 89 | "abfn": "afturbeygt fornafn", 90 | "fn": "önnur fornöfn", 91 | "gr": "greinir", 92 | "ao": "atviksorð", 93 | "fs": "forsetningar", 94 | "nhm": "nafnháttarmerki", 95 | "st": "samtengingar", 96 | "töl": "töluorð", 97 | "uh": "upphrópanir" 98 | }, 99 | 100 | "grammarTag": { 101 | "1p": "1. persóna", 102 | "1P": "1. persóna", 103 | "2p": "2. persóna", 104 | "2P": "2. persóna", 105 | "3p": "3. persóna", 106 | "3P": "3. persóna", 107 | "ao": "atviksorð", 108 | "BH": "boðháttur", 109 | "EF": "eignarfall", 110 | "EFET": "eignarfall eintölu", 111 | "EFFT": "eignarfall fleirtölu", 112 | "ESB": "efsta stig, sterk beyging", 113 | "EST": "efsta stig", 114 | "ET": "eintala", 115 | "EVB": "efsta stig, veik beyging", 116 | "FH": "framsöguháttur", 117 | "FN": "fornafn (annað en persónufornafn eða eignarfornafn)", 118 | "FSB": "frumstig, sterk beyging", 119 | "FST": "frumstig", 120 | "FT": "fleirtala", 121 | "FVB": "frumstig, veik beyging", 122 | "GM": "germynd", 123 | "gr": "með greini", 124 | "HK": "hvorugkyn", 125 | "KK": "karlkyn", 126 | "KVK": "kvenkyn", 127 | "LHNT": "lýsingarháttur þátíðar", 128 | "lo": "lýsingarorð", 129 | "MM": "miðmynd", 130 | "MST": "miðstig", 131 | "NF": "nefnifall", 132 | "NFET": "nefnifall eintölu", 133 | "NFFT": "nefnifall fleirtölu", 134 | "NH": "nafnháttur", 135 | "no": "nafnorð (--> kyn)", 136 | "NT": "nútíð", 137 | "OP": "ópersónuleg beyging", 138 | "pfn": "persónufornafn", 139 | "sagnb": "sagnbót", 140 | "so": "sagnorð", 141 | "to": "töluorð", 142 | "VH": "viðtengingarháttur", 143 | "ÞF": "þolfall", 144 | "ÞFET": "þolfall eintölu", 145 | "ÞFFT": "þolfall fleirtölu", 146 | "ÞGF": "þágufall", 147 | "ÞGFET": "þágufall eintölu", 148 | "ÞGFFT": "þágufall fleirtölu", 149 | "ÞT": "þátíð", 150 | "F": "frumstig", 151 | "E": "efsta stig", 152 | "": "án greinis" 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Uninstall Script 4 | 5 | if [ "$(which boot2docker)" == "" ]; then 6 | echo "boot2docker does not exist on your machine!" 7 | exit 1 8 | fi 9 | 10 | if [ "${USER}" != "root" ]; then 11 | echo "$0 must be run as root!" 12 | exit 2 13 | fi 14 | 15 | echo "Stopping boot2docker processes..." 16 | boot2docker stop && boot2docker delete 17 | 18 | echo "Removing boot2docker executable..." 19 | rm -f /usr/local/bin/boot2docker 20 | 21 | echo "Removing boot2docker ISO and socket files..." 22 | rm -rf ~/.boot2docker 23 | rm -rf /usr/local/share/boot2docker 24 | 25 | echo "Removing boot2docker SSH keys..." 26 | rm -f ~/.ssh/id_boot2docker* 27 | 28 | echo "Removing boot2docker OSX files..." 29 | rm -f /private/var/db/receipts/io.boot2docker.* 30 | rm -f /private/var/db/receipts/io.boot2dockeriso.* 31 | 32 | echo "Removing Docker executable..." 33 | rm -f /usr/local/bin/docker 34 | 35 | echo "All Done!" 36 | --------------------------------------------------------------------------------