use("ispec")

describe(DefaultBehavior,
  describe("FlowControl",
    describe("for",
      it("should handle a simple iteration",
        for(x <- [1,2,3], x) should == [1,2,3]
        for(x <- 1..10, x) should == [1,2,3,4,5,6,7,8,9,10]
        for(x <- set(:a, :b, :c), x) sort should == [:a, :b, :c]
      )

      it("should be possible to do something advanced in the output part",
        for(x <- 1..10, x*2) should == [2,4,6,8,10,12,14,16,18,20]

        mex = method(f, f+f+f)
        for(x <- 1...5, mex(x)) should == [3, 6, 9, 12]
      )

      it("should be possible to combine two iterations")
      it("should be possible to filter output by using 'if'")
      it("should be possible to do midlevel assignment")
      it("should be possble to combine these parts into a larger comprehension")
    )
  )
)

Add simple support for comprehensions

use("ispec")

describe(DefaultBehavior,
  describe("FlowControl",
    describe("for",
      it("should handle a simple iteration",
        for(x <- [1,2,3], x) should == [1,2,3]
        for(x <- 1..10, x) should == [1,2,3,4,5,6,7,8,9,10]
        for(x <- set(:a, :b, :c), x) sort should == [:a, :b, :c]
      )

      it("should be possible to do something advanced in the output part",
        for(x <- 1..10, x*2) should == [2,4,6,8,10,12,14,16,18,20]

        mex = method(f, f+f+f)
        for(x <- 1...5, mex(x)) should == [3, 6, 9, 12]
      )

      it("should be possible to combine two or more iterations",
        for(x <- [1,2,3], y <- [15,16,17], [x,y]) should == [[1,15],[1,16],[1,17],[2,15],[2,16],[2,17],[3,15],[3,16],[3,17]]
      )

      it("should be possible to filter output by using 'if'")
      it("should be possible to do midlevel assignment")
      it("should be possble to combine these parts into a larger comprehension")
    )
  )
)


IIk = Origin mimic

IIk Exit = Condition mimic
IIk mainContext = Ground mimic
IIk mainContext exit = method(signal!(IIk Exit))
IIk mainContext aliasMethod("exit", "quit")

IIk mainLoop = method(
  "Runs the main loop of IIk, continously reading input from 'System in' until the interpreter is quitted in some of the standard ways",

  out = System out
  err = System err
  in  = System in

  bind(
    rescue(IIk Exit, fn(c, out println("Bye."))),
    loop(
      bind(
        rescue(Condition Error, fn(c, err println("*** - #{c report}"))),
        out print("iik> ")
        out println("+> #{in read evaluateOn(mainContext) inspect}")
        out println))))

System ifMain(IIk mainLoop)

Upgrade the console a bit, to use the debugger instead of rescuing exceptions. This makes for a cleaner API and so on. Also establish the quit and abort restarts

IIk = Origin mimic

IIk Exit = Condition mimic

IIk mainContext = Ground mimic do(
  exit = method(signal!(IIk Exit))
  aliasMethod("exit", "quit"))

IIk out = System out
IIk err = System err
IIk in  = System in

IIk mainLoop = method(
  "Runs the main loop of IIk, continously reading input from 'System in' until the interpreter is quitted in some of the standard ways",

  debugger = Origin mimic
  System currentDebugger = debugger
  debugger invoke = method(
    condition, context,
    invokeRestart(:abort)
  )

  bind(
    rescue(IIk Exit, fn(c, out println("Bye."))),
    restart(quit, fn()),

    loop(
      bind(
        restart(abort, fn()),

        out print("iik> ")
        out println("+> #{in read evaluateOn(mainContext) inspect}")
        out println))))

System ifMain(IIk mainLoop)


cell(:use) jar = method(jarFile,
  use(if(#/\.jar$/ =~ jarFile,
      jarFile,
      "#{jarFile}.jar")))

Make assignment of use-modules even easier

use jar = method(jarFile,
  use(if(#/\.jar$/ =~ jarFile,
      jarFile,
      "#{jarFile}.jar")))


use("ispec")

describe(Message,
  describe("rewrite!",
    it("should rewrite a very simple message chain",
      msg = 'foo
      msg rewrite!(
        '(:x) => '(something(:x))
      )
      msg should == 'blah(foo)
    )
  )
)

Make pending spec of the rewrite stuff

use("ispec")

describe(Message,
  describe("rewrite!",
    it("should rewrite a very simple message chain")
;       msg = 'foo
;       msg rewrite!(
;         '(:x) => '(something(:x))
;       )
;       msg should == 'blah(foo)
;     )
  )
)


"LOADING: my first Ioke web application!" println

IKanServe actionForPath(#r[^/foo], method("hello world!!"))
IKanServe actionForPath(#r[^/bar], method("you requested this: #{request pathInfo}"))

Make the small example thing use the html builder

"LOADING: my first Ioke web application!" println

IKanServe actionForPath(#r[^/foo], method("hello world!!"))
IKanServe actionForPath(#r[^/bar], method("you requested this: #{request pathInfo}"))
IKanServe actionForPath(#r[^/xxx], method(
    h = IKanServe HtmlBuilder
    h html(h head(h title("Filthy!")),
      h body(
        h h2("You filthy bastard")
    ))
))

IKanServe actionForPath(#r[^/], method(
    h = IKanServe HtmlBuilder
    h html(h head(h title("nada!")),
      h body(
        h b("... really nothing here ...")
    ))
))


Struct = fn(+attributes, +:attributesWithDefaultValues,
  val = fn(+values, +:keywordValues,
    result = val mimic
    attributesWithDefaultValues each(vv,
      result cell(vv key) = vv value)
    attributes zip(values) each(vv,
      result cell(vv first) = vv second)
    keywordValues each(vv,
      result cell(vv key) = vv value)
    result
  )
  val mimic!(Struct)
  val)

Restructure the assignments a bit

Struct = fn(+attributes, +:attributesWithDefaultValues,
  val = fn(+values, +:keywordValues,
    result = val mimic
    (attributesWithDefaultValues seq +
      attributes zipped(values) +
      keywordValues seq) each(vv,
      result cell(vv first) = vv second)
    result
  )
  val mimic!(Struct)
  val)


Pattern = Origin mimic do(
  from = dmacro(
    [pattern]
    Pattern with(pattern: pattern))

  variable? = method(current, current symbol?)
  varName = method(msg, :(msg name asText[1..-1]))

  matchVariable = method(var, input, bindings,
    binding = bindings[varName(var)]
    case(binding,
      nil,
        bindings merge(varName(var) => input name asText),
      input name asText,
        bindings,
        nil))

  doMatch = method(pat, input, bindings,
    cond(
      bindings == nil,
        nil,

      pat == nil || input == nil,
        if(pat == input, bindings, nil),

      variable?(pat),
        doMatch(pat next, input next, matchVariable(pat, input, bindings)),

      pat name == input name,
        doMatch(pat next, input next, bindings),

        nil))

  match = dmacro("Does pattern match input? A variable in the form of a symbol message can match anything.",
    [input, >bindings {}]
    doMatch(self pattern, input, bindings))
)

System ifMain(
  Pattern from(I need a :X) match(I need a vacation) inspect println
  Pattern from(I need a :X) match(I really need a vacation) inspect println
  Pattern from(I :X need a :Y) match(I would need a vacation) inspect println
)

Use a restart for no-match

Pattern = Origin mimic do(
  from = dmacro(
    [pattern]
    Pattern with(pattern: pattern))

  variable? = method(current, current symbol?)
  varName = method(msg, :(msg name asText[1..-1]))

  noMatch! = method(invokeRestart(:noMatch))

  matchVariable = method(var, input, bindings,
    binding = bindings[varName(var)]
    case(binding,
      nil,
        bindings merge(varName(var) => input name asText),
      input name asText,
        bindings,
        noMatch!))

  doMatch = method(pat, input, bindings,
    cond(
      pat == nil || input == nil,
        if(pat == input, bindings, noMatch!),

      variable?(pat),
        doMatch(pat next, input next, matchVariable(pat, input, bindings)),

      pat name == input name,
        doMatch(pat next, input next, bindings),

        noMatch!))

  match = dmacro("Does pattern match input? A variable in the form of a symbol message can match anything.",
    [input, >bindings {}]
    bind(restart(noMatch, fn(nil)),
      doMatch(self pattern, input, bindings)))
)

System ifMain(
  Pattern from(I need a :X) match(I need a vacation) inspect println
  Pattern from(I need a :X) match(I really need a vacation) inspect println
  Pattern from(I :X need a :Y) match(I would need a vacation) inspect println
)


RPS = Origin mimic do(
  Player = Origin mimic
  Field = Origin mimic

  Field pass = macro(
    RPS Player with(name: call message name asText, field: self))

  scores = {} withDefault(0)

  Player throws = macro(
    field plays << (self name => call message next name)
    call message -> call message next next
  )

  win = method(p,
    scores[p key] += 1
    "#{p key} wins" println)

  draw = method("Draw" println)

  ; DSL implementation
  rules = macro(
    r = call arguments
    resultMessage = 'case([p1 value, p2 value])
    left = fnx(r, ":#{r name}")
    right = fnx(r, ":#{r next next name}")
    r each(rule,
      resultMessage << ''[`left(rule), `right(rule)] << 'win(p1)
      resultMessage << ''[`right(rule), `left(rule)] << 'win(p2)
    )
    resultMessage << 'else << 'draw

    ''(applyRules = method(p1, p2, `resultMessage))
  )

  ;; DSL usage
  rules(
    paper > rock,
    rock > scissors,
    scissors > paper
  )

  play = macro(
    field = Field with(plays: [])
    call arguments[0] evaluateOn(field)
    p1 = field plays[0]
    p2 = field plays[1]

    applyRules(p1, p2)

    field
  )
)

System ifMain(
  RPS play(
    Carlos throws paper
    Ola throws rock
  )

  RPS play(
    Carlos throws scissors
    Ola throws rock
  )

  RPS play(
    Carlos throws scissors
    Ola throws scissors
  )

  RPS play(
    Carlos throws paper
    Ola throws scissors
  )

  "\nScores:\n%:[%s: %s\n%]" format(RPS scores) print
)


Add english translation of the account example

Account = Origin mimic do(
  transfer = method(amount, from: self, to:,
    from balance -= amount
    to balance += amount
  )

  print = method(
    "<Account name: #{name} balance: #{balance}>" println
  )
)

Xiao = Account with(name: "Xiao", balance: 142.0)
Jiajun = Account with(name: "Jiajun", balance: 45.7)

Account transfer(23.0, from: Xiao, to: Jiajun)
Account transfer(10.0, to: Xiao, from: Jiajun)
Jiajun  transfer(57.4, to: Xiao)

Xiao   print
Jiajun print


Add a quite different implementation of rps

RPS = Origin mimic do(
  Player = Origin mimic
  Field = Origin mimic

  Field pass = macro(
    RPS Player with(name: call message name asText, field: self))

  scores = {} withDefault(0)

  Player throws = macro(
    field plays << (self name => call message next name)
    call message -> call message next next
  )

  play = macro(
    field = Field with(plays: [])
    call arguments[0] evaluateOn(field)
    p1 = field plays[0]
    p2 = field plays[1]

    case([p1 value, p2 value],
      or(
        [:paper, :rock],
        [:rock, :scissors],
        [:scissors, :paper]),
      scores[p1 key] += 1
      "#{p1 key} wins" println,

      or(
        [:rock, :paper],
        [:paper, :scissors],
        [:scissors, :rock]),
      scores[p2 key] += 1
      "#{p2 key} wins" println,

      "Draw" println)

    field
  )
)

System ifMain(
  RPS play(
    Carlos throws paper
    Ola throws rock
  )

  RPS play(
    Carlos throws scissors
    Ola throws rock
  )

  RPS play(
    Carlos throws scissors
    Ola throws scissors
  )

  RPS play(
    Carlos throws paper
    Ola throws scissors
  )

  "\nScores:\n%*[%s: %s\n]" format(RPS scores map(x, [x key, x value])) println
)


Add some example information on how a good Ioke build system could look like

project name = "Foobarius"
project author = "Ola Bini"
project homepage = "http://ioke.org/foobarius"
project loadPath = FileSystem["lib"]
project loadFiles = FileSystem["lib/foobarius.ik"]

spec files = FileSystem["test/**_spec.ik"]

specWithCover documentation = "Run all the specs with coverage reports turned on"
specWithCover = spec with(coverage: true)


Add a default configuration file for IKover that ignores spec files and bin files

Origin with(
  directory: "coverage-report",
  files: fn(file,
    case(file,
      #r[test/.*\Z], false,
      #r[bin/.*\Z], false,
      #/\.file_system_test_config.ik\Z/, false,
      else, true
    )
  )
)


import frontend/ParsingPool
import middle/Resolver
import backend/c89/C89Backend

main: func (argc: Int, argv: CString*) {

    if(argc <= 1) {
        "Usage: oc file.ooc" println()
        exit(1)
    }

    pool := ParsingPool new()
    mainJob := ParsingJob new(argv[1] toString(), null)
    pool push(mainJob)
    pool exhaust()
    mainJob module main? = true

    Resolver new(C89Backend new(), mainJob module) start()

}

Use rofl0r's fantastic text/Opts to avoid crashing loudly when using options :D

import structs/ArrayList
import frontend/ParsingPool
import middle/Resolver
import backend/c89/C89Backend
import text/Opts

main: func (args: ArrayList<String>) {

    opts := Opts new(args)

    if(opts args size <= 1) {
        "Usage: oc file.ooc" println()
        exit(1)
    }

    opts args each(|arg|
        compile(arg, opts)
    )

}

compile: func (file: String, opts: Opts) {

    pool := ParsingPool new()
    mainJob := ParsingJob new(file, null)
    pool push(mainJob)
    pool exhaust()
    mainJob module main? = true

    Resolver new(C89Backend new(), mainJob module) start()

}


import structs/ArrayList
import frontend/CommandLine

Rock: class {
    execName := static ""
}

main: func(args: ArrayList<String>) {
    "NDD WE DESPERATELY NEED YOU, GET ON IRC" println()
    return 1

    Rock execName = args[0]
    CommandLine new(args)
}

Revert "Hello nddrylliog." Rock on!

import structs/ArrayList
import frontend/CommandLine

Rock: class {
    execName := static ""
}

main: func(args: ArrayList<String>) {
    Rock execName = args[0]
    CommandLine new(args)
}


import Kernel, Multiboot, Hal/[Hal, Display, Panic, MM], Bochs

kmain: func (mb: MultibootInfo*, magic: UInt32) {
    multiboot = mb@
    Hal setup()

    "This kernel is written in " print()
    Display setFgColor(Color lightGreen)
    "ooc" print()
    Display setFgColor(Color lightGrey)
    "!\n\n" print()

    "Boot Loader:  " print()
    Display setFgColor(Color lightBlue)
    multiboot bootLoaderName as String println()
    Display setFgColor(Color lightGrey)

    "Command Line: " print()
    Display setFgColor(Color lightBlue)
    multiboot cmdline as String println()
    Display setFgColor(Color lightGrey)
    '\n' print()

    "Kernel Start: %p" printfln(kernelStart&)
    "Kernel End:   %p" printfln(kernelEnd&)
    "Kernel Size:  %i kB" printfln((kernelEnd& as Int - kernelStart& as Int) / 1024)
    '\n' print()

    "Total Memory: %6i kB" printfln(MM memorySize / 1024)
    "Used Memory:  %6i kB" printfln(MM usedMemory / 1024)
    "Free Memory:  %6i kB" printfln(MM getFreeMemory() / 1024)

    while(true){}
}

Clean up main with the new color funcs.

import Kernel, Multiboot, Hal/[Hal, Display, Panic, MM], Bochs

kmain: func (mb: MultibootInfo*, magic: UInt32) {
    multiboot = mb@
    Hal setup()

    "This kernel is written in " print()
    Display setFgColor(Color lightGreen, ||
        "ooc" print()
    )
    "!\n\n" print()

    "Boot Loader:  " print()
    Display setFgColor(Color lightBlue, ||
        multiboot bootLoaderName as String println()
    )

    "Command Line: " print()
    Display setFgColor(Color lightBlue, ||
        multiboot cmdline as String println()
    )
    '\n' print()

    "Kernel Start: %p" printfln(kernelStart&)
    "Kernel End:   %p" printfln(kernelEnd&)
    "Kernel Size:  %i kB" printfln((kernelEnd& as Int - kernelStart& as Int) / 1024)
    '\n' print()

    "Total Memory: %6i kB" printfln(MM memorySize / 1024)
    "Used Memory:  %6i kB" printfln(MM usedMemory / 1024)
    "Free Memory:  %6i kB" printfln(MM getFreeMemory() / 1024)

    while(true){}
}


import structs/[ArrayList, List]

import oc/middle/Resolver

import Inquisitor
import Node, Statement, Var, Access

Scope: class extends Node {

    body: List<Statement> { get set }

    init: func {
        body = ArrayList<Statement> new()
    }

    resolve: func (task: Task) {
        task queueList(body)
    }

    resolveAccess: func (acc: Access, task: Task, suggest: Func (Var)) {
        idx := -1
        //"Looking for %s in %s" printfln(acc toString(), toString())

        if(task has("noindex")) {
            size := body size
            idx = size
        } else {
            previous := task
            task walkBackwardTasks(|t|
                if(t node == this) {
                    idx = previous get("index", Int)
                    return true
                }
                previous = t
                false
            )
            if(idx == -1) {
                return // not found, don't resolve
            }
        }

        // idx + 1 to allow recursion, of course :)
        for(i in 0..(idx + 1)) {
            node := body[i]
            match (node class) {
                case Var =>
                    v := node as Var
                    if(v name == acc name) {
                        suggest(v)
                    }
            }
        }
    }

    accessResolver?: func -> Bool { true }

    add: func (s: Statement) {
        body add(s)
    }

    toString: func -> String {
        "{}"
    }

    surrender: func (inq: Inquisitor) {
        inq visitScope(this)
    }

}

Fix crash when resolving calls to other modules' functions

import structs/[ArrayList, List]

import oc/middle/Resolver

import Inquisitor
import Node, Statement, Var, Access

Scope: class extends Node {

    body: List<Statement> { get set }

    init: func {
        body = ArrayList<Statement> new()
    }

    resolve: func (task: Task) {
        task queueList(body)
    }

    resolveAccess: func (acc: Access, task: Task, suggest: Func (Var)) {
        idx := -1
        //"Looking for %s in %s" printfln(acc toString(), toString())

        if(task has("noindex")) {
            size := body size
            idx = size - 1
        } else {
            previous := task
            task walkBackwardTasks(|t|
                if(t node == this) {
                    idx = previous get("index", Int)
                    return true
                }
                previous = t
                false
            )
            if(idx == -1) {
                return // not found, don't resolve
            }
        }

        // idx + 1 to allow calling self
        for(i in 0..(idx + 1)) {
            node := body[i]
            match (node class) {
                case Var =>
                    v := node as Var
                    if(v name == acc name) {
                        suggest(v)
                    }
            }
        }
    }

    accessResolver?: func -> Bool { true }

    add: func (s: Statement) {
        body add(s)
    }

    toString: func -> String {
        "{}"
    }

    surrender: func (inq: Inquisitor) {
        inq visitScope(this)
    }

}


/* This file is part of magic-sdk, an sdk for the open source programming language magic.
 *
 * Copyright (C) 2016 magic-lang
 *
 * This software may be modified and distributed under the terms
 * of the MIT license.  See the LICENSE file for details.
 */

use base
import egl/egl

version(!gpuOff) {
GLExtensions: class {
	eglCreateImageKHR: static Func(Pointer, Pointer, UInt, Pointer, Int*) -> Pointer
	eglDestroyImageKHR: static Func(Pointer, Pointer)
	glEGLImageTargetTexture2DOES: static Func(UInt, Pointer)
	_initialized := static false
	initialize: static func {
		if (!This _initialized) {
			This eglCreateImageKHR = This _load("eglCreateImageKHR") as Func(Pointer, Pointer, UInt, Pointer, Int*) -> Pointer
			This eglDestroyImageKHR = This _load("eglDestroyImageKHR") as Func(Pointer, Pointer)
			This glEGLImageTargetTexture2DOES = This _load("glEGLImageTargetTexture2DOES") as Func(UInt, Pointer)
			This _initialized = true
		}
	}
	_load: static func (name: String) -> (Pointer, Pointer) {
		result := eglGetProcAddress(name toCString())
		if (result == null)
			Debug print("Failed to load OpenGL extension function: " + name)
		(result, null)
	}
}
}

Load function now returns closure.

/* This file is part of magic-sdk, an sdk for the open source programming language magic.
 *
 * Copyright (C) 2016 magic-lang
 *
 * This software may be modified and distributed under the terms
 * of the MIT license.  See the LICENSE file for details.
 */

use base
import egl/egl

version(!gpuOff) {
GLExtensions: class {
	eglCreateImageKHR: static Func(Pointer, Pointer, UInt, Pointer, Int*) -> Pointer
	eglDestroyImageKHR: static Func(Pointer, Pointer)
	glEGLImageTargetTexture2DOES: static Func(UInt, Pointer)
	_initialized := static false
	initialize: static func {
		if (!This _initialized) {
			This eglCreateImageKHR = This _load("eglCreateImageKHR") as Func(Pointer, Pointer, UInt, Pointer, Int*) -> Pointer
			This eglDestroyImageKHR = This _load("eglDestroyImageKHR") as Func(Pointer, Pointer)
			This glEGLImageTargetTexture2DOES = This _load("glEGLImageTargetTexture2DOES") as Func(UInt, Pointer)
			This _initialized = true
		}
	}
	_load: static func (name: String) -> Closure {
		result := eglGetProcAddress(name toCString())
		if (result == null)
			Debug print("Failed to load OpenGL extension function: " + name)
		(result, null) as Closure
	}
}
}


import Kernel, Multiboot, Hal/[Hal, Display, Panic, MM], Bochs

kmain: func (mb: MultibootInfo*, magic: UInt32) {
    multiboot = mb@
    Hal setup()

    "This kernel is written in " print()
    Display setFgColor(Color lightGreen, ||
        "ooc" print()
    )
    "!\n\n" print()

    "Boot Loader:  " print()
    Display setFgColor(Color lightBlue, ||
        multiboot bootLoaderName as String println()
    )

    "Command Line: " print()
    Display setFgColor(Color lightBlue, ||
        multiboot cmdline as String println()
    )
    '\n' print()

    "Kernel Start: %p" printfln(kernelStart&)
    "Kernel End:   %p" printfln(kernelEnd&)
    "Kernel Size:  %i kB" printfln((kernelEnd& as Int - kernelStart& as Int) / 1024)
    '\n' print()

    "Total Memory: %6i kB" printfln(MM memorySize / 1024)
    "Used Memory:  %6i kB" printfln(MM usedMemory / 1024)
    "Free Memory:  %6i kB" printfln(MM getFreeMemory() / 1024)

    while(true){}
}

Add a ridiculous(ly awesome) example of the color funcs.

import Kernel, Multiboot, Hal/[Hal, Display, Panic, MM], Bochs

kmain: func (mb: MultibootInfo*, magic: UInt32) {
    multiboot = mb@
    Hal setup()

    "This kernel is written in " print()
    Display setFgColor(Color lightGreen, ||
        "ooc" print()
    )
    "!\n\n" print()

    "Boot Loader:  " print()
    Display setFgColor(Color lightBlue, ||
        multiboot bootLoaderName as String println()
    )

    "Command Line: " print()
    Display setFgColor(Color lightBlue, ||
        multiboot cmdline as String println()
    )
    '\n' print()

    "Kernel Start: %p" printfln(kernelStart&)
    "Kernel End:   %p" printfln(kernelEnd&)
    "Kernel Size:  %i kB" printfln((kernelEnd& as Int - kernelStart& as Int) / 1024)
    '\n' print()

    "Total Memory: %6i kB" printfln(MM memorySize / 1024)
    "Used Memory:  %6i kB" printfln(MM usedMemory / 1024)
    "Free Memory:  %6i kB" printfln(MM getFreeMemory() / 1024)
    '\n' print()

    "This is " print()
    Display setFgColor(Color lightRed, ||
        "a super cool " print()
        Display setFgColor(Color red, ||
            "example of " print()
        )
        "the new " print()
        Display setBgColor(Color magenta, ||
            "setFgColor and setBgColor" print()
        )
        " functions." print()
    )

    while(true){}
}


import structs/[List, ArrayList, HashMap]
import ../../middle/[Cast, InterfaceDecl, TypeDecl]
import Skeleton

CastWriter: abstract class extends Skeleton {

    write: static func ~cast (this: This, cast: Cast) {

        if(cast inner getType() isGeneric() && cast inner getType() pointerLevel() == 0) {

            current app("(* ("). app(cast type). app("*)"). app(cast inner). app(')')

        } else if(cast getType() getRef() instanceOf(InterfaceDecl)) {

            iDecl := cast getType() getRef() as InterfaceDecl
            current app("(struct _"). app(iDecl getFatType() getInstanceType()). app(") {").
                app(".impl = "). app(cast inner getType() getRef() as TypeDecl underName()). app("__impl__"). app(iDecl getName()). app("_class(), .obj = (lang_types__Object*) ").
                app(cast inner). app('}')

        } else {

            current app("(("). app(cast type). app(") "). app(cast inner). app(')')

        }

    }

}

Fix use-object-as-interface-of-instance-of-a-subclass-of-an-abstract-class-which-implement-the-interface-we-want. That is Good(TM).

import structs/[List, ArrayList, HashMap]
import ../../middle/[Cast, InterfaceDecl, TypeDecl, Type]
import Skeleton

CastWriter: abstract class extends Skeleton {

    write: static func ~cast (this: This, cast: Cast) {

        if(cast inner getType() isGeneric() && cast inner getType() pointerLevel() == 0) {

            current app("(* ("). app(cast type). app("*)"). app(cast inner). app(')')

        } else if(cast getType() getRef() instanceOf(InterfaceDecl)) {

            iDecl := cast getType() getRef() as InterfaceDecl

            implementor := getImplementor(cast inner getType() getRef() as TypeDecl, iDecl getType())
            if(implementor == null) {
                Exception new(This, "Couldn't find implementor for %s in %s\n" format(iDecl toString(), cast inner getType() getRef() toString())) throw()
            }

            current app("(struct _"). app(iDecl getFatType() getInstanceType()). app(") {").
                app(".impl = "). app(implementor underName()). app("__impl__"). app(iDecl getName()). app("_class(), .obj = (lang_types__Object*) ").
                app(cast inner). app('}')

        } else {

            current app("(("). app(cast type). app(") "). app(cast inner). app(')')

        }

    }

    getImplementor: static func (typeDecl: TypeDecl, haystack: Type) -> TypeDecl {

        printf("Searching for implementor of %s in %s\n", haystack toString(), typeDecl toString())
        for(impl in typeDecl getInterfaceDecls()) {
            printf("%s vs %s\n", impl getSuperType() toString(), haystack toString())
            if(impl getSuperRef() getType() equals(haystack)) {
                printf("Found %s\n", impl toString())
                return typeDecl
            }
        }

        if(typeDecl getSuperRef() != null && !typeDecl getSuperRef() isClassClass()) {
            result := getImplementor(typeDecl getSuperRef(), haystack)
            if(result != null) return result
        }

        // TODO: add for interface extending other interfaces
        /*
        for(impl in typeDecl getInterfaceDecls()) {
            result := getImplementor()
        }
        */

        return null

    }

}


use oc

// sdk
import structs/ArrayList
import text/Opts
import os/Coro

// ours
import oc/frontend/[BuildParams, Driver]
import oc/structs/NStructs

main: func (mainArgs: ArrayList<String>) {
    mainCoro := Coro new()
    mainCoro initializeMainCoro()

    opts := Opts new(mainArgs)
    params := BuildParams new(opts opts)

    if(opts args empty?()) {
        "Usage: oc FILE" println()
        "Where FILE is a .use file or an .ooc file" println()
        "If no file is specified, the first .use file found will be compiled." println()
        exit(1)
    }

    opts args each(|arg|
        Driver compile(arg, params, mainCoro)
    )

}

Prepare support for .use compilation

use oc

// sdk
import structs/ArrayList
import text/Opts
import os/Coro
import io/File

// ours
import oc/frontend/[BuildParams, Driver]
import oc/structs/NStructs

main: func (mainArgs: ArrayList<String>) {
    Oc new(mainArgs)
}

Oc: class {
    mainCoro: Coro
    opts: Opts
    params: BuildParams

    init: func (mainArgs: ArrayList<String>) {
        mainCoro = Coro new()
        mainCoro initializeMainCoro()

        opts = Opts new(mainArgs)
        params = BuildParams new(opts opts)

        if(opts args empty?()) {
            "Usage: oc FILE" println()
            "Where FILE is a .use file or an .ooc file" println()
            "If no file is specified, the first .use file found will be compiled." println()
            exit(1)
        }

        opts args each(|arg|
            compileArg(arg)
        )
    }

    compileArg: func (arg: String) {
        path := match {
            case arg endsWith?(".ooc") =>
                // TODO: prepare dummy use file and stuff
                arg
            case arg endsWith?(".use") =>
                raise("use compilation unsupported for now")
                null
            case =>
                arg + ".ooc"
        }

        file := File new(path)
        if (!file exists?()) {
            "#{file path} not found, bailing out" println()
            exit(1)
        }

        Driver compile(path, params, mainCoro)
    }
}


import io/Reader

/**
 * Implement the Reader interface for Buffer.
 */
BufferReader: class extends Reader {
    buffer: Buffer

    init: func ~withBuffer (=buffer) {}

    buffer: func -> Buffer {
        return buffer
    }

    close: func {
        // nothing to close.
    }

    read: func (dest: Char*, destOffset: Int, maxRead: Int) -> SizeT {
        if (marker >= buffer size) {
            Exception new(This, "Buffer overflow! Offset is larger than buffer size.") throw()
        }

        copySize := (marker + maxRead > buffer size ? buffer size - marker : maxRead)
        memcpy(dest, buffer data + marker, copySize)
        marker += copySize

        copySize
    }

    peek: func -> Char {
        buffer get(marker)
    }

    read: func ~char -> Char {
        c := buffer get(marker)
        marker += 1
        c
    }

    hasNext?: func -> Bool {
        return marker < buffer size
    }

    seek: func (offset: Long, mode: SeekMode) -> Bool {
        match mode {
            case SeekMode SET =>
                marker = offset
            case SeekMode CUR =>
                marker += offset
            case SeekMode END =>
                marker = buffer size + offset
        }
        _clampMarker()
        true
    }

    _clampMarker: func {
        if (marker < 0) {
            marker = 0
        }

        if (marker >= buffer size) {
            marker = buffer size - 1
        }
    }

    mark: func -> Long {
        return marker
    }
}

Remove buffer method as it has a same-name field..

import io/Reader

/**
 * Implement the Reader interface for Buffer.
 */
BufferReader: class extends Reader {
    buffer: Buffer

    init: func ~withBuffer (=buffer) {}

    close: func {
        // nothing to close.
    }

    read: func (dest: Char*, destOffset: Int, maxRead: Int) -> SizeT {
        if (marker >= buffer size) {
            Exception new(This, "Buffer overflow! Offset is larger than buffer size.") throw()
        }

        copySize := (marker + maxRead > buffer size ? buffer size - marker : maxRead)
        memcpy(dest, buffer data + marker, copySize)
        marker += copySize

        copySize
    }

    peek: func -> Char {
        buffer get(marker)
    }

    read: func ~char -> Char {
        c := buffer get(marker)
        marker += 1
        c
    }

    hasNext?: func -> Bool {
        return marker < buffer size
    }

    seek: func (offset: Long, mode: SeekMode) -> Bool {
        match mode {
            case SeekMode SET =>
                marker = offset
            case SeekMode CUR =>
                marker += offset
            case SeekMode END =>
                marker = buffer size + offset
        }
        _clampMarker()
        true
    }

    _clampMarker: func {
        if (marker < 0) {
            marker = 0
        }

        if (marker >= buffer size) {
            marker = buffer size - 1
        }
    }

    mark: func -> Long {
        return marker
    }
}


include memory

version(gc) {
    include gc/gc

    gc_malloc: extern(GC_MALLOC) func (size: SizeT) -> Pointer
    gc_malloc_atomic: extern(GC_MALLOC_ATOMIC) func (size: SizeT) -> Pointer
    gc_realloc: extern(GC_REALLOC) func (ptr: Pointer, size: SizeT) -> Pointer
    gc_calloc: func (nmemb: SizeT, size: SizeT) -> Pointer {
        gc_malloc(nmemb * size)
    }
}

version(!gc) {
    gc_malloc: extern(malloc) func (size: SizeT) -> Pointer
    //gc_malloc: func (size: SizeT) -> Pointer {
    //    gc_calloc(1, size)
    //}
    gc_malloc_atomic: extern(malloc) func (size: SizeT) -> Pointer
    gc_realloc: extern(realloc) func (ptr: Pointer, size: SizeT) -> Pointer
    gc_calloc: extern(calloc) func (nmemb: SizeT, size: SizeT) -> Pointer
}

// memory management
memset: extern func (Pointer, Int, SizeT) -> Pointer
memcmp: extern func (Pointer, Pointer, SizeT) -> Int
memmove: extern func (Pointer, Pointer, SizeT)
memcpy: extern func (Pointer, Pointer, SizeT)
free: extern func (Pointer)

// note: sizeof is intentionally not here. sizeof(Int) will be translated
// to sizeof(Int_class()), and thus will always give the same value for
// all types. 'Int size' should be used instead, which will be translated
// to 'Int_class()->size'

Comment again! Apparently it makes rock crash badly.

include memory

version(gc) {
    include gc/gc

    gc_malloc: extern(GC_MALLOC) func (size: SizeT) -> Pointer
    gc_malloc_atomic: extern(GC_MALLOC_ATOMIC) func (size: SizeT) -> Pointer
    gc_realloc: extern(GC_REALLOC) func (ptr: Pointer, size: SizeT) -> Pointer
    gc_calloc: func (nmemb: SizeT, size: SizeT) -> Pointer {
        gc_malloc(nmemb * size)
    }
}

//version(!gc) {
    //gc_malloc: extern(malloc) func (size: SizeT) -> Pointer
    //gc_malloc: func (size: SizeT) -> Pointer {
    //    gc_calloc(1, size)
    //}
    //gc_malloc_atomic: extern(malloc) func (size: SizeT) -> Pointer
    //gc_realloc: extern(realloc) func (ptr: Pointer, size: SizeT) -> Pointer
    //gc_calloc: extern(calloc) func (nmemb: SizeT, size: SizeT) -> Pointer
//}

// memory management
memset: extern func (Pointer, Int, SizeT) -> Pointer
memcmp: extern func (Pointer, Pointer, SizeT) -> Int
memmove: extern func (Pointer, Pointer, SizeT)
memcpy: extern func (Pointer, Pointer, SizeT)
free: extern func (Pointer)

// note: sizeof is intentionally not here. sizeof(Int) will be translated
// to sizeof(Int_class()), and thus will always give the same value for
// all types. 'Int size' should be used instead, which will be translated
// to 'Int_class()->size'


import structs/[HashMap, MultiMap]

main: func {
    testMap(MultiMap<String, String> new(), "123456")
    testMap(HashMap<String, String> new(), "246")

    "Pass" println()
}

testMap: func (map: HashMap<String, String>, control: String) {
    map put("a", "1")
    map put("a", "2")
    map put("b", "3")
    map put("b", "4")
    map put("c", "5")
    map put("c", "6")

    result := ""
    for (v in map) {
        result = result + v
    }

    if (result != control) {
        "Fail! for #{map class name} should be #{control}, is #{result}" println()
        exit(1)
    }
}


import io/File into IO

main: func {
    file := IO File new()
}

Update namespace sample to demo an error.

import io/File into IO

main: func {
    // This works! :)
    file := IO File new()

    // This fails! :(
    anotherFile := File new()
}


Add test case for omit in tuple. Broken for now.

main: func {
    one()
    two()
    three()

    "Pass" println()
}

one: func {
    (a, b, _) :=  foo()

    if (a != 1 || b != 2) {
        "Fail! (one) a = %d, b = %d" printfln(a, b)
        exit(1)
    }
}

two: func {
    (a, _, b) :=  foo()

    if (a != 1 || b != 3) {
        "Fail! (two) a = %d, b = %d" printfln(a, b)
        exit(1)
    }
}

three: func {
    (_, a, b) :=  foo()

    if (a != 2 || b != 3) {
        "Fail! (two) a = %d, b = %d" printfln(a, b)
        exit(1)
    }
}

foo: func -> (Int, Int, Int) {
    (1, 2, 3)
}


import UseDef

import ../frontend/[Token, BuildParams]
import tinker/Errors

Use: class {

    identifier: String
    useDef: UseDef { get set }
    token: Token

    init: func (=identifier, params: BuildParams, =token) {
        uDef := UseDef parse(identifier, params)
        if(!uDef) {
            params errorHandler onError(UseNotFound new(this,
"Use not found in the ooc library path: %s
\nTo install ooc libraries, copy their directories to /usr/lib/ooc/
If you want to install libraries elsewhere, use the OOC_LIBS environment variable,
which is the path ooc will scan for .use files (in this case, %s.use).
For more information, see http://docs.ooc-lang.org/language/libs.html
-------------------" format(identifier, identifier))
            )
        } else {
	    useDef = uDef
	    useDef apply(params)
	}
    }

}

UseNotFound: class extends Error {
    uze: Use

    init: func (=uze, .message) {
        super(uze token, message)
    }
}

Fix link to usefiles doc

import UseDef

import ../frontend/[Token, BuildParams]
import tinker/Errors

Use: class {

    identifier: String
    useDef: UseDef { get set }
    token: Token

    init: func (=identifier, params: BuildParams, =token) {
        uDef := UseDef parse(identifier, params)
        if(!uDef) {
            params errorHandler onError(UseNotFound new(this,
"Use not found in the ooc library path: %s
\nTo install ooc libraries, copy their directories to /usr/lib/ooc/
If you want to install libraries elsewhere, use the OOC_LIBS environment variable,
which is the path ooc will scan for .use files (in this case, %s.use).
For more information, see http://ooc-lang.org/docs/tools/rock/usefiles/
-------------------" format(identifier, identifier))
            )
        } else {
	    useDef = uDef
	    useDef apply(params)
	}
    }

}

UseNotFound: class extends Error {
    uze: Use

    init: func (=uze, .message) {
        super(uze token, message)
    }
}


RockVersion: class {
    execName := static ""

    getMajor:    static func -> Int    { 0 }
    getMinor:    static func -> Int    { 9 }
    getPatch:    static func -> Int    { 7 }
    getRevision: static func -> String { null }
    getCodename: static func -> String { "pacino" }

    getName: static func -> String { "%d.%d.%d%s codename %s" format(
        getMajor(), getMinor(), getPatch(), (getRevision() ? "-" + getRevision() : ""),
        getCodename()) }
}

Bump version to 0.9.7a, for Windows fix

RockVersion: class {
    execName := static ""

    getMajor:    static func -> Int    { 0 }
    getMinor:    static func -> Int    { 9 }
    getPatch:    static func -> Int    { 7 }
    getRevision: static func -> String { "a" }
    getCodename: static func -> String { "pacino" }

    getName: static func -> String { "%d.%d.%d%s codename %s" format(
        getMajor(), getMinor(), getPatch(), (getRevision() ? "-" + getRevision() : ""),
        getCodename()) }
}


prefix np: <http://www.nanopub.org/nschema#>
prefix prov: <http://www.w3.org/ns/prov#>

select (count(distinct ?primarySource) as ?primarySourceCount) where {
  {

    select ?nanopub ?directSource ?indirectSource ?primarySource ?primaryAgent where {
      graph ?head {
        ?nanopub a np:Nanopublication .
        ?nanopub np:hasAssertion ?assertion .
        ?nanopub np:hasProvenance ?provenance .
      }
      graph ?provenance {
        optional {
          ?assertion prov:wasDerivedFrom* / prov:hadPrimarySource ?primarySource .
          optional {
            ?primarySource prov:wasAttributedTo ?primaryAgent .
          }
        }
        optional {
          ?assertion prov:wasDerivedFrom ?directSource .
          optional {
            ?directSource prov:wasDerivedFrom ?indirectSource .
          }
        }
      }
    }

  }
}

Simplify metric: primary source count

prefix np: <http://www.nanopub.org/nschema#>
prefix prov: <http://www.w3.org/ns/prov#>

select (count(distinct ?primarySource) as ?primarySourceCount) where {
  select ?primarySource where {
    graph ?head {
      ?nanopub a np:Nanopublication .
      ?nanopub np:hasAssertion ?assertion .
      ?nanopub np:hasProvenance ?provenance .
    }
    graph ?provenance {
      ?assertion prov:wasDerivedFrom* / prov:hadPrimarySource ?primarySource .
    }
  }
}


PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX bibo: <http://purl.org/ontology/bibo/>
PREFIX dct: <http://purl.org/dc/terms/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX rpubl: <http://rinfo.lagrummet.se/ns/2008/11/rinfo/publ#>

CONSTRUCT {

    ?s ?p ?o .
    ?current ?curr_p ?curr_o .

    ?relitem a ?reltype;
        ?relprop ?reltext .

} WHERE {

    {

        ?g foaf:primaryTopic ?current .
        GRAPH ?g { ?s ?p ?o }

    } UNION {

        ?current ?curr_p ?curr_o .

    } UNION {

        ?current ?rel ?relitem .
        FILTER(?rel = dct:publisher
            || ?rel = rpubl:forfattningssamling
            || ?rel = rpubl:utrSerie
            || ?rel = rpubl:rattsfallspublikation
            || ?rel = rpubl:allmannaRadSerie) .
        ?relitem ?relprop ?reltext .
        FILTER( isLiteral(?reltext) )
        OPTIONAL { ?relitem a ?reltype . }

    }

}

Use minimal RDF construct for elasticsearch data

PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX bibo: <http://purl.org/ontology/bibo/>
PREFIX dct: <http://purl.org/dc/terms/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX rpubl: <http://rinfo.lagrummet.se/ns/2008/11/rinfo/publ#>

CONSTRUCT {

    #?s ?p ?o .
    ?current ?curr_p ?curr_o .

    #?relitem a ?reltype;
    #    ?relprop ?reltext .

} WHERE {

    #{
    #
    #    ?g foaf:primaryTopic ?current .
    #    GRAPH ?g { ?s ?p ?o }
    #
    #} UNION {

        ?current ?curr_p ?curr_o .

    #} UNION {
    #
    #    ?current ?rel ?relitem .
    #    FILTER(?rel = dct:publisher
    #        || ?rel = rpubl:forfattningssamling
    #        || ?rel = rpubl:utrSerie
    #        || ?rel = rpubl:rattsfallspublikation
    #        || ?rel = rpubl:allmannaRadSerie) .
    #    ?relitem ?relprop ?reltext .
    #    FILTER( isLiteral(?reltext) )
    #    OPTIONAL { ?relitem a ?reltype . }
    #
    #}

}


PREFIX rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs:  <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rpath: <https://w3id.org/lodsight/rdf-path#>
PREFIX spin:  <http://spinrdf.org/spin#>

CONSTRUCT {
  [] a spin:ConstraintViolation ;
    spin:violationRoot ?path ;
    spin:violationPath rpath:start ;
    rdfs:label "Path is not continuous."@en .
}
WHERE {
  {
    SELECT ?path
    WHERE {
      ?path a rpath:Path ;
        rpath:edges/rdf:rest*/rdf:first ?edge .
      ?edge rpath:start ?start .
      FILTER NOT EXISTS {
        [] rpath:end ?start .
      }
    }
    GROUP BY ?path
    HAVING (COUNT(DISTINCT ?start) > 1)
  }
}

Fix continuous path integrity constraint

PREFIX rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs:  <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rpath: <https://w3id.org/lodsight/rdf-path#>
PREFIX spin:  <http://spinrdf.org/spin#>

CONSTRUCT {
  [] a spin:ConstraintViolation ;
    spin:violationRoot ?next ;
    spin:violationPath rpath:start ;
    spin:violationValue ?o ;
    rdfs:label "Path is not continuous."@en .
}
WHERE {
  [] rdf:first/rpath:end/rdf:type ?o ;
    rdf:rest/rdf:first ?next .
  FILTER NOT EXISTS {
    ?next rpath:start/rdf:type ?o .
  }
}


--
-- SPARQL query to add missing chromosome type (triples) to EnsEMBL RDF graph.
--
-- Prerequisite: GRANT SPARQL_UPDATE to "SPARQL";
--

PREFIX obo: <http://purl.obolibrary.org/obo/>
PREFIX owl: <http://www.w3.org/2002/07/owl#>

INSERT INTO <http://ensembl.org/Sus_scrofa> {
   ?chr2 a obo:SO_0000340
}
WHERE {
   GRAPH <http://www.animalgenome.org/QTLdb/pig> {
      ?chr1 a obo:SO_0000340 .
      BIND(uri(concat('http://rdf.ebi.ac.uk/resource/ensembl/86/sus_scrofa/Sscrofa10.2/', replace(str(?chr1), '.+/', ''))) AS ?chr2)
   }
}

--
-- SPARQL query to delete above triples
--
-- PREFIX owl: <http://www.w3.org/2002/07/owl#>
-- WITH  <http://ensembl.org/Sus_scrofa>
-- DELETE { ?s ?p ?o }
-- { ?s ?p ?o ; a obo:SO_0000340 }

Fix ns prefix in the query

--
-- SPARQL query to add missing chromosome type (triples) to EnsEMBL RDF graph.
--
-- Prerequisite: GRANT SPARQL_UPDATE to "SPARQL";
--

PREFIX obo: <http://purl.obolibrary.org/obo/>

INSERT INTO <http://ensembl.org/Sus_scrofa> {
   ?chr2 a obo:SO_0000340
}
WHERE {
   GRAPH <http://www.animalgenome.org/QTLdb/pig> {
      ?chr1 a obo:SO_0000340 .
      BIND(uri(concat('http://rdf.ebi.ac.uk/resource/ensembl/86/sus_scrofa/Sscrofa10.2/', replace(str(?chr1), '.+/', ''))) AS ?chr2)
   }
}

--
-- SPARQL query to delete above triples
--
-- PREFIX obo: <http://purl.obolibrary.org/obo/>
-- WITH  <http://ensembl.org/Sus_scrofa>
-- DELETE { ?s ?p ?o }
-- { ?s ?p ?o ; a obo:SO_0000340 }


PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs:<http://www.w3.org/2000/01/rdf-schema#>
PREFIX owl:<http://www.w3.org/2002/07/owl#>
PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
PREFIX foaf:<http://xmlns.com/foaf/0.1/>
SELECT REDUCED ?title ?description ?resource ?label (ucase(substr(?label, 1, 1)) as ?index) (regex(?label, "^[a-zA-Z]") as ?letter) {
    {
        <$this> rdfs:label ?title
        OPTIONAL {
            <$this> rdfs:comment ?description
        }
    } UNION {
        ?resource a <$this>
        OPTIONAL {
            ?resource skos:prefLabel ?label
        } OPTIONAL {
            ?resource rdfs:label ?label
        } OPTIONAL {
            ?resource foaf:name ?label
        }
    } UNION {
        <$this> owl:equivalentClass ?type . ?resource a ?type
        OPTIONAL {
            ?resource skos:prefLabel ?label
        } OPTIONAL {
            ?resource rdfs:label ?label
        } OPTIONAL {
            ?resource foaf:name ?label
        }
    }
} ORDER BY ?label ?resource LIMIT 101

Increase the number of resources in class index

PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs:<http://www.w3.org/2000/01/rdf-schema#>
PREFIX owl:<http://www.w3.org/2002/07/owl#>
PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
PREFIX foaf:<http://xmlns.com/foaf/0.1/>
SELECT REDUCED ?title ?description ?resource ?label (ucase(substr(?label, 1, 1)) as ?index) (regex(?label, "^[a-zA-Z]") as ?letter) {
    {
        <$this> rdfs:label ?title
        OPTIONAL {
            <$this> rdfs:comment ?description
        }
    } UNION {
        ?resource a <$this>
        OPTIONAL {
            ?resource skos:prefLabel ?label
        } OPTIONAL {
            ?resource rdfs:label ?label
        } OPTIONAL {
            ?resource foaf:name ?label
        }
    } UNION {
        <$this> owl:equivalentClass ?type . ?resource a ?type
        OPTIONAL {
            ?resource skos:prefLabel ?label
        } OPTIONAL {
            ?resource rdfs:label ?label
        } OPTIONAL {
            ?resource foaf:name ?label
        }
    }
} ORDER BY ?label ?resource LIMIT 1001


# # Missing Label
#
# Problem: An entity does not have a label. This may cause confusion or misuse.
#
# Solution: Add a label.

PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

SELECT DISTINCT ?entity ?property ?value WHERE {
  ?entity ?any ?o .
  BIND ("rdfs:label" AS ?property) .
  FILTER NOT EXISTS {?entity rdfs:label ?value}
  FILTER NOT EXISTS {?entity a owl:Ontology}
  FILTER NOT EXISTS {
    ?entity owl:deprecated ?dep .
    FILTER regex(str(?dep), "true")
  }
  FILTER (!isBlank(?entity))
}
ORDER BY ?entity

Exclude entities with ONLY a type declaration from label check

# # Missing Label
#
# Problem: An entity does not have a label. This may cause confusion or misuse.
#
# Solution: Add a label.

PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

SELECT DISTINCT ?entity ?property ?value WHERE {
  ?entity ?any ?o .
  BIND ("rdfs:label" AS ?property) .
  FILTER NOT EXISTS {?entity rdfs:label ?value}
  FILTER NOT EXISTS {?entity a owl:Ontology}
  FILTER NOT EXISTS {
    ?entity owl:deprecated ?dep .
    FILTER regex(str(?dep), "true")
  }
  FILTER EXISTS {
    ?entity ?property ?object .
    FILTER (?property != rdf:type)
  }
  FILTER (!isBlank(?entity))
}
ORDER BY ?entity


# 1. Directors of movies starring Brad Pitt
SELECT ?title ?name
WHERE {
  ?movie dbpprop:starring dbpedia:Brad_Pitt;
         rdfs:label ?title;
         dbpedia-owl:director [ rdfs:label ?name ].
  FILTER LANGMATCHES(LANG(?title), "EN")
  FILTER LANGMATCHES(LANG(?name),  "EN")
}

Add name lookup in Brad Pitt query.

# 1. Directors of movies starring Brad Pitt
SELECT ?title ?name
WHERE {
  ?movie dbpprop:starring [ rdfs:label "Brad Pitt"@en ];
         rdfs:label ?title;
         dbpedia-owl:director [ rdfs:label ?name ].
  FILTER LANGMATCHES(LANG(?title), "EN")
  FILTER LANGMATCHES(LANG(?name),  "EN")
}


# 1) Fjern genreSplit

SPARQL
PREFIX : <http://data.deichman.no/ontology#>
PREFIX migration: <http://migration.deichman.no>

WITH <http://deichman.no/migration>

DELETE {
	?publication migration:genreSplit ?genreSplit .
	?genreSplit ?p ?o .
}

WHERE {
	?publication migration:genreSplit ?genreSplit ;
	 a :Publication .
	?genreSplit ?p ?o .
}
;

Add queries to remove unused genres and subjects

# 1) Fjern genreSplit

SPARQL
PREFIX : <http://data.deichman.no/ontology#>
PREFIX migration: <http://migration.deichman.no/>

WITH <http://deichman.no/migration>

DELETE {
	?publication migration:genreSplit ?genreSplit .
	?genreSplit ?p ?o .
}

WHERE {
	?publication migration:genreSplit ?genreSplit ;
	 a :Publication .
	?genreSplit ?p ?o .
}
;

# 2) Fjern overflødige sjangrer

SPARQL
PREFIX : <http://data.deichman.no/ontology#>
PREFIX migration: <http://migration.deichman.no/>

WITH <http://deichman.no/migration>

DELETE {
	?genre ?p ?o .
}

WHERE {
	?genre a :Genre ;
		?p ?o .
	MINUS {?s :genre ?genre}
}
;

# 3) Fjern overflødige emner

SPARQL
PREFIX : <http://data.deichman.no/ontology#>
PREFIX migration: <http://migration.deichman.no/>

WITH <http://deichman.no/migration>

DELETE {
	?subject ?p ?o .
}

WHERE {
	?subject a :Subject ;
		?p ?o .
	MINUS {?s :subject ?subject}
}
;


# 1) Slett sjanger på tegneserier med underavdeling, legg til underavdeling som sjanger

SPARQL
PREFIX : <http://__HOST__/ontology#>
PREFIX raw: <http://__HOST__/raw#>
PREFIX literaryForm: <http://data.deichman.no/literaryForm#>

WITH <http://deichman.no/migration>

MODIFY

DELETE {
    ?work :genre ?genre .
}

INSERT {
	?work :literaryForm literaryForm:comicBook ;
		:genre `IRI(CONCAT(STR("http://__HOST__/genre/g"), MD5(?subdivision)))` .
	`IRI(CONCAT(STR("http://__HOST__/genre/g"), MD5(?subdivision)))` a :Genre ;
		:prefLabel ?subdivision .
}

WHERE {
    ?genre :prefLabel "Tegneserier" ;
    	raw:genreSubdivision ?subdivision ;
    	a :Genre .
    ?work :genre ?genre ;
    	a :Work.
}
;

Add query to edit movie genres

# 1) Gjør sjanger tegneserie med undersjanger om til litterær form + sjanger

SPARQL
PREFIX : <http://__HOST__/ontology#>
PREFIX raw: <http://__HOST__/raw#>
PREFIX literaryForm: <http://data.deichman.no/literaryForm#>

WITH <http://deichman.no/migration>

MODIFY

DELETE {
    ?work :genre ?genre .
}

INSERT {
	?work :literaryForm literaryForm:comicBook ;
		:genre `IRI(CONCAT(STR("http://__HOST__/genre/g"), MD5(?subdivision)))` .
	`IRI(CONCAT(STR("http://__HOST__/genre/g"), MD5(?subdivision)))` a :Genre ;
		:prefLabel ?subdivision .
}

WHERE {
    ?genre :prefLabel "Tegneserier" ;
    	raw:genreSubdivision ?subdivision ;
    	a :Genre .
    ?work :genre ?genre ;
    	a :Work.
}
;

# 2) Gjør sjanger Filmer med undersjanger om til medietype + sjanger

SPARQL
PREFIX : <http://__HOST__/ontology#>
PREFIX raw: <http://__HOST__/raw#>
PREFIX literaryForm: <http://data.deichman.no/literaryForm#>

WITH <http://deichman.no/migration>

MODIFY

DELETE {
    ?work :genre ?genre .
}

INSERT {
	?work :literaryForm literaryForm:comicBook ;
		:genre `IRI(CONCAT(STR("http://__HOST__/genre/g"), MD5(?subdivision)))` .
	`IRI(CONCAT(STR("http://__HOST__/genre/g"), MD5(?subdivision)))` a :Genre ;
		:prefLabel ?subdivision .
}

WHERE {
    ?genre :prefLabel "Filmer" ;
		raw:genreSubdivision ?subdivision ;
		a :Genre .
	?work :genre ?genre ;
		a :Work.
}
;


# Retrieve the number of copubs between DTU and ?collab per year

SELECT (COUNT(DISTINCT ?pub) AS ?number) ?year
WHERE {
  {
    ?collab a wos:UnifiedOrganization ;
        vivo:relatedBy ?address .
    ?address a wos:Address ;
        vivo:relates ?pub .
    ?authorship a vivo:Authorship ;
            wos:fullName ?name ;
            vivo:relates ?pub, ?address .
    ?pub a wos:Publication ;
        rdfs:label ?title ;
        vivo:dateTimeValue ?dtv ;
        vivo:relatedBy ?address .
    ?dtv vivo:dateTime ?date .
    FILTER(?startYear <= ?date)
    FILTER(?endYear >= ?date)
    BIND(STRBEFORE(STR(?date), "-") AS ?year)
    ?pub vivo:relatedBy ?dtuAddress .
    ?dtuAddress a wos:Address .
    ?dtuAddress vivo:relates d:org-technical-university-of-denmark .
  } UNION {
    ?collab a wos:UnifiedOrganization ;
        vivo:relatedBy ?address .
    ?address a wos:Address ;
        vivo:relates ?pub .
    ?pub a wos:Publication ;
        rdfs:label ?title ;
        vivo:dateTimeValue ?dtv ;
        vivo:relatedBy ?address .
    ?dtv vivo:dateTime ?date .
    FILTER(?startYear <= ?date)
    FILTER(?endYear >= ?date)
    BIND(STRBEFORE(STR(?date), "-") AS ?year)
    ?pub vivo:relatedBy ?dtuAddress .
    ?dtuAddress a wos:Address .
    ?dtuAddress vivo:relates d:org-technical-university-of-denmark .
  }
 } GROUP BY ?year ORDER BY DESC(?year)

Improve efficiency of summary copub count query

# Retrieve the number of copubs between DTU and ?collab per year

SELECT (COUNT(DISTINCT ?pub) AS ?number) ?year
WHERE {
    ?collab a wos:UnifiedOrganization ;
        vivo:relatedBy ?address .
    ?address a wos:Address ;
        vivo:relates ?pub .
    ?pub a wos:Publication ;
        vivo:dateTimeValue ?dtv .
    ?dtv vivo:dateTime ?date .
    FILTER(?startYear <= ?date)
    FILTER(?endYear >= ?date)
    BIND(STRBEFORE(STR(?date), "-") AS ?year)
    FILTER EXISTS {
      ?pub vivo:relatedBy ?dtuAddress .
      ?dtuAddress a wos:Address .
      ?dtuAddress vivo:relates d:org-technical-university-of-denmark .
    }
} GROUP BY ?year ORDER BY DESC(?year)


# Querry all applications and settings to contextualized preferences
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX c4a:  <http://rbmm.org/schemas/cloud4all/0.1/>
SELECT DISTINCT
	?type
	(str(?c) as ?contextID)
	(str(?an) as ?appName)
	(str(?aa) as ?appActive)
	(str(?si) as ?setID)
	(str(?sv) as ?setValue)
	(str(?sn) as ?setName)
WHERE
{
	?if rdf:type c4a:InferredConfiguration.
	?if c4a:id ?c.
	?if c4a:refersTo ?app.
	?app rdf:type ?type.
	?app c4a:name ?an.
	?app c4a:isActive ?aa.
	?app c4a:settings ?set.
	?set c4a:id ?si.
	?set c4a:value ?sv.
	?set c4a:name ?sn.
} ORDER BY DESC(?c)

Update Querry according to solutions IDs

# Querry all applications and settings to contextualized preferences
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX c4a:  <http://rbmm.org/schemas/cloud4all/0.1/>
SELECT DISTINCT
	?type
	(str(?c) as ?contextID)
	(str(?an) as ?appID)
	(str(?aa) as ?appActive)
	(str(?si) as ?setID)
	(str(?sv) as ?setValue)
	(str(?sn) as ?setName)
WHERE
{
	?if rdf:type c4a:InferredConfiguration.
	?if c4a:id ?c.
	?if c4a:refersTo ?app.
	?app rdf:type ?type.
	?app c4a:id ?an.
	?app c4a:isActive ?aa.
	?app c4a:settings ?set.
	?set c4a:id ?si.
	?set c4a:value ?sv.
	?set c4a:name ?sn.
} ORDER BY DESC(?c)


# # Deprecated Class Reference
#
# Problem: A deprecated class is used in a logical axiom. A deprecated class can be the child of another class (e.g. ObsoleteClass), but it cannot have children or be used in blank nodes or equivalent class statements. Additionally, a deprecated class should not have any equivalent classes or anonymous parents.
#
# Solution: Replace deprecated class.

PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

SELECT DISTINCT ?entity ?property ?value WHERE {
  {
   VALUES ?property {
     owl:equivalentClass
     rdfs:subClassOf
   }
   ?entity owl:deprecated ?dep .
   FILTER regex(str(?dep), "true") .
   ?value ?property ?entity .
   FILTER (!STRENDS(str(?property), "owl#deprecated"))
  }
  UNION
  {
   ?entity owl:deprecated ?dep .
   FILTER regex(str(?dep), "true") .
   ?entity ?property ?value .
   FILTER (!STRENDS(str(?property), "owl#deprecated")) .
   FILTER NOT EXISTS { ?property a owl:AnnotationProperty }
   FILTER NOT EXISTS {
     ?entity rdfs:subClassOf ?value .
     FILTER (!isBlank(?value))
   }
   FILTER NOT EXISTS {
     ?entity rdfs:subPropertyOf ?value .
     FILTER (!isBlank(?value))
   }
   FILTER(?property != rdf:type)
  }
}
ORDER BY ?entity

Use URIs rather than string manipulation

# # Deprecated Class Reference
#
# Problem: A deprecated class is used in a logical axiom. A deprecated class can be the child of another class (e.g. ObsoleteClass), but it cannot have children or be used in blank nodes or equivalent class statements. Additionally, a deprecated class should not have any equivalent classes or anonymous parents.
#
# Solution: Replace deprecated class.

PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

SELECT DISTINCT ?entity ?property ?value WHERE {
  {
   VALUES ?property {
     owl:equivalentClass
     rdfs:subClassOf
   }
   ?entity owl:deprecated true .
   FILTER ?dep .
   ?value ?property ?entity .
   FILTER (?property != owl:deprecated))
  }
  UNION
  {
   ?entity owl:deprecated true .
   ?entity ?property ?value .
   FILTER (?property != owl:deprecated) .
   FILTER NOT EXISTS { ?property a owl:AnnotationProperty }
   FILTER NOT EXISTS {
     ?entity rdfs:subClassOf ?value .
     FILTER (!isBlank(?value))
   }
   FILTER NOT EXISTS {
     ?entity rdfs:subPropertyOf ?value .
     FILTER (!isBlank(?value))
   }
   FILTER(?property != rdf:type)
  }
}
ORDER BY ?entity


CONSTRUCT {
	?person dbpedia-owl:birthPlace ?city.
}
WHERE {
	?person a dbpedia-owl:Artist;
	        dbpedia-owl:birthPlace ?city.
	?city rdfs:label ?name;
	      dbpedia-owl:country ?country.
	?country rdfs:label "Belgium"@en.
}

Remove unnecessary clause in example query.

CONSTRUCT {
	?person dbpedia-owl:birthPlace ?city.
}
WHERE {
	?person a dbpedia-owl:Artist;
	        dbpedia-owl:birthPlace ?city.
	?city dbpedia-owl:country ?country.
	?country rdfs:label "Belgium"@en.
}


# # Deprecated Class Reference
#
# Problem: A deprecated class is used in a logical axiom. A deprecated class can be the child of another class (e.g. ObsoleteClass), but it cannot have children or be used in blank nodes or equivalent class statements. Additionally, a deprecated class should not have any equivalent classes or anonymous parents.
#
# Solution: Replace deprecated class.

PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

SELECT DISTINCT ?entity ?property ?value WHERE {
  {
   VALUES ?property {
     owl:equivalentClass
     rdfs:subClassOf
   }
   ?entity owl:deprecated ?dep .
   FILTER regex(str(?dep), "true") .
   ?value ?property ?entity .
   FILTER (!STRENDS(str(?property), "owl#deprecated"))
  }
  UNION
  {
   ?entity owl:deprecated ?dep .
   FILTER regex(str(?dep), "true") .
   ?entity ?property ?value .
   FILTER (!STRENDS(str(?property), "owl#deprecated")) .
   FILTER NOT EXISTS { ?property a owl:AnnotationProperty }
   FILTER NOT EXISTS {
     ?entity rdfs:subClassOf ?value .
     FILTER (!isBlank(?value))
   }
   FILTER NOT EXISTS {
     ?entity rdfs:subPropertyOf ?value .
     FILTER (!isBlank(?value))
   }
   FILTER(?property != rdf:type)
  }
}
ORDER BY ?entity

Exclude 'has obsolescence reason' property from deprecated class reference check

# # Deprecated Class Reference
#
# Problem: A deprecated class is used in a logical axiom. A deprecated class can be the child of another class (e.g. ObsoleteClass), but it cannot have children or be used in blank nodes or equivalent class statements. Additionally, a deprecated class should not have any equivalent classes or anonymous parents.
#
# Solution: Replace deprecated class.

PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

SELECT DISTINCT ?entity ?property ?value WHERE {
  {
   VALUES ?property {
     owl:equivalentClass
     rdfs:subClassOf
   }
   ?entity owl:deprecated ?dep .
   FILTER regex(str(?dep), "true") .
   ?value ?property ?entity .
   FILTER (?property != owl:deprecated) .
  }
  UNION
  {
   ?entity owl:deprecated ?dep .
   FILTER regex(str(?dep), "true") .
   ?entity ?property ?value .
   FILTER (?property != owl:deprecated) .
   FILTER (?property != obo:IAO_0000231) .
   FILTER NOT EXISTS { ?property a owl:AnnotationProperty }
   FILTER NOT EXISTS {
     ?entity rdfs:subClassOf ?value .
     FILTER (!isBlank(?value))
   }
   FILTER NOT EXISTS {
     ?entity rdfs:subPropertyOf ?value .
     FILTER (!isBlank(?value))
   }
   FILTER(?property != rdf:type)
  }
}
ORDER BY ?entity


SELECT ?item ?sciname ?ncbi WHERE {
  ?item (wdt:P171*) wd:Q25314 .
  ?item wdt:P685 ?ncbi .
  ?item wdt:P225 ?sciname .
  FILTER EXISTS { ?item wdt:P18 ?picture }
  FILTER EXISTS { ?item wdt:P105 wd:Q7432 }
}


Add a query made by Pasquale answering a need expressed on the MLA list.

PREFIX mus: <http://data.doremus.org/ontology#>
PREFIX ecrm: <http://erlangen-crm.org/current/>
PREFIX efrbroo: <http://erlangen-crm.org/efrbroo/>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>

# Source: https://list.indiana.edu/sympa/arc/mla-l/2017-08/msg00248.html
# [en] Could I find any music for flute and TWO bassoons  an interesting combo

SELECT DISTINCT ?expression, SAMPLE(?composer) as ?composer, SAMPLE(?title) as ?title, ?casting
WHERE {
  ?expression a efrbroo:F22_Self-Contained_Expression ;
          mus:U70_has_title ?title ;
          mus:U13_has_casting ?casting .

  ?expCreation efrbroo:R17_created ?expression ;
          ecrm:P9_consists_of / ecrm:P14_carried_out_by / foaf:name ?composer .

  ?casting mus:U23_has_casting_detail ?allCastingDets .

  ?casting mus:U23_has_casting_detail ?castingDet1, ?castingDet2 .
  ?castingDet1 mus:U2_foresees_use_of_medium_of_performance_of_type ?bassoon ;
       mus:U30_foresees_quantity_of_mop 2 .

  ?castingDet2 mus:U2_foresees_use_of_medium_of_performance_of_type ?flute .

  VALUES (?bassoon) { ( <http://data.doremus.org/vocabulary/iaml/mop/wba> ) (<http://www.mimo-db.eu/InstrumentsKeywords/3795>) }
  VALUES (?flute) { ( <http://data.doremus.org/vocabulary/iaml/mop/wfl> ) (<http://www.mimo-db.eu/InstrumentsKeywords/3955>) }
}
GROUP BY ?expression ?casting
HAVING (COUNT(?allCastingDets) >= 2)


# 1) Slett sjanger på tegneserier med underavdeling, legg til underavdeling som sjanger

SPARQL
PREFIX : <http://__HOST__/ontology#>
PREFIX raw: <http://__HOST__/raw#>
PREFIX literaryForm: <http://data.deichman.no/literaryForm#>

WITH <http://deichman.no/migration>

MODIFY

DELETE {
    ?work :genre ?genre .
}

INSERT {
	?work :literaryForm literaryForm:comicBook ;
		:genre `IRI(CONCAT(STR("http://__HOST__/genre/g"), MD5(?subdivision)))` .
	`IRI(CONCAT(STR("http://__HOST__/genre/g"), MD5(?subdivision)))` a :Genre ;
		:prefLabel ?subdivision .
}

WHERE {
    ?genre :prefLabel "Tegneserier" ;
    	raw:genreSubdivision ?subdivision ;
    	a :Genre .
    ?work :genre ?genre ;
    	a :Work.
}
;


Create queries to process genre statements

# 1) Remove split statements from publications

SPARQL
PREFIX migration: <http://migration.deichman.no/>
PREFIX : <http://data.deichman.no/ontology#>

WITH <http://deichman.no/migration>

delete {
  ?doc ?p ?o
} where {
  ?doc a :Publication ;
    ?p ?o .
  values ?p {
    migration:genreSplit1
    migration:genreSplit2
    migration:genreSplitMain
    migration:genreSplitSub
  }
}
;


Add a SPARQL query that helps with LOV syncing

# Returns namespace mappings from LOV where the URI doesn't exist yet
# in prefix.cc, and the prefix is unassigned in prefix.cc.
# Run with Jena: sparql --query lov-mappings.sparql --results csv > out.csv
# Then import with csv-import.php
PREFIX vann: <http://purl.org/vocab/vann/>
SELECT ?prefix ?URI
FROM <http://prefix.cc/popular/all.file.vann> {
  SERVICE <http://lov.okfn.org/endpoint/lov> {
    SELECT ?prefix ?URI {
      [] vann:preferredNamespacePrefix ?prefix;
        vann:preferredNamespaceUri ?URI;
    }
  }
  FILTER(NOT EXISTS { [] vann:preferredNamespaceUri ?URI })
  FILTER(NOT EXISTS { [] vann:preferredNamespacePrefix ?prefix })
}
ORDER BY ?prefix


Add sketch of RWO to MADSRDF Name construct

PREFIX madsrdf: <http://www.loc.gov/mads/rdf/v1#>

CONSTRUCT {

    ?name a madsrdf:PersonalName ;
        madsrdf:identifiesRWO ?s ;
        madsrdf:elementList (
            ?givenElem
            ?famnameElem
        ) .

        ?famnameElem a madsrdf:FamilyNameElement ; madsrdf:elementValue ?familyName .
        ?givenElem a madsrdf:GivenNameElement ; madsrdf:elementValue ?givenName .

} WHERE {

    ?s a :Person .
    BIND(bnode() as ?name)

    OPTIONAL {
        ?s :familyName ?familyName .
        BIND(bnode() as ?famnameElem)
    }
    OPTIONAL {
        ?s givenName ?givenName .
        BIND(bnode() as ?givenElem)
    }
}


Add migration to insert initiatie musician group

PREFIX mu: <http://mu.semte.ch/vocabularies/core/>
PREFIX bravoer: <http://mu.semte.ch/vocabularies/ext/bravoer/>
PREFIX music: <http://mu.semte.ch/vocabularies/ext/music/>
PREFIX vcard: <http://www.w3.org/2006/vcard/ns#>
PREFIX dct: <http://purl.org/dc/terms/>

INSERT DATA {
  GRAPH <http://mu.semte.ch/application> {

    <http://data.bravoer.be/id/musician-groups/initiation> a bravoer:MusicianGroup ;
        mu:uuid "baa648d7-03b6-43f5-b875-1407e37b32c0" ;
        vcard:hasName "initiatie" ;
        dct:created "2018-01-03T16:21:00.000Z"^^<http://www.w3.org/2001/XMLSchema#date> .
  }
}


Add first SPARQL query file about disambiguation

# Disambiguation items that have the sitelink to a specific language Wikipedia
SELECT ?item
WHERE
{
    ?item wdt:P31 wd:Q4167410 .
    ?wiki0 schema:about ?item ;
           schema:isPartOf <https://sh.wikipedia.org/>
}


PREFIX po: <http://www.bbc.co.uk/ontologies/programmes/>
PREFIX dct: <http://purl.org/dc/terms/>

select distinct ?uri ?title ?date ?short_synopsis ?medium_synopsis ?long_synopsis ?image where {{
    graph <http://slobr.linkedmusic.org/EMS> {{
        {uri}
        ?uri a po:Episode;
            dct:date ?date ;
            dct:title ?title ;
            po:short_synopsis ?short_synopsis ;
            po:medium_synopsis ?medium_synopsis ;
            po:long_synopsis ?long_synopsis ;
            dct:relation ?image .
    }}
}}
order by desc(?date)


on run argv
	tell application "iTunes"
		set p to first item of argv
		set a to (p as POSIX file)
		add a to playlist (second item of argv)
	end tell
end run

Add explanation of arguments in AppleScript scripts

on run argv
	set posixFile to first item of argv
	set playlistName to second item of argv

	tell application "iTunes"
		set p to posixFile
		set a to (p as POSIX file)
		add a to playlist playlistName
	end tell
end run


-- execute_iterm.scpt
-- last change: 19 Jan 2013
---
-- this script require an argument that represent the command to execute

on run argv

    set command to (item 1 of argv)

    tell application "iTerm"

        try
            set mysession to current session of current terminal
        on error
            set myterm to (make new terminal)
            tell myterm
                launch session "Default"
                set mysession to current session
            end tell
        end try

        -- execute the command
        tell mysession
            write text command
        end tell

    end tell

end run

Change session name to 'rspec'

-- execute_iterm.scpt
-- last change: 19 Jan 2013
---
-- this script require an argument that represent the command to execute

on run argv

    set command to (item 1 of argv)

    tell application "iTerm"

        try
            set mysession to current session of current terminal
        on error
            set myterm to (make new terminal)
            tell myterm
                launch session "rspec"
                set mysession to current session
            end tell
        end try

        -- execute the command
        tell mysession
            write text command
        end tell

    end tell

end run


tell application "Spotify"
  set cstate to "{"
  set cstate to cstate & "\"track_id\": \"" & current track's id & "\""
  set cstate to cstate & ",\"volume\": " & sound volume
  set cstate to cstate & ",\"position\": " & player position
  set cstate to cstate & ",\"state\": \"" & player state & "\""
  set cstate to cstate & "}"

  return cstate
end tell

Fix get state for locales that have commas as decimal delimiters

on replace_chars(this_text, search_string, replacement_string)
  set AppleScript's text item delimiters to the search_string
  set the item_list to every text item of this_text
  set AppleScript's text item delimiters to the replacement_string
  set this_text to the item_list as string
  set AppleScript's text item delimiters to ""
  return this_text
end replace_chars

tell application "Spotify"
  -- force string coercion and locale format
  set position to "" & player position

  set cstate to "{"
  set cstate to cstate & "\"track_id\": \"" & current track's id & "\""
  set cstate to cstate & ",\"volume\": " & sound volume
  -- replace , with . when locale has , as decimal delimiter
  set cstate to cstate & ",\"position\": " & my replace_chars(position, ",", ".")
  set cstate to cstate & ",\"state\": \"" & player state & "\""
  set cstate to cstate & "}"

  return cstate
end tell


on run
	tell application "BibDesk"
		try
			set alertResult to display alert ("Really remove all linked files and private notes from " & name of first document as string) & "?" buttons {"Cancel", "OK"} default button "OK" cancel button "Cancel" as warning

			if button returned of alertResult is "OK" then
				save first document in "Filtered " & (name of first document as string) & ".bib"
				repeat with thePub in first document's publications
					set thePub's note to my splitNote(thePub's note)
					repeat with theFile in thePub's linked files
						remove theFile from thePub
					end repeat
				end repeat
				save first document
			end if
		on error -128
			display dialog "User cancelled."
		end try
	end tell
end run

to splitNote(theNoteText)
	try
		set oldDelims to AppleScript's text item delimiters
		set AppleScript's text item delimiters to {"---"}

		set theParts to every text item of theNoteText

		if length of theParts is greater than 1 then
			set outText to text 2 through end of last item of theParts
		else
			set outText to ""
		end if
		set AppleScript's text item delimiters to oldDelims
	on error
		set AppleScript's text item delimiters to oldDelims
	end try
	return outText
end splitNote

Simplify filterer code so it actually works.

on run
	tell application "BibDesk"
		try
			set alertResult to display alert ("Really remove all linked files and private notes from " & name of first document as string) & "?" buttons {"Cancel", "OK"} default button "OK" cancel button "Cancel" as warning

			if button returned of alertResult is "OK" then
				set theDocument to first document

				save theDocument

				set theFile to (theDocument's file) as alias

				tell application "Finder"
					set theContainer to (container of theFile) as alias
					set newFile to make new file with properties {container:theFile, name:"Filtered " & ((name of theDocument) as string)}
				end tell
				return

				save first document in (newFile as file)
				repeat with thePub in first document's publications
					set thePub's note to my splitNote(thePub's note)
					repeat with theFile in thePub's linked files
						remove theFile from thePub
					end repeat
				end repeat
				save first document
			end if
		on error -128
			display dialog "User cancelled."
		end try
	end tell
end run

to splitNote(theNoteText)
	try
		set oldDelims to AppleScript's text item delimiters
		set AppleScript's text item delimiters to {"---"}

		set theParts to every text item of theNoteText

		if length of theParts is greater than 1 then
			set outText to (text 2 through end) of last item of theParts
		else
			set outText to ""
		end if
		set AppleScript's text item delimiters to oldDelims
	on error
		set AppleScript's text item delimiters to oldDelims
	end try
	return outText
end splitNote


-- execute_iterm.scpt
-- last change: 19 Jan 2013
---
-- this script require an argument that represent the command to execute

on run argv

    set command to (item 1 of argv)

    tell application "iTerm"

        try
            set mysession to current session of current terminal
        on error
            set myterm to (make new terminal)
            tell myterm
                launch session "rspec"
                set mysession to current session
            end tell
        end try

        -- execute the command
        tell mysession
            write text command
        end tell

    end tell

end run

Change script for rspec command only

-- execute_iterm.scpt
-- last change: 19 Jan 2013
---
-- this script require an argument that represent the command to execute

on run argv

    set command to (item 1 of argv)
    tell application "iTerm"
      repeat with _terminal in terminals
        repeat with _session in (every session of _terminal whose name contains "rspec")
          tell the _session
            write text command
          end tell
        end repeat
      end repeat
    end tell
end run


# AppleScript folder action for the pdfmatch command
#
# Open with script editor, compile and save to
# ~/Library/Workflows/Applications/Folder\ Actions/
#
# Then open the "Folder Actions Setup" application and add the work folder
# where your pdfmatch.json config lives and attach this script.
#
on adding folder items to this_folder after receiving these_files
	try
		repeat with each_file in these_files
			tell application "System Events"
				if name extension of each_file is "pdf" or "tif" or "tiff" or "jpeg" or "jpg" then
					# You might need to add your node binary to your $PATH. For example:
					# export PATH=/usr/local/bin:/usr/local/opt/node@6/bin:$PATH
					set output to (do shell script "export PATH=/usr/local/bin:/usr/local/opt/node@6/bin:$PATH && cd '" & POSIX path of this_folder & "' && pdfmatch '" & POSIX path of each_file & "' --delete 2>&1")
					#display alert output
				end if
			end tell
		end repeat
	on error err_string number error_number
		display alert "Error " & error_number & ": " & err_string
	end try
end adding folder items to

Remove my $PATH setting from default apple script

# AppleScript folder action for the pdfmatch command
#
# Open with script editor, compile and save to
# ~/Library/Workflows/Applications/Folder\ Actions/
#
# Then open the "Folder Actions Setup" application and add the work folder
# where your pdfmatch.json config lives and attach this script.
#
on adding folder items to this_folder after receiving these_files
	try
		repeat with each_file in these_files
			tell application "System Events"
				if name extension of each_file is "pdf" or "tif" or "tiff" or "jpeg" or "jpg" then
					# You might need to add your node binary to your $PATH. For example:
					# export PATH=/usr/local/bin:/usr/local/opt/node@6/bin:$PATH
					set output to (do shell script "cd '" & POSIX path of this_folder & "' && pdfmatch '" & POSIX path of each_file & "' --delete 2>&1")
					#display alert output
				end if
			end tell
		end repeat
	on error err_string number error_number
		display alert "Error " & error_number & ": " & err_string
	end try
end adding folder items to


-- clears workflow cache, including album artwork and compiled scripts --

on loadConfig()
	return (load script POSIX file (do shell script "./resources/compile-config.sh"))
end loadConfig

on run query
	set config to loadConfig()
	try
		tell application "Finder"
			delete folder (workflowCacheFolder of config)
		end tell
	end try
end run

Delete Alfred Play Song playlist when clearing cache

-- clears workflow cache, including album artwork and compiled scripts --

on loadConfig()
	return (load script POSIX file (do shell script "./resources/compile-config.sh"))
end loadConfig

on run query
	set config to loadConfig()
	try
		tell application "Finder"
			delete folder (workflowCacheFolder of config)
		end tell
		tell application "Music"
			delete user playlist (workflowPlaylistName of config)
		end tell
	end try
end run


set theFolder to POSIX path of ((the path to me as text) & "::")
set Controller to run script ("script s" & return & (read alias (POSIX file (theFolder & "/lib/controller.scpt")) as «class utf8») & return & "end script " & return & "return s")

set currentTrack to Controller's getCurrentSong()

set output to item 1 of currentTrack & " - " & item 2 of currentTrack

do shell script "echo " & quoted form of output

Set current song to empty string if nothing is playing

set theFolder to POSIX path of ((the path to me as text) & "::")
set Controller to run script ("script s" & return & (read alias (POSIX file (theFolder & "/lib/controller.scpt")) as «class utf8») & return & "end script " & return & "return s")

set currentTrack to Controller's getCurrentSong()

try
  set output to quoted form of (item 1 of currentTrack & " - " & item 2 of currentTrack)
on error
  set output to ""
end try

do shell script "echo " & output


activate application "SystemUIServer"
tell application "System Events"
    tell process "SystemUIServer"
        set btMenu to (menu bar item 1 of menu bar 1 whose description contains "bluetooth")
        tell btMenu
            click
            try
                tell (menu item "Rosco's Headphones" of menu 1)
                    click
                    if exists menu item "Connect" of menu 1 then
                        click menu item "Connect" of menu 1
                        return "Connecting..."
                    else if exists menu item "Disconnect" of menu 1 then
                        click menu item "Disconnect" of menu 1
                        return "Disconnecting..."
                    end if
                end tell
            end try
        end tell
    end tell
    key code 53
    return "Device not found or Bluetooth turned off"
end tell

Update headphone connect script for Big Sur

-- Source: https://www.reddit.com/r/MacOS/comments/i4czgu/big_sur_airpods_script/gck3gz3
-- Works on macOS 11 Big Sur

use framework "IOBluetooth"
use scripting additions

set DeviceName to "Rosco's Headphones"

on getFirstMatchingDevice(deviceName)
    repeat with device in (current application's IOBluetoothDevice's pairedDevices() as list)
        if (device's nameOrAddress as string) contains deviceName then return device
    end repeat
end getFirstMatchingDevice

on toggleDevice(device)
    if not (device's isConnected as boolean) then
        device's openConnection()
        return "Connecting " & (device's nameOrAddress as string)
    else
        device's closeConnection()
        return "Disconnecting " & (device's nameOrAddress as string)
    end if
end toggleDevice

return toggleDevice(getFirstMatchingDevice(DeviceName))


-- plays selected song or playlist directly (the Play Song v1 behavior)
-- for songs, this behavior continues playing music after the song finishes

on loadConfig()
	return (load script POSIX file (do shell script "./resources/compile-config.sh"))
end loadConfig

on run query
	set config to loadConfig()

	set typeAndId to parseResultQuery(query as text) of config
	set theType to type of typeAndId
	set theId to id of typeAndId

	tell application "iTunes"

		if theType is "song" then

			set theSong to getSong(theId) of config
			play theSong

		else if theType is "playlist" then

			set thePlaylist to getPlaylist(theId) of config
			play thePlaylist

		else

			log "Unknown type: " & theType

		end if

	end tell
end run

Fix bug where Apple Music playlists could not be played

-- plays selected song or playlist directly (the Play Song v1 behavior)
-- for songs, this behavior continues playing music after the song finishes

on loadConfig()
	return (load script POSIX file (do shell script "./resources/compile-config.sh"))
end loadConfig

on run query
	set config to loadConfig()

	set typeAndId to parseResultQuery(query as text) of config
	set theType to type of typeAndId
	set theId to id of typeAndId

	tell application "iTunes"

		if theType is "song" then

			set theSong to getSong(theId) of config
			play theSong

		else if theType ends with "playlist" then

			set thePlaylist to getPlaylist(theId) of config
			play thePlaylist

		else

			log "Unknown type: " & theType

		end if

	end tell
end run


-- This Applescript changes all of the icon labels on the disk image to
--  a different color.
-- Usage: osascript set-labels.applescript <volume-name>
-- where <volume-name> is the volume name of the disk image.

on run argv
	tell application "Finder"
		set diskname to item 1 of argv
		set file_list to every file in disk diskname
		repeat with i in file_list
			if the name of i is "Applications" then
				set the position of i to {368, 135}
			else if the name of i ends with ".app" then
				set the position of i to {134, 135}
			end if
		-- The magic happens here: This will set the label color of
		--  the file icon. Change the 7 to change the color: 0 is no
		--  label, then red, orange, yellow, green, blue, purple, or gray.
			set the label index of i to 7
		end repeat
	end tell
end run

Make Mac disk image packager set application icon location more reliably.

-- This Applescript changes all of the icon labels on the disk image to
--  a different color.
-- Usage: osascript set-labels.applescript <volume-name>
-- where <volume-name> is the volume name of the disk image.

on run argv
	tell application "Finder"
		set diskname to item 1 of argv
		tell disk diskname
			set file_list to every file
			repeat with i in file_list
				if the name of i is "Applications" then
					set the position of i to {368, 135}
				else if the name of i ends with ".app" then
					set the position of i to {134, 135}
				end if
			-- The magic happens here: This will set the label color of
			--  the file icon. Change the 7 to change the color: 0 is no
			--  label, then red, orange, yellow, green, blue, purple, or gray.
				set the label index of i to 7
			end repeat
			update without registering applications
			delay 4
		end tell
	end tell
end run


on run {input}
  try
    do shell script "$HOME/Dropbox\\ \\(Personal\\)/projects/plover-tools/plover-dictionary-lookup/dictlook -x " & "\"" & input & "\""
    display dialog result buttons {"OK"} default button 1
  on error
    display dialog "No such luck." buttons {"OK"} default button 1
    beep
  end try
end run

Add practice text area to lookup dialog

on run {input}
  try
    do shell script "$HOME/Dropbox\\ \\(Personal\\)/projects/plover-tools/plover-dictionary-lookup/dictlook -x " & "\"" & input & "\""
    display dialog result default answer "" buttons {"OK"} default button 1
  on error
    display dialog "No such luck." buttons {"OK"} default button 1
    beep
  end try
end run


set close_vagrant to "z puppet; git pull; vagrant halt -f;"

-- close vagrant
tell application "iTerm"
	activate
	set myterm to (make new terminal)
	tell myterm
		launch session "Default"
		set mysession to current session
	end tell

	tell mysession
		write text close_vagrant
	end tell

	delay 5
end tell

-- quit iTerm
ignoring application responses
	tell application "iTerm"
		quit
	end tell
end ignoring

delay 2
tell application "System Events" to keystroke return

Remove git pull from closing Vagrant

set close_vagrant to "z puppet; vagrant halt -f;"

-- close vagrant
tell application "iTerm"
	activate
	set myterm to (make new terminal)
	tell myterm
		launch session "Default"
		set mysession to current session
	end tell

	tell mysession
		write text close_vagrant
	end tell

	delay 5
end tell

-- quit iTerm
ignoring application responses
	tell application "iTerm"
		quit
	end tell
end ignoring

delay 2
tell application "System Events" to keystroke return


set myTabs to {"http://app.getsentry.com/", "http://app.ubervu.com/", "http://github.com/uberVU/thehole/issues/assigned/palcu?direction=desc&labels=&milestone=&page=1&sort=updated&state=open/", "https://mail.google.com/mail/u/1/?shva=1#inbox", "https://drive.google.com/a/ubervu.com/#folders/0BzycGIkC5P50TXBlcTZoRXZ5VUE"}
tell application "Google Chrome"
	activate
	repeat with i in myTabs
		open location i
	end repeat
end tell

Change tabs to open at work

set myTabs to {"http://app.getsentry.com/", "http://github.com/uberVU/thehole/issues/assigned/palcu?direction=desc&labels=&milestone=&page=1&sort=updated&state=open/", "https://mail.google.com/mail/u/1/?shva=1#inbox", "https://drive.google.com/a/hootsuite.com/#folders/0BwuFsHJDxJWPYmxXQ1VQVlN6T2M"}
tell application "Google Chrome"
	activate
	repeat with i in myTabs
		open location i
	end repeat
end tell


set broker to "h8.opera.com"
set workers to {"h6.opera.com", "h8.opera.com", "h9.opera.com", "h10.opera.com"}
tell application "iTerm"
    activate
    set myterm to (make new terminal)
    tell myterm
        set number of columns to 80
        set number of rows to 50
        repeat with workerhost in workers
            set worker to (make new session at the end of sessions)
            tell worker
                set name to workerhost
                set foreground color to "white"
                set background color to "black"
                set transparency to 0.1
                exec command "/bin/sh -i"
                write text "ssh root@" & workerhost & " 'tail -f /var/log/celeryd.log'"
            end tell
        end repeat
        set rabbit to (make new session at the end of sessions)
        tell rabbit
            set name to "rabbit.log"
            set foreground color to "white"
            set background color to "black"
            set transparency to 0.1
            exec command "/bin/sh -i"
            write text "ssh root@" & broker & " 'tail -f /var/log/rabbitmq/rabbit.log'"
        end tell
        tell the first session
            activate
        end tell
    end tell
end tell

Update the watch workers applescript to watch the celerybeat log file.

set broker to "h8.opera.com"
set workers to {"h6.opera.com", "h8.opera.com", "h9.opera.com", "h10.opera.com"}
set clock to "h6.opera.com"
tell application "iTerm"
    activate
    set myterm to (make new terminal)
    tell myterm
        set number of columns to 80
        set number of rows to 50
        repeat with workerhost in workers
            set worker to (make new session at the end of sessions)
            tell worker
                set name to workerhost
                set foreground color to "white"
                set background color to "black"
                set transparency to 0.1
                exec command "/bin/sh -i"
                write text "ssh root@" & workerhost & " 'tail -f /var/log/celeryd.log'"
            end tell
        end repeat
        set celerybeat to (make new session at the end of sessions)
        tell celerybeat
            set name to "celerybeat.log"
            set foreground color to "white"
            set background color to "black"
            set transparency to 0.1
            exec command "/bin/sh -i"
            write text "ssh root@" & clock & " 'tail -f /var/log/celerybeat.log'"
        end tell
        set rabbit to (make new session at the end of sessions)
        tell rabbit
            set name to "rabbit.log"
            set foreground color to "white"
            set background color to "black"
            set transparency to 0.1
            exec command "/bin/sh -i"
            write text "ssh root@" & broker & " 'tail -f /var/log/rabbitmq/rabbit.log'"
        end tell
        tell the first session
            activate
        end tell
    end tell
end tell


(*
  Script object to make calling a defined function easier while in the
  iTunes and System Events name space.
*)
script remoteSpeakerFinder
  -- Given a list of buttons, find the remote speakers button
  -- by finding the first button with a name that isn't in a
  -- rejection list.
  on findCorrectButton (in_buttons)
    set buttons_to_skip to {"Burn Disc"}

    repeat with a_button in in_buttons
      try -- some buttons don't have names
        set the_name to name of a_button
        if buttons_to_skip does not contain {the_name} then
          return the_name
        end if
      end try
    end repeat

    return 16 -- default response
  end findCorrectButton
end script

(*
  Tell iTunes to use the "Mobile" set of remote speakers.
*)
tell application "System Events"
  tell process "iTunes"
     set the_buttons to (get buttons of window 1)
     set the_speaker_button to (remoteSpeakerFinder's findCorrectButton(the_buttons))

     -- Switch to the speakers in my bedroom
     set frontmost to true
     click button the_speaker_button of window 1
     key code 115                -- Home Key (first speaker in list)
     key code 125                -- Down Arrow
     key code 125                -- Down Arrow
     key code 36                 -- Return Key
  end tell
end tell

Work around an issue with iTunes 9 that causes it to delay a connection to remote speakers

(*
  Script object to make calling a defined function easier while in the
  iTunes and System Events name space.
*)
script remoteSpeakerFinder
  -- Given a list of buttons, find the remote speakers button
  -- by finding the first button with a name that isn't in a
  -- rejection list.
  on findCorrectButton (in_buttons)
    set buttons_to_skip to {"Burn Disc"}

    repeat with a_button in in_buttons
      try -- some buttons don't have names
        set the_name to name of a_button
        if buttons_to_skip does not contain {the_name} then
          return the_name
        end if
      end try
    end repeat

    return 16 -- default response
  end findCorrectButton
end script

(*
  Tell iTunes to use the "Mobile" set of remote speakers.
*)
tell application "System Events"
  tell process "iTunes"
     set the_buttons to (get buttons of window 1)
     set the_speaker_button to (remoteSpeakerFinder's findCorrectButton(the_buttons))

     -- Switch to the speakers in my bedroom
     set frontmost to true
     click button the_speaker_button of window 1
     key code 115                -- Home Key (first speaker in list)
     key code 125                -- Down Arrow
     key code 125                -- Down Arrow
     key code 36                 -- Return Key

     -- Wait for iTunes to connect to the speakers
     delay 5
  end tell
end tell


set myTabs to {"http://app.getsentry.com/", "http://github.com/uberVU/thehole/issues/assigned/palcu?direction=desc&labels=&milestone=&page=1&sort=updated&state=open/", "https://mail.google.com/mail/u/1/?shva=1#inbox", "https://drive.google.com/a/hootsuite.com/#folders/0BwuFsHJDxJWPYmxXQ1VQVlN6T2M"}
tell application "Google Chrome"
	activate
	repeat with i in myTabs
		open location i
	end repeat
end tell

Update URLs that open at the office

set myTabs to {"https://github.com/search?utf8=%E2%9C%93&q=assignee%3Apalcu+state%3Aopen&type=Issues&ref=searchresults", "https://mail.google.com/mail/u/1/?shva=1#inbox", "https://drive.google.com/a/hootsuite.com/#folders/0BwuFsHJDxJWPYmxXQ1VQVlN6T2M"}
tell application "Google Chrome"
	activate
	repeat with i in myTabs
		open location i
	end repeat
end tell


try
	get application id "com.stairways.keyboardmaestro.engine"
on error err_msg number err_num
	return "Keyboard Maestro not found. First install it and then use this workflow."
end try

tell application id "com.stairways.keyboardmaestro.engine"
	gethotkeys with asstring
end tell

Update script to get ALL macros instead of just hotkeyed macros.

try
	get application id "com.stairways.keyboardmaestro.engine"
on error err_msg number err_num
	return "Keyboard Maestro not found. First install it and then use this workflow."
end try

tell application id "com.stairways.keyboardmaestro.engine"
	gethotkeys with asstring and getall
end tell


set open_vagrant to "z puppet; vagrant up;"

tell application "iTerm"
	activate
	try
		set mysession to current session of current terminal
	on error
		set myterm to (make new terminal)
		tell myterm
			launch session "Default"
			set mysession to current session
		end tell
	end try

	tell mysession
		write text open_vagrant
	end tell
end tell

Add update script to open vagrant applescript

set open_vagrant to "z puppet; vagrant up;"
set update_master to "/Users/alex/.homesick/repos/palcu/dotfiles/scripts/update_master.sh;"

tell application "iTerm"
	activate
	try
		set mysession to current session of current terminal
	on error
		set myterm to (make new terminal)
		tell myterm
			launch session "Default"
			set mysession to current session
		end tell
	end try

	tell mysession
        write text update_master
		write text open_vagrant
	end tell
end tell


(*
Module: Hostname
  Parses /etc/hostname and /etc/mailname

Author: Raphael Pinson <raphink@gmail.com>

About: License
   This file is licenced under the LGPL v2+, like the rest of Augeas.
*)

module Hostname =
autoload xfm

(* View: lns *)
let lns = [ label "hostname" . store Rx.word . Util.eol ]

(* View: filter *)
let filter = incl "/etc/hostname"
           . incl "/etc/mailname"

let xfm = transform lns filter

Allow Creation of Hostname When File is Missing

(*
Module: Hostname
  Parses /etc/hostname and /etc/mailname

Author: Raphael Pinson <raphink@gmail.com>

About: License
   This file is licenced under the LGPL v2+, like the rest of Augeas.
*)

module Hostname =
autoload xfm

(* View: lns *)
let lns = [ label "hostname" . store Rx.word . Util.eol ] | Util.empty

(* View: filter *)
let filter = incl "/etc/hostname"
           . incl "/etc/mailname"

let xfm = transform lns filter


# Parsing /etc/inittab

#map
#  grammar inittab
#  include '/etc/inittab' '/system/config/inittab'
#end

grammar inittab

  token SEP ':'
  token EOL '\n'

  file: ( comment | record ) *

  comment: ( /#.*?\n/ | /[ \t]*\n/ )

  record: counter 'record' .
          [ seq 'record' .
            [ label 'id' . store ..? ] .
            SEP .
            [ label 'runlevels' . store ..? ] .
            SEP .
            [ label 'action' . store ..? ] .
            SEP .
            [ label 'process' . store ..? ] .
            EOL
          ]
end

Remove bogus reset of 'record' counter

# Parsing /etc/inittab

map
  grammar inittab
  include '/etc/inittab' '/system/config/inittab'
end

grammar inittab

  token SEP ':'
  token EOL '\n'

  file: ( comment | record ) *

  comment: ( /#.*?\n/ | /[ \t]*\n/ )

  record: [ seq 'record' .
            [ label 'id' . store ..? ] .
            SEP .
            [ label 'runlevels' . store ..? ] .
            SEP .
            [ label 'action' . store ..? ] .
            SEP .
            [ label 'process' . store ..? ] .
            EOL
          ]
end


(* Tests for the PuppetFileserver module *)

module Test_puppetfileserver =

let fileserver = "# This a comment

[mount1]
  # Mount1 options
  path /etc/puppet/files/%h
  allow host.domain1.com
  allow *.domain2.com
  deny badhost.domain2.com
[mount2]
  allow *
  deny *.evil.example.com
  deny badhost.domain2.com
[mount3]
allow *   # Puppet #6026: same line comment
# And trailing whitespace
allow *
"

test PuppetFileserver.lns get fileserver =
	{ "#comment" = "This a comment" }
	{ }
	{ "mount1"
		{ "#comment" = "Mount1 options" }
		{ "path" = "/etc/puppet/files/%h" }
		{ "allow" = "host.domain1.com" }
		{ "allow" = "*.domain2.com" }
		{ "deny" = "badhost.domain2.com" }
	}
	{ "mount2"
		{ "allow" = "*" }
		{ "deny" = "*.evil.example.com" }
		{ "deny" = "badhost.domain2.com" }
	}
	{ "mount3"
		{ "allow" = "*"
			{ "#comment" = "Puppet #6026: same line comment" } }
		{ "#comment" = "And trailing whitespace" }
		{ "allow" = "*" }
	}

Remove trailing white spaces from puppet test


(*
Module: Test_UpdateDB
  Provides unit tests and examples for the <UpdateDB> lens.
*)
module Test_UpdateDB =

(* Test: UpdateDB.lns
     Simple get test *)
test UpdateDB.lns get "# A comment
PRUNEPATHS=\"/tmp /var/spool /media /home/.ecryptfs\"
PRUNEFS=\"NFS nfs nfs4 rpc_pipefs\"
PRUNE_BIND_MOUNTS=\"yes\"\n" =
  { "#comment" = "A comment" }
  { "PRUNEPATHS"
    { "entry" = "/tmp" }
    { "entry" = "/var/spool" }
    { "entry" = "/media" }
    { "entry" = "/home/.ecryptfs" }
  }
  { "PRUNEFS"
    { "entry" = "NFS" }
    { "entry" = "nfs" }
    { "entry" = "nfs4" }
    { "entry" = "rpc_pipefs" }
  }
  { "PRUNE_BIND_MOUNTS" = "yes" }

(* Test: UpdateDB.lns
     Adding to a list *)
test UpdateDB.lns put "PRUNEFS=\"NFS nfs nfs4 rpc_pipefs\"\n"
  after set "/PRUNEFS/entry[last()+1]" "ecryptfs" =
"PRUNEFS=\"NFS nfs nfs4 rpc_pipefs ecryptfs\"\n"

Update tests to ensure spaces around = are OK

(*
Module: Test_UpdateDB
  Provides unit tests and examples for the <UpdateDB> lens.
*)
module Test_UpdateDB =

(* Test: UpdateDB.lns
     Simple get test *)
test UpdateDB.lns get "# A comment
PRUNEPATHS=\"/tmp /var/spool /media /home/.ecryptfs\"
PRUNEFS= \"NFS nfs nfs4 rpc_pipefs\"
PRUNE_BIND_MOUNTS = \"yes\"\n" =
  { "#comment" = "A comment" }
  { "PRUNEPATHS"
    { "entry" = "/tmp" }
    { "entry" = "/var/spool" }
    { "entry" = "/media" }
    { "entry" = "/home/.ecryptfs" }
  }
  { "PRUNEFS"
    { "entry" = "NFS" }
    { "entry" = "nfs" }
    { "entry" = "nfs4" }
    { "entry" = "rpc_pipefs" }
  }
  { "PRUNE_BIND_MOUNTS" = "yes" }

(* Test: UpdateDB.lns
     Adding to a list *)
test UpdateDB.lns put "PRUNEFS=\"NFS nfs nfs4 rpc_pipefs\"\n"
  after set "/PRUNEFS/entry[last()+1]" "ecryptfs" =
"PRUNEFS=\"NFS nfs nfs4 rpc_pipefs ecryptfs\"\n"


(*
Module: Sep
   Generic separators to build lenses

Author: Raphael Pinson <raphink@gmail.com>

About: License
  This file is licensed under the LGPLv2+, like the rest of Augeas.
*)

module Sep =

let colon = Util.del_str ":"
let comma = Util.del_str ","
let space = del Rx.space " "
let tab   = del Rx.space "\t"
let opt_space = del Rx.opt_space ""
let opt_tab   = del Rx.opt_space "\t"

Add Sep.equal, used in nrpe.aug

(*
Module: Sep
   Generic separators to build lenses

Author: Raphael Pinson <raphink@gmail.com>

About: License
  This file is licensed under the LGPLv2+, like the rest of Augeas.
*)

module Sep =

let colon = Util.del_str ":"
let comma = Util.del_str ","
let equal = Util.del_str "="
let space = del Rx.space " "
let tab   = del Rx.space "\t"
let opt_space = del Rx.opt_space ""
let opt_tab   = del Rx.opt_space "\t"