insult: new module

insult: new module

-- a port of https://github.com/LizardGamer/tumblr-argument-generator/blob/develop/app/assets/js/main.js
-- original by Lokaltog
-- github pls no delete

intro = {
  'burn in hell',
  'check your privilege',
  'fuck you',
  'fuck off',
  'please die',
  'rot in hell',
  'screw you',
  'shut the fuck up',
  'shut up',
  'kill yourself',
  'drop dead'
}
description = {
  'deluded',
  'fucking',
  'god damn',
  'judgemental',
  'worthless'
}
marginalized = {
  {
    'activist',
    'agender',
    'appearance',
    'asian',
    'attractive',
    'bi',
    'bigender',
    'black',
    'celestial',
    'chubby',
    'closet',
    'color',
    'curvy',
    'dandy',
    'deathfat',
    'demi',
    'differently abled',
    'disabled',
    'diversity',
    'dysphoria',
    'ethnic',
    'ethnicity',
    'fat love',
    'fat',
    'fatist',
    'fatty',
    'female',
    'feminist',
    'genderfuck',
    'genderless',
    'hair',
    'height',
    'indigenous',
    'intersectionality',
    'invisible',
    'kin',
    'lesbianism',
    'little person',
    'marginalized',
    'minority',
    'multigender',
    'non-gender',
    'non-white',
    'obesity',
    'otherkin',
    'pansexual',
    'polygender',
    'privilege',
    'prosthetic',
    'queer',
    'radfem',
    'skinny',
    'smallfat',
    'stretchmark',
    'thin',
    'third-gender',
    'trans*',
    'transfat',
    'transgender',
    'transman',
    'transwoman',
    'trigger',
    'two-spirit',
    'womyn',
    'poc',
    'woc'
  },
  {
    'chauvinistic',
    'misogynistic',
    'nphobic',
    'oppressive',
    'phobic',
    'shaming',
    'denying',
    'discriminating',
    'hypersexualizing',
    'intolerant',
    'racist',
    'sexualizing'
  }
}
privileged = {
  {
    'able-bodied',
    'appearance',
    'attractive',
    'binary',
    'bi',
    'cis',
    'cisgender',
    'cishet',
    'hetero',
    'male',
    'smallfat',
    'thin',
    'white'
  },
  {
    'ableist',
    'classist',
    'normative',
    'overprivileged',
    'patriarch',
    'sexist',
    'privileged'
  }
}
finisher = {
  'asshole',
  'bigot',
  'oppressor',
  'piece of shit',
  'rapist',
  'scum',
  'shitlord',
  'subhuman',
  'misogynist',
  'nazi'
}

getRandomItem = (array) ->
  array[math.random(1, #array)]

generateTerm = ->
  getRandomItem({
    'a',
    'bi',
    'dandy',
    'demi',
    'gender',
    'multi',
    'pan',
    'poly'
  }) .. getRandomItem({
    'amorous',
    'femme',
    'fluid',
    'queer',
    'romantic',
    'sexual',
  })

generateArgument = ->
  buf = {
    getRandomItem(intro),
    ', you ',
    getRandomItem(description),
    ' ',
    getRandomItem({
      generateTerm(),
      getRandomItem(marginalized[1])
    }),
    '-',
    getRandomItem(marginalized[2]),
    ', ',
    getRandomItem(privileged[1]),
    '-',
    getRandomItem(privileged[2]),
    ' ',
    getRandomItem(finisher),
    '.',
  }
  table.concat(buf)

PRIVMSG:
  '^%pinsult$': (source, destination) =>
    @Msg 'privmsg', destination, source, generateArgument()
  '^%pinsult (.+)$': (source, destination, arg) =>
    @Msg 'privmsg', destination, source, arg..": "..generateArgument()

error: pathspec 'modules/insult.moon' did not match any file(s) known to git


excuse: new module

excuse: new module

Former-commit-id: 7671455083e79ef366e5abddb036b4913de106e6 [formerly c6bf36c3ce3173ba20610269fe8e6dcecb732f80]
Former-commit-id: a84e8c2b8211a1d8e0788af05a1a75e7cc657425

PRIVMSG:
  '^%pexcuse': (source, destination) =>
    ivar2.util.simplehttp 'http://www.programmerexcuses.com/', (html) ->
      cruft, match = html\match[[(.-)]]
      if match
        say match

error: pathspec 'modules/excuse.moon' did not match any file(s) known to git


netutils: new module

netutils: new module

Some tools for network, ipv6 stats, tls cert check, etc.
Still needs some work, like cert wildcard

cqueues = require 'cqueues'
dns = require'cqueues.dns'
packet = require'cqueues.dns.packet'
record = require'cqueues.dns.record'
errno = require'cqueues.errno'
socket = require'cqueues.socket'
context = require'openssl.ssl.context'
http_tls = require'http.tls'
pkey = require'openssl.pkey'
auxlib = require"openssl.auxlib"
util = require'util'
{:bold, :split, :green, :red, :simplehttp, :json, :urlEncode} = require'util'

cache = {}

HasValue = (table, value) ->
  if(type(table) ~= 'table') then return
  for _, v in next, table
    if(v == value) then return true

Good = ->
  "#{green '🔒'} TLS #{green 'ok'}"

Bad = ->
  "#{red '🔓 '} #{red 'Bad'} TLS"

Query = (host, types='AAAA,A', timeout=15) ->
  out = {}

  for type in *split(types, ',')
    answer = dns.query(host, type, 'IN', timeout)

    for rec in answer\grep{section:packet.section.ANSWER}
      out[#out+1] = tostring(rec)

  return out

{
  PRIVMSG: {
    '^%pttls (.*)$': (source, destination, arg) =>
      host = arg\match'^%s*(.-)[:%s].*$' or arg
      port = arg\match'^.*[: ](.*)%s*$' or 443
      port = tonumber(port) or 0
      if port <= 0 or port > 65535
        return reply "Think you're clever?"
      hosts = Query(host)
      if #hosts == 0
        -- assume IP
        hosts = {host}
      found = false
      for ip in *hosts
        sock = socket.connect{host:ip, :port, verify:false, tls_sendname:host}
        ok, sock, err = pcall -> sock\connect 5
        if not ok
          return say "Error connecting to #{ip}:#{port} : #{sock}"
        if ip\match':'
          ip = '[' .. ip .. ']'
        if not sock
          reply "Error #{err} connecting to #{ip}:#{port} : #{errno.strerror err}"
        else
          ctx = http_tls.new_client_context()
          --ctx = context.new('SSL3', false)
          --ctx\setOptions(context.OP_NO_COMPRESSION+contextopenssl_ctx.OP_SINGLE_ECDH_USE)
          --ctx\setEphemeralKey(pkey.new{ type = "EC", curve = "prime256v1" }
          ok, tls, err = pcall -> sock\starttls 5
          if not ok
            return say "TLS negotiation error : #{tls}"
          if tls
            ssl = tls\checktls!
            if sock
              sock\close!
            cipher = ssl\getCipherInfo!
            if http_tls.banned_ciphers[cipher.name]
              return say "Banned cipher: #{cipher.name} when negotiating TLS #{ip}:#{port}"
            cert = ssl\getPeerCertificate!
            before, after = cert\getLifetime!
            cn = tostring cert\getSubject!
            san = cert\getSubjectAlt!
            validhosts = {cn\match'CN=(.*)'}
            for type, sanhost in auxlib.pairs(san)
              table.insert(validhosts, sanhost)
            -- cheat and parse text
            text = cert\text!
            @Log 'debug', text
            expires = text\match('Not After : (.-)%s*Sub')
            verdict = Good!
            reason = ''
            unless HasValue(validhosts, host)
              verdict = Bad!
              reason = "Hostname #{host} not in list #{table.concat validhosts, ', '}"
            if after < os.time!
              verdict = Bad!
              reason ..= " #{red 'Expired'} cert!"

            say "#{verdict} #{reason} #{ip}:#{port}. Expires #{expires} Cipher: #{cipher.bits} bits #{cipher.name}."
          else
            reply "Error #{err} when negotiating TLS #{ip}:#{port} : #{err}"
          found = true
        if found
          break
    '^%pconnect (.*)[:%s]([0-9]+)$': (source, destination, host, port) =>
      port = tonumber port
      if port < 0 or port > 65535
        return reply "Think you're clever?"
      hosts = Query(host)
      if #hosts == 0
        -- assume IP
        hosts = {host}
      for ip in *hosts
        sock = socket.connect(ip, port)
        ok, sock, err = pcall -> sock\connect 5
        if not ok
          return say "Error connecting to #{ip}:#{port} : #{sock}"
        if ok and sock
          sock\close!
        if ip\match':'
          ip = '[' .. ip .. ']'
        if not sock
          reply "Error #{err} connecting to #{ip}:#{port} : #{errno.strerror err}"
        else
          say "Yup, could connect to #{ip}:#{port}"
          break
    '^%pdns (.*)$': (source, destination, arg) =>
      args = split arg, ' '
      argc = #args
      host = args[1]
      types = 'AAAA,A'
      if argc == 2
        types = args[1]
        host = args[2]

      out = Query(host, types)

      if #out == 0
        say "No answers"
      say table.concat(out, ' ')

    '^%pipv6 stats$': (source, destination) =>
      @Send "WHO #{destination}"
    '^%pipv6 stats (.*)$': (source, destination, dest) =>
      @Send "WHO #{dest}"
  }
  ['352']: {
    (source, destination, input) =>
      --:efnet.port80.se 352 xt #jensaskaret xt 2a02:cc41:100f::1 efnet.port80.se xt H :0 Tor H.
      unless cache[destination]
        cache[destination] = {}

      nick = input.nick
      host = input.host
      --if @channels[destination]
      cache[destination][nick] = host

  }
  ['315']: {
    (source, destination, input) =>
      -- nondeterministic order.. hey ho here we go
      -- TODO use condition?
      cqueues.sleep(2)
      ipv4 = 0
      ipv6 = 0
      cloak = 0
      for nick, host in pairs(cache[destination])
        if host\match ':'
          ipv6 += 1
        elseif host\match '/' -- freenode cloak
          cloak += 1
        elseif host\match '%d+%.%d+%.%d+%.%d+'
          ipv4 += 1
        else
          timeout = 360
          ok, packet, err = pcall(dns.query, host, 'AAAA', 'IN', timeout)
          if not ok
            print 'pack', ok, packet, err
            print(debug.traceback())
          elseif not packet
            print 'no packet for host', host
            ipv4 += 1
          elseif packet\count() >= 2 -- 1 for question and atleast 1 for answer
            ipv6 = ipv6 + 1
          else
            ipv4 = ipv4 + 1
      -- Empty cache
      cache[destination] = nil
      percent = math.floor(100*ipv6/(ipv4+ipv6+cloak))
      out = "IP stats: #{bold percent}% IPv6. #{ipv6} IPv6 clients. #{ipv4} IPv4 clients. "
      if cloak > 0
        out = out .. "#{cloak} cloaked hosts."
      say out
  }
}

error: pathspec 'modules/netutils.moon' did not match any file(s) known to git


bobross: new module

bobross: new module

Former-commit-id: 0477fac29ab2ca1f13c4e3ca6c6ea87ba2708310
Former-commit-id: 32ab9cecadc13572d66853d2190bac4fd54afa97

util = require'util'

data = [[

[
  "That's a crooked tree. We'll send him to Washington.",
  "The only thing worse than yellow snow is green snow.",
  "I like to beat the brush.",
  "In painting, you have unlimited power. You have the ability to move mountains. You can bend rivers. But when I get home, the only thing I have power over is the garbage.",
  "You need the dark in order to show the light.",
  "Look around. Look at what we have. Beauty is everywhere you only have to look to see it.",
  "Just go out and talk to a tree. Make friends with it.",
  "There's nothing wrong with having a tree as a friend.",
  "Trees cover up a multitude of sins.",
  "They say everything looks better with odd numbers of things. But sometimes I put even numbers\u00e2\u20ac\u201djust to upset the critics.",
  "How do you make a round circle with a square knife? That's your challenge for the day.",
  "A thin paint will stick to a thick paint.",
  "Just beat the devil out of it.",
  "We don't make mistakes we just have happy little accidents.",
  "We'll paint one happy little tree right here.",
  "Just pretend you are a whisper floating across a mountain.",
  "From all of us here, I want to wish you happy painting and God bless, my friends.",
  "We tell people sometimes: we're like drug dealers, come into town and get everybody absolutely addicted to painting. It doesn't take much to get you addicted.",
  "The secret to doing anything is believing that you can do it. Anything that you believe you can do strong enough, you can do. Anything. As long as you believe.",
  "Water's like me. It's laaazy\u00c2 ... Boy, it always looks for the easiest way to do things",
  "I really believe that if you practice enough you could paint the 'Mona Lisa' with a two-inch brush.",
  "If I paint something, I don't want to have to explain what it is.",
  "We artists are a different breed of people. We're a happy bunch.",
  "I guess I'm a little weird. I like to talk to trees and animals. That's okay though; I have more fun than most people.",
  "Let's get crazy.",
  "I can't think of anything more rewarding than being able to express yourself to others through painting.",
  "Exercising the imagination, experimenting with talents, being creative; these things, to me, are truly the windows to your soul.",
  "All you need to paint is a few tools, a little instruction, and a vision in your mind.",
  "I started painting as a hobby when I was little. I didn't know I had any talent. I believe talent is just a pursued interest. Anybody can do what I do.",
  "Everyone is going to see things differently - and that's the way it should be.",
  "No pressure. Just relax and watch it happen.",
  "When you do it your way you can go anywhere you choose.",
  "You can create beautiful things - but you have to see them in your mind first",
  "It's so important to do something every day that will make you happy",
  "Don't be afraid to make these big decisions. Once you start, they sort of just make themselves.",
  "With something so strong, a little bit can go a long way.",
  "You have to allow the paint to break to make it beautiful.",
  "Think about a cloud. Just float around and be there.",
  "In nature, dead trees are just as normal as live trees.",
  "It's hard to see things when you're too close. Take a step back and look.",
  "Only think about one thing at a time. Don't get greedy.",
  "If you do too much it's going to lose its effectiveness.",
  "Use absolutely no pressure. Just like an angel's wing.",
  "You're meant to have fun in life.",
  "In life you need colors.",
  "It's a super day, so why not make a beautiful sky?",
  "Just let go - and fall like a little waterfall.",
  "It's beautiful - and we haven't even done anything to it yet.",
  "Be careful. You can always add more - but you can't take it away.",
  "Pretend you're water. Just floating without any effort. Having a good day.",
  "When things happen - enjoy them. They're little gifts.",
  "Take your time. Speed will come later.",
  "It's amazing what you can do with a little love in your heart.",
  "God gave you this gift of imagination. Use it.",
  "Paint anything you want on the canvas. Create your own world.",
  "That's what painting is all about. It should make you feel good when you paint.",
  "You can do anything your heart can imagine.",
  "With practice comes confidence.",
  "This is happy place, little squirrels live here and play.",
  "We have no limits to our world. We're only limited by our imagination.",
  "Be so very light. Be a gentle whisper.",
  "The least little bit can do so much.",
  "All you have to do is let your imagination go wild.",
  "Didn't you know you had that much power? You can move mountains. You can do anything.",
  "If you don't like it - change it. It's your world.",
  "There is immense joy in just watching - watching all the little creatures in nature.",
  "Don't forget to tell these special people in your life just how special they are to you.",
  "That is when you can experience true joy, when you have no fear.",
  "We don't really know where this goes - and I'm not sure we really care.",
  "Life is too short to be alone, too precious. Share it with a friend.",
  "Work on one thing at a time. Don't get carried away - we have plenty of time.",
  "If we're going to have animals around we all have to be concerned about them and take care of them.",
  "Almost everything is going to happen for you automatically - you don't have to spend any time working or worrying.",
  "Sometimes you learn more from your mistakes than you do from your masterpieces.",
  "There are no limits in this world.",
  "You can create anything that makes you happy.",
  "You want your tree to have some character. Make it special.",
  "In your world you have total and absolute power.",
  "The man who does the best job is the one who is happy at his job.",
  "Everything's not great in life, but we can still find beauty in it.",
  "Don't hurry. Take your time and enjoy.",
  "You're the greatest thing that has ever been or ever will be. You're special. You're so very special.",
  "There is no right or wrong - as long as it makes you happy and doesn't hurt anyone.",
  "Everyone needs a friend. Friends are the most valuable things in the world.",
  "There are no mistakes. You can fix anything that happens.",
  "That's why I paint - because I can create the kind of world I want - and I can make this world as happy as I want it.",
  "It's life. It's interesting. It's fun.",
  "Just think about these things in your mind - then bring them into your world.",
  "In your imagination you can go anywhere you want.",
  "That's what makes life fun. That you can make these decisions. That you can create the world that you want.",
  "Go out on a limb - that's where the fruit is.",
  "In this world, everything can be happy.",
  "All you have to learn here is how to have fun.",
  "Isn't it great to do something you can't fail at?",
  "Anytime you learn something your time and energy are not wasted.",
  "A tree cannot be straight if it has a crooked trunk.",
  "You've got to learn to fight the temptation to resist these things. Just let them happen.",
  "You create the dream - then you bring it into your world.",
  "These things happen automatically. All you have to do is just let them happen.",
  "You can do anything here. So don't worry about it.",
  "This present moment is perfect simply due to the fact you're experiencing it.",
  "Only God can make a tree - but you can paint one.",
  "You can't make a mistake. Anything that happens you can learn to use - and make something beautiful out of it.",
  "Put light against light - you have nothing. Put dark against dark - you have nothing. It's the contrast of light and dark that each give the other one meaning.",
  "This is an example of what you can do with just a few things, a little imagination and a happy dream in your heart.",
  "If what you're doing doesn't make you happy - you're doing the wrong thing.",
  "Just relax and let it flow. That easy.",
  "Every single thing in the world has its own personality - and it is up to you to make friends with the little rascals.",
  "Trees grow however makes them happy.",
  "Don't kill all your dark areas - you need them to show the light.",
  "Everyone wants to enjoy the good parts - but you have to build the framework first.",
  "A big strong tree needs big strong roots.",
  "The light is your friend. Preserve it.",
  "Everybody's different. Trees are different. Let them all be individuals.",
  "We want to use a lot pressure while using no pressure at all.",
  "Follow the lay of the land. It's most important.",
  "We don't have anything but happy trees here.",
  "Even trees need a friend. We all need friends.",
  "Isn't it fantastic that you can change your mind and create all these happy things?",
  "The first step to doing anything is to believe you can do it. See it finished in your mind before you ever start.",
  "No worries. No cares. Just float and wait for the wind to blow you around.",
  "It just happens - whether or not you worried about it or tried to plan it.",
  "If it's not what you want - stop and change it. Don't just keep going and expect it will get better.",
  "You can create the world you want to see and be a part of. You have that power.",
  "How to paint. That's easy. What to paint. That's much harder.",
  "We can always carry this a step further. There's really no end to this.",
  "But we're not there yet, so we don't need to worry about it.",
  "This is your creation - and it's just as unique and special as you are.",
  "La- da- da- da- dah. Just be happy.",
  "Just take out whatever you don't want. It'll change your entire perspective.",
  "If you don't think every day is a good day - try missing a few. You'll see.",
  "There isn't a rule. You just practice and find out which way works best for you.",
  "Just let your mind wander and enjoy. This should make you happy.",
  "We don't have to be committed. We are just playing here.",
  "Remember how free clouds are. They just lay around in the sky all day long.",
  "Any little thing can be your friend if you let it be.",
  "The very fact that you're aware of suffering is enough reason to be overjoyed that you're alive and can experience it.",
  "And that's when it becomes fun - you don't have to spend your time thinking about what's happening - you just let it happen.",
  "This is probably the greatest thing to happen in my life - to be able to share this with you.",
  "If there are two big trees, eventually there will be a little tree.",
  "Everybody needs a friend.",
  "You can do anything here - the only pre-requisite is that it makes you happy.",
  "The more we do this - the more it will do good things to our heart.",
  "Even the worst thing we can do here is good.",
  "Absolutely no pressure. You are just a whisper floating across a mountain.",
  "You have freedom here. The only guide is your heart.",
  "Trees grow in all kinds of ways. They're not all perfectly straight. Not every limb is perfect.",
  "We must be quiet, soft and gentle.",
  "You can't have light without dark. You can't know happiness unless you've known sorrow.",
  "Just let this happen. We just let this flow right out of our minds.",
  "Just make a decision and let it go.",
  "Everything is happy if you choose to make it that way.",
  "You could sit here for weeks with your one hair brush trying to do that - or you could do it with one stroke with an almighty brush.",
  "We're not trying to teach you a thing to copy. We're just here to teach you a technique, then let you loose into the world.",
  "A tree needs to be your friend if you're going to paint him.",
  "You have to make almighty decisions when you're the creator.",
  "This is your world, whatever makes you happy you can put in it. Go crazy.",
  "We don't have to be concerned about it. We just have to let it fall where it will.",
  "We don't need any guidelines or formats. All we need to do is just let it flow right out of us.",
  "Let all these little things happen. Don't fight them. Learn to use them.",
  "I sincerely wish for you every possible joy life could bring.",
  "We spend so much of our life looking - but never seeing.",
  "Talent is a pursued interest. That is to say, anything you practice you can do.",
  "Let's make some happy little clouds in our world"
]
]]

PRIVMSG:
  '^%pbobross$': =>
    quotes = util.json.decode data
    choice = math.random(1, #quotes)
    say quotes[choice]

error: pathspec 'modules/bobross.moon' did not match any file(s) known to git


Added tool to dump framebuffer contents after certain draw calls.

The tool will dump framebuffer contents after calls like glDrawElements within
the provided range of calls.

-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this
-- file, You can obtain one at http://mozilla.org/MPL/2.0/.
--
-- Copyright 2016 [bk]door.maus

Trace = require "glurg.trace.Trace"
Retrace = require "glurg.common.Retrace"
Texture = require "glurg.resources.Texture"
TextureBlobBuilder = require "glurg.resources.TextureBlobBuilder"

Args = { ... }
if #Args < 3
	io.stderr\write("dump_framebuffer.moon <file.trace> <start-call> <end-call> <output-dir>\n")

	return 1

save_framebuffer_from_call = (retrace, index) ->
	render_state = retrace\next!

	depth_builder = TextureBlobBuilder!
	if not depth_builder\extract_framebuffer_attachment(render_state, 'depth')
		io.stdout\write("couldn't extract depth attachment\n")
	else
		blob = depth_builder\build!
		texture = Texture(blob)
		texture\save_png(string.format("%s/%010d_depth.png", Args[4], index))

	color_builder = TextureBlobBuilder!
	if not color_builder\extract_framebuffer_attachment(render_state, 'color', 1)
		io.stdout\write("couldn't extract color attachment\n")
	else
		blob = depth_builder\build!
		texture = Texture(blob)
		texture\save_png(string.format("%s/%010d_color.png", Args[4], index))

Funcs = {
	"glDrawArrays": true,
	"glDrawElements": true,
	"glDrawRangeElements": true
}

StartCall = tonumber(Args[2])
EndCall = tonumber(Args[3])

framebuffers = {}
do
	trace = Trace(Args[1])
	while not trace.is_end_of_file
		event = trace\next_event!
		if event.type == 'leave'
			if Funcs[event.call.signature.name] and event.call.index >= StartCall then
				io.stdout\write("queuing call #{event.call.index}\n")
				table.insert(framebuffers, event.call.index)
				if event.call.index > EndCall
					break
			trace\delete_call(event.call_index)
do
	retrace = Retrace(Args[1], framebuffers)
	retrace\start!
	for i = 1, #framebuffers
		io.stdout\write("saving framebuffer from call #{framebuffers[i]}\n")
		io.stdout\flush!
		save_framebuffer_from_call(retrace, framebuffers[i])
	retrace\stop!

error: pathspec 'utilities/lua/dump_framebuffer.moon' did not match any file(s) known to git


lexer/statement: add initial statement code

Added module patterns:

 * Call
 * Vararg
 * BinaryExpression
 * UnaryExpression
 * Expression
 * ValueNoUnary
 * Value
 * VariableList
 * Assignment
 * Statement

-- vim:set noet sts=0 sw=3 ts=3:
import Number, Variable, Macro, String, Boolean, Nil,
	Whitespace from require "sun.lexer.literal"
import P, V, S from require "lpeg"

Literal = Number + Boolean + Nil + Variable + String

-- Expressions

binary_symbols = {
	"+",  "-",  "*",  "//",  "/",  "^",  "%", "&", "~", "|", ">>", "<<", "..",
	"<", "<=", ">", ">=", "==", "!=", "&&", "||"
}
to_unpack = {}
local BinarySymbolPattern
for i=1, #binary_symbols do
	if #(binary_symbols[i]) == 1
		to_unpack[#to_unpack + 1] = binary_symbols[i]
	else
		if BinarySymbolPattern
			BinarySymbolPattern = BinarySymbolPattern + P(binary_symbols[i])
		else
			BinarySymbolPattern = P(binary_symbols[i])

BinarySymbolPattern = BinarySymbolPattern + S(table.concat(binary_symbols))

Base = {
	Call: Variable * P"(" * Whitespace * V"Vararg" ^ -1 * Whitespace * P")"
	Vararg: (V"Call" + V"Expression") * (Whitespace * P"," * Whitespace * (
		V"Call" + V"Expression")) ^ 0
	BinaryExpression: V"Value" * Whitespace * BinarySymbolPattern *
		Whitespace * V"Expression"
	UnaryExpression: S"#-~!" * Whitespace * V"ValueNoUnary"
	Expression: V"BinaryExpression" + V"UnaryExpression" + V"Value"
	ValueNoUnary: V"Call" + Literal * P"[" * V"Value" * P"]" + Literal + (
		P"(" * Whitespace * V"Value" * Whitespace * P")"
	)
	Value: V"UnaryExpression" + V"ValueNoUnary"
}

patterns = {}
do
	temp = {}
	names = {"Call", "Vararg", "BinaryExpression", "UnaryExpression",
		"Expression", "ValueNoUnary", "Value"}
	Vararg_0, Call_0 = {}, {}
	for k, v in pairs(Base)
		for i, _v in pairs(names) do
			temp[_v] = {_v} if not temp[_v]
			temp[_v][k] = v
	for k, v in pairs(temp) do
		patterns[k] = P(v)
import Call, Vararg, BinaryExpression, UnaryExpression, Expression,
	ValueNoUnary, Value from patterns

VariableList = Variable * (Whitespace * P"," * Whitespace * Variable) ^ 0
Assignment = VariableList * Whitespace * P"=" * Whitespace * Vararg

Statement = Whitespace * (Assignment + Call) * Whitespace * ";"

return {
	:Call, :Vararg, :BinaryExpression, :UnaryExpression, :Expression,
	:ValueNoUnary, :Value, :VariableList, :Assignment, :Statement
}

error: pathspec 'sun/lexer/statement.moon' did not match any file(s) known to git


Translation to Dutch

Translation to Dutch

-- Copyright (C) 2017-2019 DBot

-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-- of the Software, and to permit persons to whom the Software is furnished to do so,
-- subject to the following conditions:

-- The above copyright notice and this permission notice shall be included in all copies
-- or substantial portions of the Software.

-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
-- INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-- PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
-- FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-- DEALINGS IN THE SOFTWARE.

-- editor stuffs

gui.ppm2.dxlevel.not_supported = 'Uw DirectX™ level is te laag. Ten minste 9.0 is vereist. Als je 8.1 voor framerate gebruikt, heb je ofwel de oudste videokaart of slechte drivers.\nOmdat framerate in gmod alleen laag kan zijn vanwege andere addons die zinloze hoge CPU belasting creëren.\nJa, dit bericht zal meerdere malen verschijnen om je te ergeren. Omdat WAT DE NEUK WAAROM ZOU JE MELDINGEN GEVEN OVER ONTBREKENDE TEXTUREN???'
gui.ppm2.dxlevel.toolow = 'DirectX™ level is te laag voor PPM/2'

gui.ppm2.editor.eyes.separate = 'Gebruik gescheiden instellingen voor de ogen'
gui.ppm2.editor.eyes.url = 'Oog URL textuur'
gui.ppm2.editor.eyes.url_desc = 'Bij gebruik van de oog-URL-structuur; De volgende opties hebben geen effect'

gui.ppm2.editor.eyes.lightwarp_desc = 'Lightwarp heeft alleen effect op EyeRefract ogen'
gui.ppm2.editor.eyes.lightwarp = "Lightwarp"
gui.ppm2.editor.eyes.desc1 = "Lightwarp textuur URL invoer\nIt moet 256x16 zijn!"
gui.ppm2.editor.eyes.desc2 = "Glanssterkte\nDeze parameters passen de sterkte van real time reflecties op het oog aan\nOm veranderingen te zien, zet ppm2_cl_reflections convar op 1\nAndere spelers zouden alleen reflecties zien met ppm2_cl_reflecties ingesteld op 1\n0 - is gematteerd; 1 - is gespiegeld"

for _, {tprefix, prefix} in ipairs {{'def', ''}, {'left', 'Left '}, {'right', 'Right '}}
	gui.ppm2.editor.eyes[tprefix].lightwarp.shader = "#{prefix}Gebruik EyeRefract shader"
	gui.ppm2.editor.eyes[tprefix].lightwarp.cornera = "#{prefix}Gebruik Eye Cornera diffuus"
	gui.ppm2.editor.eyes[tprefix].lightwarp.glossiness = "#{prefix}Glans"

	gui.ppm2.editor.eyes[tprefix].type = "#{prefix}Oogtype"
	gui.ppm2.editor.eyes[tprefix].reflection_type = "#{prefix}Type oogreflectie"
	gui.ppm2.editor.eyes[tprefix].lines = "#{prefix}Ooglijnen"
	gui.ppm2.editor.eyes[tprefix].derp = "#{prefix}Derp ogen"
	gui.ppm2.editor.eyes[tprefix].derp_strength = "#{prefix}Derp oog sterkte"
	gui.ppm2.editor.eyes[tprefix].iris_size = "#{prefix}Ooggrootte"

	gui.ppm2.editor.eyes[tprefix].points_inside = "#{prefix}Ooglijntjes binnenin"
	gui.ppm2.editor.eyes[tprefix].width = "#{prefix}Oogbreedte"
	gui.ppm2.editor.eyes[tprefix].height = "#{prefix}Ooghoogte"

	gui.ppm2.editor.eyes[tprefix].pupil.width = "#{prefix}Pupil breedte"
	gui.ppm2.editor.eyes[tprefix].pupil.height = "#{prefix}Pupil hoogte"
	gui.ppm2.editor.eyes[tprefix].pupil.size = "#{prefix}Pupil grootte"

	gui.ppm2.editor.eyes[tprefix].pupil.shift_x = "#{prefix}Pupil verschuiving X"
	gui.ppm2.editor.eyes[tprefix].pupil.shift_y = "#{prefix}Pupil verschuiving Y"
	gui.ppm2.editor.eyes[tprefix].pupil.rotation = "#{prefix}Oog rotatie"

	gui.ppm2.editor.eyes[tprefix].background = "#{prefix}Oog achtergrond"
	gui.ppm2.editor.eyes[tprefix].pupil_size = "#{prefix}Pupil"
	gui.ppm2.editor.eyes[tprefix].top_iris = "#{prefix}Bovenste oog iris"
	gui.ppm2.editor.eyes[tprefix].bottom_iris = "#{prefix}Onderste oog iris"
	gui.ppm2.editor.eyes[tprefix].line1 = "#{prefix}Oog lijn 1"
	gui.ppm2.editor.eyes[tprefix].line2 = "#{prefix}Oog lijn 2"
	gui.ppm2.editor.eyes[tprefix].reflection = "#{prefix}Oogreflectie effect"
	gui.ppm2.editor.eyes[tprefix].effect = "#{prefix}Oog effect"

gui.ppm2.editor.generic.title = 'PPM/2 Pony Editor'
gui.ppm2.editor.generic.title_file = '%q - PPM/2 Pony Editor'
gui.ppm2.editor.generic.title_file_unsaved = '%q* - PPM/2 Pony Editor (niet opgeslagen wijzigingen!)'

gui.ppm2.editor.generic.yes = 'Yas!'
gui.ppm2.editor.generic.no = 'Noh!'
gui.ppm2.editor.generic.ohno = 'Onoh!'
gui.ppm2.editor.generic.okay = 'Okai ;w;'
gui.ppm2.editor.generic.datavalue = '%s\nGegevenswaarde: %q'
gui.ppm2.editor.generic.url = '%s\n\nLink gaat naar: %s'
gui.ppm2.editor.generic.url_field = 'URL veld'
gui.ppm2.editor.generic.spoiler = 'Mysterieuze spoiler'

gui.ppm2.editor.generic.restart.needed = 'Editor moet opnieuw worden opgestart'
gui.ppm2.editor.generic.restart.text = 'U moet de editor herstarten voor het toepassen van wijzigingen.\nNu herstarten?\nNiet opgeslagen gegevens gaan verloren!'
gui.ppm2.editor.generic.fullbright = 'Vol helder'
gui.ppm2.editor.generic.wtf = 'Om de een of andere reden heeft uw speler geen NetworkedPonyData - Niets te bewerken!\nProbeer ppm2_reload in je console en probeer de editor opnieuw te openen'

gui.ppm2.editor.io.random = 'Willekeurig!'
gui.ppm2.editor.io.newfile.title = 'Nieuw Bestand'
gui.ppm2.editor.io.newfile.confirm = 'Wilt u echt een nieuw bestand aanmaken?'
gui.ppm2.editor.io.newfile.toptext = 'Reset'
gui.ppm2.editor.io.delete.confirm = 'Wilt u dat bestand echt verwijderen?\nHet zal voor altijd verdwenen zijn!\n(een lange tijd!)'
gui.ppm2.editor.io.delete.title = 'Echt verwijderen?'

gui.ppm2.editor.io.filename = 'Bestandsnaam'
gui.ppm2.editor.io.hint = 'Bestand openen door te dubbelklikken'
gui.ppm2.editor.io.reload = 'Bestandslijst opnieuw laden'
gui.ppm2.editor.io.failed = 'Heeft niet kunnen importeren.'

gui.ppm2.editor.io.warn.oldfile = '!!! Het kan wel of niet werken. U zult worden geplet.'
gui.ppm2.editor.io.warn.text = "Op dit moment heeft u uw wijzigingen niet aangegeven.\nWilt u echt een ander bestand openen?"
gui.ppm2.editor.io.warn.header = 'Niet opgeslagen wijzigingen!'
gui.ppm2.editor.io.save.button = 'Opslaan'
gui.ppm2.editor.io.save.text = 'Voer de bestandsnaam in zonder ppm2/ en .dat\nTip: om op te slaan als autoload, type "_current" (zonder citaten)'
gui.ppm2.editor.io.wear = 'Wijzigingen aanbrengen (dragen)'

gui.ppm2.editor.seq.standing = 'Staand'
gui.ppm2.editor.seq.move = 'In beweging'
gui.ppm2.editor.seq.walk = 'Wandelen'
gui.ppm2.editor.seq.sit = 'Zitten'
gui.ppm2.editor.seq.swim = 'Zwemmen'
gui.ppm2.editor.seq.run = 'Rennen'
gui.ppm2.editor.seq.duckwalk = 'Wandel als een eend'
gui.ppm2.editor.seq.duck = 'Doe als een eend'
gui.ppm2.editor.seq.jump = 'Springen'

gui.ppm2.editor.misc.race = 'Ras'
gui.ppm2.editor.misc.weight = 'Gewicht'
gui.ppm2.editor.misc.size = 'Pony grootte'
gui.ppm2.editor.misc.hide_weapons = 'Moet wapens verbergen'
gui.ppm2.editor.misc.chest = 'Mannelijke borstkas'
gui.ppm2.editor.misc.gender = 'Geslacht'
gui.ppm2.editor.misc.wings = 'Vleugels Type'
gui.ppm2.editor.misc.flexes = 'Flexibele besturing'
gui.ppm2.editor.misc.no_flexes2 = 'Geen flexibiliteit op het nieuwe model'
gui.ppm2.editor.misc.no_flexes_desc = 'U kunt elke flexstatuscontroller apart uitschakelen\nDeze buigingen kunnen dus worden aangepast met add-ons van derden (zoals PAC3)'

gui.ppm2.editor.misc.hide_pac3 = 'Entiteiten verbergen wanneer een PAC3 entiteit wordt gebruikt'
gui.ppm2.editor.misc.hide_mane = 'Mane verbergen wanneer een PAC3 entiteit wordt gebruikt'
gui.ppm2.editor.misc.hide_tail = 'Verberg de staart wanneer een PAC3 entiteit wordt gebruikt'
gui.ppm2.editor.misc.hide_socks = 'Sokken verbergen bij gebruik van een PAC3 entiteit'

gui.ppm2.editor.tabs.main = 'Algemeen'
gui.ppm2.editor.tabs.files = 'Bestanden'
gui.ppm2.editor.tabs.old_files = 'Oude Bestanden'
gui.ppm2.editor.tabs.cutiemark = 'Cutiemark'
gui.ppm2.editor.tabs.head = 'Hoofd anatomie'
gui.ppm2.editor.tabs.eyes = 'Ogen'
gui.ppm2.editor.tabs.face = 'Gezicht'
gui.ppm2.editor.tabs.mouth = 'Mond'
gui.ppm2.editor.tabs.left_eye = 'Linker oog'
gui.ppm2.editor.tabs.right_eye = 'Rechter oog'
gui.ppm2.editor.tabs.mane_horn = 'Mane en Hoorn'
gui.ppm2.editor.tabs.mane = 'Mane'
gui.ppm2.editor.tabs.details = 'Details'
gui.ppm2.editor.tabs.url_details = 'URL Details'
gui.ppm2.editor.tabs.url_separated_details = 'URL Gescheiden Details'
gui.ppm2.editor.tabs.ears = 'Oren'
gui.ppm2.editor.tabs.horn = 'Hoorn'
gui.ppm2.editor.tabs.back = 'Rug'
gui.ppm2.editor.tabs.wings = 'Vleugels'
gui.ppm2.editor.tabs.left = 'Links'
gui.ppm2.editor.tabs.right = 'Rechts'
gui.ppm2.editor.tabs.neck = 'Nek'
gui.ppm2.editor.tabs.body = 'Pony lichaam'
gui.ppm2.editor.tabs.tattoos = 'Tatoeages'
gui.ppm2.editor.tabs.tail = 'Staart'
gui.ppm2.editor.tabs.hooves = 'Hoeven anatomie'
gui.ppm2.editor.tabs.bottom_hoof = 'Onder hoef'
gui.ppm2.editor.tabs.legs = 'Benen'
gui.ppm2.editor.tabs.socks = 'Sokken'
gui.ppm2.editor.tabs.newsocks = 'Nieuwe Sokken'
gui.ppm2.editor.tabs.about = 'Over'

gui.ppm2.editor.old_tabs.mane_tail = 'Mane en staart'
gui.ppm2.editor.old_tabs.wings_and_horn_details = 'Vleugels en hoorn details'
gui.ppm2.editor.old_tabs.wings_and_horn = 'Vleugels en hoorn'
gui.ppm2.editor.old_tabs.body_details = 'Lichaam details'
gui.ppm2.editor.old_tabs.mane_tail_detals = 'Mane en staart URL details'

gui.ppm2.editor.cutiemark.display = 'Toon cutiemarkering'
gui.ppm2.editor.cutiemark.type = 'Cutiemark type'
gui.ppm2.editor.cutiemark.size = 'Cutiemark grootte'
gui.ppm2.editor.cutiemark.color = 'Cutiemark kleur'
gui.ppm2.editor.cutiemark.input = 'Cutiemark URL afbeelding invoer veld\nMoet PNG of JPEG zijn (werkt hetzelfde als\nPAC3 URL textuur)'

gui.ppm2.editor.face.eyelashes = 'Wimpers'
gui.ppm2.editor.face.eyelashes_color = 'Wimpers kleur'
gui.ppm2.editor.face.eyelashes_phong = 'Wimpers phong parameters'
gui.ppm2.editor.face.eyebrows_color = 'Wenkbrauwen kleur'
gui.ppm2.editor.face.new_muzzle = 'Gebruik nieuwe snuit voor het mannelijk model'

gui.ppm2.editor.face.nose = 'Neus kleur'
gui.ppm2.editor.face.lips = 'Lippen kleur'
gui.ppm2.editor.face.eyelashes_separate_phong = 'Afzonderlijke wimpers Phong'
gui.ppm2.editor.face.eyebrows_glow = 'Gloeiende wenkbrauwen'
gui.ppm2.editor.face.eyebrows_glow_strength = 'Wenkbrauwen gloed sterkte'
gui.ppm2.editor.face.inherit.lips = 'Neem de Lippen kleur van het lichaam'
gui.ppm2.editor.face.inherit.nose = 'Neem de neus kleur van het lichaam'

gui.ppm2.editor.mouth.fangs = 'Tanden'
gui.ppm2.editor.mouth.alt_fangs = 'Alternatieve hoektanden'
gui.ppm2.editor.mouth.claw = 'Klauwtanden'

gui.ppm2.editor.mouth.teeth = 'Tand kleur'
gui.ppm2.editor.mouth.teeth_phong = 'Tanden phong parameters'
gui.ppm2.editor.mouth.mouth = 'Mond kleur'
gui.ppm2.editor.mouth.mouth_phong = 'Mond phong parameters'
gui.ppm2.editor.mouth.tongue = 'Tong kleur'
gui.ppm2.editor.mouth.tongue_phong = 'Tong phong parameters'

gui.ppm2.editor.mane.type = 'Mane Type'
gui.ppm2.editor.mane.phong = 'Afzonderlijk mane phong instellingen van het lichaam'
gui.ppm2.editor.mane.mane_phong = 'Mane phong parameters'
gui.ppm2.editor.mane.phong_sep = 'Gescheiden bovenste en onderste mane kleuren'
gui.ppm2.editor.mane.up.phong = 'Bovenste Mane Phong instellingen'
gui.ppm2.editor.mane.down.type = 'Onderste Mane Type'
gui.ppm2.editor.mane.down.phong = 'Onderste Mane Phong instellingen'
gui.ppm2.editor.mane.newnotice = 'De volgende opties hebben alleen effect op een nieuw model'

for i = 1, 2
	gui.ppm2.editor.mane['color' .. i] = "Mane kleur #{i}"
	gui.ppm2.editor.mane.up['color' .. i] = "Bovenste mane kleur #{i}"
	gui.ppm2.editor.mane.down['color' .. i] = "Onderste mane kleur #{i}"

for i = 1, 6
	gui.ppm2.editor.mane['detail_color' .. i] = "Mane detail kleur #{i}"
	gui.ppm2.editor.mane.up['detail_color' .. i] = "Bovenste mane kleur #{i}"
	gui.ppm2.editor.mane.down['detail_color' .. i] = "Onderste mane kleur #{i}"

	gui.ppm2.editor.url_mane['desc' .. i] = "Mane URL Detail #{i} invoer veld"
	gui.ppm2.editor.url_mane['color' .. i] = "Mane URL detail kleur #{i}"

	gui.ppm2.editor.url_tail['desc' .. i] = "Staart URL Detail #{i} invoer veld"
	gui.ppm2.editor.url_tail['color' .. i] = "Staart URL detail kleur #{i}"

	gui.ppm2.editor.url_mane.sep.up['desc' .. i] = "Bovenste mane URL Detail #{i} invoer veld"
	gui.ppm2.editor.url_mane.sep.up['color' .. i] = "Bovenste Mane URL detail kleur #{i}"

	gui.ppm2.editor.url_mane.sep.down['desc' .. i] = "Onderste mane URL Detail #{i} invoer veld"
	gui.ppm2.editor.url_mane.sep.down['color' .. i] = "Onderste Mane URL detail kleur #{i}"

gui.ppm2.editor.ears.bat = 'Vleermuis pony oren'
gui.ppm2.editor.ears.size = 'Oren grootte'

gui.ppm2.editor.horn.detail_color = 'Hoorn detail kleur'
gui.ppm2.editor.horn.glowing_detail = 'Glanzende Hoorn Detail'
gui.ppm2.editor.horn.glow_strength = 'Horn gloed sterkte'
gui.ppm2.editor.horn.separate_color = 'Aparte hoornkleur van het lichaam'
gui.ppm2.editor.horn.color = 'Hoorn kleur'
gui.ppm2.editor.horn.horn_phong = 'Hoorn phong parameters'
gui.ppm2.editor.horn.magic = 'Hoorn magie kleur'
gui.ppm2.editor.horn.separate_magic_color = 'Aparte magische kleur van oogkleur'
gui.ppm2.editor.horn.separate = 'Aparte hoornkleur van het lichaam'
gui.ppm2.editor.horn.separate_phong = 'Aparte hoorn phong instellingen van het lichaam'

for i = 1, 3
	gui.ppm2.editor.horn.detail['desc' .. i] = "Hoorn URL detail #{i}"
	gui.ppm2.editor.horn.detail['color' .. i] = "URL Detail kleur #{i}"

gui.ppm2.editor.wings.separate_color = 'Aparte vleugel kleur van het lichaam'
gui.ppm2.editor.wings.color = 'Vleugel color'
gui.ppm2.editor.wings.wings_phong = 'Vleugel phong parameters'
gui.ppm2.editor.wings.separate = 'Aparte vleugel kleur van het lichaam'
gui.ppm2.editor.wings.separate_phong = 'Aparte vleugel phong instellingen van het lichaam'
gui.ppm2.editor.wings.bat_color = 'Vleermuis vleugels kleur'
gui.ppm2.editor.wings.bat_skin_color = 'Vleermuis vleugels huidskleur'
gui.ppm2.editor.wings.bat_skin_phong = 'Vleermuis vleugels huid phong parameters'

gui.ppm2.editor.wings.normal = 'Normale vleugels'
gui.ppm2.editor.wings.bat = 'Vleermuisvleugels'
gui.ppm2.editor.wings.bat_skin = 'Vleermuis vleugels huid'

gui.ppm2.editor.wings.left.size = 'Linker vleugel grootte'
gui.ppm2.editor.wings.left.fwd = 'Linker vleugel voor'
gui.ppm2.editor.wings.left.up = 'Linker vleugel boven'
gui.ppm2.editor.wings.left.inside = 'Linker vleugel binnen

gui.ppm2.editor.wings.right.size = 'Rechter vleugel grootte'
gui.ppm2.editor.wings.right.fwd = 'Rechter vleugel voor'
gui.ppm2.editor.wings.right.up = 'Rechter vleugel boven'
gui.ppm2.editor.wings.right.inside = 'Rechter vleugel binnen'

for i = 1, 3
	gui.ppm2.editor.wings.details.def['detail' .. i] = "Vleugels URL detail #{i}"
	gui.ppm2.editor.wings.details.def['color' .. i] = "URL Detail kleur #{i}"
	gui.ppm2.editor.wings.details.bat['detail' .. i] = "Vleermuisvleugels URL detail #{i}"
	gui.ppm2.editor.wings.details.bat['color' .. i] = "Vleermuisvleugels URL Detail kleur #{i}"
	gui.ppm2.editor.wings.details.batskin['detail' .. i] = "Vleermuisvleugels huid URL detail #{i}"
	gui.ppm2.editor.wings.details.batskin['color' .. i] = "Vleermuisvleugels huid URL Detail kleur #{i}"

gui.ppm2.editor.neck.height = 'Nek hoogte'

gui.ppm2.editor.body.suit = 'Kostuum'
gui.ppm2.editor.body.color = 'Lichaams kleur'
gui.ppm2.editor.body.body_phong = 'Lichaam phong parameters'
gui.ppm2.editor.body.spine_length = 'Rug lengte'
gui.ppm2.editor.body.url_desc = 'Lichaam detail URL afbeelding invoer veld\nMoet PNG of JPEG zijn (werkt hetzelfde als \nPAC3 URL structuur)'

gui.ppm2.editor.body.disable_hoofsteps = 'Hoef stappen uitschakelen'
gui.ppm2.editor.body.disable_wander_sounds = 'Wandelgeluiden uitschakelen'
gui.ppm2.editor.body.disable_new_step_sounds = 'Aangepaste stapgeluiden uitschakelen'
gui.ppm2.editor.body.disable_jump_sound = 'Spring geluid uitschakelen'
gui.ppm2.editor.body.disable_falldown_sound = 'Neer val geluid uitschakelen'
gui.ppm2.editor.body.call_playerfootstep = 'Noem PlayerFootstep bij elk geluid'
gui.ppm2.editor.body.call_playerfootstep_desc = 'Noem PlayerFootstep haak op elk daadwerkelijk geluid dat u hoort.\nMet behulp van deze optie kunnen andere geïnstalleerde addons vertrouwen op PPM2\'s diepgang\ndie luisteren naar PlayerFootstep haak. Dit moet alleen worden uitgeschakeld wanneer u onbetrouwbare resultaten van andere addons krijgt.\nof uw FPS daalt naar lage waarden omdat een van de geïnstalleerde addons slecht gecodeerd is.'

for i = 1, PPM2.MAX_BODY_DETAILS
	gui.ppm2.editor.body.detail['desc' .. i] = "Detail #{i}"
	gui.ppm2.editor.body.detail['color' .. i] = "Detail kleur #{i}"
	gui.ppm2.editor.body.detail['glow' .. i] = "Detail #{i} gloeit"
	gui.ppm2.editor.body.detail['glow_strength' .. i] = "Detail #{i} gloeikracht"

	gui.ppm2.editor.body.detail.url['desc' .. i] = "Detail #{i}"
	gui.ppm2.editor.body.detail.url['color' .. i] = "Detail kleur #{i}"

gui.ppm2.editor.tattoo.edit_keyboard = 'Bewerken met behulp van het toetsenbord'
gui.ppm2.editor.tattoo.type = 'Type'
gui.ppm2.editor.tattoo.over = 'Tatoeage over het lichaam details'
gui.ppm2.editor.tattoo.glow = 'Tatoeage is gloeiend'
gui.ppm2.editor.tattoo.glow_strength = 'De sterkte van de tatoegering gloed'
gui.ppm2.editor.tattoo.color = 'Kleur van Tattoo'

gui.ppm2.editor.tattoo.tweak.rotate = 'Rotatie'
gui.ppm2.editor.tattoo.tweak.x = 'X Positie'
gui.ppm2.editor.tattoo.tweak.y = 'Y Positie'
gui.ppm2.editor.tattoo.tweak.width = 'Breedte Schaal'
gui.ppm2.editor.tattoo.tweak.height = 'Hoogte schaal'

for i = 1, PPM2.MAX_TATTOOS
	gui.ppm2.editor.tattoo['layer' .. i] = "Tatoegeringslaag #{i}"

gui.ppm2.editor.tail.type = 'Staart type'
gui.ppm2.editor.tail.size = 'Staart grootte'
gui.ppm2.editor.tail.tail_phong = 'Staart phong parameters'
gui.ppm2.editor.tail.separate = 'Aparte staart phong instellingen van het lichaam'

for i = 1, 2
	gui.ppm2.editor.tail['color' .. i] = 'Staart kleur ' .. i

for i = 1, 6
	gui.ppm2.editor.tail['detail' .. i] = "Staart detail kleur #{i}"
	gui.ppm2.editor.tail.url['detail' .. i] = "Staart URL detail #{i}"
	gui.ppm2.editor.tail.url['color' .. i] = "Staart URL detail #{i}"

gui.ppm2.editor.hoof.fluffers = 'Hoef Fluffers'

gui.ppm2.editor.legs.height = 'Benen hoogte'
gui.ppm2.editor.legs.socks.simple = 'Sokken (eenvoudige textuur)'
gui.ppm2.editor.legs.socks.model = 'Sokken (als model)'
gui.ppm2.editor.legs.socks.color = 'Sokken model kleur'
gui.ppm2.editor.legs.socks.socks_phong = 'Sokken phong parameters'
gui.ppm2.editor.legs.socks.texture = 'Sokken textuur'
gui.ppm2.editor.legs.socks.url_texture = 'Sokken URL textuur'

for i = 1, 6
	gui.ppm2.editor.legs.socks['color' .. i] = 'Sokken detail kleur ' .. i

gui.ppm2.editor.legs.newsocks.model = 'Sokken (als een nieuw model)'

for i = 1, 3
	gui.ppm2.editor.legs.newsocks['color' .. i] = 'Nieuwe sokken kleur ' .. i

gui.ppm2.editor.legs.newsocks.url = 'Nieuwe sokken URL textuur'

-- shared editor stuffs

gui.ppm2.editor.tattoo.help = "Om de bewerkmodus te verlaten, drukt u op Escape of klikt u ergens met de muis
Om tatto te verplaatsen, gebruikt u WASD
Om hoger/lager te schalen gebruikt u de pijlen omhoog/omlaag
Om breder/kleiner te schalen gebruik rechts/links pijlen
Om links/rechts te draaien gebruikt u Q/E"

gui.ppm2.editor.reset_value = 'Reset %s'

gui.ppm2.editor.phong.info = 'Meer info over Phong op de wiki'
gui.ppm2.editor.phong.exponent = 'Phong Exponent - hoe sterk reflecterende eigenschap\nvan een ponyhuid is\nZet bijna op nul om een robotachtige uitstraling te krijgen van uw\npony huid'
gui.ppm2.editor.phong.exponent_text = 'Phong Exponent'
gui.ppm2.editor.phong.boost.title = 'Phong Verhogen - vermenigvuldigt spiegelende kaartreflecties'
gui.ppm2.editor.phong.boost.boost = 'Phong Verhogen'
gui.ppm2.editor.phong.tint.title = 'Tint kleur - welke kleuren weerspiegelt in de kaart\nWit - Weerspiegelt alle kleuren\n(In witte kamer - witte spiegelkaart)'
gui.ppm2.editor.phong.tint.tint = 'Tint kleur'
gui.ppm2.editor.phong.frensel.front.title = 'Phong Voorkant - Fresnel 0 graden reflectie hoekvermenigvuldiger'
gui.ppm2.editor.phong.frensel.front.front = 'Phong Voorkant'
gui.ppm2.editor.phong.frensel.middle.title = 'Phong Midden - Fresnel 45 graden reflectie hoekvermenigvuldiger'
gui.ppm2.editor.phong.frensel.middle.front = 'Phong Midden'
gui.ppm2.editor.phong.frensel.sliding.title = 'Phong glijdend - Fresnel 90 graden reflectie hoekvermenigvuldiger'
gui.ppm2.editor.phong.frensel.sliding.front = 'Phong glijdend'
gui.ppm2.editor.phong.lightwarp = 'Lightwarp'
gui.ppm2.editor.phong.url_lightwarp = 'Lightwarp textuur URL invoer\nIt moet 256x16 zijn!'
gui.ppm2.editor.phong.bumpmap = 'Bumpmap URL invoer'

gui.ppm2.editor.info.discord = "Sluit je aan bij DBot's Discord!"
gui.ppm2.editor.info.ponyscape = "PPM/2 is een Ponyscape project"
gui.ppm2.editor.info.creator = "PPM/2 is gemaakt en ontwikkeld door DBot"
gui.ppm2.editor.info.newmodels = "Nieuwe modellen zijn gemaakt door Durpy"
gui.ppm2.editor.info.cppmmodels = "CPPM modellen (inclusief ponyhanden) behoren tot UnkN', 'http://steamcommunity.com/profiles/76561198084938735"
gui.ppm2.editor.info.oldmodels = "Oude modellen zijn van Scentus en anderen"
gui.ppm2.editor.info.bugs = "Heeft u een bug gevonden? Meld hier!"
gui.ppm2.editor.info.sources = "U kunt hier bronnen vinden"
gui.ppm2.editor.info.githubsources = "Of op de GitHub-mirror"
gui.ppm2.editor.info.thanks = "Met dank aan everypony die kritiek heeft geuit,\ngeholpen en getest van PPM/2!"

-- other stuff

info.ppm2.fly.pegasus = 'Je moet een Pegasus of een Alicorn zijn om te vliegen!'
info.ppm2.fly.cannot = 'Je kunt %s nu niet gebruiken.'

gui.ppm2.emotes.sad = 'Verdrietig'
gui.ppm2.emotes.wild = 'Wild'
gui.ppm2.emotes.grin = 'Grijns'
gui.ppm2.emotes.angry = 'Boos'
gui.ppm2.emotes.tongue = ':P'
gui.ppm2.emotes.angrytongue = '>:P'
gui.ppm2.emotes.pff = 'Pffff!'
gui.ppm2.emotes.kitty = ':3'
gui.ppm2.emotes.owo = 'oWo'
gui.ppm2.emotes.ugh = 'Uuugh'
gui.ppm2.emotes.lips = 'Lippen likken'
gui.ppm2.emotes.scrunch = 'Knarsen'
gui.ppm2.emotes.sorry = 'Sorry'
gui.ppm2.emotes.wink = 'Knipoogje'
gui.ppm2.emotes.right_wink = 'Rechter knipoogje'
gui.ppm2.emotes.licking = 'Likken'
gui.ppm2.emotes.suggestive_lips = 'Suggestieve lippen likken'
gui.ppm2.emotes.suggestive_no_tongue = 'Suggestieve w/o tong'
gui.ppm2.emotes.gulp = 'Slikken'
gui.ppm2.emotes.blah = 'Blah blah blah'
gui.ppm2.emotes.happi = 'Blij'
gui.ppm2.emotes.happi_grin = 'Blije grijns'
gui.ppm2.emotes.duck = 'EEND'
gui.ppm2.emotes.ducks = 'DUCK INSANITY'
gui.ppm2.emotes.quack = 'KWAK'
gui.ppm2.emotes.suggestive = 'Suggestieve w/ tong'

message.ppm2.emotes.invalid = 'Geen emotie met ID: %s'

gui.ppm2.editor.intro.text = "Welkom bij mijn nieuwe..... Robosurgeon voor pony's! Het stelt u in staat om........\n" ..
	"hmmm..... een pony te worden, en ja, dit proces is IRREVERSCHAPPELIJK! Maar u hoeft zich geen zorgen te maken,\n" ..
	"u verliest geen van uw hersencellen voor, in en na de operatie, omdat het een zeer zachte operatie uitvoert.....\n\n" ..
	"Eigenlijk heb ik geen idee, jij biologisch wezen! Zijn mechanische handen zullen je omhullen in de strakste knuffels die je ooit hebt gekregen!\n" ..
	"En, alstublieft, niet sterven in het proces, want dit zou VERVALLEN VAN UW LEVENSLANGE GARANTIE veroorzaken..... en je zult geen pony zijn!\n" ..
	"----\n\n\n" ..
	"Let op: Haal Robosurgeon niet uit elkaar. Ieders handen/handschoenen niet in bewegende delen van Robosurgeon..\n" ..
	"Schakel het apparaat niet uit terwijl het werkt.\nProbeer niet te weerstaan aan zijn acties.\n" ..
	"Wees altijd voorzichtig met Robosurgeon\n" ..
	"Sla nooit Robosurgeon op zijn interface.\n" ..
	"DBot's DLibCo neemt geen verantwoordelijkheid voor eventuele schade veroorzaakt door verkeerd gebruik van Robosurgeon.\n" ..
	"De garantie vervalt als de gebruiker sterft.\n" ..
	"Geen terugbetalingen."
gui.ppm2.editor.intro.title = 'Welkom hier, Mens!!'
gui.ppm2.editor.intro.okay = "Ok, ik zal deze licentie toch nooit lezen"

message.ppm2.debug.race_condition = 'Ontvangen NetworkedPonyData voordat de entiteit op de client werd aangemaakt! Wachten.....'

gui.ppm2.spawnmenu.newmodel = 'Spawn nieuw model'
gui.ppm2.spawnmenu.newmodelnj = 'Spawn nieuw nj model'
gui.ppm2.spawnmenu.oldmodel = 'Spawn oud model'
gui.ppm2.spawnmenu.oldmodelnj = 'Spawn oud nj model'
gui.ppm2.spawnmenu.cppmmodel = 'Spawn CPPM model'
gui.ppm2.spawnmenu.cppmmodelnj = 'Spawn CPPM nj model'
gui.ppm2.spawnmenu.cleanup = 'Opruimen ongebruikt models'
gui.ppm2.spawnmenu.reload = 'Herlaad lokale gegevens'
gui.ppm2.spawnmenu.require = 'Gegevens vereisen van de server'
gui.ppm2.spawnmenu.drawhooves = 'Laat hoeven zien als handen'
gui.ppm2.spawnmenu.nohoofsounds = 'Geen hoefgeluiden'
gui.ppm2.spawnmenu.noflexes = 'Schakel flexes uit (emotes)'
gui.ppm2.spawnmenu.advancedmode = 'Activeer de geavanceerde modus voor PPM2 editor'
gui.ppm2.spawnmenu.reflections = 'Activeer reflecties in real-time'
gui.ppm2.spawnmenu.reflections_drawdist = 'Reflecties tekenen afstand'
gui.ppm2.spawnmenu.reflections_renderdist = 'Reflecties laad afstand'
gui.ppm2.spawnmenu.doublejump = 'Dubbel springen activeert vliegen'

tip.ppm2.in_editor = 'In PPM/2 Editor'
tip.ppm2.camera = "%s's PPM/2 Camera"

message.ppm2.queue_notify = '%i texturen staan in de rij om te worden weergegeven'

error: pathspec 'moon/dlib/i18n/ppm2/nl.moon' did not match any file(s) known to git


Added Log object.

Added Log object.

This will make it easier to allow printing useful messages, and also filtering
them.

-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this
-- file, You can obtain one at http://mozilla.org/MPL/2.0/.
--
-- Copyright 2016 [bk]door.maus

Promise = require "glurg.common.Promise"

class Log
	new: =>
		@message_threshold = 'high'

	_should_print: (importance) =>
		Promise.keep_any("importance",
			importance == 'high', importance == 'medium', importance == 'low')

		return switch @message_threshold
			when 'high'
				importance == 'high'
			when 'medium'
				importance == 'high' or importance == 'medium'
			when 'low'
				true
			else
				assert(false, "invalid verbosity threshold")

	_print: (importance, prefix, message, ...) =>
		Promise.keep("importance", Promise.IsString(importance))
		Promise.keep("prefix", Promise.IsString(prefix))
		Promise.keep("message", Promise.IsString(message))

		if @\_should_print(importance)
			if prefix != ""
				io.stdout\write("[", prefix, "]", " ")

			io.stdout\write(string.format(message, ...), "\n")
			io.stdout\flush!

	info: (importance, message, ...) =>
		@\_print(importance, "", message, ...)

	warn: (importance, message, ...) =>
		@\_print(importance, "warning", message, ...)

	error: (message, ...) =>
		@\_print('high', "error", message, ...)

return Log!

error: pathspec 'glurg/common/Log.moon' did not match any file(s) known to git


textutils: new module with some helpful trix for filters

Former-commit-id: 837ab2e3afaf2615e723313da06aebef5f168358 [formerly 777f69fc23a19d59139a45361bbc47846a2c4ccf]
Former-commit-id: 2670ff1a056d0be5b1ec85b123046034b2f49c63

PRIVMSG:
  '^%pupper (.+)$': (source, destination, arg) =>
    say arg\upper!
  '^%plower (.+)$': (source, destination, arg) =>
    say arg\lower!
  '^%preverse (.+)$': (source, destination, arg) =>
    say arg\reverse!
  '^%plen (.+)$': (source, destination, arg) =>
    say tostring(arg\len!)
  '^%pnicks$': (source, destination) =>
    say table.concat([n for n,k in pairs(ivar2.channels[destination].nicks)], ' ')
  '^%prandom (.+)$': (source, destination, arg) =>
    words = [word for word in arg\gmatch('%S+')]
    say words[math.random(1, #words)]

error: pathspec 'modules/textutils.moon' did not match any file(s) known to git


duckduckgo: new module

duckduckgo: new module

json = require 'json'
simplehttp = require 'simplehttp'

urlEncode = (str, space) ->
  space = space or '+'

  str = str\gsub '([^%w ])', (c) ->
      string.format  "%%%02X", string.byte(c)
  return str\gsub(' ', space)

PRIVMSG:
  '^%pddg (.+)$': (source, destination, term) =>
    term = urlEncode term
    simplehttp "http://api.duckduckgo.com/?q=#{term}&format=json", (d) ->
      data = json.decode d
      out = {}
      topic = data.RelatedTopics[1] if data.RelatedTopics and #data.RelatedTopics>0
      if data.Heading == ''
        return
      table.insert out, "\002#{data.Heading}\002:"
      table.insert out, data.AbstractText unless data.AbstractText == ''
      table.insert out, data.Image unless data.Image == ''
      table.insert out, data.AbstractURL unless data.AbstractURL == ''
      table.insert out, data.Definition unless data.Definition == ''
      table.insert out, data.DefinitionText unless data.DefinitionText == ''
      if #out < 3
        table.insert out, topic.FirstURL
        table.insert out, topic.Text

      @Msg 'privmsg', destination, source, table.concat(out, ' ')

error: pathspec 'modules/duckduckgo.moon' did not match any file(s) known to git


Added utility demonstrating Glurg trace functionality.

-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this
-- file, You can obtain one at http://mozilla.org/MPL/2.0/.
--
-- Copyright 2016 [bk]door.maus

Trace = require "glurg.trace.Trace"

Args = { ... }
if #Args < 2
	io.stderr\write("print_trace_functions.moon <file.trace> <function>\n")

	return 1

print_call = (call, comment) ->
	io.stdout\write(call.signature.name)
	io.stdout\write("(")
	for i = 1, call.num_arguments
		io.stdout\write(call.signature\get_parameter_name(i))
		io.stdout\write(" = ")

		value = call\get_argument_by_index(i)
		local result
		switch value.type
			when 'nil' then result = "NULL"
			when 'blob' then result = "char[#{value\query!.length}]"
			when 'enumeration'
				result = value\query!.value_name
			when 'bitmask'
				result = string.format("0x%08x", value\query!.value)
			when 'array'
				result = string.format('object[%d]', #value\query!)
			when 'structure' then result = 'struct'
			else result = value\query!
		io.stdout\write(tostring(result))

		if i != call.num_arguments
			io.stdout\write(", ")

	io.stdout\write(");")
	if comment != nil
		io.stdout\write(" // #{comment}")
	io.stdout\write("\n")

trace = Trace(Args[1])
while not trace.is_end_of_file
	event = trace\next_event!
	if event.type == 'leave' and event.call.signature.name == Args[2]
		print_call(event.call, event.call_index)
		trace\delete_call(event.call_index)

error: pathspec 'utilities/lua/print_trace_functions.moon' did not match any file(s) known to git


Added a "clone" mixin

Added a "clone" mixin

moon = require "moon"

return class clone
	new: =>
	clone: =>
		c = @@!
		moon.mixin_table c, @
		c

error: pathspec 'LovePunk/utils/mixins/clone.moon' did not match any file(s) known to git


Added missing TextureAtlasFilter to example/tutorial.

-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this
-- file, You can obtain one at http://mozilla.org/MPL/2.0/.
--
-- Copyright 2016 [bk]door.maus

class Texture
	new: (name) =>
		@name = name
		@is_deleted = false
		@subs = {}
		@width = 1
		@height = 1

	_add_sub: (x, y, width, height, call, compressed) =>
		glurg.common.Log\info('low',
			"extracting texture (%d, %d; %d x %d; compressed = %s) from atlas %d at call %d...",
			x, y, width, height, tostring(compressed), @name, call.index)

		local texture
		do
			builder = glurg.resources.TextureBlobBuilder!
			do
				local extracted
				if compressed
					extracted = builder\extract_compressed_2d(call)
				else
					extracted = builder\extract_2d(call)

				if not extracted
					glurg.common.Log\warn('low', "couldn't extract texture")
					return false, nil

			blob = builder\build!
			if blob.is_data
				glurg.common.Log\warn('low', "couldn't extract texture; is data")
				return false, nil

			texture = glurg.resources.Texture(blob)

		glurg.common.Log\info('low', "successfully extracted texture")
		sub = { :x, :y, :width, :height, :texture }
		table.insert(@subs, sub)

		return true, sub

	get_sub: (x, y) =>
		for i = 1, #@subs
			sub = @subs[#@subs - i + 1]
			match_x = x >= sub.x and x < sub.x + sub.width
			match_y = y >= sub.y and y < sub.y + sub.height

			if match_x and match_y then
				return sub

		return nil

class TextureAtlasFilter extends glurg.filters.Filter
	new: (event) =>
		@_textures = {}
		@_texture_units = {}
		@active_texture_unit = 0
		@event = event or {}

	_get_texture: (name) =>
		if @_textures[name] == nil
			@_textures[name] = Texture(name)

		return @_textures[name]

	_set_texture_unit: (name) =>
		@_texture_units[@active_texture_unit] = name

	get_texture: (name) =>
		return @_textures[name]

	get_current_texture: (unit) =>
		return @\_get_texture(@_texture_units[unit])

	glActiveTexture: (trace, call) =>
		active_unit = call\get_argument_by_name("texture")\query!
		first_unit = active_unit.signature\get_value_by_name("GL_TEXTURE0")\query!

		@active_texture_unit = active_unit.value\query! - first_unit

		return false

	glBindTexture: (trace, call) =>
		target = call\get_argument_by_name("target")\query!
		if target.value_name == "GL_TEXTURE_2D"
			@\_set_texture_unit(call\get_argument_by_name("texture")\query!)

		return false

	_set_texture_size: (trace, call) =>
		target = call\get_argument_by_name("target")\query!
		level = call\get_argument_by_name("level")\query!
		if target.value_name == "GL_TEXTURE_2D" and level == 0
			texture = @get_current_texture(@active_texture_unit)
			texture.width = call\get_argument_by_name("width")\query!
			texture.height = call\get_argument_by_name("height")\query!
		return false

	glCompressedTexImage2D: (trace, call) =>
		return @\_set_texture_size(trace, call)

	glTexImage2D: (trace, call) =>
		return @\_set_texture_size(trace, call)

	glTexSubImage2D: (trace, call) =>
		x = call\get_argument_by_name("xoffset")\query!
		y = call\get_argument_by_name("yoffset")\query!
		width = call\get_argument_by_name("width")\query!
		height = call\get_argument_by_name("height")\query!

		success, sub = @\get_current_texture(@active_texture_unit)\_add_sub(
			x, y, width, height, call, false)
		if success and @event.on_subimage
			return @event\on_subimage(sub, call)

		return false

	glCompressedTexSubImage2D: (trace, call) =>
		x = call\get_argument_by_name("xoffset")\query!
		y = call\get_argument_by_name("yoffset")\query!
		width = call\get_argument_by_name("width")\query!
		height = call\get_argument_by_name("height")\query!

		success, sub = @\get_current_texture(@active_texture_unit)\_add_sub(
			x, y, width, height, call, true)
		if success and @event.on_compressed_subimage
			return @event\on_compressed_subimage(sub, call)

		return false

	glDeleteTextures: (trace, call) =>
		textures = call\get_argument_by_name("textures")\query!
		for i = 1, #textures
			if @_textures[textures[i]]
				@_textures[textures[i]].is_deleted = true
				@_textures[textures[i]] = nil

		return false

return TextureAtlasFilter

error: pathspec 'misc/tutorial/heuristics/TextureAtlasFilter.moon' did not match any file(s) known to git


thank-you: new module, don't mention it

thank-you: new module, don't mention it

Former-commit-id: a222138e3a738c7e2b32a641caac237d1fa5b4a9 [formerly 06e6653a2d38d8f4fce5dee904ed23aa1cbf6f30]
Former-commit-id: eabc6beb41fdd45f33e0f06f907114cb21fad14c

-- Ported from hubot which sites this source:
-- http://www.macmillandictionary.com/thesaurus-category/british/Ways-of-accepting-someone-s-thanks

response = {
  "you're welcome",
  "no problem",
  "not at all",
  "don’t mention it",
  "it’s no bother",
  "it’s my pleasure",
  "my pleasure",
  "it’s all right",
  "it’s nothing",
  "think nothing of it",
  "sure",
  "sure thing"
}

answer = (s, d, a) =>
  reply response[math.random(#response)]

PRIVMSG:
  "#{ivar2.config.nick}.-takk": answer
  "#{ivar2.config.nick}.-thank": answer
  "takk.-#{ivar2.config.nick}": answer
  "thanks.-#{ivar2.config.nick}": answer

error: pathspec 'modules/thank-you.moon' did not match any file(s) known to git


thank-you: new module, don't mention it

thank-you: new module, don't mention it


added Quarters

added Quarters

export ^

require "items"
require "rooms/abstract_producer"

class Quarters extends Producer
    color: {211, 107, 37}
    name: "quarters"
    required_resources: {
        [Energy]: 4
        [Material]: 6
        [Food]: 4
    }
    productionRate: 2 -- seconds (should be 30)
    producedResource: Minion

    new: (@shape, origin, @leftTurns)=>
        super(@shape, origin, @leftTurns)
        @productionCounter = 0

    -- TODO

    canProduce: =>

    produceResource: =>
        super()
        -- TODO: add new minion to spacebase crew

error: pathspec 'src/rooms/quarters.moon' did not match any file(s) known to git


Implement LunoPunk.geometry.Point

Implement LunoPunk.geometry.Point

export ^

-- Implementation of the AS3 Point. The API interface was used for function
-- names, but the code is original work.
class Point
	new: (x = 0, y = 0) =>
		-- Add the clone mixin
		clone = require "LunoPunk.utils.mixins.clone"
		clone @
		@x, @y = x, y

	-- The length of the line from (0, 0) to the point
	length: => math.sqrt @x^2 + @y^2

	-- Add two points together
	add: (p) => Point @x + p.x, @y + p.y

	__add: (p) => @add p

	-- Copies point data from p to this Point
	copyFrom: (p) => @x, @y = p.x, p.y

	-- The distance between two points
	distance: (p1, p2) -> math.sqrt (p1.x - p2.x)^2 + (p1.y - p2.y)^2

	-- determine if two points are equal
	equals: (p) => @x == p.x and @y == p.y

	-- determines a point between two points
	-- TODO
	-- interpolate: (p1, p2) =>

	-- scales the line between (0,0) and current point to a set length
	normalize: (length) =>
		l = @length!
		return if l == 0
		@x = length * @x / l
		@y = length * @y / l

	-- offsets the point by an amount
	offset: (dx, dy) =>
		@x += dx
		@y += dy

	-- Converts polar coordinates to a new point
	-- TODO
	-- polar: (length, angle) ->

	-- set the point to a new value
	set: (x, y) => @x, @y = x, y

	-- Subtracts p from this point to create a new Point
	subtract: (p) => Point @x - p.x, @y - p.y

	toString: => string.format "(%f, %f)", @x, @y

	__tostring: => @toString!

export ^

-- Implementation of the AS3 Point. The API interface was used for function
-- names, but the code is original work.
class Point
	new: (x = 0, y = 0) =>
		-- Add the clone mixin
		clone = require "LunoPunk.utils.mixins.clone"
		clone @
		@x, @y = x, y

	-- The length of the line from (0, 0) to the point
	length: => math.sqrt @x^2 + @y^2

	-- Add two points together
	add: (p) => Point @x + p.x, @y + p.y

	__add: (p) => @add p

	-- Copies point data from p to this Point
	copyFrom: (p) => @x, @y = p.x, p.y

	-- The distance between two points
	distance: (p1, p2) -> math.sqrt (p1.x - p2.x)^2 + (p1.y - p2.y)^2

	-- determine if two points are equal
	equals: (p) => @x == p.x and @y == p.y

	-- determines a point between two points
	-- TODO
	-- interpolate: (p1, p2) =>

	-- scales the line between (0,0) and current point to a set length
	-- TODO
	-- normalize: (thinkness) =>

	-- offsets the point by an amount
	offset: (dx, dy) =>
		@x += dx
		@y += dy

	-- Converts polar coordinates to a new point
	-- TODO
	-- polar: (length, angle) ->

	-- set the point to a new value
	set: (x, y) => @x, @y = x, y

	-- Subtracts p from this point to create a new Point
	subtract: (p) => Point @x - p.x, @y - p.y

	toString: => string.format "(%f, %f)", @x, @y

	__tostring: => @toString!


Sylfest: new module

Sylfest: new module

Former-commit-id: 12f541b9ca9acac337c54338a002a2ae2f0c7cec [formerly 4984f74107d90a6ef59aa94d24f6ee40c9e44919]
Former-commit-id: f0dd14fd96ebc69bd1ded2f3a9614d874c0dea39

trim = (s) ->
  string.match s, '^%s*(.*%S)' or ''

-- the words we want to match
word = "[%wæøåÆØÅ]+"

-- These are the endings we don't approve
badends = { "'en", "'ene", "'et", "'ing", "'ar", "'ane" }

-- No [$|%s] in lua patterns so we just construct two patterns
patternends = { '$', '%s' }

-- Linestart exceptions
lineexceptions = { '^"', "^'", "^-", "^ %-" }

-- Construct all the patterns we need to check
patterns = {}
for wend in *badends
  for pend in *patternends
    table.insert patterns, word .. wend .. pend

-- Check every word against our bad patterns.
checkWord = (source, destination, line) =>
  -- First check for exceptions
  for pattern in *lineexceptions
    if line\match pattern
      -- Line is excepted.
      return

  out = {}
  for pattern in *patterns
    for word in line\gmatch pattern
      table.insert out, trim(word)

  if #out > 0
    @Msg 'privmsg', destination, source, "Sylfest likar ikkje: %s", table.concat(out, ', ')

PRIVMSG:
  ".*": checkWord

error: pathspec 'modules/sylfest.moon' did not match any file(s) known to git


Placeholders.

Placeholders.

Class = require "class"

Class "Colony",
	__init: (arg) =>
		@name = arg.name or "Unknown colony"

		@resources = arg.resources or {}
		@population = arg.population or {}

		@structures = arg.structures or {}

error: pathspec 'game/colony.moon' did not match any file(s) known to git


excuse: new module

excuse: new module

Former-commit-id: e38d357bc2c4651e1068a826f88770f573780de3 [formerly 10d5aa2c66f7d37ab78b025a10466a6005635a95]
Former-commit-id: aa789c72913503f28c5ec2881861537b3af2939e

PRIVMSG:
  '^%pexcuse': (source, destination) =>
    ivar2.util.simplehttp 'http://www.programmerexcuses.com/', (html) ->
      cruft, match = html\match[[(.-)]]
      if match
        say match


randomtube: new module

randomtube: new module

{:simplehttp, :json, :bold} = require'util'
pgsql = require'cqueues_pgsql'

conn = false

connect = () ->
	conn = pgsql.connectdb("dbname=" .. tostring(ivar2.config.dbname) .. " user=" .. tostring(ivar2.config.dbuser) .. " password=" .. tostring(ivar2.config.dbpass) .. " host=" .. tostring(ivar2.config.dbhost) .. " port=" .. tostring(ivar2.config.dbport))
	if conn\status! ~= pgsql.CONNECTION_OK then
		ivar2:Log('error', "Unable to connect to DB: %s", conn:errorMessage())

dbh = ->
	connect! unless conn

	if conn\status! != pgsql.CONNECTION_OK
		log\error conn\errorMessage
		connect!

	success, err = conn\exec('SELECT NOW()')
	unless success
		log\error "SQL Connection :#{err}"
		connect!

	return conn

res2rows = (res) ->
	if not res\status! == 2 then error(res\errorMessage(), nil)
	rows = {}

	for i=1, res\ntuples()
		row = {}
		for j=1, res\nfields!
			row[res\fname(j)] = res\getvalue(i, j)
		rows[#rows+1] = row
	return rows

PRIVMSG:
	'^%prandomtube$': (source, destination) =>
		query = [[
			SELECT
				date_trunc('second', time) as time,
				date_trunc('second', age(now(), date_trunc('second', time))) as age,
				nick,
				url
			FROM urls
			WHERE
				channel = $1
			AND
				(url ILIKE '%youtube.com%' OR url ILIKE '%youtu.be%')
			ORDER BY RANDOM()
			LIMIT 1
		]]
		rows = res2rows(dbh!\execParams(query, destination))
		if #rows == 1
			url = rows[1].url
			nick = rows[1].nick
			age = rows[1].age
			say "%s by %s, %s ago", url, nick, age

error: pathspec 'modules/randomtube.moon' did not match any file(s) known to git


navnedag: module for norwegian name days

Former-commit-id: 1ad12fadd1570ae84a25f94541166c85873d3f4c [formerly b5b5f1a27a8929dee5fc403ec278e7b1311dbbb7]
Former-commit-id: c5d38441b1c2af53e2ca1c07b7a40f6e5745a720

os = require'os'
util = require'util'
data =
  "01.01":"Jesus"
  "02.01":"Dagfinn Dagfrid"
  "03.01":"Alfred Alf"
  "04.01":"Roar Roger"
  "05.01":"Hanna Hanne"
  "06.01":"Aslaug Åslaug"
  "07.01":"Eldbjørg Knut"
  "08.01":"Torfinn Turid"
  "09.01":"Gunnar Gunn"
  "10.01":"Sigmund Sigrun"
  "11.01":"Børge Børre"
  "12.01":"Reinhard Reinert"
  "13.01":"Gisle Gislaug"
  "14.01":"Herbjørn Herbjørg"
  "15.01":"Laurits Laura"
  "16.01":"Hjalmar Hilmar"
  "17.01":"Anton Tønnes Tony"
  "18.01":"Hildur Hild"
  "19.01":"Marius Margunn"
  "20.01":"Fabian Sebastian Bastian"
  "21.01":"Agnes Agnete"
  "22.01":"Ivan Vanja"
  "23.01":"Emil Emilie Emma"
  "24.01":"Joar Jarle Jarl"
  "25.01":"Paul Pål"
  "26.01":"Øystein Esten"
  "27.01":"Gaute Gurly Gry"
  "28.01":"Karl Karoline"
  "29.01":"Herdis Hermod Hermann"
  "30.01":"Gunnhild Gunda"
  "31.01":"Idun Ivar"
  "01.02":"Birte Bjarte"
  "02.02":"Jomar Jostein"
  "03.02":"Ansgar Asgeir"
  "04.02":"Veronika Vera"
  "05.02":"Agate Ågot"
  "06.02":"Dortea Dorte"
  "07.02":"Rikard Rigmor Riborg"
  "08.02":"Åshild Åsne"
  "09.02":"Lone Leikny"
  "10.02":"Ingfrid Ingrid"
  "11.02":"Ingve Yngve"
  "12.02":"Randulf Randi Ronja"
  "13.02":"Svanhild Svanlaug"
  "14.02":"Hjørdis Jardar"
  "15.02":"Sigfred Sigbjørn"
  "16.02":"Julian Juliane Jill"
  "17.02":"Aleksandra Sandra Sondre"
  "18.02":"Frøydis Frode"
  "19.02":"Ella Elna"
  "20.02":"Halldis Halldor"
  "21.02":"Samuel Selma Celine"
  "22.02":"Tina Tine Tim"
  "23.02":"Torstein Torunn"
  "24.02":"Mattias Mattis Mats"
  "25.02":"Viktor Viktoria"
  "26.02":"Inger Ingjerd"
  "27.02":"Laila Lill"
  "28.02":"Marina Maren"
  "01.03":"Audny Audun"
  "02.03":"Erna Ernst"
  "03.03":"Gunnbjørg Gunnveig"
  "04.03":"Ada Adrian"
  "05.03":"Patrick Patricia"
  "06.03":"Annfrid Andor"
  "07.03":"Arild Are"
  "08.03":"Beate Betty Bettina"
  "09.03":"Sverre Sindre"
  "10.03":"Edel Edle"
  "11.03":"Edvin Tale"
  "12.03":"Gregor Gro"
  "13.03":"Greta Grete"
  "14.03":"Mathilde Mette"
  "15.03":"Christel Christer Chris"
  "16.03":"Gudmund Gudny"
  "17.03":"Gjertrud Trude"
  "18.03":"Aleksander Sander Edvard"
  "19.03":"Josef Josefine"
  "20.03":"Joakim Kim"
  "21.03":"Bendik Bengt Bent"
  "22.03":"Paula Pauline"
  "23.03":"Gerda Gerd"
  "24.03":"Ulrikke Rikke"
  "25.03":"Maria Marie Mari"
  "26.03":"Gabriel Glenn"
  "27.03":"Rudolf Rudi"
  "28.03":"Åsta Åste"
  "29.03":"Jonas Jonatan"
  "30.03":"Holger Olga"
  "31.03":"Vebjørn Vegard"
  "01.04":"Aron Arve Arvid"
  "02.04":"Sigvard Sivert"
  "03.04":"Gunnvald Gunnvor"
  "04.04":"Nanna Nancy Nina"
  "05.04":"Irene Eirin Eril"
  "06.04":"Åsmund Asmund"
  "07.04":"Oddveig Oddvin"
  "08.04":"Asle Atle"
  "09.04":"Rannveig Rønnaug"
  "10.04":"Ingvald Ingveig"
  "11.04":"Ylva Ulf"
  "12.04":"Julius Julie"
  "13.04":"Asta Astrid"
  "14.04":"Ellinor Nora"
  "15.04":"Oda Odin Odd"
  "16.04":"Magnus Mons"
  "17.04":"Elise Else Elsa"
  "18.04":"Eilen Eilert"
  "19.04":"Arnfinn Arnstein"
  "20.04":"Kjellaug Kjellrun"
  "21.04":"Jeanette Jannike"
  "22.04":"Oddgeir Oddny"
  "23.04":"Georg Jørgen Jørg"
  "24.04":"Albert Olaug"
  "25.04":"Markus Mark"
  "26.04":"Terese Tea"
  "27.04":"Charles Charlotte Lotte"
  "28.04":"Vivi Vivian"
  "29.04":"Toralf Torolf"
  "30.04":"Gina Gitte"
  "01.05":"Filip Valborg"
  "02.05":"Åsa Åse"
  "03.05":"Gjermund Gøril"
  "04.05":"Monika Mona"
  "05.05":"Gudbrand Gullborg"
  "06.05":"Guri Gyri"
  "07.05":"Maia Mai Maiken"
  "08.05":"Åge Åke"
  "09.05":"Kasper Jesper"
  "10.05":"Asbjørg Asbjørn Espen"
  "11.05":"Magda Malvin"
  "12.05":"Normann Norvald"
  "13.05":"Linda Line Linn"
  "14.05":"Kristian Kristen Karsten"
  "15.05":"Hallvard Hallvor"
  "16.05":"Sara Siren"
  "17.05":"Harald Ragnhild"
  "18.05":"Eirik Erik Erika"
  "19.05":"Torjus Torje Truls"
  "20.05":"Bjørnar Bjørnhild"
  "21.05":"Helene Ellen Eli"
  "22.05":"Henning Henny"
  "23.05":"Oddleif Oddlaug"
  "24.05":"Ester Iris"
  "25.05":"Ragna Ragnar"
  "26.05":"Annbjørg Annlaug"
  "27.05":"Katinka Cato"
  "28.05":"Vilhelm William Willy"
  "29.05":"Magnar Magnhild"
  "30.05":"Gard Geir"
  "31.05":"Pernille Preben"
  "01.06":"June Juni"
  "02.06":"Runa Runar Rune"
  "03.06":"Rasmus Rakel"
  "04.06":"Heidi Heid"
  "05.06":"Torbjørg Torbjørn Torben"
  "06.06":"Gustav Gyda"
  "07.06":"Robert Robin"
  "08.06":"Renate René"
  "09.06":"Kolbein Kolbjørn"
  "10.06":"Ingolf Ingunn"
  "11.06":"Borgar Bjørge Bjørg"
  "12.06":"Sigfrid Sigrid Siri"
  "13.06":"Tone Tonje Tanja"
  "14.06":"Erlend Erland"
  "15.06":"Vigdis Viggo"
  "16.06":"Torhild Toril Tiril"
  "17.06":"Botolf Bodil"
  "18.06":"Bjarne Bjørn"
  "19.06":"Erling Elling"
  "20.06":"Salve Sølve Sølvi"
  "21.06":"Agnar Annar"
  "22.06":"Håkon Maud"
  "23.06":"Elfrid Eldrid"
  "24.06":"Johannes Jon Hans"
  "25.06":"Jørund Jorunn"
  "26.06":"Jenny Jonny"
  "27.06":"Aina Ina Ine"
  "28.06":"Lea Leo Leon"
  "29.06":"Peter Petter Per"
  "30.06":"Solbjørg Solgunn"
  "01.07":"Ask Embla"
  "02.07":"Kjartan Kjellfrid"
  "03.07":"Andrea Andrine André"
  "04.07":"Ulrik Ulla"
  "05.07":"Mirjam Mina"
  "06.07":"Torgrim Torgunn"
  "07.07":"Håvard Hulda"
  "08.07":"Sunniva Synnøve Synne"
  "09.07":"Gøran Jøran Ørjan"
  "10.07":"Anita Anja"
  "11.07":"Kjetil Kjell"
  "12.07":"Elias Eldar"
  "13.07":"Mildrid Melissa Mia"
  "14.07":"Solfrid Solrun"
  "15.07":"Oddmund Oddrun"
  "16.07":"Susanne Sanna"
  "17.07":"Guttorm Gorm"
  "18.07":"Arnulf Ørnulf"
  "19.07":"Gerhard Gjert"
  "20.07":"Margareta Margit Marit"
  "21.07":"Johanne Janne Jane"
  "22.07":"Malene Malin Mali"
  "23.07":"Brita Brit Britt"
  "24.07":"Kristine Kristin Kristi"
  "25.07":"Jakob Jack Jim"
  "26.07":"Anna Anne Ane"
  "27.07":"Marita Rita"
  "28.07":"Reidar Reidun"
  "29.07":"Olav Ola Ole"
  "30.07":"Aurora Audhild Aud"
  "31.07":"Elin Eline"
  "01.08":"Peder Petra"
  "02.08":"Karen Karin"
  "03.08":"Oline Oliver Olve"
  "04.08":"Arnhild Arna Arnt"
  "05.08":"Osvald Oskar"
  "06.08":"Gunnlaug Gunnleiv"
  "07.08":"Didrik Doris"
  "08.08":"Evy Yvonne"
  "09.08":"Ronald Ronny"
  "10.08":"Lorents Lars Lasse"
  "11.08":"Torvald Tarald"
  "12.08":"Klara Camilla"
  "13.08":"Anny Anine Ann"
  "14.08":"Hallgeir Hallgjerd"
  "15.08":"Margot Mary Marielle"
  "16.08":"Brynjulf Brynhild"
  "17.08":"Verner Wenche"
  "18.08":"Tormod Torodd"
  "19.08":"Sigvald Sigve"
  "20.08":"Bernhard Bernt"
  "21.08":"Ragnvald Ragni"
  "22.08":"Harriet Harry"
  "23.08":"Signe Signy"
  "24.08":"Belinda Bertil"
  "25.08":"Ludvig Lovise Louise"
  "26.08":"Øyvind Eivind Even"
  "27.08":"Roald Rolf"
  "28.08":"Artur August"
  "29.08":"Johan Jone Jo"
  "30.08":"Benjamin Ben"
  "31.08":"Berta Berte"
  "01.09":"Solveig Solvår"
  "02.09":"Lisa Lise Liss"
  "03.09":"Alise Alvhild Vilde"
  "04.09":"Ida Idar"
  "05.09":"Brede Brian Njål"
  "06.09":"Sollaug Siril Siv"
  "07.09":"Regine Rose"
  "08.09":"Amalie Alma Allan"
  "09.09":"Trygve Tyra Trym"
  "10.09":"Tord Tor"
  "11.09":"Dagny Dag"
  "12.09":"Jofrid Jorid"
  "13.09":"Stian Stig"
  "14.09":"Ingebjørg Ingeborg"
  "15.09":"Aslak Eskil"
  "16.09":"Lillian Lilly"
  "17.09":"Hildebjørg Hildegunn"
  "18.09":"Henriette Henry"
  "19.09":"Konstanse Connie"
  "20.09":"Tobias Tage"
  "21.09":"Trine Trond"
  "22.09":"Kyrre Kåre"
  "23.09":"Snorre Snefrid"
  "24.09":"Jan Jens"
  "25.09":"Ingvar Yngvar"
  "26.09":"Einar Endre"
  "27.09":"Dagmar Dagrun"
  "28.09":"Lena Lene"
  "29.09":"Mikael Mikal Mikkel"
  "30.09":"Helga Helge Hege"
  "01.10":"Rebekka Remi"
  "02.10":"Live Liv"
  "03.10":"Evald Evelyn"
  "04.10":"Frans Frank"
  "05.10":"Brynjar Boye Bo"
  "06.10":"Målfrid Møyfrid"
  "07.10":"Birgitte Birgit Berit"
  "08.10":"Benedikte Bente"
  "09.10":"Leidulf Leif"
  "10.10":"Fridtjof Frida Frits"
  "11.10":"Kevin Kennet Kent"
  "12.10":"Valter Vibeke"
  "13.10":"Torgeir Terje Tarjei"
  "14.10":"Kaia Kai"
  "15.10":"Hedvig Hedda"
  "16.10":"Flemming Finn"
  "17.10":"Marta Marte"
  "18.10":"Kjersti Kjerstin"
  "19.10":"Tora Tore"
  "20.10":"Henrik Heine Henrikke"
  "21.10":"Bergljot Birger"
  "22.10":"Karianne Karine Kine"
  "23.10":"Severin Søren"
  "24.10":"Eilif Eivor"
  "25.10":"Margrete Merete Märtha"
  "26.10":"Amandus Amanda"
  "27.10":"Sturla Sture"
  "28.10":"Simon Simen"
  "29.10":"Noralf Norunn"
  "30.10":"Aksel Åmund Ove"
  "31.10":"Edit Edna"
  "01.11":"Veslemøy Vetle"
  "02.11":"Tove Tuva"
  "03.11":"Raymond Roy"
  "04.11":"Otto Ottar"
  "05.11":"Egil Egon"
  "06.11":"Leonard Lennart"
  "07.11":"Ingebrigt Ingelin"
  "08.11":"Ingvild Yngvild"
  "09.11":"Tordis Teodor"
  "10.11":"Gudbjørg Gudveig"
  "11.11":"Martin Morten Martine"
  "12.11":"Torkjell Torkil"
  "13.11":"Kirsten Kirsti"
  "14.11":"Fredrik Fred Freddy"
  "15.11":"Oddfrid Oddvar"
  "16.11":"Edmund Edgar"
  "17.11":"Hugo Hogne Hauk"
  "18.11":"Magne Magny"
  "19.11":"Elisabet Lisbet"
  "20.11":"Halvdan Helle"
  "21.11":"Mariann Marianne"
  "22.11":"Cecilie Silje Sissel"
  "23.11":"Klement Klaus"
  "24.11":"Gudrun Guro"
  "25.11":"Katarina Katrine Kari"
  "26.11":"Konrad Kurt"
  "27.11":"Torlaug Torleif"
  "28.11":"Ruben Rut"
  "29.11":"Sofie Sonja"
  "30.11":"Andreas Anders"
  "01.12":"Arnold Arnljot Arnt"
  "02.12":"Borghild Borgny Bård"
  "03.12":"Sveinung Svein"
  "04.12":"Barbara Barbro"
  "05.12":"Stine Ståle"
  "06.12":"Nils Nikolai"
  "07.12":"Hallfrid Hallstein"
  "08.12":"Marlene Marion Morgan"
  "09.12":"Anniken Annette"
  "10.12":"Judit og Jytte"
  "11.12":"Daniel Dan"
  "12.12":"Pia Peggy"
  "13.12":"Lucia Lydia"
  "14.12":"Steinar Stein"
  "15.12":"Hilda Hilde"
  "16.12":"Oddbjørg Oddbjørn"
  "17.12":"Inga Inge"
  "18.12":"Kristoffer Kate"
  "19.12":"Iselin Isak"
  "20.12":"Abraham Amund"
  "21.12":"Tomas Tom Tommy"
  "22.12":"Ingemar Ingar"
  "23.12":"Sigurd Sjur"
  "24.12":"Adam Eva"
  "25.12":"Ingen navnedag"
  "26.12":"Stefan Steffen"
  "27.12":"Narve Natalie"
  "28.12":"Unni Une Unn"
  "29.12":"Vidar Vemund"
  "30.12":"David Diana Dina"
  "31.12":"Sylfest Sylvia Sylvi"

PRIVMSG:
  "^%pnavnedag$": (source, destination) =>
    now = os.date'%d.%m'
    names = table.concat(util.split(data[now], ' '), ', ')
    say names
  "^%pnavnedag (%d+).(%d+)$": (source, destination, day, month) =>
    day = string.format('%02d', day)
    month = string.format('%02d', month)
    now = day .. '.' .. month
    names = table.concat(util.split(data[now], ' '), ', ')
    say names

error: pathspec 'modules/navnedag.moon' did not match any file(s) known to git


googleapi: new module

googleapi: new module

Former-commit-id: 40c01614e5d7d3f8a4b3b3d654220ffc007e8b8b [formerly 8949777748152afda26972d08cecef378b0d03ad]
Former-commit-id: 6723ebb9c8f1e47eff7321221cccce1da1e74187

-- ported from luabot's google module. Thanks!
html2unicode = require'html'

PRIVMSG:
  '^%pg (.+)': (source, destination, query) =>
    data, err = ivar2.util.simplehttp 'http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q='..ivar2.util.urlEncode(query), (data) ->

      if query == 'google'
        return reply "wow. That's really clever."

      unless data
        return reply "no response"

      if data\sub(1, 1) ~= '{' then
        return false, 'invalid reply?'

      resp = ivar2.util.json.decode(data)
      unless resp.responseData
        return reply 'no response data'

      res = resp.responseData.results
      if res[1]
        say(html2unicode(res[1].titleNoFormatting)..': '..res[1].unescapedUrl)
      else
        return reply 'no results'

error: pathspec 'modules/googleapi.moon' did not match any file(s) known to git


aunesand: new module

aunesand: new module

Former-commit-id: 6fc256338f69324c6afaa57301973355e9097697 [formerly 4e80b58a167b42669f0be5262db1a577439bb556]
Former-commit-id: 5d2ce5be31a37bd096e1ac8b853739e861fcd626

html2unicode = require'html'

hex_to_char = (x) ->
  string.char(tonumber(x, 16))

unescape = (url) ->
  url\gsub("%%(%x%x)", hex_to_char)

PRIVMSG:
  '^%paunesand': (source, destination) =>
    rnd = math.random(1,3000)
    ivar2.util.simplehttp 'http://p3.no/uv/aune-sands-poesigenerator/?cachebuster='..rnd, (html) ->
      match = html\match[[<a title="Del diktet på Facebook" href="(.*)"]]
      if match
        poem = match\match[[facebookdescription=(.-)-]]
        poem = poem\gsub '+', ' '
        poem = unescape(poem)
        if poem
          say html2unicode(poem)

error: pathspec 'modules/aunesand.moon' did not match any file(s) known to git


complete: new module

complete: new module

-- ported from luabot's complete module by anders. Thanks!
html2unicode = require'html'

PRIVMSG:
  '^%pcomplete (.+)$': (s, d, query) =>
    URL = "http://www.google.com/complete/search?client=serp&hl=en&xhr=t&q="..ivar2.util.urlEncode(query)
    ivar2.util.simplehttp URL, (response) ->
      d = json.decode(response)
      out = {}

      for k, v in ipairs(d[2]) do
        completion = v[1]\gsub("<.->", "")
        out[#out + 1] = html2unicode(completion).."?"

      if #out > 0
        say(table.concat(out, " "))

error: pathspec 'modules/complete.moon' did not match any file(s) known to git


translate: new module, (ab)use google translate

Former-commit-id: 8eb089498db53745fd7114ef722ea855a18c0dae [formerly 5f79b3b41e7aae52e391885bdfcf724d8d03adb2]
Former-commit-id: 820748c513a6f4b082a79f316babe159ceedd3e5

-- google translate
json = require'json'
simplehttp = require'simplehttp'

languages =
  "af": "Afrikaans",
  "sq": "Albanian",
  "ar": "Arabic",
  "az": "Azerbaijani",
  "eu": "Basque",
  "bn": "Bengali",
  "be": "Belarusian",
  "bg": "Bulgarian",
  "ca": "Catalan",
  "zh-CN": "Simplified Chinese",
  "zh-TW": "Traditional Chinese",
  "hr": "Croatian",
  "cs": "Czech",
  "da": "Danish",
  "nl": "Dutch",
  "en": "English",
  "eo": "Esperanto",
  "et": "Estonian",
  "tl": "Filipino",
  "fi": "Finnish",
  "fr": "French",
  "gl": "Galician",
  "ka": "Georgian",
  "de": "German",
  "el": "Greek",
  "gu": "Gujarati",
  "ht": "Haitian Creole",
  "iw": "Hebrew",
  "hi": "Hindi",
  "hu": "Hungarian",
  "is": "Icelandic",
  "id": "Indonesian",
  "ga": "Irish",
  "it": "Italian",
  "ja": "Japanese",
  "kn": "Kannada",
  "ko": "Korean",
  "la": "Latin",
  "lv": "Latvian",
  "lt": "Lithuanian",
  "mk": "Macedonian",
  "ms": "Malay",
  "mt": "Maltese",
  "no": "Norwegian",
  "fa": "Persian",
  "pl": "Polish",
  "pt": "Portuguese",
  "ro": "Romanian",
  "ru": "Russian",
  "sr": "Serbian",
  "sk": "Slovak",
  "sl": "Slovenian",
  "es": "Spanish",
  "sw": "Swahili",
  "sv": "Swedish",
  "ta": "Tamil",
  "te": "Telugu",
  "th": "Thai",
  "tr": "Turkish",
  "uk": "Ukrainian",
  "ur": "Urdu",
  "vi": "Vietnamese",
  "cy": "Welsh",
  "yi": "Yiddish"

getCode = (language) ->
  for code, lang in pairs languages
    if lang\lower! == language\lower!
      return code
    else if language\lower! == code\lower!
      return code

urlEncode = (str, space) ->
  space = space or '+'
  str = tostring(str)

  str = str\gsub '([^%w ])', (c) ->
    string.format  "%%%02X", string.byte(c)
  return str\gsub(' ', space)

buildQueryStr = (tbl) ->
  out = {}
  for k,v in pairs tbl
    table.insert out, k..'='..urlEncode(v)
  table.concat out, '&'

translate = (source, destination, origin, target, term) =>
  origin = getCode(origin) or 'auto'
  target = getCode(target) or 'en'
  args =
    client: 'p'
    hl: 'en'
    multires: 1
    sc: 1
    sl: origin
    ssel: 0
    tl: target
    tsel: 0
    uptl: "en"
    text: term

  simplehttp "https://translate.google.com/translate_a/t?" .. buildQueryStr(args), (data) ->
    if #data > 4
      parsed = json.decode data
      language = parsed.src
      out = table.concat [k.trans for k in *parsed.sentences]
      if #out > 0
        @Msg 'privmsg', destination, source, "\002#{languages[target]}\002: #{out}"

PRIVMSG:
  '^%ptranslate ([%w%-]+) ([%w%-]+) (.*)$': translate

error: pathspec 'modules/translate.moon' did not match any file(s) known to git