stage

stage

lazuli = require "lazuli"
import respond_to from require "lapis.application"
import from_json from require "lapis.util"
import hmac_sha1, encode_base64 from require "lapis.util.encoding"
config = (require "lapis.config").get!

class extends lazuli.Application
  @enable "user_management"

  @include "apps.profile"

  layout: require "views.main_layout"

  handle_404: =>
    status: 404, "Error 404: Failed to find route: #{@req.cmd_url}"

  [index: "/"]: =>
    "This project is in "..config.projectStage.." stage."

  [githubhook: "/githubhook"]: =>
    return status: 400, "no payload" unless @params.payload
    pl=from_json @params.payload
    return status: 400, "broken payload" unless pl
    return status: 200, "wrong branch" unless pl.ref == "refs/heads/deploy" -- should be 428, but then githup fucks up
    require"os".execute "/usr/bin/nohup /bin/zsh ./githubhook.zsh > ./githubhook.log &"
    "ok"

  [make_invite_key: "/mik/:username"]: =>
    if @modules.user_management.currentuser
      if config.projectStage=="alpha" and @modules.user_management.currentuser.id==1 or config.projectStage=="beta"
        return layout: false, encode_base64 hmac_sha1 config.secret, @params.username

  [make_invite_key_form: "/mik"]: respond_to {
    GET: =>
      if not @modules.user_management.currentuser
        return redirect_to: @url_for "lazuli_modules_usermanagement_login"
      if config.projectStage~="beta"
        if not (@modules.user_management.currentuser and @modules.user_management.currentuser.is_admin)
          return redirect_to: @url_for "index"
      render: true
    POST: =>
      if not @modules.user_management.currentuser
        return redirect_to: @url_for "lazuli_modules_usermanagement_login"
      if config.projectStage~="beta"
        if not (@modules.user_management.currentuser and @modules.user_management.currentuser.is_admin)
          return redirect_to: @url_for "index"
      @invkey=encode_base64 hmac_sha1 config.secret, @params.username
      render: true
  }

lazuli = require "lazuli"
import respond_to from require "lapis.application"
import from_json from require "lapis.util"
import hmac_sha1, encode_base64 from require "lapis.util.encoding"
config = (require "lapis.config").get!

class extends lazuli.Application
  @enable "user_management"

  @include "apps.profile"

  layout: require "views.main_layout"

  handle_404: =>
    status: 404, "Error 404: Failed to find route: #{@req.cmd_url}"

  [index: "/"]: =>
    "WIP!"

  [githubhook: "/githubhook"]: =>
    return status: 400, "no payload" unless @params.payload
    pl=from_json @params.payload
    return status: 400, "broken payload" unless pl
    return status: 200, "wrong branch" unless pl.ref == "refs/heads/deploy" -- should be 428, but then githup fucks up
    require"os".execute "/usr/bin/nohup /bin/zsh ./githubhook.zsh > ./githubhook.log &"
    "ok"

  [make_invite_key: "/mik/:username"]: =>
    if @modules.user_management.currentuser
      if config.projectStage=="alpha" and @modules.user_management.currentuser.id==1 or config.projectStage=="beta"
        return layout: false, encode_base64 hmac_sha1 config.secret, @params.username

  [make_invite_key_form: "/mik"]: respond_to {
    GET: =>
      if not @modules.user_management.currentuser
        return redirect_to: @url_for "lazuli_modules_usermanagement_login"
      if config.projectStage~="beta"
        if not (@modules.user_management.currentuser and @modules.user_management.currentuser.is_admin)
          return redirect_to: @url_for "index"
      render: true
    POST: =>
      if not @modules.user_management.currentuser
        return redirect_to: @url_for "lazuli_modules_usermanagement_login"
      if config.projectStage~="beta"
        if not (@modules.user_management.currentuser and @modules.user_management.currentuser.is_admin)
          return redirect_to: @url_for "index"
      @invkey=encode_base64 hmac_sha1 config.secret, @params.username
      render: true
  }


hotfix: forgot includes

hotfix: forgot includes

import Widget from require "lapis.html"
import slugify from require "lapis.util"

class loginDo extends Widget
  content: =>
    if @errors
      h1 "Login failed"
      ul ->
        for e in *@errors
          li e
      a href: @url_for("lazuli_modules_usermanagement_login"), "Back"
    else
      h1 "Login successful"
      text "User id: "..@modules.user_management.currentuser.id
    div class: "providers", ->
      for k,v in pairs @providerHtml
        div class: "provider "..slugify(k), ->
          raw v

import Widget from require "lapis.html"

class loginDo extends Widget
  content: =>
    if @errors
      h1 "Login failed"
      ul ->
        for e in *@errors
          li e
      a href: @url_for("lazuli_modules_usermanagement_login"), "Back"
    else
      h1 "Login successful"
      text "User id: "..@modules.user_management.currentuser.id
    div class: "providers", ->
      for k,v in pairs @providerHtml
        div class: "provider "..slugify(k), ->
          raw v


Minor fix to graphics.Image to use the correct variable

require "LunoPunk.Graphic"
require "LunoPunk.RenderMode"
require "LunoPunk.graphics.atlas.Atlas"
require "LunoPunk.graphics.atlas.AtlasRegion"
require "LunoPunk.graphics.atlas.TextureAtlas"
require "LunoPunk.geometry.Rectangle"

export ^

-- Performance-optimized non-animated image. Can be drawn to the screen with transformations.
class Image extends Graphic
	new: (source, clipRect = nil, name = "") =>
		super!

		-- Init variables
		-- Rotation of the image, in degrees.
		@angle = 0

		-- Scale of the image, effects both x and y scale.
		@scale = 1

		-- X scale of the image.
		@scaleX = 1

		-- Y scale of the image.
		@scaleY = 1

		-- X origin of the image, determines transformation point.
		-- Defaults to top-left corner.
		@originX = 0

		-- Y origin of the image, determines transformation point.
		-- Defaults to top-left corner.
		@originY = 0

		-- Optional blend mode to use when drawing this image.
		-- Use constants from the flash.display.BlendMode class.
		@blend = nil

		@__alpha = 1
		@__flipped = false
		@__color = 0x00FFFFFF
		@__red, @__green, @__blue = 1, 1, 1
		@__matrix = LP.matrix\clone!

		-- check if the _source or _region were set in a higher class
		if @__source == nil and @__region == nil
			@__imgName = name
			if instance source, TextureAtlas
				@__setAtlasRegion source\getRegion name
			elseif instance source, AtlasRegion
				@__setAtlasRegion source
			elseif LP.renderMode == RenderMode.Hardware
				if type(source) == "string"
					@__imgName = source
				else if name == ""
					@__imgName = @@.__name

				@__setAtlasRegion Atlas.loadImageAsRegion source
			elseif source["type"] and source\type! == "Image" -- Löve Image
				@__setImageSource source
			else
				if type(source) == "string"
					@__imgName = source
				else if name == ""
					@__imgName = @@.__name

				@__setImageSource LP.getImage source

			assert false, "Invalid source image." if @__source == nil and @__region == nil

		if clipRect != nil
			clipRect.width = @__sourceRect\width! if clipRect\width! == 0
			clipRect.height = @__sourceRect\height! if clipRect\height! == 0
			@__region = @__region\clip clipRect if not @__blit -- creat a new clipped region
			@__sourceRect = clipRect

	__setAtlasRegion: (region) =>
		@__blit = false
		@__region = region
		@__sourceRect = Rectangle 0, 0, region\width!, region\height!

	__setImageSource: (img) =>
		@__blit = true
		@__sourceRect = Rectangle 0, 0, img\getWidth!, img\getHeight!
		@__source = img

	-- Renders the image.
	render: (point, camera) =>
		sx = @scale * @scaleX
		sy = @scale * @scaleY

		-- determine drawing location
-- 		@__point.x = point.x + @x - @originX - camera.x * @scrollY
-- 		@__point.y = point.y + @y - @originY - camera.y * @scrollY
		@__point.x = point.x + @x - camera.x * @scrollX
		@__point.y = point.y + @y - camera.y * @scrollY

		if @__blit
			if @angle == 0 and sx == 1 and sy == 1 and @blend == nil
				-- render without transformation
				love.graphics.draw @__source, @__point.x, @__point.y
			else
				-- TODO render from matrix
				-- render with transformation
-- 				@__matrix.b, @__matrix.c = 0, 0
-- 				@__matrix.a = sx
-- 				@__matrix.d = sy
-- 				@__matrix.tx = -@originX * sx
-- 				@__matrix.ty = -@originY * sy
-- 				@__matrix\rotate @angle * LP.RAD! if @angle != 0
-- 				@__matrix.tx += @originX + @__point.x
-- 				@__matrix.ty += @originY + @__point.y

				x, y = @__point.x, @__point.y
				angle = @angle * LP.RAD!
				ox = @originX
				oy = @originY
				love.graphics.draw @__source, x, y, angle, sx, sy, ox, oy
		else -- @__blit
			fsx = LP.screen\fullScaleX!
			fsy = LP.screen\fullScaleY!

			if @angle == 0
				-- recalculation of @__point for scaled origins
				if not (sx == 1 and sy == 1)
					@__point.x = point.x + @x - @originX * sx - camera.x * @scrollX
					@__point.y = point.y + @y - @originY * sy - camera.y * @scrollY

				@__point.x = math.floor @__point.x * fsx
				@__point.y = math.floor @__point.y * fsy

				-- render without rotation
				@__region\draw @__point.x, @__point.y, super.__layer,
					sx * fsx * (if @__flipped then -1 else 1), sy * fsy, @angle,
					@__red, @__green, @__blue, @__alpha
			else
				theta = @angle * LP.RAD!
				cos = math.cos theta
				sin = math.sin theta

				sx *= -1 if @__flipped

				-- optimized matrix math
				b = sx * fsx * sin
				a = sx * fsx * cos

				d = sy * fsy * cos
				a = sy * fsy * -sin

				tx = -@originX * sx
				ty = -@originY * sy
				tx1 = tx * cos - ty * sin
				ty = ((tx * sin + ty * cos) + @originY + @__point.y) * fsy
				tx = (tx1 + @originX + @__point.x) * fsx

				@__region\drawMatrix tx, ty, a, b, c, d, @__layer, @__red, @__green, @__blue, @__alpha

	width: => @__source\getWidth!
	height: => @__source\getHeight!

require "LunoPunk.Graphic"
require "LunoPunk.RenderMode"
require "LunoPunk.graphics.atlas.Atlas"
require "LunoPunk.graphics.atlas.AtlasRegion"
require "LunoPunk.graphics.atlas.TextureAtlas"
require "LunoPunk.geometry.Rectangle"

export ^

-- Performance-optimized non-animated image. Can be drawn to the screen with transformations.
class Image extends Graphic
	new: (source, clipRect = nil, name = "") =>
		super!

		-- Init variables
		-- Rotation of the image, in degrees.
		@angle = 0

		-- Scale of the image, effects both x and y scale.
		@scale = 1

		-- X scale of the image.
		@scaleX = 1

		-- Y scale of the image.
		@scaleY = 1

		-- X origin of the image, determines transformation point.
		-- Defaults to top-left corner.
		@originX = 0

		-- Y origin of the image, determines transformation point.
		-- Defaults to top-left corner.
		@originY = 0

		-- Optional blend mode to use when drawing this image.
		-- Use constants from the flash.display.BlendMode class.
		@blend = nil

		@__alpha = 1
		@__flipped = false
		@__color = 0x00FFFFFF
		@__red, @__green, @__blue = 1, 1, 1
		@__matrix = LP.matrix

		-- check if the _source or _region were set in a higher class
		if @__source == nil and @__region == nil
			@__imgName = name
			if instance source, TextureAtlas
				@__setAtlasRegion source\getRegion name
			elseif instance source, AtlasRegion
				@__setAtlasRegion source
			elseif LP.renderMode == RenderMode.Hardware
				if type(source) == "string"
					@__imgName = source
				else if name == ""
					@__imgName = @@.__name

				@__setAtlasRegion Atlas.loadImageAsRegion source
			elseif source["type"] and source\type! == "Image" -- Löve Image
				@__setImageSource source
			else
				if type(source) == "string"
					@__imgName = source
				else if name == ""
					@__imgName = @@.__name

				@__setImageSource LP.getImage source

			assert false, "Invalid source image." if @__source == nil and @__region == nil

		if clipRect != nil
			clipRect.width = @__sourceRect\width! if clipRect\width! == 0
			clipRect.height = @__sourceRect\height! if clipRect\height! == 0
			@__region = @__region\clip clipRect if not @__blit -- creat a new clipped region
			@__sourceRect = clipRect

	__setAtlasRegion: (region) =>
		@__blit = false
		@__region = region
		@__sourceRect = Rectangle 0, 0, region\width!, region\height!

	__setImageSource: (img) =>
		@__blit = true
		@__sourceRect = Rectangle 0, 0, img\getWidth!, img\getHeight!
		@__source = img

	-- Renders the image.
	render: (point, camera) =>
		sx = @scale * @scaleX
		sy = @scale * @scaleY

		-- determine drawing location
-- 		@__point.x = point.x + @x - @originX - camera.x * @scrollY
-- 		@__point.y = point.y + @y - @originY - camera.y * @scrollY
		@__point.x = point.x + @x - camera.x * @scrollX
		@__point.y = point.y + @y - camera.y * @scrollY

		if @__blit
			if @angle == 0 and sx == 1 and sy == 1 and @blend == nil
				-- render without transformation
				love.graphics.draw @__source, @__point.x, @__point.y
			else
				-- TODO render from matrix
				-- render with transformation
-- 				@__matrix.b, @__matrix.c = 0, 0
-- 				@__matrix.a = sx
-- 				@__matrix.d = sy
-- 				@__matrix.tx = -@originX * sx
-- 				@__matrix.ty = -@originY * sy
-- 				@__matrix\rotate @angle * LP.RAD! if @angle != 0
-- 				@__matrix.tx += @originX + @__point.x
-- 				@__matrix.ty += @originY + @__point.y

				x, y = @__point.x, @__point.y
				angle = @angle * LP.RAD!
				ox = @originX
				oy = @originY
				love.graphics.draw @__source, x, y, angle, sx, sy, ox, oy
		else -- @__blit
			fsx = LP.screen\fullScaleX!
			fsy = LP.screen\fullScaleY!

			if @angle == 0
				-- recalculation of @__point for scaled origins
				if not (sx == 1 and sy == 1)
					@__point.x = point.x + @x - @originX * sx - camera.x * @scrollX
					@__point.y = point.y + @x - @originY * sy - camera.y * @scrollY

				@__point.x = math.floor @__point.x * fsx
				@__point.y = math.floor @__point.y * fsy

				-- render without rotation
				@__region\draw @__point.x, @__point.y, super.__layer,
					sx * fsx * (if @__flipped then -1 else 1), sy * fsy, @angle,
					@__red, @__green, @__blue, @__alpha
			else
				theta = @angle * LP.RAD!
				cos = math.cos theta
				sin = math.sin theta

				sx *= -1 if @__flipped

				-- optimized matrix math
				b = sx * fsx * sin
				a = sx * fsx * cos

				d = sy * fsy * cos
				a = sy * fsy * -sin

				tx = -@originX * sx
				ty = -@originY * sy
				tx1 = tx * cos - ty * sin
				ty = ((tx * sin + ty * cos) + @originY + @__point.y) * fsy
				tx = (tx1 + @originX + @__point.x) * fsx

				@__region\drawMatrix tx, ty, a, b, c, d, @__layer, @__red, @__green, @__blue, @__alpha

	width: => @__source\getWidth!
	height: => @__source\getHeight!


textutils: botsnack, botreply?

textutils: botsnack, botreply?

Former-commit-id: d30835f6c686c0cd32a7a0f3df589e0d82a4555f
Former-commit-id: f1f813c0ec97d082aa6504ba99bb337f694bf378

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) =>
    chan = ivar2.channels[destination] or ivar2.channels[destination\lower!]
    say table.concat([ivar2.util.nonickalert(chan.nicks, n) for n,k in pairs(chan.nicks)], ' ')
  '^%prandom (.+)$': (source, destination, arg) =>
    words = [word for word in arg\gmatch('%S+')]
    say words[math.random(1, #words)]
  '^%pbold (.+)$': (source, destination, arg) =>
    say ivar2.util.bold(arg)
  '^%punderline (.+)$': (source, destination, arg) =>
    say ivar2.util.underline(arg)
  '^%pitalic (.+)$': (source, destination, arg) =>
    say ivar2.util.italic(arg)
  '^%pinvert (.+)$': (source, destination, arg) =>
    say ivar2.util.reverse(arg)
  '^%ptrim (.+)$': (source, destination, arg) =>
    say ivar2.util.trim(arg)
  '^%pcolor ([0-9]+) (.+)$': (source, destination, color, arg) =>
    say ivar2.util.color(arg, color)
  '^%pfirst (.+)$': (source, destination, arg) =>
    say ivar2.util.split(arg, '%s')[1]
  '^%psplit (.-) (.*)$': (source, destination, arg, args) =>
    say table.concat(ivar2.util.split(args, arg), ' ')
  '^%preplace (.-) (.-) (.*)$': (source, destination, pat, repl, arg) =>
    new, n = string.gsub(arg, pat, repl)
    say(new)
  '^%pnocolor (.*)$': (source, destination, arg) =>
    say ivar2.util.stripformatting(arg)
  '^%pstutter (.*)$': (source, destination, arg) =>
    -- Stutter by anders from luabot
    s_senpai = 0.65
    say arg\gsub("(%a[%w%p]+)", (w) ->
      if math.random! >= s_senpai
        return (w\sub(1, 1).."-")\rep(math.random(1, 3))..w
      else
        return w)
  '^%prot13 (.+)$': (source, destination, arg) =>
    say ivar2.util.rot13(arg)
  '^%phex (.+)$': (source, destination, arg) =>
    say arg\gsub '.', (b) ->
      ('%02x ')\format(b\byte!)
  '^%prtl (.+)$': (source, destination, arg) =>
    say ''..arg
  '^%pltr (.+)$': (source, destination, arg) =>
    say ''..arg
  '^%pemote (.+)$': (source, destination, arg) =>
    @Action destination, arg
  'botsnack': =>
    replies = {
      'Nom nom nom.'
      'Ooooh'
      'Yummi!'
      'Delightful.'
      'That makes me happy'
      'How kind!'
      'Sweet.'
      "Sorry, but I can't handle more right now."
      "*burp*"
      "Ah.. Hiccup!"
    }
    reply replies[math.random #replies]
  "#{ivar2.config.nick}.?%?": =>
    replies = {
      "Sorry, but I tried my best"
      "I am not fully sentient yet, but I'm learning every day"
      "Please, I tried my best."
      "That was what my very best, just for you"
      "Maybe another time"
      "Sorry, not feeling so good"
      "Oof."
      "Whoopsie."
      "Just give me some time, I will get it eventually"
      "ಠ_ಠ"
      "( ͡° ͜ʖ ͡°) "
    }
    reply replies[math.random #replies]
  --'^%prepeat (%d+) (.*)$': (source, destination, nr, command) =>
  --  for i=1, nr
  --    @DispatchCommand 'PRIVMSG', command, source, destination

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) =>
    chan = ivar2.channels[destination] or ivar2.channels[destination\lower!]
    say table.concat([ivar2.util.nonickalert(chan.nicks, n) for n,k in pairs(chan.nicks)], ' ')
  '^%prandom (.+)$': (source, destination, arg) =>
    words = [word for word in arg\gmatch('%S+')]
    say words[math.random(1, #words)]
  '^%pbold (.+)$': (source, destination, arg) =>
    say ivar2.util.bold(arg)
  '^%punderline (.+)$': (source, destination, arg) =>
    say ivar2.util.underline(arg)
  '^%pitalic (.+)$': (source, destination, arg) =>
    say ivar2.util.italic(arg)
  '^%pinvert (.+)$': (source, destination, arg) =>
    say ivar2.util.reverse(arg)
  '^%ptrim (.+)$': (source, destination, arg) =>
    say ivar2.util.trim(arg)
  '^%pcolor ([0-9]+) (.+)$': (source, destination, color, arg) =>
    say ivar2.util.color(arg, color)
  '^%pfirst (.+)$': (source, destination, arg) =>
    say ivar2.util.split(arg, '%s')[1]
  '^%psplit (.-) (.*)$': (source, destination, arg, args) =>
    say table.concat(ivar2.util.split(args, arg), ' ')
  '^%preplace (.-) (.-) (.*)$': (source, destination, pat, repl, arg) =>
    new, n = string.gsub(arg, pat, repl)
    say(new)
  '^%pnocolor (.*)$': (source, destination, arg) =>
    say ivar2.util.stripformatting(arg)
  '^%pstutter (.*)$': (source, destination, arg) =>
    -- Stutter by anders from luabot
    s_senpai = 0.65
    say arg\gsub("(%a[%w%p]+)", (w) ->
      if math.random! >= s_senpai
        return (w\sub(1, 1).."-")\rep(math.random(1, 3))..w
      else
        return w)
  '^%prot13 (.+)$': (source, destination, arg) =>
    say ivar2.util.rot13(arg)
  '^%phex (.+)$': (source, destination, arg) =>
    say arg\gsub '.', (b) ->
      ('%02x ')\format(b\byte!)
  '^%prtl (.+)$': (source, destination, arg) =>
    say ''..arg
  '^%pltr (.+)$': (source, destination, arg) =>
    say ''..arg
  '^%pemote (.+)$': (source, destination, arg) =>
    @Action destination, arg
  --'^%prepeat (%d+) (.*)$': (source, destination, nr, command) =>
  --  for i=1, nr
  --    @DispatchCommand 'PRIVMSG', command, source, destination


Use double instead of float

Use double instead of float

--
-- Copyright (C) 2017-2018 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.

wUInt = (def = 0, size = 8) ->
	return (arg = def) -> net.WriteUInt(arg, size)

wInt = (def = 0, size = 8) ->
	return (arg = def) -> net.WriteInt(arg, size)

rUInt = (size = 8, min = 0, max = 255) ->
	return -> math.Clamp(net.ReadUInt(size), min, max)

rInt = (size = 8, min = -128, max = 127) ->
	return -> math.Clamp(net.ReadInt(size), min, max)

rFloat = (min = 0, max = 255) ->
	return -> math.Clamp(net.ReadDouble(), min, max)

wFloat = net.WriteDouble
rBool = net.ReadBool
wBool = net.WriteBool
rColor = net.ReadColor
wColor = net.WriteColor
rString = net.ReadString
wString = net.WriteString

COLOR_FIXER = (r = 255, g = 255, b = 255, a = 255) ->
	func = (arg = Color(r, g, b, a)) ->
		if type(arg) ~= 'table'
			return Color(255, 255, 255)
		else
			{:r, :g, :b, :a} = arg
			if r and g and b and a
				return Color(r, g, b, a)
			else
				return Color(255, 255, 255)
	return func

URL_FIXER = (arg = '') ->
	arg = tostring(arg)
	if arg\find('^https?://')
		return arg
	else
		return ''

rURL = -> URL_FIXER(rString())

FLOAT_FIXER = (def = 1, min = 0, max = 1) ->
	defFunc = -> def if type(def) ~= 'function'
	defFunc = def if type(def) == 'function'
	return (arg = defFunc()) -> math.Clamp(tonumber(arg) or defFunc(), min, max)

INT_FIXER = (def = 1, min = 0, max = 1) ->
	defFunc = -> def if type(def) ~= 'function'
	defFunc = def if type(def) == 'function'
	return (arg = defFunc()) -> math.floor(math.Clamp(tonumber(arg) or defFunc(), min, max))

PPM2.PonyDataRegistry = {
	'age': {
		default: -> PPM2.AGE_ADULT
		getFunc: 'Age'
		enum: {'FILLY', 'ADULT', 'MATURE'}
	}

	'race': {
		default: -> PPM2.RACE_EARTH
		getFunc: 'Race'
		enum: [arg for _, arg in ipairs PPM2.RACE_ENUMS]
	}

	'wings_type': {
		default: -> 0
		getFunc: 'WingsType'
		enum: [arg for _, arg in ipairs PPM2.AvaliablePonyWings]
	}

	'gender': {
		default: -> PPM2.GENDER_FEMALE
		getFunc: 'Gender'
		enum: [arg for _, arg in ipairs PPM2.AGE_ENUMS]
	}

	'weight': {
		default: -> 1
		getFunc: 'Weight'
		min: PPM2.MIN_WEIGHT
		max: PPM2.MAX_WEIGHT
		type: 'FLOAT'
	}

	'ponysize': {
		default: -> 1
		getFunc: 'PonySize'
		min: PPM2.MIN_SCALE
		max: PPM2.MAX_SCALE
		type: 'FLOAT'
	}

	'necksize': {
		default: -> 1
		getFunc: 'NeckSize'
		min: PPM2.MIN_NECK
		max: PPM2.MAX_NECK
		type: 'FLOAT'
	}

	'legssize': {
		default: -> 1
		getFunc: 'LegsSize'
		min: PPM2.MIN_LEGS
		max: PPM2.MAX_LEGS
		type: 'FLOAT'
	}

	'spinesize': {
		default: -> 1
		getFunc: 'BackSize'
		min: PPM2.MIN_SPINE
		max: PPM2.MAX_SPINE
		type: 'FLOAT'
	}

	'male_buff': {
		default: -> PPM2.DEFAULT_MALE_BUFF
		getFunc: 'MaleBuff'
		min: PPM2.MIN_MALE_BUFF
		max: PPM2.MAX_MALE_BUFF
		type: 'FLOAT'
	}

	'eyelash': {
		default: -> 0
		getFunc: 'EyelashType'
		enum: [arg for _, arg in ipairs PPM2.EyelashTypes]
	}

	'tail': {
		default: -> 0
		getFunc: 'TailType'
		enum: [arg for _, arg in ipairs PPM2.AvaliableTails]
	}

	'tail_new': {
		default: -> 0
		getFunc: 'TailTypeNew'
		enum: [arg for _, arg in ipairs PPM2.AvaliableTailsNew]
	}

	'mane': {
		default: -> 0
		getFunc: 'ManeType'
		enum: [arg for _, arg in ipairs PPM2.AvaliableUpperManes]
	}

	'mane_new': {
		default: -> 0
		getFunc: 'ManeTypeNew'
		enum: [arg for _, arg in ipairs PPM2.AvaliableUpperManesNew]
	}

	'manelower': {
		default: -> 0
		getFunc: 'ManeTypeLower'
		enum: [arg for _, arg in ipairs PPM2.AvaliableLowerManes]
	}

	'manelower_new': {
		default: -> 0
		getFunc: 'ManeTypeLowerNew'
		enum: [arg for _, arg in ipairs PPM2.AvaliableLowerManesNew]
	}

	'socks_texture': {
		default: -> 0
		getFunc: 'SocksTexture'
		enum: [arg for _, arg in ipairs PPM2.SocksTypes]
	}

	'socks_texture_url': {
		default: -> ''
		getFunc: 'SocksTextureURL'
		type: 'URL'
	}

	'tailsize': {
		default: -> 1
		getFunc: 'TailSize'
		min: PPM2.MIN_TAIL_SIZE
		max: PPM2.MAX_TAIL_SIZE
		type: 'FLOAT'
	}

	'cmark': {
		default: -> true
		getFunc: 'CMark'
		type: 'BOOLEAN'
	}

	'cmark_size': {
		default: -> 1
		getFunc: 'CMarkSize'
		min: 0
		max: 1
		type: 'FLOAT'
	}

	'cmark_color': {
		default: -> Color(255, 255, 255)
		getFunc: 'CMarkColor'
		type: 'COLOR'
	}

	'eyelash_color': {
		default: -> Color(0, 0, 0)
		getFunc: 'EyelashesColor'
		type: 'COLOR'
	}

	'eyelashes_phong_separate': {
		default: -> false
		getFunc: 'SeparateEyelashesPhong'
		type: 'BOOLEAN'
	}

	'fangs': {
		default: -> false
		getFunc: 'Fangs'
		type: 'BOOLEAN'
	}

	'bat_pony_ears': {
		default: -> false
		getFunc: 'BatPonyEars'
		type: 'BOOLEAN'
	}

	'claw_teeth': {
		default: -> false
		getFunc: 'ClawTeeth'
		type: 'BOOLEAN'
	}

	'cmark_type': {
		default: -> 4
		getFunc: 'CMarkType'
		enum: [arg for _, arg in ipairs PPM2.DefaultCutiemarks]
	}

	'cmark_url': {
		default: -> ''
		getFunc: 'CMarkURL'
		type: 'URL'
	}

	'body': {
		default: -> Color(255, 255, 255)
		getFunc: 'BodyColor'
		type: 'COLOR'
	}

	'eyebrows': {
		default: -> Color(0, 0, 0)
		getFunc: 'EyebrowsColor'
		type: 'COLOR'
	}

	'eyebrows_glow': {
		default: -> false
		getFunc: 'GlowingEyebrows'
		type: 'BOOLEAN'
	}

	'eyebrows_glow_strength': {
		default: -> 1
		getFunc: 'EyebrowsGlowStrength'
		type: 'FLOAT'
		min: 0
		max: 1
	}

	'hide_manes': {
		default: -> true
		getFunc: 'HideManes'
		type: 'BOOLEAN'
	}

	'hide_manes_socks': {
		default: -> true
		getFunc: 'HideManesSocks'
		type: 'BOOLEAN'
	}

	'hide_manes_mane': {
		default: -> true
		getFunc: 'HideManesMane'
		type: 'BOOLEAN'
	}

	'hide_manes_tail': {
		default: -> true
		getFunc: 'HideManesTail'
		type: 'BOOLEAN'
	}

	'horn_color': {
		default: -> Color(255, 255, 255)
		getFunc: 'HornColor'
		type: 'COLOR'
	}

	'wings_color': {
		default: -> Color(255, 255, 255)
		getFunc: 'WingsColor'
		type: 'COLOR'
	}

	'separate_wings': {
		default: -> false
		getFunc: 'SeparateWings'
		type: 'BOOLEAN'
	}

	'separate_horn': {
		default: -> false
		getFunc: 'SeparateHorn'
		type: 'BOOLEAN'
	}

	'separate_magic_color': {
		default: -> false
		getFunc: 'SeparateMagicColor'
		type: 'BOOLEAN'
	}

	'horn_magic_color': {
		default: -> Color(255, 255, 255)
		getFunc: 'HornMagicColor'
		type: 'COLOR'
	}

	'horn_glow': {
		default: -> false
		getFunc: 'HornGlow'
		type: 'BOOLEAN'
	}

	'horn_glow_strength': {
		default: -> 1
		getFunc: 'HornGlowSrength'
		min: 0
		max: 1
		type: 'FLOAT'
	}

	'horn_detail_color': {
		default: -> Color(90, 90, 90)
		getFunc: 'HornDetailColor'
		type: 'COLOR'
	}

	'separate_eyes': {
		default: -> false
		getFunc: 'SeparateEyes'
		type: 'BOOLEAN'
	}

	'separate_mane': {
		default: -> false
		getFunc: 'SeparateMane'
		type: 'BOOLEAN'
	}

	'socks': {
		default: -> false
		getFunc: 'Socks'
		type: 'BOOLEAN'
	}

	'new_male_muzzle': {
		default: -> true
		getFunc: 'NewMuzzle'
		type: 'BOOLEAN'
	}

	'noflex': {
		default: -> false
		getFunc: 'NoFlex'
		type: 'BOOLEAN'
	}

	'socks_model': {
		default: -> false
		getFunc: 'SocksAsModel'
		type: 'BOOLEAN'
	}

	'socks_model_new': {
		default: -> false
		getFunc: 'SocksAsNewModel'
		type: 'BOOLEAN'
	}

	'socks_model_color': {
		default: -> Color(255, 255, 255)
		getFunc: 'SocksColor'
		type: 'COLOR'
	}

	'socks_new_model_color1': {
		default: -> Color(255, 255, 255)
		getFunc: 'NewSocksColor1'
		type: 'COLOR'
	}

	'socks_new_model_color2': {
		default: -> Color(0, 0, 0)
		getFunc: 'NewSocksColor2'
		type: 'COLOR'
	}

	'socks_new_model_color3': {
		default: -> Color(0, 0, 0)
		getFunc: 'NewSocksColor3'
		type: 'COLOR'
	}

	'socks_new_texture_url': {
		default: -> ''
		getFunc: 'NewSocksTextureURL'
		type: 'URL'
	}

	'suit': {
		default: -> 0
		getFunc: 'Bodysuit'
		enum: [arg for _, arg in ipairs PPM2.AvaliablePonySuits]
	}

	'left_wing_size': {
		default: -> 1
		getFunc: 'LWingSize'
		min: PPM2.MIN_WING
		max: PPM2.MAX_WING
		type: 'FLOAT'
	}

	'left_wing_x': {
		default: -> 0
		getFunc: 'LWingX'
		min: PPM2.MIN_WINGX
		max: PPM2.MAX_WINGX
		type: 'FLOAT'
	}

	'left_wing_y': {
		default: -> 0
		getFunc: 'LWingY'
		min: PPM2.MIN_WINGY
		max: PPM2.MAX_WINGY
		type: 'FLOAT'
	}

	'left_wing_z': {
		default: -> 0
		getFunc: 'LWingZ'
		min: PPM2.MIN_WINGZ
		max: PPM2.MAX_WINGZ
		type: 'FLOAT'
	}

	'right_wing_size': {
		default: -> 1
		getFunc: 'RWingSize'
		min: PPM2.MIN_WING
		max: PPM2.MAX_WING
		type: 'FLOAT'
	}

	'right_wing_x': {
		default: -> 0
		getFunc: 'RWingX'
		min: PPM2.MIN_WINGX
		max: PPM2.MAX_WINGX
		type: 'FLOAT'
	}

	'right_wing_y': {
		default: -> 0
		getFunc: 'RWingY'
		min: PPM2.MIN_WINGY
		max: PPM2.MAX_WINGY
		type: 'FLOAT'
	}

	'right_wing_z': {
		default: -> 0
		getFunc: 'RWingZ'
		min: PPM2.MIN_WINGZ
		max: PPM2.MAX_WINGZ
		type: 'FLOAT'
	}

	'teeth_color': {
		default: -> Color(255, 255, 255)
		getFunc: 'TeethColor'
		type: 'COLOR'
	}

	'mouth_color': {
		default: -> Color(219, 65, 155)
		getFunc: 'MouthColor'
		type: 'COLOR'
	}

	'tongue_color': {
		default: -> Color(235, 131, 59)
		getFunc: 'TongueColor'
		type: 'COLOR'
	}

	'bat_wing_color': {
		default: -> Color(255, 255, 255)
		getFunc: 'BatWingColor'
		type: 'COLOR'
	}

	'bat_wing_skin_color': {
		default: -> Color(255, 255, 255)
		getFunc: 'BatWingSkinColor'
		type: 'COLOR'
	}

	'separate_horn_phong': {
		default: -> false
		getFunc: 'SeparateHornPhong'
		type: 'BOOLEAN'
	}

	'separate_wings_phong': {
		default: -> false
		getFunc: 'SeparateWingsPhong'
		type: 'BOOLEAN'
	}

	'separate_mane_phong': {
		default: -> false
		getFunc: 'SeparateManePhong'
		type: 'BOOLEAN'
	}

	'separate_tail_phong': {
		default: -> false
		getFunc: 'SeparateTailPhong'
		type: 'BOOLEAN'
	}

	'alternative_fangs': {
		default: -> false
		getFunc: 'AlternativeFangs'
		type: 'BOOLEAN'
	}

	'hoof_fluffers': {
		default: -> false
		getFunc: 'HoofFluffers'
		type: 'BOOLEAN'
	}

	'hoof_fluffers_strength': {
		default: -> 1
		getFunc: 'HoofFluffersStrength'
		min: 0
		max: 1
		type: 'FLOAT'
	}

	'ears_size': {
		default: -> 1
		getFunc: 'EarsSize'
		min: 0.1
		max: 2
		type: 'FLOAT'
	}

	'bat_pony_ears_strength': {
		default: -> 1
		getFunc: 'BatPonyEarsStrength'
		min: 0
		max: 1
		type: 'FLOAT'
	}

	'fangs_strength': {
		default: -> 1
		getFunc: 'FangsStrength'
		min: 0
		max: 1
		type: 'FLOAT'
	}

	'clawteeth_strength': {
		default: -> 1
		getFunc: 'ClawTeethStrength'
		min: 0
		max: 1
		type: 'FLOAT'
	}

	'lips_color_inherit': {
		default: -> true
		getFunc: 'LipsColorInherit'
		type: 'BOOLEAN'
	}

	'nose_color_inherit': {
		default: -> true
		getFunc: 'NoseColorInherit'
		type: 'BOOLEAN'
	}

	'lips_color': {
		default: -> Color(172, 92, 92)
		getFunc: 'LipsColor'
		type: 'COLOR'
	}

	'nose_color': {
		default: -> Color(77, 84, 83)
		getFunc: 'NoseColor'
		type: 'COLOR'
	}

	'weapon_hide': {
		default: -> true
		getFunc: 'HideWeapons'
		type: 'BOOLEAN'
	}
}

for _, {internal, publicName} in ipairs {{'_left', 'Left'}, {'_right', 'Right'}, {'', ''}}
	PPM2.PonyDataRegistry["eye_url#{internal}"] = {
		default: -> ''
		getFunc: "EyeURL#{publicName}"
		type: 'URL'
	}

	PPM2.PonyDataRegistry["eye_bg#{internal}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "EyeBackground#{publicName}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["eye_hole#{internal}"] = {
		default: -> Color(0, 0, 0)
		getFunc: "EyeHole#{publicName}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["eye_iris1#{internal}"] = {
		default: -> Color(200, 200, 200)
		getFunc: "EyeIrisTop#{publicName}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["eye_iris2#{internal}"] = {
		default: -> Color(200, 200, 200)
		getFunc: "EyeIrisBottom#{publicName}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["eye_irisline1#{internal}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "EyeIrisLine1#{publicName}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["eye_irisline_direction#{internal}"] = {
		default: -> false
		getFunc: "EyeLineDirection#{publicName}"
		type: 'BOOLEAN'
	}

	PPM2.PonyDataRegistry["eye_irisline2#{internal}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "EyeIrisLine2#{publicName}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["eye_reflection#{internal}"] = {
		default: -> Color(255, 255, 255, 127)
		getFunc: "EyeReflection#{publicName}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["eye_effect#{internal}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "EyeEffect#{publicName}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["eye_lines#{internal}"] = {
		default: -> true
		getFunc: "EyeLines#{publicName}"
		type: 'BOOLEAN'
	}

	PPM2.PonyDataRegistry["eye_iris_size#{internal}"] = {
		default: -> 1
		getFunc: "IrisSize#{publicName}"
		min: PPM2.MIN_IRIS
		max: PPM2.MAX_IRIS
		type: 'FLOAT'
		modifiers: true
	}

	PPM2.PonyDataRegistry["eye_derp#{internal}"] = {
		default: -> false
		getFunc: "DerpEyes#{publicName}"
		type: 'BOOLEAN'
	}

	PPM2.PonyDataRegistry["eye_use_refract#{internal}"] = {
		default: -> false
		getFunc: "EyeRefract#{publicName}"
		type: 'BOOLEAN'
	}

	PPM2.PonyDataRegistry["eye_cornera#{internal}"] = {
		default: -> false
		getFunc: "EyeCornerA#{publicName}"
		type: 'BOOLEAN'
	}

	PPM2.PonyDataRegistry["eye_derp_strength#{internal}"] = {
		default: -> 1
		getFunc: "DerpEyesStrength#{publicName}"
		min: PPM2.MIN_DERP_STRENGTH
		max: PPM2.MAX_DERP_STRENGTH
		type: 'FLOAT'
		modifiers: true
	}

	PPM2.PonyDataRegistry["eye_type#{internal}"] = {
		default: -> 0
		getFunc: "EyeType#{publicName}"
		enum: [arg for _, arg in ipairs PPM2.AvaliableEyeTypes]
	}

	PPM2.PonyDataRegistry["eye_reflection_type#{internal}"] = {
		default: -> 0
		getFunc: "EyeReflectionType#{publicName}"
		enum: [arg for _, arg in ipairs PPM2.AvaliableEyeReflections]
	}

	PPM2.PonyDataRegistry["hole_width#{internal}"] = {
		default: -> 1
		getFunc: "HoleWidth#{publicName}"
		min: PPM2.MIN_PUPIL_SIZE
		max: PPM2.MAX_PUPIL_SIZE
		type: 'FLOAT'
		modifiers: true
	}

	PPM2.PonyDataRegistry["hole_height#{internal}"] = {
		default: -> 1
		getFunc: "HoleHeight#{publicName}"
		min: PPM2.MIN_PUPIL_SIZE
		max: PPM2.MAX_PUPIL_SIZE
		type: 'FLOAT'
		modifiers: true
	}

	PPM2.PonyDataRegistry["iris_width#{internal}"] = {
		default: -> 1
		getFunc: "IrisWidth#{publicName}"
		min: PPM2.MIN_PUPIL_SIZE
		max: PPM2.MAX_PUPIL_SIZE
		type: 'FLOAT'
		modifiers: true
	}

	PPM2.PonyDataRegistry["iris_height#{internal}"] = {
		default: -> 1
		getFunc: "IrisHeight#{publicName}"
		min: PPM2.MIN_PUPIL_SIZE
		max: PPM2.MAX_PUPIL_SIZE
		type: 'FLOAT'
		modifiers: true
	}

	PPM2.PonyDataRegistry["eye_glossy_reflection#{internal}"] = {
		default: -> 0.16
		getFunc: "EyeGlossyStrength#{publicName}"
		min: 0
		max: 1
		type: 'FLOAT'
	}

	PPM2.PonyDataRegistry["hole_shiftx#{internal}"] = {
		default: -> 0
		getFunc: "HoleShiftX#{publicName}"
		min: PPM2.MIN_HOLE_SHIFT
		max: PPM2.MAX_HOLE_SHIFT
		type: 'FLOAT'
		modifiers: true
	}

	PPM2.PonyDataRegistry["hole_shifty#{internal}"] = {
		default: -> 0
		getFunc: "HoleShiftY#{publicName}"
		min: PPM2.MIN_HOLE_SHIFT
		max: PPM2.MAX_HOLE_SHIFT
		type: 'FLOAT'
		modifiers: true
	}

	PPM2.PonyDataRegistry["eye_hole_size#{internal}"] = {
		default: -> .8
		getFunc: "HoleSize#{publicName}"
		min: PPM2.MIN_HOLE
		max: PPM2.MAX_HOLE
		type: 'FLOAT'
		modifiers: true
	}

	PPM2.PonyDataRegistry["eye_rotation#{internal}"] = {
		default: -> 0
		getFunc: "EyeRotation#{publicName}"
		min: PPM2.MIN_EYE_ROTATION
		max: PPM2.MAX_EYE_ROTATION
		type: 'INT'
	}

for i = 1, 3
	PPM2.PonyDataRegistry["horn_url_#{i}"] = {
		default: -> ''
		getFunc: "HornURL#{i}"
		type: 'URL'
	}

	PPM2.PonyDataRegistry["bat_wing_url_#{i}"] = {
		default: -> ''
		getFunc: "BatWingURL#{i}"
		type: 'URL'
	}

	PPM2.PonyDataRegistry["bat_wing_skin_url_#{i}"] = {
		default: -> ''
		getFunc: "BatWingSkinURL#{i}"
		type: 'URL'
	}

	PPM2.PonyDataRegistry["wings_url_#{i}"] = {
		default: -> ''
		getFunc: "WingsURL#{i}"
		type: 'URL'
	}

	PPM2.PonyDataRegistry["horn_url_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "HornURLColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["bat_wing_url_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "BatWingURLColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["bat_wing_skin_url_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "BatWingSkinURLColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["wings_url_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "WingsURLColor#{i}"
		type: 'COLOR'
	}

for i = 1, 6
	PPM2.PonyDataRegistry["socks_detail_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "SocksDetailColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["mane_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "ManeColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["mane_detail_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "ManeDetailColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["mane_url_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "ManeURLColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["mane_url_#{i}"] = {
		default: -> ''
		getFunc: "ManeURL#{i}"
		type: 'URL'
	}

	PPM2.PonyDataRegistry["tail_detail_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "TailDetailColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["tail_url_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "TailURLColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["tail_url_#{i}"] = {
		default: -> ''
		getFunc: "TailURL#{i}"
		type: 'URL'
	}

	PPM2.PonyDataRegistry["tail_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "TailColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["lower_mane_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "LowerManeColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["lower_mane_url_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "LowerManeURLColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["lower_mane_url_#{i}"] = {
		default: -> ''
		getFunc: "LowerManeURL#{i}"
		type: 'URL'
	}

	PPM2.PonyDataRegistry["upper_mane_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "UpperManeColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["upper_mane_url_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "UpperManeURLColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["upper_mane_url_#{i}"] = {
		default: -> ''
		getFunc: "UpperManeURL#{i}"
		type: 'URL'
	}

	PPM2.PonyDataRegistry["lower_mane_detail_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "LowerManeDetailColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["upper_mane_detail_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "UpperManeDetailColor#{i}"
		type: 'COLOR'
	}

for i = 1, PPM2.MAX_BODY_DETAILS
	PPM2.PonyDataRegistry["body_detail_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "BodyDetailColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["body_detail_#{i}"] = {
		default: -> 0
		getFunc: "BodyDetail#{i}"
		enum: [arg for _, arg in ipairs PPM2.BodyDetailsEnum]
	}

	PPM2.PonyDataRegistry["body_detail_url_#{i}"] = {
		default: -> ''
		getFunc: "BodyDetailURL#{i}"
		type: 'URL'
	}

	PPM2.PonyDataRegistry["body_detail_url_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "BodyDetailURLColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["body_detail_glow_#{i}"] = {
		default: -> false
		getFunc: "BodyDetailGlow#{i}"
		type: 'BOOLEAN'
	}

	PPM2.PonyDataRegistry["body_detail_glow_strength_#{i}"] = {
		default: -> 1
		getFunc: "BodyDetailGlowStrength#{i}"
		type: 'FLOAT'
		min: 0
		max: 1
	}

for i = 1, PPM2.MAX_TATTOOS
	PPM2.PonyDataRegistry["tattoo_type_#{i}"] = {
		default: -> 0
		getFunc: "TattooType#{i}"
		enum: [arg for _, arg in ipairs PPM2.TATTOOS_REGISTRY]
	}

	PPM2.PonyDataRegistry["tattoo_posx_#{i}"] = {
		default: -> 0
		getFunc: "TattooPosX#{i}"
		min: -100
		max: 100
		type: 'FLOAT'
	}

	PPM2.PonyDataRegistry["tattoo_posy_#{i}"] = {
		default: -> 0
		getFunc: "TattooPosY#{i}"
		fix: (arg = 0) -> math.Clamp(tonumber(arg) or 0, -100, 100)
		min: -100
		max: 100
		type: 'FLOAT'
	}

	PPM2.PonyDataRegistry["tattoo_rotate_#{i}"] = {
		default: -> 0
		getFunc: "TattooRotate#{i}"
		min: -180
		max: 180
		type: 'INT'
	}

	PPM2.PonyDataRegistry["tattoo_scalex_#{i}"] = {
		default: -> 1
		getFunc: "TattooScaleX#{i}"
		min: 0
		max: 10
		type: 'FLOAT'
	}

	PPM2.PonyDataRegistry["tattoo_glow_strength_#{i}"] = {
		default: -> 1
		getFunc: "TattooGlowStrength#{i}"
		min: 0
		max: 1
		type: 'FLOAT'
	}

	PPM2.PonyDataRegistry["tattoo_scaley_#{i}"] = {
		default: -> 1
		getFunc: "TattooScaleY#{i}"
		min: 0
		max: 10
		type: 'FLOAT'
	}

	PPM2.PonyDataRegistry["tattoo_glow_#{i}"] = {
		default: -> false
		getFunc: "TattooGlow#{i}"
		type: 'BOOLEAN'
	}

	PPM2.PonyDataRegistry["tattoo_over_detail_#{i}"] = {
		default: -> false
		getFunc: "TattooOverDetail#{i}"
		type: 'BOOLEAN'
	}

	PPM2.PonyDataRegistry["tattoo_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "TattooColor#{i}"
		type: 'COLOR'
	}

for _, ttype in ipairs {'Body', 'Horn', 'Wings', 'BatWingsSkin', 'Socks', 'Mane', 'Tail', 'UpperMane', 'LowerMane', 'LEye', 'REye', 'BEyes', 'Eyelashes', 'Mouth', 'Teeth', 'Tongue'}
	PPM2.PonyDataRegistry[ttype\lower() .. '_phong_exponent'] = {
		default: -> 3
		getFunc: ttype .. 'PhongExponent'
		min: 0.04
		max: 10
		type: 'FLOAT'
	}

	PPM2.PonyDataRegistry[ttype\lower() .. '_phong_boost'] = {
		default: -> 0.09
		getFunc: ttype .. 'PhongBoost'
		min: 0.01
		max: 1
		type: 'FLOAT'
	}

	PPM2.PonyDataRegistry[ttype\lower() .. '_phong_front'] = {
		default: -> 1
		getFunc: ttype .. 'PhongFront'
		min: 0
		max: 20
		type: 'FLOAT'
	}

	PPM2.PonyDataRegistry[ttype\lower() .. '_phong_middle'] = {
		default: -> 5
		getFunc: ttype .. 'PhongMiddle'
		min: 0
		max: 20
		type: 'FLOAT'
	}

	PPM2.PonyDataRegistry[ttype\lower() .. '_phong_sliding'] = {
		default: -> 10
		getFunc: ttype .. 'PhongSliding'
		min: 0
		max: 20
		type: 'FLOAT'
	}

	PPM2.PonyDataRegistry[ttype\lower() .. '_phong_tint'] = {
		default: -> Color(255, 200, 200)
		getFunc: ttype .. 'PhongTint'
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry[ttype\lower() .. '_lightwarp_texture'] = {
		default: -> 0
		getFunc: ttype .. 'Lightwarp'
		enum: [arg for _, arg in ipairs PPM2.AvaliableLightwarps]
	}

	PPM2.PonyDataRegistry[ttype\lower() .. '_lightwarp_texture_url'] = {
		default: -> ''
		getFunc: ttype .. 'LightwarpURL'
		type: 'URL'
	}

	PPM2.PonyDataRegistry[ttype\lower() .. '_bumpmap_texture_url'] = {
		default: -> ''
		getFunc: ttype .. 'BumpmapURL'
		type: 'URL'
	}

for _, {:flex, :active} in ipairs PPM2.PonyFlexController.FLEX_LIST
	continue if not active
	PPM2.PonyDataRegistry["flex_disable_#{flex\lower()}"] = {
		default: -> false
		getFunc: "DisableFlex#{flex}"
		type: 'BOOLEAN'
	}

testMinimalBits = 0

for key, value in pairs PPM2.PonyDataRegistry
	if value.enum
		value.min = 0
		value.max = #value.enum - 1
		value.type = 'INT'

	switch value.type
		when 'INT'
			error("Variable #{key} has invalid minimal value (#{type(value.min)})") if type(value.min) ~= 'number'
			error("Variable #{max} has invalid maximal value (#{type(value.max)})") if type(value.max) ~= 'number'
			value.fix = INT_FIXER(value.default, value.min, value.max)
			if value.min >= 0
				selectBits = net.ChooseOptimalBits(value.max - value.min)
				testMinimalBits += selectBits
				value.read = rUInt(selectBits, value.min, value.max)
				value.write = wUInt(value.default(), selectBits)
			else
				selectBits = net.ChooseOptimalBits(math.max(math.abs(value.max), math.abs(value.min)))
				testMinimalBits += selectBits
				value.read = rInt(selectBits, value.min, value.max)
				value.write = wInt(value.default(), selectBits)
		when 'FLOAT'
			error("Variable #{key} has invalid minimal value (#{type(value.min)})") if type(value.min) ~= 'number'
			error("Variable #{max} has invalid maximal value (#{type(value.max)})") if type(value.max) ~= 'number'
			value.fix = FLOAT_FIXER(value.default, value.min, value.max)
			value.read = rFloat(value.min, value.max)
			value.write = (arg = value.default()) -> wFloat(arg)
			testMinimalBits += 32
		when 'URL'
			value.fix = URL_FIXER
			value.read = rURL
			value.write = wString
			testMinimalBits += 8
		when 'BOOLEAN'
			value.fix = (arg = value.default()) -> tobool(arg)
			value.read = rBool
			value.write = wBool
			testMinimalBits += 1
		when 'COLOR'
			{:r, :g, :b, :a} = value.default()
			value.fix = COLOR_FIXER(r, g, b, a)
			value.read = rColor
			value.write = wColor
			testMinimalBits += 32
		else
			error("Unknown variable type - #{value.type} for #{key}")

-- print('Minimal required bits - ' .. testMinimalBits)
PPM2.testMinimalBits = testMinimalBits

for key, value in pairs PPM2.PonyDataRegistry
	error("Data has no fix function: #{key}") if not value.fix

--
-- Copyright (C) 2017-2018 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.

wUInt = (def = 0, size = 8) ->
	return (arg = def) -> net.WriteUInt(arg, size)

wInt = (def = 0, size = 8) ->
	return (arg = def) -> net.WriteInt(arg, size)

rUInt = (size = 8, min = 0, max = 255) ->
	return -> math.Clamp(net.ReadUInt(size), min, max)

rInt = (size = 8, min = -128, max = 127) ->
	return -> math.Clamp(net.ReadInt(size), min, max)

rFloat = (min = 0, max = 255) ->
	return -> math.Clamp(net.ReadFloat(), min, max)

wFloat = net.WriteFloat
rBool = net.ReadBool
wBool = net.WriteBool
rColor = net.ReadColor
wColor = net.WriteColor
rString = net.ReadString
wString = net.WriteString

COLOR_FIXER = (r = 255, g = 255, b = 255, a = 255) ->
	func = (arg = Color(r, g, b, a)) ->
		if type(arg) ~= 'table'
			return Color(255, 255, 255)
		else
			{:r, :g, :b, :a} = arg
			if r and g and b and a
				return Color(r, g, b, a)
			else
				return Color(255, 255, 255)
	return func

URL_FIXER = (arg = '') ->
	arg = tostring(arg)
	if arg\find('^https?://')
		return arg
	else
		return ''

rURL = -> URL_FIXER(rString())

FLOAT_FIXER = (def = 1, min = 0, max = 1) ->
	defFunc = -> def if type(def) ~= 'function'
	defFunc = def if type(def) == 'function'
	return (arg = defFunc()) -> math.Clamp(tonumber(arg) or defFunc(), min, max)

INT_FIXER = (def = 1, min = 0, max = 1) ->
	defFunc = -> def if type(def) ~= 'function'
	defFunc = def if type(def) == 'function'
	return (arg = defFunc()) -> math.floor(math.Clamp(tonumber(arg) or defFunc(), min, max))

PPM2.PonyDataRegistry = {
	'age': {
		default: -> PPM2.AGE_ADULT
		getFunc: 'Age'
		enum: {'FILLY', 'ADULT', 'MATURE'}
	}

	'race': {
		default: -> PPM2.RACE_EARTH
		getFunc: 'Race'
		enum: [arg for _, arg in ipairs PPM2.RACE_ENUMS]
	}

	'wings_type': {
		default: -> 0
		getFunc: 'WingsType'
		enum: [arg for _, arg in ipairs PPM2.AvaliablePonyWings]
	}

	'gender': {
		default: -> PPM2.GENDER_FEMALE
		getFunc: 'Gender'
		enum: [arg for _, arg in ipairs PPM2.AGE_ENUMS]
	}

	'weight': {
		default: -> 1
		getFunc: 'Weight'
		min: PPM2.MIN_WEIGHT
		max: PPM2.MAX_WEIGHT
		type: 'FLOAT'
	}

	'ponysize': {
		default: -> 1
		getFunc: 'PonySize'
		min: PPM2.MIN_SCALE
		max: PPM2.MAX_SCALE
		type: 'FLOAT'
	}

	'necksize': {
		default: -> 1
		getFunc: 'NeckSize'
		min: PPM2.MIN_NECK
		max: PPM2.MAX_NECK
		type: 'FLOAT'
	}

	'legssize': {
		default: -> 1
		getFunc: 'LegsSize'
		min: PPM2.MIN_LEGS
		max: PPM2.MAX_LEGS
		type: 'FLOAT'
	}

	'spinesize': {
		default: -> 1
		getFunc: 'BackSize'
		min: PPM2.MIN_SPINE
		max: PPM2.MAX_SPINE
		type: 'FLOAT'
	}

	'male_buff': {
		default: -> PPM2.DEFAULT_MALE_BUFF
		getFunc: 'MaleBuff'
		min: PPM2.MIN_MALE_BUFF
		max: PPM2.MAX_MALE_BUFF
		type: 'FLOAT'
	}

	'eyelash': {
		default: -> 0
		getFunc: 'EyelashType'
		enum: [arg for _, arg in ipairs PPM2.EyelashTypes]
	}

	'tail': {
		default: -> 0
		getFunc: 'TailType'
		enum: [arg for _, arg in ipairs PPM2.AvaliableTails]
	}

	'tail_new': {
		default: -> 0
		getFunc: 'TailTypeNew'
		enum: [arg for _, arg in ipairs PPM2.AvaliableTailsNew]
	}

	'mane': {
		default: -> 0
		getFunc: 'ManeType'
		enum: [arg for _, arg in ipairs PPM2.AvaliableUpperManes]
	}

	'mane_new': {
		default: -> 0
		getFunc: 'ManeTypeNew'
		enum: [arg for _, arg in ipairs PPM2.AvaliableUpperManesNew]
	}

	'manelower': {
		default: -> 0
		getFunc: 'ManeTypeLower'
		enum: [arg for _, arg in ipairs PPM2.AvaliableLowerManes]
	}

	'manelower_new': {
		default: -> 0
		getFunc: 'ManeTypeLowerNew'
		enum: [arg for _, arg in ipairs PPM2.AvaliableLowerManesNew]
	}

	'socks_texture': {
		default: -> 0
		getFunc: 'SocksTexture'
		enum: [arg for _, arg in ipairs PPM2.SocksTypes]
	}

	'socks_texture_url': {
		default: -> ''
		getFunc: 'SocksTextureURL'
		type: 'URL'
	}

	'tailsize': {
		default: -> 1
		getFunc: 'TailSize'
		min: PPM2.MIN_TAIL_SIZE
		max: PPM2.MAX_TAIL_SIZE
		type: 'FLOAT'
	}

	'cmark': {
		default: -> true
		getFunc: 'CMark'
		type: 'BOOLEAN'
	}

	'cmark_size': {
		default: -> 1
		getFunc: 'CMarkSize'
		min: 0
		max: 1
		type: 'FLOAT'
	}

	'cmark_color': {
		default: -> Color(255, 255, 255)
		getFunc: 'CMarkColor'
		type: 'COLOR'
	}

	'eyelash_color': {
		default: -> Color(0, 0, 0)
		getFunc: 'EyelashesColor'
		type: 'COLOR'
	}

	'eyelashes_phong_separate': {
		default: -> false
		getFunc: 'SeparateEyelashesPhong'
		type: 'BOOLEAN'
	}

	'fangs': {
		default: -> false
		getFunc: 'Fangs'
		type: 'BOOLEAN'
	}

	'bat_pony_ears': {
		default: -> false
		getFunc: 'BatPonyEars'
		type: 'BOOLEAN'
	}

	'claw_teeth': {
		default: -> false
		getFunc: 'ClawTeeth'
		type: 'BOOLEAN'
	}

	'cmark_type': {
		default: -> 4
		getFunc: 'CMarkType'
		enum: [arg for _, arg in ipairs PPM2.DefaultCutiemarks]
	}

	'cmark_url': {
		default: -> ''
		getFunc: 'CMarkURL'
		type: 'URL'
	}

	'body': {
		default: -> Color(255, 255, 255)
		getFunc: 'BodyColor'
		type: 'COLOR'
	}

	'eyebrows': {
		default: -> Color(0, 0, 0)
		getFunc: 'EyebrowsColor'
		type: 'COLOR'
	}

	'eyebrows_glow': {
		default: -> false
		getFunc: 'GlowingEyebrows'
		type: 'BOOLEAN'
	}

	'eyebrows_glow_strength': {
		default: -> 1
		getFunc: 'EyebrowsGlowStrength'
		type: 'FLOAT'
		min: 0
		max: 1
	}

	'hide_manes': {
		default: -> true
		getFunc: 'HideManes'
		type: 'BOOLEAN'
	}

	'hide_manes_socks': {
		default: -> true
		getFunc: 'HideManesSocks'
		type: 'BOOLEAN'
	}

	'hide_manes_mane': {
		default: -> true
		getFunc: 'HideManesMane'
		type: 'BOOLEAN'
	}

	'hide_manes_tail': {
		default: -> true
		getFunc: 'HideManesTail'
		type: 'BOOLEAN'
	}

	'horn_color': {
		default: -> Color(255, 255, 255)
		getFunc: 'HornColor'
		type: 'COLOR'
	}

	'wings_color': {
		default: -> Color(255, 255, 255)
		getFunc: 'WingsColor'
		type: 'COLOR'
	}

	'separate_wings': {
		default: -> false
		getFunc: 'SeparateWings'
		type: 'BOOLEAN'
	}

	'separate_horn': {
		default: -> false
		getFunc: 'SeparateHorn'
		type: 'BOOLEAN'
	}

	'separate_magic_color': {
		default: -> false
		getFunc: 'SeparateMagicColor'
		type: 'BOOLEAN'
	}

	'horn_magic_color': {
		default: -> Color(255, 255, 255)
		getFunc: 'HornMagicColor'
		type: 'COLOR'
	}

	'horn_glow': {
		default: -> false
		getFunc: 'HornGlow'
		type: 'BOOLEAN'
	}

	'horn_glow_strength': {
		default: -> 1
		getFunc: 'HornGlowSrength'
		min: 0
		max: 1
		type: 'FLOAT'
	}

	'horn_detail_color': {
		default: -> Color(90, 90, 90)
		getFunc: 'HornDetailColor'
		type: 'COLOR'
	}

	'separate_eyes': {
		default: -> false
		getFunc: 'SeparateEyes'
		type: 'BOOLEAN'
	}

	'separate_mane': {
		default: -> false
		getFunc: 'SeparateMane'
		type: 'BOOLEAN'
	}

	'socks': {
		default: -> false
		getFunc: 'Socks'
		type: 'BOOLEAN'
	}

	'new_male_muzzle': {
		default: -> true
		getFunc: 'NewMuzzle'
		type: 'BOOLEAN'
	}

	'noflex': {
		default: -> false
		getFunc: 'NoFlex'
		type: 'BOOLEAN'
	}

	'socks_model': {
		default: -> false
		getFunc: 'SocksAsModel'
		type: 'BOOLEAN'
	}

	'socks_model_new': {
		default: -> false
		getFunc: 'SocksAsNewModel'
		type: 'BOOLEAN'
	}

	'socks_model_color': {
		default: -> Color(255, 255, 255)
		getFunc: 'SocksColor'
		type: 'COLOR'
	}

	'socks_new_model_color1': {
		default: -> Color(255, 255, 255)
		getFunc: 'NewSocksColor1'
		type: 'COLOR'
	}

	'socks_new_model_color2': {
		default: -> Color(0, 0, 0)
		getFunc: 'NewSocksColor2'
		type: 'COLOR'
	}

	'socks_new_model_color3': {
		default: -> Color(0, 0, 0)
		getFunc: 'NewSocksColor3'
		type: 'COLOR'
	}

	'socks_new_texture_url': {
		default: -> ''
		getFunc: 'NewSocksTextureURL'
		type: 'URL'
	}

	'suit': {
		default: -> 0
		getFunc: 'Bodysuit'
		enum: [arg for _, arg in ipairs PPM2.AvaliablePonySuits]
	}

	'left_wing_size': {
		default: -> 1
		getFunc: 'LWingSize'
		min: PPM2.MIN_WING
		max: PPM2.MAX_WING
		type: 'FLOAT'
	}

	'left_wing_x': {
		default: -> 0
		getFunc: 'LWingX'
		min: PPM2.MIN_WINGX
		max: PPM2.MAX_WINGX
		type: 'FLOAT'
	}

	'left_wing_y': {
		default: -> 0
		getFunc: 'LWingY'
		min: PPM2.MIN_WINGY
		max: PPM2.MAX_WINGY
		type: 'FLOAT'
	}

	'left_wing_z': {
		default: -> 0
		getFunc: 'LWingZ'
		min: PPM2.MIN_WINGZ
		max: PPM2.MAX_WINGZ
		type: 'FLOAT'
	}

	'right_wing_size': {
		default: -> 1
		getFunc: 'RWingSize'
		min: PPM2.MIN_WING
		max: PPM2.MAX_WING
		type: 'FLOAT'
	}

	'right_wing_x': {
		default: -> 0
		getFunc: 'RWingX'
		min: PPM2.MIN_WINGX
		max: PPM2.MAX_WINGX
		type: 'FLOAT'
	}

	'right_wing_y': {
		default: -> 0
		getFunc: 'RWingY'
		min: PPM2.MIN_WINGY
		max: PPM2.MAX_WINGY
		type: 'FLOAT'
	}

	'right_wing_z': {
		default: -> 0
		getFunc: 'RWingZ'
		min: PPM2.MIN_WINGZ
		max: PPM2.MAX_WINGZ
		type: 'FLOAT'
	}

	'teeth_color': {
		default: -> Color(255, 255, 255)
		getFunc: 'TeethColor'
		type: 'COLOR'
	}

	'mouth_color': {
		default: -> Color(219, 65, 155)
		getFunc: 'MouthColor'
		type: 'COLOR'
	}

	'tongue_color': {
		default: -> Color(235, 131, 59)
		getFunc: 'TongueColor'
		type: 'COLOR'
	}

	'bat_wing_color': {
		default: -> Color(255, 255, 255)
		getFunc: 'BatWingColor'
		type: 'COLOR'
	}

	'bat_wing_skin_color': {
		default: -> Color(255, 255, 255)
		getFunc: 'BatWingSkinColor'
		type: 'COLOR'
	}

	'separate_horn_phong': {
		default: -> false
		getFunc: 'SeparateHornPhong'
		type: 'BOOLEAN'
	}

	'separate_wings_phong': {
		default: -> false
		getFunc: 'SeparateWingsPhong'
		type: 'BOOLEAN'
	}

	'separate_mane_phong': {
		default: -> false
		getFunc: 'SeparateManePhong'
		type: 'BOOLEAN'
	}

	'separate_tail_phong': {
		default: -> false
		getFunc: 'SeparateTailPhong'
		type: 'BOOLEAN'
	}

	'alternative_fangs': {
		default: -> false
		getFunc: 'AlternativeFangs'
		type: 'BOOLEAN'
	}

	'hoof_fluffers': {
		default: -> false
		getFunc: 'HoofFluffers'
		type: 'BOOLEAN'
	}

	'hoof_fluffers_strength': {
		default: -> 1
		getFunc: 'HoofFluffersStrength'
		min: 0
		max: 1
		type: 'FLOAT'
	}

	'ears_size': {
		default: -> 1
		getFunc: 'EarsSize'
		min: 0.1
		max: 2
		type: 'FLOAT'
	}

	'bat_pony_ears_strength': {
		default: -> 1
		getFunc: 'BatPonyEarsStrength'
		min: 0
		max: 1
		type: 'FLOAT'
	}

	'fangs_strength': {
		default: -> 1
		getFunc: 'FangsStrength'
		min: 0
		max: 1
		type: 'FLOAT'
	}

	'clawteeth_strength': {
		default: -> 1
		getFunc: 'ClawTeethStrength'
		min: 0
		max: 1
		type: 'FLOAT'
	}

	'lips_color_inherit': {
		default: -> true
		getFunc: 'LipsColorInherit'
		type: 'BOOLEAN'
	}

	'nose_color_inherit': {
		default: -> true
		getFunc: 'NoseColorInherit'
		type: 'BOOLEAN'
	}

	'lips_color': {
		default: -> Color(172, 92, 92)
		getFunc: 'LipsColor'
		type: 'COLOR'
	}

	'nose_color': {
		default: -> Color(77, 84, 83)
		getFunc: 'NoseColor'
		type: 'COLOR'
	}

	'weapon_hide': {
		default: -> true
		getFunc: 'HideWeapons'
		type: 'BOOLEAN'
	}
}

for _, {internal, publicName} in ipairs {{'_left', 'Left'}, {'_right', 'Right'}, {'', ''}}
	PPM2.PonyDataRegistry["eye_url#{internal}"] = {
		default: -> ''
		getFunc: "EyeURL#{publicName}"
		type: 'URL'
	}

	PPM2.PonyDataRegistry["eye_bg#{internal}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "EyeBackground#{publicName}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["eye_hole#{internal}"] = {
		default: -> Color(0, 0, 0)
		getFunc: "EyeHole#{publicName}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["eye_iris1#{internal}"] = {
		default: -> Color(200, 200, 200)
		getFunc: "EyeIrisTop#{publicName}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["eye_iris2#{internal}"] = {
		default: -> Color(200, 200, 200)
		getFunc: "EyeIrisBottom#{publicName}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["eye_irisline1#{internal}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "EyeIrisLine1#{publicName}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["eye_irisline_direction#{internal}"] = {
		default: -> false
		getFunc: "EyeLineDirection#{publicName}"
		type: 'BOOLEAN'
	}

	PPM2.PonyDataRegistry["eye_irisline2#{internal}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "EyeIrisLine2#{publicName}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["eye_reflection#{internal}"] = {
		default: -> Color(255, 255, 255, 127)
		getFunc: "EyeReflection#{publicName}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["eye_effect#{internal}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "EyeEffect#{publicName}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["eye_lines#{internal}"] = {
		default: -> true
		getFunc: "EyeLines#{publicName}"
		type: 'BOOLEAN'
	}

	PPM2.PonyDataRegistry["eye_iris_size#{internal}"] = {
		default: -> 1
		getFunc: "IrisSize#{publicName}"
		min: PPM2.MIN_IRIS
		max: PPM2.MAX_IRIS
		type: 'FLOAT'
		modifiers: true
	}

	PPM2.PonyDataRegistry["eye_derp#{internal}"] = {
		default: -> false
		getFunc: "DerpEyes#{publicName}"
		type: 'BOOLEAN'
	}

	PPM2.PonyDataRegistry["eye_use_refract#{internal}"] = {
		default: -> false
		getFunc: "EyeRefract#{publicName}"
		type: 'BOOLEAN'
	}

	PPM2.PonyDataRegistry["eye_cornera#{internal}"] = {
		default: -> false
		getFunc: "EyeCornerA#{publicName}"
		type: 'BOOLEAN'
	}

	PPM2.PonyDataRegistry["eye_derp_strength#{internal}"] = {
		default: -> 1
		getFunc: "DerpEyesStrength#{publicName}"
		min: PPM2.MIN_DERP_STRENGTH
		max: PPM2.MAX_DERP_STRENGTH
		type: 'FLOAT'
		modifiers: true
	}

	PPM2.PonyDataRegistry["eye_type#{internal}"] = {
		default: -> 0
		getFunc: "EyeType#{publicName}"
		enum: [arg for _, arg in ipairs PPM2.AvaliableEyeTypes]
	}

	PPM2.PonyDataRegistry["eye_reflection_type#{internal}"] = {
		default: -> 0
		getFunc: "EyeReflectionType#{publicName}"
		enum: [arg for _, arg in ipairs PPM2.AvaliableEyeReflections]
	}

	PPM2.PonyDataRegistry["hole_width#{internal}"] = {
		default: -> 1
		getFunc: "HoleWidth#{publicName}"
		min: PPM2.MIN_PUPIL_SIZE
		max: PPM2.MAX_PUPIL_SIZE
		type: 'FLOAT'
		modifiers: true
	}

	PPM2.PonyDataRegistry["hole_height#{internal}"] = {
		default: -> 1
		getFunc: "HoleHeight#{publicName}"
		min: PPM2.MIN_PUPIL_SIZE
		max: PPM2.MAX_PUPIL_SIZE
		type: 'FLOAT'
		modifiers: true
	}

	PPM2.PonyDataRegistry["iris_width#{internal}"] = {
		default: -> 1
		getFunc: "IrisWidth#{publicName}"
		min: PPM2.MIN_PUPIL_SIZE
		max: PPM2.MAX_PUPIL_SIZE
		type: 'FLOAT'
		modifiers: true
	}

	PPM2.PonyDataRegistry["iris_height#{internal}"] = {
		default: -> 1
		getFunc: "IrisHeight#{publicName}"
		min: PPM2.MIN_PUPIL_SIZE
		max: PPM2.MAX_PUPIL_SIZE
		type: 'FLOAT'
		modifiers: true
	}

	PPM2.PonyDataRegistry["eye_glossy_reflection#{internal}"] = {
		default: -> 0.16
		getFunc: "EyeGlossyStrength#{publicName}"
		min: 0
		max: 1
		type: 'FLOAT'
	}

	PPM2.PonyDataRegistry["hole_shiftx#{internal}"] = {
		default: -> 0
		getFunc: "HoleShiftX#{publicName}"
		min: PPM2.MIN_HOLE_SHIFT
		max: PPM2.MAX_HOLE_SHIFT
		type: 'FLOAT'
		modifiers: true
	}

	PPM2.PonyDataRegistry["hole_shifty#{internal}"] = {
		default: -> 0
		getFunc: "HoleShiftY#{publicName}"
		min: PPM2.MIN_HOLE_SHIFT
		max: PPM2.MAX_HOLE_SHIFT
		type: 'FLOAT'
		modifiers: true
	}

	PPM2.PonyDataRegistry["eye_hole_size#{internal}"] = {
		default: -> .8
		getFunc: "HoleSize#{publicName}"
		min: PPM2.MIN_HOLE
		max: PPM2.MAX_HOLE
		type: 'FLOAT'
		modifiers: true
	}

	PPM2.PonyDataRegistry["eye_rotation#{internal}"] = {
		default: -> 0
		getFunc: "EyeRotation#{publicName}"
		min: PPM2.MIN_EYE_ROTATION
		max: PPM2.MAX_EYE_ROTATION
		type: 'INT'
	}

for i = 1, 3
	PPM2.PonyDataRegistry["horn_url_#{i}"] = {
		default: -> ''
		getFunc: "HornURL#{i}"
		type: 'URL'
	}

	PPM2.PonyDataRegistry["bat_wing_url_#{i}"] = {
		default: -> ''
		getFunc: "BatWingURL#{i}"
		type: 'URL'
	}

	PPM2.PonyDataRegistry["bat_wing_skin_url_#{i}"] = {
		default: -> ''
		getFunc: "BatWingSkinURL#{i}"
		type: 'URL'
	}

	PPM2.PonyDataRegistry["wings_url_#{i}"] = {
		default: -> ''
		getFunc: "WingsURL#{i}"
		type: 'URL'
	}

	PPM2.PonyDataRegistry["horn_url_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "HornURLColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["bat_wing_url_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "BatWingURLColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["bat_wing_skin_url_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "BatWingSkinURLColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["wings_url_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "WingsURLColor#{i}"
		type: 'COLOR'
	}

for i = 1, 6
	PPM2.PonyDataRegistry["socks_detail_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "SocksDetailColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["mane_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "ManeColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["mane_detail_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "ManeDetailColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["mane_url_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "ManeURLColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["mane_url_#{i}"] = {
		default: -> ''
		getFunc: "ManeURL#{i}"
		type: 'URL'
	}

	PPM2.PonyDataRegistry["tail_detail_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "TailDetailColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["tail_url_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "TailURLColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["tail_url_#{i}"] = {
		default: -> ''
		getFunc: "TailURL#{i}"
		type: 'URL'
	}

	PPM2.PonyDataRegistry["tail_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "TailColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["lower_mane_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "LowerManeColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["lower_mane_url_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "LowerManeURLColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["lower_mane_url_#{i}"] = {
		default: -> ''
		getFunc: "LowerManeURL#{i}"
		type: 'URL'
	}

	PPM2.PonyDataRegistry["upper_mane_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "UpperManeColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["upper_mane_url_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "UpperManeURLColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["upper_mane_url_#{i}"] = {
		default: -> ''
		getFunc: "UpperManeURL#{i}"
		type: 'URL'
	}

	PPM2.PonyDataRegistry["lower_mane_detail_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "LowerManeDetailColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["upper_mane_detail_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "UpperManeDetailColor#{i}"
		type: 'COLOR'
	}

for i = 1, PPM2.MAX_BODY_DETAILS
	PPM2.PonyDataRegistry["body_detail_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "BodyDetailColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["body_detail_#{i}"] = {
		default: -> 0
		getFunc: "BodyDetail#{i}"
		enum: [arg for _, arg in ipairs PPM2.BodyDetailsEnum]
	}

	PPM2.PonyDataRegistry["body_detail_url_#{i}"] = {
		default: -> ''
		getFunc: "BodyDetailURL#{i}"
		type: 'URL'
	}

	PPM2.PonyDataRegistry["body_detail_url_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "BodyDetailURLColor#{i}"
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry["body_detail_glow_#{i}"] = {
		default: -> false
		getFunc: "BodyDetailGlow#{i}"
		type: 'BOOLEAN'
	}

	PPM2.PonyDataRegistry["body_detail_glow_strength_#{i}"] = {
		default: -> 1
		getFunc: "BodyDetailGlowStrength#{i}"
		type: 'FLOAT'
		min: 0
		max: 1
	}

for i = 1, PPM2.MAX_TATTOOS
	PPM2.PonyDataRegistry["tattoo_type_#{i}"] = {
		default: -> 0
		getFunc: "TattooType#{i}"
		enum: [arg for _, arg in ipairs PPM2.TATTOOS_REGISTRY]
	}

	PPM2.PonyDataRegistry["tattoo_posx_#{i}"] = {
		default: -> 0
		getFunc: "TattooPosX#{i}"
		min: -100
		max: 100
		type: 'FLOAT'
	}

	PPM2.PonyDataRegistry["tattoo_posy_#{i}"] = {
		default: -> 0
		getFunc: "TattooPosY#{i}"
		fix: (arg = 0) -> math.Clamp(tonumber(arg) or 0, -100, 100)
		min: -100
		max: 100
		type: 'FLOAT'
	}

	PPM2.PonyDataRegistry["tattoo_rotate_#{i}"] = {
		default: -> 0
		getFunc: "TattooRotate#{i}"
		min: -180
		max: 180
		type: 'INT'
	}

	PPM2.PonyDataRegistry["tattoo_scalex_#{i}"] = {
		default: -> 1
		getFunc: "TattooScaleX#{i}"
		min: 0
		max: 10
		type: 'FLOAT'
	}

	PPM2.PonyDataRegistry["tattoo_glow_strength_#{i}"] = {
		default: -> 1
		getFunc: "TattooGlowStrength#{i}"
		min: 0
		max: 1
		type: 'FLOAT'
	}

	PPM2.PonyDataRegistry["tattoo_scaley_#{i}"] = {
		default: -> 1
		getFunc: "TattooScaleY#{i}"
		min: 0
		max: 10
		type: 'FLOAT'
	}

	PPM2.PonyDataRegistry["tattoo_glow_#{i}"] = {
		default: -> false
		getFunc: "TattooGlow#{i}"
		type: 'BOOLEAN'
	}

	PPM2.PonyDataRegistry["tattoo_over_detail_#{i}"] = {
		default: -> false
		getFunc: "TattooOverDetail#{i}"
		type: 'BOOLEAN'
	}

	PPM2.PonyDataRegistry["tattoo_color_#{i}"] = {
		default: -> Color(255, 255, 255)
		getFunc: "TattooColor#{i}"
		type: 'COLOR'
	}

for _, ttype in ipairs {'Body', 'Horn', 'Wings', 'BatWingsSkin', 'Socks', 'Mane', 'Tail', 'UpperMane', 'LowerMane', 'LEye', 'REye', 'BEyes', 'Eyelashes', 'Mouth', 'Teeth', 'Tongue'}
	PPM2.PonyDataRegistry[ttype\lower() .. '_phong_exponent'] = {
		default: -> 3
		getFunc: ttype .. 'PhongExponent'
		min: 0.04
		max: 10
		type: 'FLOAT'
	}

	PPM2.PonyDataRegistry[ttype\lower() .. '_phong_boost'] = {
		default: -> 0.09
		getFunc: ttype .. 'PhongBoost'
		min: 0.01
		max: 1
		type: 'FLOAT'
	}

	PPM2.PonyDataRegistry[ttype\lower() .. '_phong_front'] = {
		default: -> 1
		getFunc: ttype .. 'PhongFront'
		min: 0
		max: 20
		type: 'FLOAT'
	}

	PPM2.PonyDataRegistry[ttype\lower() .. '_phong_middle'] = {
		default: -> 5
		getFunc: ttype .. 'PhongMiddle'
		min: 0
		max: 20
		type: 'FLOAT'
	}

	PPM2.PonyDataRegistry[ttype\lower() .. '_phong_sliding'] = {
		default: -> 10
		getFunc: ttype .. 'PhongSliding'
		min: 0
		max: 20
		type: 'FLOAT'
	}

	PPM2.PonyDataRegistry[ttype\lower() .. '_phong_tint'] = {
		default: -> Color(255, 200, 200)
		getFunc: ttype .. 'PhongTint'
		type: 'COLOR'
	}

	PPM2.PonyDataRegistry[ttype\lower() .. '_lightwarp_texture'] = {
		default: -> 0
		getFunc: ttype .. 'Lightwarp'
		enum: [arg for _, arg in ipairs PPM2.AvaliableLightwarps]
	}

	PPM2.PonyDataRegistry[ttype\lower() .. '_lightwarp_texture_url'] = {
		default: -> ''
		getFunc: ttype .. 'LightwarpURL'
		type: 'URL'
	}

	PPM2.PonyDataRegistry[ttype\lower() .. '_bumpmap_texture_url'] = {
		default: -> ''
		getFunc: ttype .. 'BumpmapURL'
		type: 'URL'
	}

for _, {:flex, :active} in ipairs PPM2.PonyFlexController.FLEX_LIST
	continue if not active
	PPM2.PonyDataRegistry["flex_disable_#{flex\lower()}"] = {
		default: -> false
		getFunc: "DisableFlex#{flex}"
		type: 'BOOLEAN'
	}

testMinimalBits = 0

for key, value in pairs PPM2.PonyDataRegistry
	if value.enum
		value.min = 0
		value.max = #value.enum - 1
		value.type = 'INT'

	switch value.type
		when 'INT'
			error("Variable #{key} has invalid minimal value (#{type(value.min)})") if type(value.min) ~= 'number'
			error("Variable #{max} has invalid maximal value (#{type(value.max)})") if type(value.max) ~= 'number'
			value.fix = INT_FIXER(value.default, value.min, value.max)
			if value.min >= 0
				selectBits = net.ChooseOptimalBits(value.max - value.min)
				testMinimalBits += selectBits
				value.read = rUInt(selectBits, value.min, value.max)
				value.write = wUInt(value.default(), selectBits)
			else
				selectBits = net.ChooseOptimalBits(math.max(math.abs(value.max), math.abs(value.min)))
				testMinimalBits += selectBits
				value.read = rInt(selectBits, value.min, value.max)
				value.write = wInt(value.default(), selectBits)
		when 'FLOAT'
			error("Variable #{key} has invalid minimal value (#{type(value.min)})") if type(value.min) ~= 'number'
			error("Variable #{max} has invalid maximal value (#{type(value.max)})") if type(value.max) ~= 'number'
			value.fix = FLOAT_FIXER(value.default, value.min, value.max)
			value.read = rFloat(value.min, value.max)
			value.write = (arg = value.default()) -> wFloat(arg)
			testMinimalBits += 32
		when 'URL'
			value.fix = URL_FIXER
			value.read = rURL
			value.write = wString
			testMinimalBits += 8
		when 'BOOLEAN'
			value.fix = (arg = value.default()) -> tobool(arg)
			value.read = rBool
			value.write = wBool
			testMinimalBits += 1
		when 'COLOR'
			{:r, :g, :b, :a} = value.default()
			value.fix = COLOR_FIXER(r, g, b, a)
			value.read = rColor
			value.write = wColor
			testMinimalBits += 32
		else
			error("Unknown variable type - #{value.type} for #{key}")

-- print('Minimal required bits - ' .. testMinimalBits)
PPM2.testMinimalBits = testMinimalBits

for key, value in pairs PPM2.PonyDataRegistry
	error("Data has no fix function: #{key}") if not value.fix


github: some color to increase readability

Former-commit-id: dbfea1ee2774f6c6ed89732bece20e451bcd452e
Former-commit-id: 85ee1a2926d787ace4f0d23f26a594a3ae951869

util = require 'util'

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

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

acolor = (action) ->
  if action == 'opened'
    return util.green action
  if action == 'closed'
    return util.red action
  if action == 'deleted'
    return util.red action
  if action == 'synchronize'
    return util.purple action

  return action

handlers = {
  push: (repo, destination, json) ->
    branch = util.bold(json.ref\gsub 'refs/heads/', '')
    for i, c in pairs(json.commits)
      if i > 3
        break
      message = c.message\gsub '\n.*', ''
      if i == 1
        message = message .. ' ' .. json.compare
      ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{branch}, #{util.nonickalertword c.author.username}: #{message}"
    if #json.commits >= 4
      ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{branch}, #{#json.commits-3} more commits not displayed."
  watch: (repo, destination, json) ->
    action = json.action
    if action == 'started'
      ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: +1 #{util.yellow '★'} (Total: #{json.repository.stargazers_count})"
    else
      ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: #{action} watching"
  ping: (repo, destination, json) ->
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: ping"
  commit_comment: (repo, destination, json) ->
    --commenter = json.comment.user.login
    body = json.comment.body
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: <#{util.nonickalertword json.sender.login}> #{body}"
  pull_request: (repo, destination, json) ->
    action = acolor json.action
    number = util.bold json.number
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: #{action} PR ##{number}: #{json.pull_request.title} #{json.pull_request.html_url}"
  pull_request_review_comment: (repo, destination, json) ->
    body = json.comment.body
    number = util.bold json.pull_request.number
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: PR ##{number} <#{util.nonickalertword json.sender.login}> #{body}"
  issues: (repo, destination, json) ->
    action = acolor json.action
    nr = util.bold json.issue.number
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: #{action} issue ##{nr}: #{json.issue.title} #{json.issue.html_url}"
  issue_comment: (repo, destination, json) ->
    action = acolor json.action
    nr = util.bold json.issue.number
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: Issue ##{nr} <#{util.nonickalertword json.sender.login}> #{json.comment.body} #{json.issue.html_url}"
  fork: (repo, destination, json) ->
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: forked to #{json.forkee.html_url}"
  create: (repo, destination, json) ->
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: created #{json.ref_type} #{util.bold json.ref}"
  delete: (repo, destination, json) ->
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: deleted #{json.ref_type} #{util.bold json.ref}"
  gollum: (repo, destination, json) ->
    return
  release: (repo, destination, json) ->
    return
}

ivar2.webserver.regUrl '/github/(.*)', (req, res) ->
  destination = req.url\match('/github/(.+)/?$')
  destination = unescape(destination)
  json = util.json.decode(req.body)

  repo = json.repository.full_name

  event = req.headers['X-GitHub-Event']
  handler = handlers[event]
  if handler
    handler(repo, destination, json)
  else
    ivar2\Log('error', 'Unknown github event: %s', event)

  res\set_status(200)
  res\set_header('Content-Type', 'text/plain')
  res\set_body('ok')
  res\send()

return {}

util = require 'util'

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

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

handlers = {
  push: (repo, destination, json) ->
    branch = util.bold(json.ref\gsub 'refs/heads/', '')
    for i, c in pairs(json.commits)
      if i > 3
        break
      message = c.message\gsub '\n.*', ''
      if i == 1
        message = message .. ' ' .. json.compare
      ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{branch}, #{util.nonickalertword c.author.username}: #{message}"
    if #json.commits >= 4
      ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{branch}, #{#json.commits-3} more commits not displayed."
  watch: (repo, destination, json) ->
    action = json.action
    if action == 'started'
      ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: +1 ★ (Total: #{json.repository.stargazers_count})"
    else
      ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: #{action} watching"
  ping: (repo, destination, json) ->
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: ping"
  commit_comment: (repo, destination, json) ->
    --commenter = json.comment.user.login
    body = json.comment.body
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: <#{util.nonickalertword json.sender.login}> #{body}"
  pull_request: (repo, destination, json) ->
    action = json.action
    number = util.bold json.number
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: #{action} PR ##{number}: #{json.pull_request.title} #{json.pull_request.html_url}"
  pull_request_review_comment: (repo, destination, json) ->
    body = json.comment.body
    number = util.bold json.pull_request.number
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: PR ##{number} <#{util.nonickalertword json.sender.login}> #{body}"
  issues: (repo, destination, json) ->
    action = json.action
    nr = util.bold json.issue.number
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: #{action} issue ##{nr}: #{json.issue.title} #{json.issue.html_url}"
  issue_comment: (repo, destination, json) ->
    action = json.action
    nr = util.bold json.issue.number
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: Issue ##{nr} <#{util.nonickalertword json.sender.login}> #{json.comment.body} #{json.issue.html_url}"
  fork: (repo, destination, json) ->
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: forked to #{json.forkee.html_url}"
  create: (repo, destination, json) ->
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: created #{json.ref_type} #{util.bold json.ref}"
  delete: (repo, destination, json) ->
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: deleted #{json.ref_type} #{util.bold json.ref}"
  gollum: (repo, destination, json) ->
    return
  release: (repo, destination, json) ->
    return
}

ivar2.webserver.regUrl '/github/(.*)', (req, res) ->
  destination = req.url\match('/github/(.+)/?$')
  destination = unescape(destination)
  json = util.json.decode(req.body)

  repo = json.repository.full_name

  event = req.headers['X-GitHub-Event']
  handler = handlers[event]
  if handler
    handler(repo, destination, json)
  else
    ivar2\Log('error', 'Unknown github event: %s', event)

  res\set_status(200)
  res\set_header('Content-Type', 'text/plain')
  res\set_body('ok')
  res\send()

return {}


benis: remove unused import

benis: remove unused import

Former-commit-id: af3f44025e990fb1f86df83891b2df2a9caa27dd [formerly a266159c20f21e4e9a73107e0131d44c13f97d9a]
Former-commit-id: 39755fdc20209892946bf439dc0968231f85e603

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

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

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