emoji: new module to print emojis

emoji: new module to print emojis

Former-commit-id: b8ca9ef8722366f20b10a53f826dcd1ba5c0e9ab [formerly b3a8a48e78a770980bb2baeb066e528fc148ed63]
Former-commit-id: 8526996789a41a1903905024091723f1eecd700c

emojis =
  emoticons:'😀😁😂😃😄😅😆😇😈😉😊😋😌😍😎😏
    😐😑😒😓😔😕😖😗😘😙😚😛😜😝😞😟
    😠😡😢😣😤😥😦😧😨😩😪😫😬😭😮😯
    😰😱😲😳😴😵😶😷😸😹😺😻😼😽😾😿
    🙀🙅🙆🙇🙈🙉🙊🙋🙌🙍🙎🙏',
  transport:'🚀🚁🚂🚃🚄🚅🚆🚇🚈🚉🚊🚋🚌🚍🚎🚏
    🚐🚑🚒🚓🚔🚕🚖🚗🚘🚙🚚🚛🚜🚝🚞🚟
    🚠🚡🚢🚣🚤🚥🚦🚧🚨🚩🚪🚫🚬🚭🚮🚯
    🚰🚱🚲🚳🚴🚵🚶🚷🚸🚹🚺🚻🚼🚽🚾🚿
    🛀🛁🛂🛃🛄🛅',
  symbol:'☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏
    ☐☑☒☓☔☕☖☗☘☙☚☛☜☝☞☟
    ☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯
    ☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿
    ♀♁♂♃♄♅♆♇♈♉♊♋♌♍♎♏
    ♐♑♒♓♔♕♖♗♘♙♚♛♜♝♞♟
    ♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯
    ♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿
    ⚀⚁⚂⚃⚄⚅⚆⚇⚈⚉⚊⚋⚌⚍⚎⚏
    ⚐⚑⚒⚓⚔⚕⚖⚗⚘⚙⚚⚛⚜⚝⚞⚟
    ⚠⚡⚢⚣⚤⚥⚦⚧⚨⚩⚪⚫⚬⚭⚮⚯
    ⚰⚱⚲⚳⚴⚵⚶⚷⚸⚹⚺⚻⚼⚽⚾⚿
    ⛀⛁⛂⛃⛄⛅⛆⛇⛈⛉⛊⛋⛌⛍⛎⛏
    ⛐⛑⛒⛓⛔⛕⛖⛗⛘⛙⛚⛛⛜⛝⛞⛟
    ⛠⛡⛢⛣⛤⛥⛦⛧⛨⛩⛪⛫⛬⛭⛮⛯
    ⛰⛱⛲⛳⛴⛵⛶⛷⛸⛹⛺⛻⛼⛽⛾⛿',
  misc:'🌀🌁🌂🌃🌄🌅🌆🌇🌈🌉🌊🌋🌌🌍🌎🌏
    🌐🌑🌒🌓🌔🌕🌖🌗🌘🌙🌚🌛🌜🌝🌞🌟
    🌠
    🌰🌱🌲🌳🌴🌵🌷🌸🌹🌺🌻🌼🌽🌾🌿
    🍀🍁🍂🍃🍄🍅🍆🍇🍈🍉🍊🍋🍌🍍🍎🍏
    🍐🍑🍒🍓🍔🍕🍖🍗🍘🍙🍚🍛🍜🍝🍞🍟
    🍠🍡🍢🍣🍤🍥🍦🍧🍨🍩🍪🍫🍬🍭🍮🍯
    🍰🍱🍲🍳🍴🍵🍶🍷🍸🍹🍺🍻🍼
    🎀🎁🎂🎃🎄🎅🎆🎇🎈🎉🎊🎋🎌🎍🎎🎏
    🎐🎑🎒🎓
    🎠🎡🎢🎣🎤🎥🎦🎧🎨🎩🎪🎫🎬🎭🎮🎯
    🎰🎱🎲🎳🎴🎵🎶🎷🎸🎹🎺🎻🎼🎽🎾🎿
    🏀🏁🏂🏃🏄🏆🏇🏈🏉🏊

    🏠🏡🏢🏣🏤🏥🏦🏧🏨🏩🏪🏫🏬🏭🏮🏯
    🏰
    🐀🐁🐂🐃🐄🐅🐆🐇🐈🐉🐊🐋🐌🐍🐎🐏
    🐐🐑🐒🐓🐔🐕🐖🐗🐘🐙🐚🐛🐜🐝🐞🐟
    🐠🐡🐢🐣🐤🐥🐦🐧🐨🐩🐪🐫🐬🐭🐮🐯
    🐰🐱🐲🐳🐴🐵🐶🐷🐸🐹🐺🐻🐼🐽🐾
    👀👂👃👄👅👆👇👈👉👊👋👌👍👎👏
    👐👑👒👓👔👕👖👗👘👙👚👛👜👝👞👟
    👠👡👢👣👤👥👦👧👨👩👪👫👬👭👮👯
    👰👱👲👳👴👵👶👷👸👹👺👻👼👽👾👿
    💀💁💂💃💄💅💆💇💈💉💊💋💌💍💎💏
    💐💑💒💓💔💕💖💗💘💙💚💛💜💝💞💟
    💠💡💢💣💤💥💦💧💨💩💪💫💬💭💮💯
    💰💱💲💳💴💵💶💷💸💹💺💻💼💽💾💿
    📀📁📂📃📄📅📆📇📈📉📊📋📌📍📎📏
    📐📑📒📓📔📕📖📗📘📙📚📛📜📝📞📟
    📠📡📢📣📤📥📦📧📨📩📪📫📬📭📮📯
    📰📱📲📳📴📵📶📷📹📺📻📼
    🔀🔁🔂🔃🔄🔅🔆🔇🔈🔉🔊🔋🔌🔍🔎🔏
    🔐🔑🔒🔓🔔🔕🔖🔗🔘🔙🔚🔛🔜🔝🔞🔟
    🔠🔡🔢🔣🔤🔥🔦🔧🔨🔩🔪🔫🔬🔭🔮🔯
    🔰🔱🔲🔳🔴🔵🔶🔷🔸🔹🔺🔻🔼🔽
    🕀🕁🕂🕃
    🕐🕑🕒🕓🕔🕕🕖🕗🕘🕙🕚🕛🕜🕝🕞🕟
    🕠🕡🕢🕣🕤🕥🕦🕧
    🗻🗼🗽🗾🗿'

for cat, str in pairs emojis
  str, n = str\gsub('%s', '')
  emojis[cat] = str

PRIVMSG:
  '^%pemoji all$': (source, dest, arg) =>
    out = {}
    for cat, str in pairs emojis
      table.insert out, str
    @Msg 'privmsg', dest, source, table.concat out
  '^%pemoji$': (source, dest, arg) =>
    out = {}
    for cat, str in pairs emojis
      table.insert out, cat
    @Msg 'privmsg', dest, source, table.concat(out, ', ')
  '^%pemoji (.+)$': (source, dest, cat) =>
    @Msg 'privmsg', dest, source, emojis[cat]

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


thanks: new module

thanks: new module

Former-commit-id: 6208e9300353072565bb74cec3ade54e9f640a1a [formerly 69b6f4412c999e1d19fa7b773fad58fb14d900a6]
Former-commit-id: 824a4ffb611dda8c1e4426ec9d967a1d8ba0da8e

PRIVMSG:
  '^%pthanks (.+)$': (s,d,a) =>
    @Msg 'privmsg', d, s, "#{a}: This community thanks you for this well thought out and high quality comment. You have clearly shown us some knowledgeable information for which we are truly grateful. In all seriousness, comments such as this degrade the community and add no value. Please reconsider next time."

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


Tests for Map added.

Tests for Map added.

describe "Map", ->
	Map = require "nyaa.map"

	GroundType = require "game.groundType_reference"
	Structure = require "game.structure"
	StructureReference = require "game.structure_reference"

	TEST_GROUND = GroundType
		name: "Test Ground Type"

	TEST_STRUCTURE = Structure
		reference: StructureReference {}

	it "Map {}", ->
		assert Map {}

	it "\\get", ->
		m = Map {}

		assert m\get 1, 1, 1

	it "\\set", ->
		m = Map {}

		m\set 1, 1, 1,
			groundType: TEST_GROUND

		assert.are.same TEST_GROUND, m\get(1, 1, 1).groundType

		m\set 1, 2, 1,
			structure: TEST_STRUCTURE

		assert.are.same TEST_STRUCTURE, m\get(1, 1, 1).structure

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


benis: new module stolen.

benis: new module stolen.

Former-commit-id: 50ddd66bc4701b7e4f7cf139d9a5e4561ea227d2 [formerly 9386ea512de44dd07e3e038b3dbd2cbc2d6891bc]
Former-commit-id: 5e26eb7df0932019443760a506ba974a69c58a14

-- code from q66's module from luabot ported from rfs benis module
reduce = (fun, list, def) ->
  for k, v in ipairs(list)
    def = fun(def, v)
  return def

rand = math.random
tconc = table.concat

benisify = (s) ->
  reduce (acc, f) ->
    f(acc),
    {
      (s) -> s\lower()
      (s) -> s\gsub('x', 'cks')
      (s) -> s\gsub('ing', 'in')
      (s) -> s\gsub('you', 'u')
      (s) -> s\gsub 'oo', ->
        ('u')\rep(rand(1, 5))
      (s) ->
        s\gsub '[%w_]%z', (x) ->
          x\sub(1, 1)\rep(rand(1, 2))
      (s) ->
        s\gsub 'ck', ->
          'g'\rep(rand(1, 5))
      (s) ->
        s\gsub '(t+)%f[aeiouys ]', (x) ->
          ('d')\rep(#x)
      (s) ->
        s\gsub '(t+)$', (x) ->
          ('d')\rep(#x)
      (s) -> s\gsub('p', 'b'),
      (s) -> s\gsub('%f[%w_]the%f[^%w_]', 'da'),
      (s) -> s\gsub('%f[%w_]c', 'g'),
      (s) -> s\gsub('%f[%w_]is%f[^%w_]', 'are'),
      (s) -> s\gsub '(c+)(.)', (x, y) ->
        (y == 'e' or y == 'i' or y == 'y') and (x .. y) or ('g')\rep(rand(1, 5)) ..  (y == 'c' and 'g' or y)
      (s) ->
        s\gsub '([qk]+)%f[aeiouy ]', ->
          ('g')\rep(rand(1, 5))
      (s) ->
        s\gsub '([qk]+)$', ->
          ('g')\rep(rand(1, 5))
      (s) ->
          endswith = s\find '[?!.]$'
          repf = (x) ->
              ret = x\rep(rand(2, 5)) .. ' '
              for i = 1, rand(2, 5)
                  ret = ret .. (':')\rep(rand(1, 2)) .. ('D')\rep(rand(1, 4))
              return ret
          unless endswith then return s\gsub('$', repf)
          s\gsub('[?!.]+', repf)
    }, s

PRIVMSG:
  '^%pbenis (.*)$':(source, destination, arg) =>
    say(benisify(arg))

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


logger: log incoming messages to postgresql

Former-commit-id: da70322b67135bf21cda8eae6d096a203de6d7f7 [formerly 8c976347fa83ee67f31f214803ca1d17366ecc0a]
Former-commit-id: 1d1effb59a910a6c12a3697002b7a9994e396823

dbi = require 'DBI'
require'logging.console'
log = logging.console()

conn = false

schemas = {[[
  CREATE TABLE IF NOT EXISTS log (
    time timestamp DEFAULT now(),
    nick text,
    channel text,
    message text,
    type text
  );]],
  [[CREATE INDEX idx_time ON log(time);]],
  [[CREATE INDEX idx_channel ON log(channel);]]
}

connect = ->
  conn, err = DBI.Connect('PostgreSQL', ivar2.config.dbname, ivar2.config.dbuser, ivar2.config.dbpass, ivar2.config.dbhost, ivar2.config.dbport)
  unless conn
    log\error "Unable to connect to DB: #{err}"
    return

  conn\autocommit(true)

  --for s in *schemas
  --  a,b = DBI.Do(conn, s)

dbh = ->
  connect! unless conn

  -- Check if connection is alive
  alive = conn\ping!
  connect! unless alive

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

  return conn

dblog = (type, source, destination, arg) =>
  nick = source.nick

  if type == 'PRIVMSG'
    -- action
    if arg\sub(1,1) == '\001' and arg\sub(-1) == '\001'
      arg = arg\sub(9, -2)
    type = 'ACTION'

  unless arg
    arg = ''

  insert = dbh!\prepare('INSERT INTO log(nick,channel,message,type) values(?,?,?,?)')
  stmt, err = insert\execute(nick, destination, arg, type)
  unless stmt
    log\error err

return {
  PRIVMSG: {
    (s, d, a) =>
      dblog @, 'PRIVMSG', s, d, a
  }
  NOTICE: {
    (s, d, a) =>
      dblog @, 'NOTICE', s, d, a
  }
  JOIN: {
    (s, d, a) =>
      dblog @, 'JOIN', s, d, a
  }
  PART: {
    (s, d, a) =>
      dblog @, 'PART', s, d, a
  }
  KICK: {
    (s, d, a) =>
      dblog @, 'KICK', s, d, a
  }
  MODE: {
    (s, d, a) =>
      dblog @, 'MODE', s, d, a
  }
  TOPIC: {
    (s, d, a) =>
      dblog @, 'TOPIC', s, d, a
  }
  NICK: {
    (s, d, a) =>
      dblog @, 'NICK', s, d, a
  }
  QUIT: {
    (s, d, a) =>
      dblog @, 'QUIT', s, d, a
  }
}

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


gay: new module

gay: new module

FABULOUS_COLORS = {4, 7, 9, 10, 12, 13, 6}

i = 0

gayify = (s) ->
  if s == "" return ""
  s\gsub "[%z\1-\127\194-\244][\128-\191]*", (c) ->
    ret = string.format("\03%02d%s", FABULOUS_COLORS[i + 1], c)
    i = (i + 1) % #FABULOUS_COLORS
    return ret

PRIVMSG:
  '^%pgay (.+)$': (source, destination, arg) =>
      @Msg 'privmsg', destination, source, gayify arg

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


Added MoonScript utility to save images from 2D texture targets.

-- 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

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

Args = { ... }
if #Args < 2
	io.stderr\write("save_images_2d.moon <file.trace> <output-directory>\n")

	return 1

hashes = {}
save_image_from_call = (call) ->
	builder = TextureBlobBuilder!
	if not builder\extract_2d(call) then
		io.stdout\write("couldn't extract texture.\n")
		return false

	blob = builder\build!
	if blob.is_data then
		io.stdout\write("texture is data, not pixels.\n")
		return false

	if hashes[blob.hash] then
		io.stdout\write("texture already saved from previous call\n")
		return false

	texture = Texture(blob)
	texture\save_png(string.format("%s/%9d.png", Args[2], call.index))

	io.stdout\write("extracted texture.\n")
	hashes[blob.hash] = true

	return true

Funcs =
	"glTexImage2D": true
	"glTexSubImage2D": true

trace = Trace(Args[1])
while not trace.is_end_of_file
	event = trace\next_event!
	if event.type == 'leave' and Funcs[event.call.signature.name]
		io.stdout\write("extracting texture from call #{event.call.index}...\n")
		save_image_from_call(event.call)
		trace\delete_call(event.call_index)

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


cubesensors: new module

cubesensors: new module

round = (x) ->
  x + 0.5 - (x + 0.5) % 1

PRIVMSG:
  '^%pinnev.+r$': (source, destination, input) =>
    ivar2.util.simplehttp ivar2.config.cubeapiurl, (data) ->
      result = json.decode data
      if result
        r = result[1]
        temp = r.rtemp
        noise = tonumber(r.noisedba) or 0
        say '\002%.1f\002 °C, \002%s\002 luftkvalitet, \002%s\002 fukt, \002%s\002 lys, \002%s\002 dBA støynivå', temp, round(r.voc), round(r.humidity), round(r.light), noise

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


gay: new module

gay: new module

Former-commit-id: 717861461a2982591878c5aed0dfa2f0430d446c [formerly ba543309d76ce64ec1d87907dded190ea0834289]
Former-commit-id: fffad96e149b83417ed69ff7e412585a585257c4


list: new module, list commands and patterns in commands

listModules = (source, destination, arg) =>
  out = {}
  for moduleName, moduleTable in next, @Events!['PRIVMSG']
    unless @IsModuleDisabled moduleName, destination
      table.insert out, moduleName
  if #out > 0
    @Msg 'privmsg', destination, source, "Modules: %s", table.concat(out, ', ')

listPatterns = (source, destination, moduleName) =>
  moduleTable = @Events!['PRIVMSG'][moduleName]
  unless moduleTable
    return

  if @IsModuleDisabled moduleName, destination
    return

  out = {}
  for pattern, callback in next, moduleTable
    table.insert out, pattern

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

PRIVMSG:
  '%plist$': listModules
  '%plist (%w+)$': listPatterns

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


Add SMTP mock module

Add SMTP mock module

Does not do much really, just logs email send requests and enables an
error to be orchestrated to test the response of that part of the
system.

import insert from table

class SmtpMock
    calls: { }

    message: (msg) ->
        message: msg
        smtp_mock_message: true

    send: (tbl) ->
        insert SmtpMock.calls, tbl
        if SmtpMock.err
            nil, 'smtpmock: Required orchestrated error on email sending'
        else
            true

error: pathspec 'spec/smtp-mock.moon' did not match any file(s) known to git


cubesensors: new module

cubesensors: new module

Former-commit-id: f609189c53fbed9a1c4abda13a2d53252909aa2f [formerly e88ccd27e2f9023ca2b22c2699cde7ff07d05724]
Former-commit-id: d7cc3abb79aeb75b2f7e7b682f0c0f7f2763789d


Added tests for `merge_object` function

Added tests for `merge_object` function

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/SuperPaintman/umka.git/'


debug

debug

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/nonchip/komischfarben2.git/'


complete: new module

complete: new module

Former-commit-id: d2b2d52c57e420a5608637a789c346fbf4a4e399 [formerly 37668f4852b7de292acb48f8d7f3652ab4d9712c]
Former-commit-id: 4e5d342f9e34d7d83a0fad973305bfb893380c12

-- 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


Added tests for `in_array` function

Added tests for `in_array` function


rss: simple module for subscribing to rss feeds

-- Module for subscribing to RSS and announce to channels
feedparser = require 'feedparser' -- http://feedparser.luaforge.net/
{:simplehttp, :json, :urlEncode, :bold} = require'util'
html2unicode = require 'html'

moduleName = 'rss'
key = moduleName
store = ivar2.persist

-- Function that add functionality to extract specific information for specific sites
feedSpecific = (link, id, entry) ->
  if link == 'https://comics.io/my/'

    title = entry.summary\match '
(.-)
' or ''
    img, alt = entry.summary\match '
'
    return "#{html2unicode title} #{img} #{html2unicode alt}"

  return "#{entry.title} - #{entry.link}"

poll = ->
  for c,_ in pairs(ivar2.channels)
    channelKey = key..':'..c
    channels = store[channelKey] or {}
    -- TODO separate channel logic for polling logic for the cases where
    -- two channels subscribe to the same feed
    for name, channel in pairs(channels)
      lastKey = channelKey .. ':' .. name .. ':last'
      lastmKey = lastKey..'modified'
      last = store[lastKey] or ''
      lastlastModified = store[lastmKey]
      simplehttp {url:channel.url,headers:{'If-Modified-Since':lastlastModified}}, (data, url, response) ->
        lastModified = response.headers['Last-Modified']
        if not lastModified
          lastModified = response.headers['Date']

        store[lastmKey] = lastModified

        -- Unmodified content
        if response.status_code == 304
          -- return from the simplehttp callback
          return

        feed, err = feedparser.parse data
        if err
          ivar2\Log 'error', "#{moduleName}: Error during parsing: <#{err}> data for feed: <#{name}> with URL <#{channel.url}>"
        else
          out = {}
          for i, e in pairs(feed.entries)
            -- Attempt to get a unique entry ID
            guid = e.guid
            if not guid then guid = e.id
            if not guid then guid = e.link
            if not guid
              ivar2\Log 'error', "#{moduleName}: No GUID when parsing entry: <#{e}> data for feed: <#{name}> with URL <#{channel.url}>"

            if guid == last
              break

            table.insert out, "[#{bold name}]: #{feedSpecific(feed.feed.id, feed.feed.link, e)}"

            -- First entry is the newest entry, look for that one on the
            -- next iteration
            if i == 1
              store[lastKey] = guid

            -- First time
            if last == ''
              break

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

subscribe = (source, destination, name, url) =>
  channelKey = key..':'..destination
  channels = store[channelKey] or {}
  channels[name] = {channel:destination, name:name, url:url}
  store[channelKey] = channels
  reply "Ok. Subscribed to #{bold name}"
  poll!

unsubscribe = (source, destination, name) =>
  channelKey = key..':'..destination
  channels = store[channelKey] or {}
  unless channels[name]
    reply "Wasn't subscribed. But, sure."
  else
    channels[name] = nil
    store[channelKey] = channels
    lastKey = channelKey .. ':' .. name .. ':last'
    store[lastKey] = nil
    reply "Ok. Stopped caring about #{bold name}"

list = (source, destination) =>
  channelKey = key..':'..destination
  channels = store[channelKey] or {}
  out = {}
  for name, game in pairs(channels)
      out[#out+1] = name
  say "Subscribed to: #{table.concat(out, ', ')}"

-- Start the subscribe poller
ivar2\Timer(moduleName, 300, 300, poll)

PRIVMSG:
  '^%prss latest (.*)': getLatest
  '^%prss subscribe (.-) (.*)': subscribe
  '^%prss unsubscribe (.*)': unsubscribe
  '^%prss list': list
  -- for debugging
  '^%prss poll': poll

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