Compare commits

..
12 Commits
Author SHA1 Message Date
josh 5ff83f6734 Add propane and initial scene grammar 2023-11-17 19:22:18 -05:00
josh 6e04286cc2 Default to 800x600 transparent image output 2023-10-11 09:58:21 -04:00
josh f8fc3518dd Update write_png() to take a Color array 2023-10-10 19:25:24 -04:00
josh 8c109a741b Add Vector struct 2023-10-10 17:25:56 -04:00
josh 5b734c315d Add "test" rscons task 2023-10-10 11:36:46 -04:00
josh 8170593d56 Add Color struct 2023-10-10 10:49:13 -04:00
josh e6c943aab4 Add fart.png to write RGBA PNG images 2023-10-10 10:29:00 -04:00
josh 5b449506cb Add fart.hton module 2023-10-09 19:13:11 -04:00
josh 42e2508766 Add crc32() 2023-10-09 19:06:51 -04:00
josh 9f39cddc24 Add BFile struct 2023-10-09 18:55:51 -04:00
josh 4c57df0774 Update Rsconscript and add main.d 2023-09-30 21:05:12 -04:00
josh c8658e5e00 Remove C sources 2023-09-30 20:45:35 -04:00
36 changed files with 1887 additions and 632 deletions

No files matched your search

+1
View File
@@ -1,5 +1,6 @@
/fart /fart
*.bmp *.bmp
*.png *.png
/.propane*
/.rscons* /.rscons*
/build/ /build/
+24 -7
View File
@@ -1,12 +1,29 @@
configure do configure do
check_cxx_compiler "clang++" check_d_compiler
check_cfg package: "libpng"
end end
env do |env| fart_env = env "fart" do |env|
env["CCFLAGS"] += %w[-Wall -O2 -std=c++23] env["DFLAGS"] += %w[-Werror -O2]
env["CPPPATH"] += %w[src] env["D_IMPORT_PATH"] += %w[src]
sources = glob("src/**/*.cpp") env.Command("^/src/sceneparser.d", "src/sceneparser.propane",
env.Program("fart", sources) "CMD" => %w[./propane ${_SOURCES} ${_TARGET}],
"CMD_DESC" => "Generating scene parser")
env.add_build_hook do |builder|
if builder.sources.first =~ /sceneparser\.d/
builder.vars["DFLAGS"] -= %w[-Werror]
end
end
env["sources"] = glob("src/**/*.d") + ["^/src/sceneparser.d"]
env.Program("fart", "${sources}")
end
task "test" do
test_env = fart_env.clone "test" do |env|
env["DFLAGS"] += %w[-funittest]
env.Program("^/farttest", "${sources}")
end
test_env.process
sh test_env.expand("^/farttest")
end end
Executable
+45
View File
@@ -0,0 +1,45 @@
#!/usr/bin/env ruby
# The MIT License (MIT)
#
# Copyright (c) 2010-2023 Josh Holtrop
#
# 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.
script = File.join(File.dirname(__FILE__), ".propane-1.0.0-5dab693259ff5ad86cc8d86fdd20c552.rb")
unless File.exist?(script)
if File.read(__FILE__, mode: "rb") =~ /^#==>(.*)/
require "zlib"
require "base64"
encoded_compressed = $1
unescaped_compressed = Base64.decode64(encoded_compressed)
inflated = Zlib::Inflate.inflate(unescaped_compressed)
File.open(script, "wb") do |fh|
fh.write(inflated)
end
else
raise "Could not decompress."
end
end
load script
if __FILE__ == $0
Propane::CLI.new.run(ARGV)
end
#==>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 truncated
+8 -500
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
# Copyright (c) 2013-2025 Josh Holtrop # Copyright (c) 2013-2022 Josh Holtrop
# #
# MIT License # MIT License
# #
@@ -24,515 +24,23 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
BASE64CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" script = File.join(File.dirname(__FILE__), ".rscons-3.1.0-4892f95d56c30bbe9aa0c9964062ec5b.rb")
def base64_decode(s)
out = ""
v = 0
bits = 0
s.each_char do |c|
if cv = BASE64CHARS.index(c)
v = (v << 6) | cv
bits += 6
elsif c == "="
break
end
if bits >= 8
out += (v >> (bits - 8)).chr
v &= 0xFFFFFFFF >> (32 - (bits - 8))
bits -= 8
end
end
out
end
script = File.join(File.dirname(__FILE__), ".rscons-3.4.2-b1e276fdbe6b603498fe893d904fe368.rb")
unless File.exist?(script) unless File.exist?(script)
if File.read(__FILE__, mode: "rb") =~ /^#==>(.*)/m if File.read(__FILE__, mode: "rb") =~ /^#==>(.*)/
require "zlib" require "zlib"
require "base64"
encoded_compressed = $1 encoded_compressed = $1
compressed = base64_decode(encoded_compressed) unescaped_compressed = Base64.decode64(encoded_compressed)
if ENV["rscons_dist_specs"] inflated = Zlib::Inflate.inflate(unescaped_compressed)
require "digest/md5"
if Digest::MD5.hexdigest(compressed) != "b1e276fdbe6b603498fe893d904fe368"
raise "Hash mismatch when decompressing rscons executable"
end
end
inflated = Zlib::Inflate.inflate(compressed)
File.open(script, "wb") do |fh| File.open(script, "wb") do |fh|
fh.write(inflated) fh.write(inflated)
end end
else else
raise "Error expanding rscons executable" raise "Could not decompress."
end end
end end
load script load script
if __FILE__ == $0 if __FILE__ == $0
Rscons::Cli.new.run(ARGV) Rscons::Cli.new.run(ARGV)
end end
#==> #==>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 truncated
#eJztvWt7GzmOKPy9f0WlkulIji0nPTu776NO2k5spzt7nMuxnT6Zo3g0slSya6Lb
#Vkl2fBztbz8AeANIVkl2knl79zmZ6UTFCwiCIAiCIHj/3vaiLLbP8sl2NrlMisXZ
#9Q9F9h+LvMiSdJLNty/m81nqkgb5eVbO0x/G08FilCVHZX86KX9IEv39fFLm8JUk
#/VGvLJOnT5MyGw0pJUmODo4PTpJnSfox6zwepzp1kA2TqyKfZ418uplsjLOy7J1n
#TZ0L+dNufzqaFlBRtdbqzWajvN+b59NJC3J70KYqYuvkQ1utNclHOzZDgNN1d6Bh
#11w2Gdjf08Uc0U1jcBnI/qIossncoYn95E1mJdBuUJmvu9zKev0LgJ98GX9hudTq
#uJWX3d5O43he5JPzpshOklE+yUoAPG6VQJl5I/04STeTrSfRctRM9yqfX3TzySD7
#TC1izmaSf/EqUNuYl9wTdBD5svtQUPQ3UkcR9tE6BX3SrqrBRy9oDjsS5MZqQKfy
#5KkmV5n/nyzZSp6s2Xl/cAMsqgus4qO1Ooljv0Yn/ZRsVPq06ffKLBl7iVcX2SRp
#wxD8zFN9DqcZ/vOfn4x9VFT18yLLJj+vrP5TRfXrbDSaXv28qvqfK6qfjRYZx76i
#+r9UVB/DVJ3Mez+vqP6Xiur9695kjdb/taL61QVIytWk+7eqvk9HAz54sepPqgcO
#q/PBq6heNXBYnQ9eRfXKgYPqfPAqqlcNHFbng1dRvWrgsDofvIrqVQOH1fngVVSv
#G7hVbFM1akVWZvManonJmUA+iG/5tZ4YrBB/HJQnhL56XdRNjtfsCf+dT1tKKQEY
#BqzLnxX5ZW9ucEUNJqpLAIJH71/8tfvu8PnJy7dHr5Nn/5lsjwHRqy/j8rrcZng0
#Dt783klPDo5ep6fJMxjPz/OsGKfN5Mcfkz9ddYb5cJr0L3pFrw/px7Osn/dGp618
#0h8tBhm22irnvXlrOL+eMd3JIyiUms+vdyIdNr/Uv/g3/me1PuCfUOVTKt5zp4wR
#hN58XnSLrDfIiqQN2OaXWfeyV+S9ybx0BXr9PgwusEr7bJGPBt1BXsQyQ+3OKzDp
#zi+wsTJsu+wX+Wweq1TmI8Wrk2F+viiyWJnLrDibauLh+IKulM+B5qAMaJLt+mBg
#Js2Lhc22HYN0Gtyj4723b467L96/Otzv7r86goH+8iVJqZyZuFCwNchGGTBeWN6M
#667tNYB+P89HUAW5BdSVriQIlNW0754X08UMK3RO2Uirzs175adu9jnrL3AYu7ML
#WPkNl+zGMgMIxWLSKIgxiOqbBBJm5mTQnQHTjsvNpLyYXnUpeTPpjUbmZzbpnY1A
#GBkeMZ3cg0mfAYMDW0/6WScd9vIRyazxGKCWOEtMVzSSvDkcCy/JFPUbhKJ+0g92
#+oaFUQ/GSXnPh+8mY2pZIhWyoI9d6kba9/tq6tOs6g5681562kn9iukpm9qxbsXb
#q5n9yNQ0flD5mH60JtmVowYM4QJ4ejTtDbpserGKLczjnMA3VoiHj4ZrWsHXLGJr
#UZICpXIalncc6CKbL4pJ8jiAiTvFayqtB6kx7IFIbNbxtpzG+TBgpFY2nnEpCkTu
#A/xiirIDyH2ZF9PJOOOkBignAKVFoDopzJjeYjQXA4j5LKeloCrcstiYcdEeomiW
#TOrhpDeG3Z3K+uK3aUus0ab99TiQAPHhXUxGQJRk16YbduSkCXnX321mn2ElgYG5
#14jwOaypf2t8fPRlq7nNFYDIhAgqm/3yZsprlri8DnNZ92ZZA9vRW5JB6isyjyO+
#02htNB9sx0oP8hL/3UyMIMehAnwePNlMHvwkaoR4d3ilUyvpDFCi85YgtFSO0FJg
#0MXeRbuFEzdo2UlDndJpEw6+imZzNUkRyep+aCCnklCjEiU1ssgawEkA3EEhDFlY
#CgpXVs+imNjlE4YkG65qRgNJEm+Ni6wMwSoYrxm18ehMYeZBe51WdB+U8wEou5u0
#u99M0pcEMtG1ksb9mzx5lDxZbt+/8VtDE8my2U439V5jk6wQbqg16NZsAVOJFBZd
#tTufdsuG/vDVbE6s/ijrTQx9kSYBbXgmyNniPJsbac+lIaa77qvSRTaegpaqMhvq
#H4f8S+gr4ly2inF36GWzUSdQoO5l/fm0yDPbOKiT8+TmS28zOfuSnClz0tNnvyQ9
#RTaHnKl7XYGfzW/YXw7LSfZ5bqQtYmwxud6JFYcJ09jPixasUoSrK5JsJZ2HrYeb
#ycNW6+Fp01/skgSrFWOowCvBsPcXWTLJR7XLhuoP8VswxCCT5usPs1+whSnGIiiG
#rBg2nC7eDDmLZqvcC8QUB5zqbtRr1rr1lDnb4IBpAbgWaj2qt5hPsQwjvI9j9f6N
#96xGL7GLsy4DUzqqvRy4xM4pX+ou+UIAny0NqEKAxpuJi1HREa/jFm9HRNaKS5SQ
#kYDITib77QyV28aur6eeZef5hPXLjIiFC/KKq57E+GpTfFAUaFD5JcnEsAFvwlZS
#qp5Ut5eDuhkbznD7s+6WIKbl/BCgIpk5pPhiQi2PzGy+hcgl0F8ncQNZln0G2bAT
#lKPlJD1CWPnkPLl/owosU5xIfAOPf+4sxlWH/rtJ8YB2tm6cfN9P7msubahNynSG
#DK4UbtNRFIsxSxL+uXfPz2oNQeWBoTK6aiJ1R9zB4w+jzot9FLYkDSYh5UR+dO66
#PuhfrQErqdMsOoRNmMtUVgNlmM37F4223iNuJnwWs5qfsutILUjdpKZcDb+ro14J
#VDJ0PMXTWw2kRlQYGBpfq+93eVurNxL5MDJOHBSXm2q7H2j3tSzo9P4Y9kSBxgYI
#hXIz+fFsNO1/YtyHycBWRTmvMDfrPRmVK0d5P7vXeBzKFscXDiCaAO3W0jfWuQFo
#jTOQVzRH2omaKWac2knnlOFKuLvFDL+smSw2frRJMLAaQdcrJ55avFJRHeb5ZDKd
#wxIKv0a4e8DsfJL0IPUiK2RjCrk0INPqSbh+28lkagmF3c0n2SDS4jwrupfnODKj
#3vhs0CMeVam6suBUkaPWAuBWH+nS2YppcD1KQmMSDmyDZnIPK0evAoiQvXJv62HU
#CfE+ZfPdrWFV2/zqGSfpKBuCXaPZv/s79zV23uEodTqn0oTNT2Oc4luhBQWs5XVa
#pX9hmCgw/ekCbTZSYnDqqQIV5FtHVgmDs27umTVq4h99IIbHfW8YXxt7xBCUTyNk
#CT1u2cmHPuokZsV4GPjoRgAqQaw8Kn8zWP2X1VYjNTuZRkx6duDXU7954SvGHUeu
#cqTq+Pw6z0aDRDa8Ctc1bNRK3UJ7a9k2lCPr6ylpllF7Lf4UYgcTWoNMtQSrAq4d
#tiVft/tTJ4EhLGFuTObDRvqnrZ/+rUwVULU0L0lhlhCXnB8o07cn0zc3KEshAQtb
#d45KLBoWt+7fuOJLeTYN3aE82Dd8ymBNLc49WWIhITM+45Baixm6pngA/QNrSwSf
#DH9BMqT3b0wDy5RIobCposUq2WS2pPXr1m052PDNx8nvfFrHZ2ayA5P2YTxv+TBN
#2kmaLtucaHeaIAanxAkI0whLsNorItXQX02NRJXoqJ9loUlmOoEEuy0XhzorD0MY
#HNc7PYoSLh722YpkMXfHe95sCRoMZguItNEiCxZWyoM54x/IKHgdB8Zfcf0KZTbv
#soYaFQhIK3zE9ysuw9P3k0+T6dVEgcIz50RMTLM20EqEWGkRowVAs2bCrs8HlYeQ
#eluAuyLSIevP7bzSd7baaTi0vaANedgubL1K2JD/6apjbZzKgOnsLP4W3dqtpENG
#3AXjRa/M+8xIZ0nlfBYasX01iiNgGEgD8XKc0WFvQ8Fut/cPXj5/f3jSRR+Ek6P3
#eyev3r7p/v786NXzF4cHxwYEjUJIq3umPVHOTRG1soNMKO8F49s5bQDBPBw7uKkN
#ip4Dt0N+pHwryJJNPGvQfhgmQ6whUvNGMQkEnw2aQaXfYCRT6DOfZ8gRULjIhg31
#zyakzoseJmpF3gBVKUIvtCV9h2aNQN0eAPFTG0gHJqaIqc0PLsbkKJJNLtvkv02b
#Tdho4t+nDMVWvFcMjCQEsGKv7ILguJgOjOePPZVqC2CWcDNEvzsc9c7LBv3NNqf0
#rc5R73knqDoLpEU2GjUePAl348UlP9W9mhZ04HaM5elDnw2LNstP+cw7Q1RlY+dt
#mCMO2/CgFACwwYnAwz9oBoxuEBSTyW0q0IsYmS8qxSXuuNC/iDnJ8IxHjsP9Ni5g
#EEbZ6jZoQzEibkxo4zEKbWXIJiMARUTq0PmhXME0AYSZPuJeiFDwEBI3+BUNKdJ0
#CFP4e3S6Wn0j0IgaefVs9Yr+RbBjqsVet5nu7b08fP7rMeiVHQ2GqHUaL324v7q0
#pECMSurUW2GPE+D+jRF56d67dyC93x0dvHz1AZTbwLdAjXBHl3v15gBxecD6xmEj
#ZfRZ/jcgjoH0tT0mrMrrsphO598CLQNq7XGrqfFVY/fqzd5aA/fu+clvNaPmQT18
#9eLw1Zv/sRoyFKxjhhDs/qujtaCuwBfHczyZbvWvz69ycYEhMl5YRVA8MkJemaAt
#aGUwvSpjLa0PZaZ8Lb8vukjzrf/V2wyoa8A8PzZgHjxhDk110EbV0BxSa0ObVUMD
#Tl0bHHowF3NaRXca6ZbYLqwmaxWcR7eEs+bwZLEKavIEpSP2guIy0BCZonNPah1G
#l6lUhUi3i2XQR9BSfXGly8x6eUFLv9GTpRoDSqFQsfW5yPOi6F03aanGZZoncpEI
#tZWe7ashkq6uXJW2EtsfDhZjo2Ip1bd70SsvkmdWE55PuxdhAdqlkTGue3bd+LGN
#nklNYQkRlsVuOS+UNdgcCV2Pz6ajZrKj0tROOCGd2daLelvhnZJNA5J5UKEfAVlU
#DIakudk9NnOwilFh3Y2ZMguv74SMhaXHij6ONLsY/KeTdk1q6s0sZlnhWHEg8buY
#0JI94VyUwhBCDNYQuWzk4DOwt0CawNcDWI+rqfxtzBnV7fA2cjNrBZUpiVFY70Fd
#yXDXk5ttrISk0hgoLiNYhShAJZcEPEpi4FwRYRyDtJKOUoXNkwtCXmjdswO15/O8
#Cimx2x8P5L6akgFtq9Mc/3ZweCjWDMQkKIFLQ9pEC3xDg0DD4HiQosVzu0+Wzq2+
#gNOhgpsEr3It0VecsTHQMOfZuEu1Ij1/9bY1m8LANDobtm+bxl3ztKmOMKdMbE9b
#qKyskhnVRhp7YrH6sMIdHSh74+1MoiT3U306QabDtjxJOFWLoam7ki2M+czeZxrm
#o2yBzkCVF9lfoHEiK8qfNQhtaVOpBDp2w11ZetDEMuvNL4K5gtnCl6FczLLCqEXt
#tEkuGBUjJC43KfelML13VlZlldNF0c8iF6WgTmUeOe6Eydnk0iWyS1MwWSMN54Os
#mw2HsGrV3AADXp9ZTgwNl8y6j91z/i0dTQt7FciSwFyOgoTpaDHPaEwau9Lza1d3
#HQp7y4jOsL4Vu45OqEzon61xb0Z8rb4dG0eaVkVCEbpr3Ots25Rge4SBGZ5xz6BL
#m6WFrs3jFrpdTng0bWXuOg+f9owjSa8jxm7ZVKFbZbgSlI0NWAMLWONnblzQ/dNk
#axpvJn45oe8WMNOAgo0NjqcV1yzNCQ+W6ijNErvKhkiun7GxRyRVkQar1WQuUVii
#yM7zEp0NWJlGrBVWT9AahUKkeI3oxftzHqdrJ5eTi7xMtMl0vCjJwWV6mRVFPhhk
#kwSda0CMnNGgpREi55N5F6B39fk7rFao4rJzTrtmiKFUFc+UvJMAyCC8CozonKGn
#LlGDQ9wB0NwW4HlO/XAzllRqt7R61aCAWlH1N64iN1ChHUBYBlN0LTrueoS86uXz
#7nBaNPZUOp2v2I4qOno4NkPqoT4+6BWDO1PPoIU3AtUvM8esNAuEHio2u3xVUG5Z
#yo9zMcN7G6CkZjtuqu+6jqlqm8RIbopwJ2+u8+hDV634zC6mk2vtGLzjC2vVG8Jh
#/GmQF91Zw3jJoriyxXl5z+83gMg19XUYddendd0ubJhPaBWzAGPjc7th2DXexBpV
#mqJrD4N3rqhdAA2foq+eswao9ZCnrXUYqUQG15S8Fd0IFSoPa4T5Ns6X+lN4Iu6K
#SkAq8e0X0gdY/NMvQtBZGec2KZZGmLAb7hzLx4Mm9Mau7IBxIt2NdOQWBITVOnma
#/Ab7/koadtV6m036OY5zdBlFBbMhsRfVDAlEYoUCEShynFRPn5qBtW2jGq/TWlYr
#8w6lqgrBEnrGWIi35PTFEnTMcQ/IMjln4GBuoGLReKz2QEVWkrd0w0wRDbdsOhVC
#lUke2TztzXfz5exLcu9Mm3jM0bjZG8CvHqzD0GN/wfAPqfFAzy6mIDtxudcXJqAj
#OWzeKJPtcaEQJSHZsU/k1O4uVLheuE6gmuU42jgsM631UdKIcEDHjQt6EqN5rCdg
#tnqj0Y6625AJ56R7FX1wdz+hAu6RWR09RLUlBN/JonUmAOUjp+nGtqKSXkChjaCQ
#zgyo5zbPQ5dD/r6/iIBQLs9z/o7aNE2Eh/qliNxK+BzwekqKmEHmsTK6VoxH3H16
#D/1o6EiVmKuHSig5aplWW8m7aVnmmNLPi/5i1CsSyznX5ORz/0ZzJxCr8+RU85y5
#h7PeZlyFlNseD/6SRnfoNu0f5XSSrghK8vvB0fGrt2/Q//DPrX9p/ZTWSNo9u7l9
#99vbN3/tqoMsrNqmBO0sV7XR965BAd+aFBJxyp7q4ifEZEMQVMQlhI4xKpwDEkYX
#Jt3nH9N80ogExrNXHjeTtKUDMiCANOYOIzxoqFjc4YY7zjgvMlZDWeojOkbl9cxh
#w/WruQ4VEFCXXLzLxbhLlY19anc0nX4C7dTksp2C0HfsPSQ7z7QSSpep1GUzoVgy
#FL1Op7AVK4HeZJPSzMeHhyx0rjoMxlWq1qXhhZN6wwu6G9349+O3b1p4gNFQ4Jt1
#yiVXw/XEZzsBlNwYXeUyvinQiwXJdzRh3JBwj22aUeya9U2rhKqxmlt+K2wwvuBT
#9AH+0WZW+92wgFzhuv1CpHgSu0kYLSc3k4PsbHFOiyIP3rP3fO+3g+7+wYv3v6b+
#iYHyi6Vp305OVPftnURQJbNBCexmhDLs4/u9BfoM4qUBWJ1REBN6yXSCl6E/1fs3
#c7/DH+LF+G/joKy5Vg9hetq66JVI6Z2GJTqnyddQRNCDMettiIO3hoBESB3FJQO1
#OIGIgOVnTKKOFqJ8XnMhIUaqCHFuzVIBNTuWiOgsqqWQCujliaY/GgsCG8BnNsEg
#Y5NzILNmQlD6cUE7y6g8VJwnaKP+p/CmpKYSbIqY+6QytNuv9//Susg+Kw3CmFbM
#EekfjI9tJA34Bk1tahhZ0V6T/SuYWE2Prhbs9cTEQqnW+GMAukNc9mwMKZWo1gnY
#BfS/JIN+J6UyAMUFxpHGuCLvz6niaThzFJbPIm1+r9nwFQPH+6LxQZF0nl9mE6V2
#QyF0pJ4OE7G3tnIdBBWslFhsVmSX+XRRxsp//aSSWZrWDePaTXb4ZMscBDRC4jcj
#N8X/IKMAy0AP/gO8vzHNuCAypxUUKemSTmFtGpPY8YnDa9dPP1uyag7aAsFEtDmr
#Z6MefoZWCCWcdH8ESannBmK5ZYNBia0n6HLlN5KbfBokjwIKMS0XPpVq+iUq0Lp6
#zOvXfVZQD9l3UwDuOAIenTE2RIDzsor4Xz0Hb9EDkMGLGa6kWICiVqwik2soagj3
#jOq33lStuz26zd5IfVv+Yd4r3nrrbGan6I8fVWZjGqcMtOdfBev3Rmj4AewsB4dA
#+Pj5G8uI3bBik8nZobWY5P/hDCuBNJW7RI0RHeixdqzOiK5066mMm6K6mchY3xsH
#UZBEORaq63UicKN6ajLpipt+rmg+IkaasoaMTzgQCLoFB2E1wrVNLGzNP2IX9EU5
#gnTvnmV7c3/Ola2zxZsgRbqWszfRJwaYvCcDH4X75TIboWOndY2Nz+2OxZcWAQkU
#+Rso3PixTebS0CBnDjdxasQlzaxXzJVL8PxC+w9tdz5+/Lh9ui2KKGdedyeJ3Uai
#WEPKe29ednIVddrJgnJxhsChDWdm3FBlH28m6mJFYJThNhYNIH4Wa3oYKWRIzmIw
#wYTXBU9pjILRj6wkUddgFtbp1iwg8AnYYNDVtdh5TNcCvTUH1AXICnkycp4QAVYT
#eSreRw3WK20g+1E3YiJZBAHCaOjVi5Io6lnkHyWsDB5Q2YBEMgiuLVPDA75tmblf
#kfWVAhgTH6P/mrD8mmhX1vlEGC70ISGe2LpuoJt3VhQtodVc9Qo8smyDKuPALyEZ
#NKppUSxm8xaGqZtjdLz2x8n9G9NAEHrDon4TuqwEbEKnEi7WUGzI40VinuBeyfUM
#7/4KwG3+pGpGNSJeStDRB3f/hgjZXEsVDFDuYGVStiM6j8NBnsjUFFy3S30kVlw7
#cWyozg7G0wF0Oy3OUseMVmQL0kQwM9SB1oDvyuVXUQl2ktwFoN6jYY95HQnPUH66
#Kd1O/RoseP+8N1/EvEyVb5fwTPXyeDAz6U17YT2jPT8Lq/lrVG/pYbUbHCybDIeu
#8PuxqadewSCmXODNFor9xcQKhUvjE8Mb3kk67PM0aTtLhAbq1zJYsJrWmY7V1lnm
#HvmGaX8z2dArgHF707HGga4bznNpg7fuQvzTIGGQDPrRIkvQ1Okr1GZjg7UdPzyr
#cwa3aXhs9+dVZ82Gu21A0RgHyfCiu3OY1yp08gyaLYQv4+7VtPikX4xI79/UHeou
#t12AEiMAQu3KAmy66XxOq42JIg7N2ELLbQUSlsDzVFSwWiCdZkogeKJ5Zu85rA4U
#uuIlh7ol51mw8kZIFH3cA//k5HL8D3TI1Z3XgV15KtNDY5e1UjPYaC9J7eUtDoHd
#4Gq1WiIMtre5FlGxBWQND+q7pT7m76LeDHCMcBqEa4oGaroD8SrIcZzN5yp8KF3M
#AISJKvRElG62Rf4AVZHB6/V1Fay2XJDwlzx8oSLZBmzqouGtw4qro7wgm6j216mp
#yE+1KsZG34fhwCriourA1FZUNDb6/b4hguEdNSDpHpbFgcCj0L3EVKHxMFXiztMA
#ky6dRLVXVwWLad+mrUgsDQ3Ifxij34eqf7rqnMMPEJaT89AOR0WwrnVw6/fZZhqk
#JSdBv1/pdquRcKqxL2lhMLTayi9C1BR9+tTBYwhDIdoWAeY7yWNY9p5YnHSQFbaH
#Js4xPuOglvWdnQLFoMtJyQ9rusBI+zTy2QDVNCAM7bwxZFkTNNuIf7jmk8+f78Ap
#jx798XgFcUJeefTobtzCCfGV/PL58y04hgr/l+KZAeeYwVocs38rfhmsxy+Dlfwy
#CPllYPgFfowG/Z/wr5BhqBRWtwwz8BmGUWGwgl0GtewyWJ9ZBopVBjWsMrgDqwxu
#yyqDtcXL8Dx6d4Hsh/1PKiip3ZnoJGeWi+tSnLEMlIdMq1JJTHV4KJhORXwAXelc
#Bc9zzaukdZt/KBQ5rFndpB0nrUPpCrYlh006+3S+pZZ/p8TpWmQRQI7U+x90um3o
#qtwUWhGFj362E1cXwz7q6suHiR3qWj2LImyK/STtttD+AbNqa6uvok5sbY3yM7sJ
#c/vcjiWVvu9gxtwLY2zI3d1M1M4dA0uBskaPv5C81jdjvLtT+dCW5zFwy/m0QBtK
#gXqhBl05Y+1cUpC8kjFd64IMAg31T7c6Ir0uP5tpE3kH1M5T9K93Nzh5CeNb/8O6
#s2EvUShw3hRIVfCn26R5G7vhORK71U/1dq3KAxWk0tbB25eMB+9r/3vcKjIURBDP
#fIIuLiBH8AewA4hRfKsy2cCPS+i4d25k3mv7maW6sx/XvhtKfc/VgUkP9+koKH1w
#s7e3TJ3cS7vHb98f7R0cq+wqMrDyJ8+Pfj04qSk+FcX3D969fHV4UFN+PLQVlnYa
#aN5/EuMgt1/TCTz8NBqI/AiPYn3BBVJVY+SEei5OFAVaUYfTumT80oGb3nhCKOLz
#NYjQe6/3l6mKBuggdG8/uyvnd0VvzMTXAS5ubM9wEGTHloFA8HuZJGdF1vsUocBX
#iA7QOv8wwgM06O8kPkDH/e8oQD58uLUEQUr8PxliC64vQz58+H9CpHI/lo9n02Le
#MD/q5Icp010hRUS5W8uS/UTV5pLEYXdHMTK4vRDRWNy/MY0v+dS34uP7yon9Wysa
#gz+KkBBcwDwaefJtBYao7IuN/e6r1+/eHp10feEhat1JhOz/k9SQqv4FckT21UkT
#2dX/f2QK7N4a8F+dJIHsFTJEl7i19IB6Ra+45sKDcKmQGxS0PWYrcds/usnc1Qfr
#VXPOFneCiFWskj010qdGwsRljHRl48DYmPLToHU61v+uHVtT8/qK/tpfdKtdb9x0
#EsbGT0CpSvosvBhagRe9c+ZuHeUQU4z7QlMTNUW9693rzLzKlWHEHBVVDFBM7QCn
#n1atFnzUbrNAZJ+zdSW+nrOMmirhtlJeV/PluwnpyyS7LnknmX64/8+R6WFvAmlu
#eubkuOnYt5HgtZYtjgXjo7Dlu68I2nDXsAa8qCf7aoOttnTewnqqV5l1rJ+2U1Sn
#whAe2L9plMJ+17FNvPvyDVhz4kxXtFPtzUTee9p7XNnQ0YTOTK6GbMoDkHHxW/Qt
#afV7M5Cj2Z8bGy5iz3yQq7NkGZIqnzBPW4nMwed8riEjQuoXekjmHBVTRw2oQqwm
#F9B1uZ14P9zzJ+SFdlAUk2m7ffDm7cGbE1c3RU0f/nvy07/VvUGoeF8NKgqA+KCo
#UloMqw8k3TSInOYK2hCp0l3RxiENwxzzSJQROGGQg7oe2TdBvmmXTKzWO/UpH0Zh
#Ub+iQZwXWWUY5yo4OqyzDHifrVUzqFjrH8JPA+i44htSWUew9aIVRQo8fVoRZrte
#MAfHd8K1T2aR4p2qMx1dmR/v8Zo8XVVzx0H1C1A0OLX25AFtxENpKdx4xEWkDG/K
#4kubp8GQ6wnBX56gNS5W+TSmSEilWb0EhV2uuBblohsQYeTFJ0Ez8YCDfwnq3orO
#SUVnhG+AC+R2cEUcwBLWvs5Go+lVLc0JAJGcj2U1vacTauS04mla6WfWCKoJ97Qa
#uO+KaZ9DDcv1e9E4xTrMsqUGg1FxvrnHfasS5S74M67iyqMa6TXPJnjxD5Rk4Yy4
#XMu1zL+5sIaX0Xc4WMMN13ChNl74DlXcdIWvmWwkP61vwHKK9p/+Vwe9QZbJVj/Z
#IlpFLE7xZOtJQcseCtN0b4+mKsDTWXfQzWtVX7X8098RPZtHj4xd7FrH9ee7HG/M
#M5DywE1P59cAGR1LT35h2Sc0xid/vBH+/Dkyxh8+/OEHud5d5/uZnvuAfmsMGwzf
#8Izj+/V25077HLvTRlemU+6tRLR2aOLLp4lOtYlXFyAOEQBrzuOSwZ24RLzw7Phk
#X8mCQX/poYDYsxrw2Z2e/aNcDIf5Z6h59P7FX7vvDp+fvHx79JpejxnDWnX1ZVxe
#l9sYOL8FpSl0fmuartGXYRTr+zei3eUaXVvDFML6L4baEWPTT29vTZUtBzBNvdzj
#3+rzD/fra9fni4eZVKHDrcNIKfYqlCk28ovt7x+8+/XgjdLU0i28L/zswY05nlim
#p5tRLnd+5jWj/kU9+LQtWiRCd5BE717pd3rojkC6tVVko6nyVd/Cy1CjZ7O8n1ap
#YhbS2xf/fvz+JXaS4Aj2iN0d/daGp3VkX+I9EbbGxie+ifEfSkFkZPAFd1lQxGEu
#1fJVFWAgeCNF5PBbmQFo/MOehKnSnOsc9lc43qtnaeSOeK0qHd1tr278ypB/AQig
#6XfEVgg3xubAsF3zoBOrvwObTBB86Ho3BK5HSte/wGoFUfr8SM3dXqFnLqTsvVa2
#aYD34Ob50TLBv2kq4U9taKaf2iy9PLV11YzTtYt+aXOOQ48rSJRNHZtlRrTy/FjJ
#EPxtX7hbYro6gldl9Fth6sMhG2CITbbVvVWv5W/YrH79S2CAyUyyLunTABLSVGVx
#nJkQxUF+/Xo/2Xr9MmGC1JV1I9BxieYlNTMGBu2UlbCGa1WAUHP5WgZqFFrHBrZW
#7dPzvnGMS8nVyxEXBjw2rHt7cfruOfLuMeruuV971cNLTQfDSxh8h+a/7TAbjNYZ
#ZvMEnRjmaJpnLJHpYvXeT12emMZECVt6aT4R6JLBs/zDG+kKVsA7+e+O3gKdjrs0
#KAeJTDRj4o/WGiMU8oLHsn2boXcq6fmjR6lLk0z74UOcaz98uB3ffPiwHuNS+yHn
#EhrfB4dvzL0GqbXYV2PkscuHD/6Q9ZNWfzZLcMeZtPZMwX0jcwZW5giF2CWKMd1X
#ggh/QGFvLduPk1S4Z1C56jHcjwofbPVbNflth2x//QHT32x4UudAlO5HBnP/1fHz
#49dy+oMqvf/+9Tvqk8quISYrYDHcGuRlryyzMd5b2NpSJ+G2xrs9bA73kd6Y/wb/
#H3Lab023vmacdUPnazQ0LK8n897nrelkdP01TXoTY2AzAvchOwLuNWA1LV6Z4dKu
#B5N8ZBMik4dO1V3/DvcVA4Zs/G2Z8jDGTIcHuhPDUfY5dYmSvSCBwEO6xsiXnAFd
#bVmvvcgWOHV5wcZ3xDLDgXDH8TyFT6WerX/4+2ujKtNFRpnh9ZfSosuULl7NUA5e
#ILAs2BUwv/G4M+gesVSOINjIUlzLFJUOG3MMgM7yvHkzNUBB4fiV5YnNVEquMmhJ
#MoCOfzNqrti/YLIYEUz4FsouwOG/a/QGjUIwiBqT74QGmpC+5eBb4FxnVw2gS6Hd
#9rrifmld2BUwOp7w0FcZ/pB9I1WPIK0/bHGFz6Dz/XD5DmPHtTmjtvoDsm8n0D6f
#QExvM0oSz/SGympwuuIdFSqoXTc0cT1Otf4tm/72I7HvjQNvy9pDeXlrI8Uq4TQL
#NAVhOzbqQMoyvQFTWoOu5ZGssvuQUUkAyqsjwaFPA9vIVnnRK7IBK1qzynvt+Os8
#ZbMsuX7Q2jHKz0Tp6tVmgJEp8dyitMrX8av/rX338Y0enioJDAlEFfi3hqNNrlxX
#//rcLGpnOT6Ow5KlnoEpCJhy1tWsXGGrvSvSL1cHUKKASe4LHyi+mhaDyIO7KooS
#O3ZJngYnMYRP7B0eLzgYvmCUT84xnJWoasLJAIAuxmayFuJdVrLsnl2b0EDMiCyK
#8FBFLMqADn+YO2P2bj4gi/JjkfLoGXs2ajf3TfwyCnFDPJ8o0QAqmEhn+Ccfklut
#F8Eo2rmOKXiqfHFt+Zivqn4dSBNlwj1ocu8p46rmqCnXiDwWEFVqMDH/xqLHReK5
#DbozEPzqmJjfwYg+P5z1L6YVwLvFdDqP1Zl0VTSySNuWKF4cMPMsoHzWMLcPvKkH
#BQUX0fvbkzk6MCHjxV556vXn+WXW1SVLP36vTnfHxzqh07bPOxFxvUv7+Eg8YKtf
#84r7FZ31ShtFjAqHT5/t6uyOLbuZbPBOnWrP2S3uq+oov04YtPs3u+I2qWAw6Adv
#zj6WxjiwPsRCbyIE01U+v0gUyRNLcvMor34OgmZF1A3J71tdx4KZ6Pwa3cjgaPsR
#0eTh2ToRrn6QpEjfqeBjtl+uLHwNpyDO+8DrFPZLksd/7s28Phm84K2mjoh8Z2Re
#NuhG36h0JWsetWbPc8LyI2S1pryOhSoA8mcbXCp7LtBL7F5Mp58oHYQMBj3cTGbT
#co6/vLFwL3Z/phvQ5gVI9iCKOeN78f7V4f7B0bG7riEeGqXJw2/0+M+hmicpW8hS
#8y4GDQ4BNCsBgEyLPwpo4leqYvdvQqDiHndvMDCdlO3XRyLZRRnMDp75sTNm8XPn
#igzlvBiZUpdZcTYVi46ILqrrinx69TeC8K4V+/HZK1cFyy/0UmniVIHdyuWJMxtb
#FKxCgGnsmN+9WYt/uONKRA/S64yT31i5g0mntwDhwutVxOubVKx06ywpdavJLSRh
#ECq1NVjMdB5hyP2lKYEcpdvOfdWUAuHSaZOgPxvhC7tW5TA/lSw4pfvmqs6zKjhe
#oQn8CEupZ3nwu2mLx9zvVYaOz22xasqJUyF05AQiJXXX6kAYFv7KBG6l8dhJlArH
#47vaMqCGyis5fqNt8mpxg3gp1R16P9lAY6yiO25efnU99JbSrChDiakUDf3FhSZq
#vhEJVS+bqJJyW99FlxF8JSGCoeWSVb1QLBPoO5SKoauyU69HlKUeka7sDJVp/OiX
#r9VCTIuwdt2ySaxy63YlRY2C0jV0wxW70XYSdpNJ228r8lhw5btJvMRum7jsq1z6
#QBKiyjid8G6IV8SFNMS1OJp9PT6bjgJhKYsKJ6wKHUH/Q3MvfNH6OMdLKy9MtGs1
#l7wOiPUyikckBj+bsh2z/QwfcY9S1HBZ+CA8nzb0ZHj0Ffc4z9ZAwylRDQ73aKo8
#PX5ir2ArWimvwk3ZNzb02ed50TNBOyTVXJabP7x0CrsdlxA8r+xukZv4xuyzdV4u
#zhrpx4/oAL2dRhFqAa/vJD/+KCvio2fzLm59dsip2u1hlttsn4NXhFi1Jd4YIvfb
#6M7MBzQVPYN+0iXRce9TBhvrUY82uRQ5v7qZZsV7027QZn2zucjRuDIQISh8jGb9
#GixsZd0mb2lWTFm4YLkfa9W+Xqxr0i0Z2G/JDYzJJJ5EMXXVy1E+cddOW8jE1qZC
#WFi9OR8HqHkQi8rtjleijEFxKi7XcKXiK3ZloM0OFv0MNDtab6Cbi5F7nh2LuCVH
#ZSaPeG6LwYZRwdgF0MFgKsgbvFcXeHFI4mGMAShwzZ5UJq6gZsycYKogeiwZ4xbE
#G0e3dpmlNGQV7lRlG+R42ircYmW9cYw99ehhGZh0fAdr8wKKz7qrYfMHwdfj3qAK
#R4UvziWPXO5NQP72dxDNc2U3xuU58nNQTJmx/Ct6vi0mCHwf4yBs4tEzDJP+Hvbj
#f9cyyLyXAJTQTyZ0QfglWy//jtfgLvPsih5OVC3Y+xJ0Za6YjuXLo+rd2eksU0ah
#WIj5KrsYIOdvyOT+D6WbNrJ4q74/6rzeOJtfTAfdcV6WMNwN9akji/LgMFbnt9c6
#VVHSe9g1IkJgUy9jpQoqAeBgpOZ622jL0q1gz21ccwPdqGahi1EmsLTfe8WxfAZP
#m1DeT7LP+E4PDQQMfrEg7Skxqi4+b4mX9RWs4E0fPgr2oUCAiFcO/Kf3dA8TE4JD
#fzsDsErgSrxKsdpBSzeBdxdUgurdC39vlBgcVDGh4reGsDjOMydv3bMnTuljQ3VK
#zMRAKyTaZuQCdGEfaQaT5fXVWzdymm0KAXHZpi0AT0Syt704I4F8DsSXtCyibkjL
#EEut2WsZqBgM29bNCq+UXi/xjMiwoC6oxyTU1l/0iiLnoyTtnB1T3z5dy7Ruf7Bi
#ahoZcGsmvLLSmucDYYq5Z1PdtFWZVXxlWVwXU/+EEppZaeUbuMjmi4GIcLAYVHPx
#Ak9coIBox1tLFKMvBr6sq3+5U85Ru7Ww2HbMEIiQAqIz95Ib7EsMOmCzDKrYbTsn
#QN1r9gAFbV0hUs5MsRhwckXQBwZexBdeq3wRE/aGaLM0rOFxBueisDjGky4yOj4u
#Yb223OTs9/KpVZ0t6thCdZDu9kZrfKRXHWOI8feDxAskHVY8mUtxCnzusqrZXUKG
#7ohq3iTwtTuvajUleMGmYJ/1KAIsxUHUMJe308KtBBM//HDIoGFl361mrbdluQRx
#m4WmRrFbcXadkm3toUjHiV9GGqvM0BMJti/RPuAfdae4dt7Fz3B6iRsErfzN5VPK
#nhbCaWyfRGZoNdhvSzBxLgfjGSF1UM3foAfv0a4hdb23MQNxVd0j9861eO/Z6I3O
#lKPUx6hBZ33Mpov5bDG3tpm4EWmF+Wi3y6YTQ9+IxVCwmI1NfUUn/DmWTM1Ei30X
#WBl2IF1p3WzpONesniOgVLJWYY+HCQxMwN13lq7rC6HIKMYoEqDJ+UsJFFWZG5iq
#nj+VMfOY9U+/b4GGuWgEJsoxGpAM7ZdUYlEZTEe9JLw4a/ypuPnbR/hfY+dZBx8U
#xrB3da4KTVaL12HWtGaF9TEm1LU8hn/sOsb7on8DZxXZUJUKZcmsyCdzq5sXi4mJ
#omN4dzOhM17gA/UGHHTIvvJuz9gw0gI/GVMhDvzD43xoKlbFyXJRmvytfBneIVeD
#LiGGIX0cyMhZtgq3I3u3BqSgToRjFAnk+XgNhCSGSjCv86GB4ZSv6bw36sasiOpT
#HnTML/KSFUZMiAOGjfRPsMT5sMjqssRIIGZ75DLZ7MKAhBkdnKQdgCLbQBN1AHh5
#6nbxschOG3r8R9MCMOiOe8WnxQwt2qYtDFVh4j2lTflWXmyuGA4fTou7r5hyx1i1
#ap6pnWZMPareDYuQBaC+zJjjg7VVGN1FhUzRC5bOVIFQbr6UXxJQimHS6GOI1iC1
#u6GB70JBq5WUE6nvxu1iUjpPDFPfbs0kZKf9RWNme4D0Ei+OHKKBrwMElC7M02xZ
#xT+jrDfpCh8SJeXl92YSba7a+aQj4sQ/q0CCbfIUR3Qtq+lF4jybdPkKp4vTqGh7
#RUPWtQHx9KBbQvvWK3qyXnCIzxTRosrj2DgrEhFxbFhyYNTi1WWcfRe9lKXjDIQh
#UVBk3O/SqUOswcrxR0G33hA5CH07BCRLBDwUVKxdvRC39Dq8bA1y9po4b7dap2Ra
#ZVjeqZIGLREyEpngnZMBpoyhkdg6xrDBydGvMd1QA8YqJblsM/ExquJlIbv8YHFV
#dj+99zZOPPU656bcL8V3Q8iDbHmR8poWOutOLvY3oO5UeLjc1aoYrpPEFtVIsmBl
#qEXpczy7KUZXi4aLz0laBalNtkVVw0kCOgmaZ2Ou4sZPMI3NM25mWV0LOMw0xmpR
#NyLphPqJez7ctqLP7DqmTszwqqvveSqcwLLqJDeOJsF7ETQTBOOxJxU4w84noI0M
#nHMnbemW1oavF2ZsCU8tTKuRk4uqEznCSoYgCs+6oUPpS3V8NZ9qM4VDSU3MpX0P
#mUCKgEmmJJ9XbCVxqZyFvMNBaxpQ9gBWaZMuUJGzL50nJCxP+rhR7wQS2k0vYjSR
#BLvr7PwKjy5jqnW5FMUz9IyrGlp34l1k4+llRmzqVxfsdwfWo5DAyHtaKvicV2Eb
#DNAyrGtV36gowL1FLzD1bdJ0K4W1TxW3C54PnviUimgOCAt4UVJV6fDsKY6nhhoZ
#q0rPjcjZ00oTq+/PoCQbep6gEgR/5eUFLHIqucGnAp79UKpyLMIT6YbnafEscT7V
#3OVCeLmww6LatknENEMZU+cyI7ahcynIYzykijTZpCXomVUJmOkXlUJDFq+aiQ1t
#vQFQ7zNrhvrXKXiWZnrEfWD5MISnxceeb1+I9yqoziuEsG1cPD28Mma3lWRVFYUA
#WukkQW8qB5B8u4cY8BWLSjBmwfKi/ngW92qHE8ZCkr+fMvZey20ncAhh7LGybngB
#y3CUoRoUO40YjURHq71iVvgPaWnN9c/KqhbXqiNWFDn5SJtX8K6Rmx/Ggwwfp+Eu
#ZHpebCbTs380AycyJ/oi89IdkEfHNOq6xadf6O9AZTuPT1tSScY9BlGgEe9m5IpO
#Sweu197n2tGeZzbDqXcHJeLurugW2XX0CP+MUX5FeCiAsdbM4wNUuRCsiDccXWQm
#04l/scUkhQKbbh3aYL4qlVPunhagvVF+me3EeshVJzI9IOqcgzdEY2taC+PLEiOi
#WYOqlpGgXI0TScW6JlFUf3N3fHZbO4vE3lRe7cdkVSY4KuHX0fSsN9ovjdO+dwtX
#WaFZP1QCWg0dJD4AbsvvbmUmt7u6Sft5QKuxMUMvqYJHfVXGqGimBDCYXk1GUxiy
#RQH7kEFWVjwOye73gJik+BfdUT7O9cHYX/zdRlA6E4GRgSUopHb2GTZGOw1st4ke
#4u5BhIveT3/513Ix5rWo3n5+DqXb7ePfnv/Uusg+D+i7QeDO8gnxH8Fr4oWoVQAj
#q3GdJBH7qiJHu93RK6Qd09zKrFuWI/QGKkbSy/1iPp+V7W3u3g6ryAzwy8SNEDRZ
#gh4Bw1bAnHIHIanTI1SvIU2Qg5skpKdykrzJoNRvJyfvFE6AdN66mOJ44y/18KbG
#vW1+qIUQ0ZZy2YVDVxxT9UCc10MEhAsXtY1eGRj2GH6rqniJ2K9M8dPVcQdmN4Ns
#TQdYhTHfy848Ra56XPVzQ8dEdvJLxcgUXPesu9BtZxEqFPdvkCZL3FdmLXfqUrU3
#M+TREtGO0pGeN+x+jK5RORG96NCVOBvQCdUDDFBVHijbR6QnKW8/NPmoldXKEdOf
#TmoiaqennmDRqoZEv13dry18osvJEW0XWceIoIVRFY2P1dszoa/t+sNcPbARyVMh
#4ZJ7zzQfO3m2GiXuDqzvfSTTSS1eUvRnk8v4ndroOqQfhTaX9h10mNdebPsqqPGL
#1PNe+Uk7n2MogdlFr8y4lSJryZsv3mhHuzbr4Ut0ymmENpGboP5/ykq8D0rMaA6N
#HXIngEa7/Q4rUh9uUdlve35Bb0lMJyL6yMGb3zupetuwVUL31ZIFTUJS9/jg3fOj
#5ydvj2pgguJM10VDxw665NjRC6rnn0FB0iRKNW3oG6kVTXhwAHJVozVNICC8mivb
#QHVXJ1b5O5h8XCpNUbogUUdHyS1sDBiUKK4FcWpDHXmKGwOJzjPIBCR48FjSLlYm
#6D2VUCJuWlz77jt8w94hbLgaA9XwYFVc8JNymtVOt4bpZsL6FUIyuNARZvXbm54S
#l4LowdApijpi1ZAE8wpGYTOEWWVkZt/IoJxyFOL4NwjTtJWiqNVfAe3386I1u2K7
#DnqgJVXttEGageKFIt6ORvJQYfwwVQ6yukHfFADK/nU5z8bs6cX+BZRrI6Sq1g6z
#3uWtGnNrGrS5epl4Ka7utJPUkdC9L7l6sSgvbK+CLYGMa8XcjMgDld10Ydi6qtaG
#p0w3W0/izAbdmueTBQuyYOMUmCzfcqnA4q79Gd59AI7QiWg/qRAyju9c2SrmXysq
#iI/KLyxSl+WGNRy4IqoXVY2gWa0P+XuCgF+DqAsZJQQql9GX51CrVwyiGjPbt6Aq
#fNbrf5oXvX7W+enU1459eqnxFJ31HJ/oyVDUFDdNO+x5WHFhrvKYMriEpuCs1ivl
#zED9pUrjoXGtLiAB6chPWvOIb8JjLBerVttCN5vgfbHBTsMkSNeR6kbqa8YbOy+m
#i9ktFM016smGcHNtI5U11mhBdcJWqStaB9th0bEg2n32aHe7fzGeBt/dI5ECWwr/
#W5aYiY/uqJDf/JNOO0YjljKaiI9u6X2yG2zt8SdYZvzvLm9+fMk+YAVlX8VYfHSH
#8rPwPmW2bHc+XfQvzDczFauLfs5CoN7L7KpkfWNTWRI002xsfLri7MONC6gU4Ows
#nf+5uB4a1q5bI82/ylZ4Mp0dZpcZWguTp1HL4UzFQlM+YvwjsCC2eC55z7nP6Gzo
#LeZT3KU1zI8QpMnBO6v6Zy1Lo2MgG58BaHt+mt0X8nLqXaZa/lxMvLRgvL0QZbFB
#V5TjIx+ONwlhVpw8fe1Y33aEzUuiWfUQB8bhTRfxrjtlDsEqmF1gQOaFSRtxn7WD
#pbbp9jHDzSCLPWYZZA5q6g3Pw7TuBUWnjDZSkWWcGIOMUX4WpJmX378hcwhPL05V
#XxCYwJJy61elBfQX5Xw6VhE4GlYj8fnKPJmr9BijID2CDQt/z95EFBLoVb1z7kUQ
#DeSDly8mvORT3cAuEw/sIIsJNdKWKGaci7eU4XOjg6ntAc23lMSE9+4fWVBgH3JE
#fgL68LxXzPNhD694Nc4Wc7pjJiJMNn0gBsm28rpo8rbj9itEJaoUa1QNrSvQtVNe
#Bz0gMq/AysslqxRs+TrKPJXOCuBXehp2e1EW22gvHcEXEh3SjvH2vBKO6sFiVTxp
#aLnaTlytZtpkDy6rDlkxvQ793e4TNz+C9F9NeYtIDfV1RytQfaVyDdXR54JFD40Q
#KfWJYdeZihbem/w1R3Z1r22LaywqOA/JeM5tLRGYJUjmydwZYeUMVUsI5s51SGmy
#fNCBmDL34NOW0NnizNJnjVnd8OAa29GT0LvYItaILXX9AZ2K8bXTthlfHF0ajiLU
#RSMtizJrg8zKgi0VVoy5aaoE9totoMJ6+TnrNySITR8kTdkumYPDyGvhkXP1yTJ2
#gWkSMuz4reJi52rvSSEOyk+lFxHb8D5LWHMfnCKKaIUip8mH6sLvdDEZpJVbYwmY
#0Fm5Ytroo1hczle8LgQ0N+HcWDfCrbdraJc+697bNEQnK78uEQ+y7Qf+Dq6ZiWx7
#PMAz3ZrL3dg81fBWRxQm7rXgg12qDKnSWW7XAiMCSvzwug67Tfcsqb5GJ9QM0189
#vyIZXLuopWCc7CJVLZcV6XoqRtQYaQgJIqPHtZtdLy60C0QmCeXO6CODsaswlrHO
#GLIiQ9OQt4XzLh6UF0RJPrxuRPvEBTDIDtUg30tSCjn6EXodV8LGClEm5RmbFpXC
#wQsCQHXQUwEFhoO8fBhcMPSIEaAhL+tSLCpTT38O5JihW5G3f73VyWVlUePWFXlE
#gHWGc4xbadz9c7fa0KrlMk51M7KT0udMMdezhK11dXhHFAN5LyLWV48g0rdq5RKa
#JCqlo5ZvPrQxg3lM5YmRQbOiGXHmuxalVoRpbB3LNkHJuunEz+5ZjN2INYVJEnuo
#b9LCtzyiUFG48DuUQtZYoJi8NkC6oiZgMsH2yMSuYbCpQuTANgpfiRAH3oOmsk+b
#LNAMpsjbVUwK2SVeih68b4e3ES1LNVxpzWrKN3yl86b0n1TPmXgOC9Vvu6hR1nKa
#rs9O+1LvNzt1qXZhIGLfZ6FWYeKNSIzrJ1CUSl1Gpa6gUj5cYy1IOH3NyHS5crGG
#QI/Uq9eN9TdaZGuVY3Hj3D8kxyO5msfStxnF1Un0fyYYXqKx0/541W7uUISJZdUY
#qTgW3Jtvew0fG3lDPkCXuTuEIRRW+AxE8FuJTuUd737d3W7yI8UrwH199XdjY3sD
#b/iyeT7IvXvr1LQ58de5HdMQHYU+etJstU6DQcHTQoYGXjQ2kJYpxQTZ/giNP9je
#TOTVbLt4cKcE342CW/7xmKKhUbvtqZ8fbSE4PHTRJ4gN/9Zobew0G087f/vl9NEv
#TfhqPhAMSXYL3HYObLQeoMWDJ5vJg5/gvz+zsnRpFAuyNHLeS58q7/9f5H0TLAqw
#2mNAZiKcJHUtdUm6olb/ujcJq9BRa0UNyqugZ5J0ZFc3fEqqvjdP9fF+Fwh58+Xy
#S3JJ+lBaOUE7mtx12ocZu7qDdnNajxFwbpIv/S9Jv5Mm6Sm+xwY6bl9fdX+IdruH
#H+HPQ9B10VujnfSTpfOpiDY9QFV5jEZq/1EP4hjyTzo63nv75rj75uS3o4Pn+8fo
#qkQM9HHwSPKMdr188AQPM/JIt8MDf2KdozNlg2m3oaGXr37tpOgH3J2W6ak/0Nuj
#fLL4vC2GWTfrjEvpNq522/3ZIp8MpyAVyn5v0tj+m14Dp8XHcqO93aRJHzQwLq/y
#yZe4lCaa/P1qnPcTAI73wpM3i/FZVrwdHk7PQZEdvTNNlMkWrTV/J2JVlnpGVJRt
#VBLSJ6ZBedArAOcQUcC+Px8lW5Pk4qo1AYwVMl/XZOilHB3oJ1F2U0FyhtNi3NOh
#HkgglsEiVDo/GU8g68DRVbMOlwVXapk0HpkEAriVPFk2Yx5eEk+6EaPUdTyab8ij
#UG366sCKe4q3OdXHx49p7EYBPhq4owCQLVsvBgb0jgebjYVnXqvR18iPEURpoYwF
#t/Ps9AG4ezw29fqLz1t6aZyjw7wNDMII5qqqtxV8R3ndRaEk+J1cb+GrD1FyiwAl
#fsDgeCgvoxoaTaI65ggdow0cr90ixk6N6sFaB+2jCkc2RqY/MQ5jsFdSPYm+EEIj
#oKZzNurNSrw/lo+zhv5wGF0AEvS4n85JtpPGvz5ONpJ/fdxseuuFLrH1TNfCQvSX
#GwNYBVToUwYPIFUCMhUElBKUzgk9cqVLtvoZu/NivSjZNRcgq8LJe11PB/CnEaMC
#y4sk7kjKIWCIWoNZDUBdZDmuACkK604tmR+rcM2UYxePDxT6QnMVNlrGlTJ3nngx
#pTHAsqva+lg2Ph5vNH+OruMPnlTwon2DRTUDmkOAslXHSRv3J4SqTphcPXoQbbxO
#5lYIoKorb/ZRWMSMHku0WaZw1Q1fne8HwlWpPBQU7HxSKVp1IWKG7aqQJZxl0PmY
#uqBrNitDLSbJO90TsrzSvskTQE11rE1ZInRdQMpW6WLrSXpGniEJ2LF2282En95Q
#f7xqtmmHsxTdSbv3bx48WcJfP8noLv65FBZUEnf99Xgl38zwmjOPD4qaQmM89IOS
#6mDgzKZDR+QL9MJ5+NAmOvXXgqBVpgsac0bjiT88lqI8sx1swt6h3PDmhWkLOOUh
#/O+RNz19SgXFsQVfebD4Y8Odv7VPH30EefDoYxP1ctiWtnUaJjY/BqoqEeTpU4lJ
#oiNCCtitjXYS7GzxD5BIk9UDoqED+rqIVqCgMzQxGj+2S9CSZnLSyblVMUDVCyu2
#E2UR8hUI3W+jN5nqLPR3s9F7qxY78m7FD3jpkLTelh09mzVQ3TWn6toSp/pO50Pp
#OdK152HrvR6riqfhGbY4fVe+6fcasabWuRNYeZoc3ID3noljoVwiwXR0/KE3U1ME
#vVQoHgCAjOsR/7HIyMT6P/FfcXfXtmKjyAdX/E90BJzsKjBJe3t+B5CME95MEo/a
#MLxas0V5EYSE8btQTWYNJOKt6Jlg3Lsztq67hCFWwNhFq2ZLLF1dfJbGXvCRa6KD
#mrZAs9efy5SFlaGbFLjN9CsFneDh+7TwWGdv5pIZV5WsNGA36o3PBr2oSsB2uErP
#i+5wa29s1Rh/lL2c7DHw32B6VXK7DDdSVNxXU730uIV3zX208C4tWqNEYXQ4d/tq
#HEb9VQme1XAb6cgemm/xHCxlXMYfqVeaUhFj/DeOLJGh0dAleefwSR+vKP5xRfFC
#jC29xMFLb1sHGPPWdc56c9AZiWkE03Vk4E/zp8poEC7ANSIh1NSig+Cw5CPBMEBi
#1yFddVJW742lHlui4p4XiY6O4y7f7I6vuzbRpPWnPZNoFUZ9h9ZF0PE8ND5llofx
#qF+DdYesLN+12oFUewYsTuoNCm6xMCme8mkLxlsKWiO/oGzWBc2qYepSRtR6FkM0
#YIZa6wYnE+6TAdofmVa634IyX93vzukzbIlcwnzGM4MCWUG9GJqrCcbjFMXpZEVq
#jE4riFR/dm1nCep0zuGzd89hr/W9+LNoOhNd9vEGaO9eM0TfeMWVkXeBz+ldYFMS
#rYf2I0oSN/vtpJC4u+7aM2vhc0I3KqfzCwrn5cQK67IKxJX4L1mL3MoXjg3ym2z0
#AMmmrK2pTmhI4QRSr1fqqxOJer58M2kT1rYPMvi5+mdT6yviqW06ZlL5OoVOTtQZ
#N9dGVBm2JX7w8abR+dvyFDaiy8pDUqjFH8WtOifVDvPPPLwNFI63dYGjvFC7h6p4
#wcEHZcSURqgZJQYniJm7jCgyQLGmi8aj4pKyw0idUn65vPxiqqiE2RdaY5f3by4v
#2Vu2y2XwpF7A6RXgVQhwhOLDrNEE2KhvJuqlaXO/QV2QEEGP1u57VVcJ52rUwl6K
#Tvm16zScysDHnyagKla8zzi/nmX6gUakLU3wZdKglzQplXY6JgotXqe+f+NzmM1u
#rmkbE7OQl4wwnyprDZKgnUWefjFPpEzmFdyeBQ83KjZYNfyhvMBz2x/izat/OhsM
#g9MoPvEgwWsOE1LDDJNNCEYgtrzBztMozfZcwy4cZjGxK7yV2NpArapII3W4Agtt
#BraeeUEVjP6wENZHETaiVq3BAoEC6LnbVes30cMPqaoQ+XQJpFOLJ/GiaoHt9uaN
#DR6EkKIfGiaFD9dNXDiF9ue17wfdZ4uvCUpqNCZvCXBDtJiUF/lwHgxifIcQo4Al
#KgYU5SsmfNcsl5CLK3r19MUC2msFBLYbumay5JUwFIeoo5kOdBIZ9/QTsFGT85Dh
#DckZzaBETAXk09D1c7292v7By+fvD0+6L96/Otw/ODrG3RZVM/FG1WWttg4nab9m
#1/rnvrFT2O8SJnU2humuU17xa8jmy692mH02v/KzomfT357hlTH94Z6hcAnaE8Ym
#sFut7eOLHgyABKjSBNhj2JTqn3/t9fv4E7lcbWOZl37yNDlaTPBQmD5/1qQNHSq1
#Em7s0940CHMSkQhD8JwZt7nxkhdrdYP7pcx91G+ETxL5mFnsFSLjOEnrSrjTrngv
#ppHOMQSOe8np8f+HVzALfBzsSffx48f4X6v1L+Yn/tdUR+bl9TjSyryroqh0y4vM
#3vbbpQ+8i2TJ4ptlyV6oigmbX3BLOW7RTUsVvC5FO8+rt2hpzSaNjr7QnuL7Yokp
#oo8782kYXjGf0iFWi05ZvFzfyuO5H6k/8gwjrCa/jI/b8W8Hh4fpKZmiRAJGb0op
#2dGnw0tA37b63hnBigLqpErNphat+bT7S4WzcNqscRdWpn+HUFpepDFEAJWqrIj2
#2Un74wGd5AaF67XNikZiSzLnVWN01xZ3++iWny7Y9isppwacBSy+oRUb13Cq9fr4
#r8fby5XcDmAcj6fZ5DLVPI7/Mja/QSaXTL0kQ6gpE0wABc0fxjVYv/YYBD1NOuG9
#Jp/SzxrczhOMg2/rqVof9bcJw001dNrr/HM+MRYNnbafzfAMweKr3bpISJso8OTx
#gCeyoqQ9Hd/Vb2rJkeZeKxRWvJN29w/evXx1eJB6VkNz7EsRkuJH87UQJPV36cl2
#/52VXfNA066Nb0VHzItJ/h+QCOPOIYpXX+5mTeYv5Mgri7BvyAp8s2lkoNx61NQs
#dPNSafDBYMZuTphB1nUGjU/89Vf1h5JcDIx29hn2b0CxPUx/TWahtY5XNba8mocF
#KEOXue2xHUKbLN8xDwdbXB4Oz30T1wBd2nG3SOsR9+z/IWD+aD3+UZG57Rk3M9pZ
#BJz9lBeWq/Cue5OwKOfM22gDOdR7cJCD6bSVpQJWPJoqlRFxZfT+bkCRYF+cT2YL
#vN/JNsMelqseaWLSDFSj2aiHD337C6qa4G11iOhLYNlTHRBYw1y5ssrK8VoS2/CN
#0WcelKAERj7HuCCo68Pax0mxyyd8AIlnxoML6vfWIkyIZIu9UbKu/A6IZaTsyfOj
#Xw9OKC7qbvB8uyt2/Pb90d7BsSoXLgIk2LFJa5mNMDG+mqlk+vH7ly9ffVim/pPO
#vEUr/j0GirAQDsg9jb28qwUMjHi4p4OX26lvVUwUrv4L2nYVET3bZPPdBxRhSDI1
#akhLDNHMQEXOngcxSoiXRtUAxGnrvUhqTSUVvs+GlAis8olIZzGKXhEzfzr1UMRD
#k+K2WaCAxWgY95+OkSy0QWpSKkVBh7ZriEC3ob4h+8eezHG8pBMbgbgzQlmAIJ6B
#1QHtLeUqFWmVhBTxNUMBttw+zCf4Kkli7nfdvyFtK3IpxMzk5lJf7ELjs7lM5hg3
#eusrMlKrMLsLRnXmeCCsDkRqx8OG4IoFUq31Mv6mqrZS2vadw6FUX7pTyifPR/Mg
#TTeQKUpMkEtMZMZ3YMq/ffHvTpTC9+GrF+b7NMKIwRO7BDZ4SXnXe0oZ/1g9wAgV
#/y1dzbnBM7obphe+0Ihcl4iwlCbUkL9ni0hbSrLdg6f9m1soBgGlwmiy2Me6Q7Lr
#nkTecOV/lMDTL8P6WG4m8ReJQ+6r6uf6W87vycbaYhnoJ160WU2xtRQU8053O9lV
#fZa7C58DRoPK9e7+zYg+l8j8EaGLftcDdXnUI7Zp2anpKiFiJhNvcVnxr99IV7XC
#1dC2bd/N8jaC4R+xC2X0CBglllbvlqWxUY8mgqZUQRTCV8eY87Gs0EzupDxq2scK
#2hGlkh4OtcswZ4e91/sVHBGsFqldKivXPLuSGIFSxbnfeFZqy4ISI8lT7xXeyolY
#+QTZ7dvWpyrrtx0XAb4AcFTygmGsw1NrbkdW8UoVi/THA1JYkmemJSgJetrxXmp3
#fQiDz51oMHymxRGI45P9t+9PPHOjexKGooNWa/YOQhRrOTtDJr9/Y/q1XI/Rg5Fd
#xdCRO1i34bPZdZTJmFXGi8YqTTK7OuIiezKVe1KZuwv6cM8/va+bTEShbl7qZyas
#ZtQaZZNzUEZ+SZ40gS+iEh3/kCeztosKQ8ratXz9AfhE4SJx2zFzJWnLVzwCAKRh
#oBLnP94gAMY0P/f4ddEP9D6HcwLZXtfs3Te8N1n0VSARYDh1Xfrlm9fd/bcnr5+f
#7P3WBG10hKE+6U2xkETMEX4YUaoYjoszLBZCgAytR4o7Brp89FqBLFj0m03/0p0k
#bUcDO1UbITVk6O2s21658Y/owQ520Q/gehc1AcN6L6ZqIeya4dx6avktIhH0Syyg
#2rjtnzwcNEAFB6m3wSKeKnqrDlsSIPIAdtQ7+rE5dbCfEAVCM76LZiexqduiqtfB
#v+822TxUg0+Q6sbdJlVE+qwiZqAaBtpYjXGDXkTcNLFy24GsrI+Rg5UrCvRnDTuK
#m3TSUWbFZYaU8Z+vX+fMpmqI10KdN9DwBWNEmhoh6SU3oTTinrSjT3qbf9WqZWIT
#P6X16+c7a1nW1+SfuATaNm+xFkau/gRri3+YRufvMUqzGtXvu6jH99rJ390Me5j0
#Rni2dp0QwFJfaaGwlD0XzDqtfhPGu3rp3VIJZmq6B83N5TtNdSqUN6G9mWlNE2tN
#x7UOJj125Nxkf38Nc1p/qX/2NuArNfz9V8fPj193qxT9UEl2Xf0mptOaXSQp++0k
#mAvfbtd4mH3+77hrOzz4cIsB/TWbZIWau6PsM4hEHXiG3K6/+ZofMTh/w/FUToLB
#mBpfAGW6a7cDq7O3hARjr94gCZKNfQNGImqxfivsXustHmvwWL1p0F9avg0Xhtao
#VVz4/Gh9HqThQg6ErHneT0Z6IHtF/wL2GF9tdvp2LKaGdE0O+6qWnJ/sP0tGYW23
#nyFftPJLUq5wucBFxB2uaE8L6bE26/erT2P3lt5JM15xwQr/mWyPBv0g2sas3+2P
#6ZY6VH63h5KuDeX8nVy4NYzWPA9rfkMbbswBoHbeaBzXtMpyFrnDieFXH/5Zcxbu
#XBe43bmNPcv5fa+cTtKJ6yvZP+768a3mwt6HD6tmw6xL80EV9rgP0DrPJjZ3/+Dd
#rwdv6qMBcXh7deD2YtDknlMz8bujg3dHb4GNj7t7e8TK1Eh9SQU9VZcfsNnvpP5E
#HF/QSGGdR27hUCNIsdIY/u5dtVq1vuNCdBrrifBdvBG+q8qlTz5vr3L5BeQRatxL
#Eyc+2hZtOJ6N8bQQJhQe4dga+uz5gSLMabOTtqqOGHQRdL21acANpyFHAdv/6tjJ
#Fsahr/HE5Q/fU9G494p2Ka/vbCAJfA/Meln+T1d7w5gwkWNUKcUkrurg0hU93I9f
#Mbw9G4tLRn8UZgYt2F7RXsGMx78dvnoBsnglN643QYRzoEWjWT9lngVJGP7wXoNC
#3rU2tps7jc7ftk8fNR8s0d708cn9Gwt6+fHjT5XPJ/1TpzVR8rvNa35x7b/o7OZd
#uPscP/5t7VkOI/KN5/ntN3F1kzj7PC96vjNS2i2pqbrYznfuRD6ejTKdEfSi6sGu
#Fa9AoTUXtRDGCLHntKqYxlRHrtE/o4OLertnoZfvzJkXZ3d9hL6eav/nv5px9vjV
#/z5Y34iiOvjdtMd/ikUWr+7+dzTJ/vX53t7dbLJ09+uPZ5RVY9lumzE00tK9z6ZB
#tlHaPz/WfZf3VFyeXiyxiHJD1VluIQ68pKHEc3sQAbpDiJFYbP9AeNVhtLdXjRHl
#xTHaMwjdjQ64Gle3q3Pv0HJtTz98qOkqZVa0yC0s3GHU5H4FFepwMtl3wYrq3p5G
#+zWjsl89Jvs1mCh7693IU4eOzr09QlhxPcr8YOUsVTw8/P3182MtVX9IYki5Ig6v
#HxKOmS5h8cPcbyVp/ij4mlfVy+tJ3/jJWNMtLKq0xISWW+11OMpJ/JsYI+r1nb2j
#V+9OMM7In646qgI1nrDfreJM7X3M8g1rjvVEwt9QG/9hMVvkzfbscz4nZXI+BXX3
#MhsJCOrGefKWevyOFsl2+9XkEpb+wVt9Q/GXJHehf7XXRGu2gL1NPm35fk8ifyGy
#CJOfouthGDNHXdbGKMr6QmNDPZjMkWe53L/w6gJN+UQUeh2Gv8GAUeYho/NYP3e0
#tYXhyHeajZ32MwwE19yRoeDiT93ZUHBBUZWNV4s9PyqG64on7NzQtspR3s/uNR4z
#hUIqX2ewQ6l7xk+0K+gtaVx2exNzc7Thk5hnrktnHQBcZWIgI5HDIdIjzJoOK0dc
#9ouDCTpXzfJsovGndkEAXClieC6F6DATS88mGMhroEIkqqfQ7TUHPqF09OzkCwgJ
#disbv1rTSSPdek5RNrbQW9h78Z03XeGgwwGdKUCkNyf7r47SJrsVDqKQ+z9GYsfb
#cvYuMffNjTeZqSYtDX4/1o2aFPlWX0Ax83NFM8OEjgCaoaeuHM5YCDoO56VCF8d6
#a9jLRxhb3qN5LKg+soYuzptWsVkfr2hTBVHZushGM7+tiJRcG+w/Evt2myKLfett
#xTDbcsj+5nf1426uxUJ1hJ7SS16/3TfjQQn44IxwgNbvB5oslqMe95sOh/KULYLq
#YApTvMy7qknf09dAgk1bP7s1LE9Ax+2AvPsnqvs0H/2BFMJjjZl6qadNVpxNy3VY
#UJdcDzrCLaFWlN1SBT3RZZL7N0YT+/3g6PjV2zex2NgxZkQP+GkBq/29VUvGGgsN
#LMxsJtvWIm9tsmJ8+y8Uj3SvN0EvTWRt6CCrEuvck1jnREBHIWNiOpy72zcMIulr
#vId1ZgEXOTFCBK9r8mn0+UXG9UV8D0JH9mmlFRAOp9NP2QBfjMCYG9HuqPclgUf5
#4a5HLoe71Dgj3IuKK+vZZsAkm2wGbbplbzNYMjzFlYekA0XVDVm1o2/Wsg7xcbdd
#v39cq+Cy+unTg7cvf3iPKUjHB4+XSQfvnfRGxiB8mnS0ekP/uOQWPkn7w6+icBvA
#bj3fTEgRoCaOgSRIC0WtpAGqzATGG8UAninBZiRh+5WymeQTpXiNgOFayXsop4cF
#iPSPxURFIMWqxDVbJ6hbLeh56h+w8bOEQh8iCrT8P6NPhUo2VyoB80xu6DOJtspp
#KiAZqAAIwQzYs9+PCcIBDSQ+rDjIS/ppSrSgBrpV99Q+b6vMkCfmwKHYj2Q6NCX1
#aKhnGJJXQ+qFeoWAOLBUfUu3UsrRtRC0bnJAVnKUCVMTOpuSLbDhAqhNrQqAj1LE
#W8OdJLCNofdw8P0ISCBIVqWZX/TmQNfMwE7Ors3hDf6cTkbXKgvNkpYa+GFAYftQ
#z5HnLcbRvsoxkq3qsQKMUbwdcUoiYZmc58glxmDbm1y7AigzNHBE0BCllZwAVA3N
#AGdQf1DzbZzha6coN9B6SisvYjMrpnQMlJf2WR4ASayglDaqjryIH4gh391SuZfI
#L1wlc9yPCdCkMQyPpueq+VmRXebThQ42RI75tL1sDKaZ7ugUhplyCZpeMFSDF9gg
#6mOuISWdEkyshyYhgRKGsCZai3r2xs6WCT0OiyQ12lZjNO3DdLezxiy8ceVsqVso
#kr23h2+PsBXSXJ7Rp21GaTOoYCUN0KhAdi7m082EVCIN4QTrkghx3bVigjpLMhjf
#DC5Z37HLpdfn5IVlZoJF3KykE82UHhdIxGSK35Qw2np+gstTKcUacBLyN8GDH9fJ
#Re8y8yDhc6xTzS2XJF2UOkSVjhaTRH+PrpGZkRV7izIzrIaN0mULN8dVtwxbLUqa
#p0ok4K0xc5GeGjTaVMAsRoNak19wtXDriTkCAMWn28Wp0e3ipZkHqGkZhWxvlOPm
#kZbP50e//t6kGv8X0VCbvw==
+41
View File
@@ -0,0 +1,41 @@
scene
{
options
{
multisample 3
width 800
height 600
ambient_occlusion 5
}
camera
{
position <2, -3, 2>
look_at <0, 0, 1>
up <0, 0, 1>
}
light
{
position <200, -10, 50>
}
define material white
{
color <1, 1, 1>
}
sphere
{
radius 1
material white
translate <0, 0, 1>
}
plane
{
position <0, 0, 1>, 0
material white
}
}
+228
View File
@@ -0,0 +1,228 @@
scene
{
options
{
multisample 3
}
camera
{
position <3, -2.6, 2>
look_at <1.5, -1, 0>
up <0, 0, 1>
}
light
{
position <-2, -5, 6>
}
plane
{
position <1, -1, 1.5>, 3
material
{
color <1, 1, 0>
}
}
define material green
{
color <0, 1, 0>
shininess 3
}
subtract
{
intersect
{
box
{
size <1, 1, 1>
material
{
color <1, 0.4, 0.4>
}
}
sphere
{
radius 0.67
material
{
color <0, 0, 1>
shininess 3
}
}
}
union
{
cyl
{
size <0.35, 0.35, 1.2>
translate <0, 0, -0.6>
material green
}
union
{
cyl
{
size <0.35, 0.35, 1.2>
rotate 90, <1, 0, 0>
translate <0, 0, -0.6>
material green
}
cyl
{
size <0.35, 0.35, 1.2>
rotate 90, <0, 1, 0>
translate <0, 0, -0.6>
material green
}
}
}
}
scale <0.5, 0.5, 0.5>
{
translate <0, -3, -2>
{
intersect
{
box
{
size <1, 1, 1>
material
{
color <1, 0.4, 0.4>
}
}
sphere
{
radius 0.67
material
{
color <0, 0, 1>
shininess 3
}
}
}
translate <0, -1.5, -1>
{
box
{
size <1, 1, 1>
material
{
color <1, 0.4, 0.4>
}
}
}
translate <1.5, 0, -1>
{
sphere
{
radius 0.67
material
{
color <0, 0, 1>
shininess 3
}
}
}
}
translate <3, 0, -2>
{
union
{
cyl
{
size <0.35, 0.35, 1.2>
translate <0, 0, -0.6>
material green
}
union
{
cyl
{
size <0.35, 0.35, 1.2>
rotate 90, <1, 0, 0>
translate <0, 0, -0.6>
material green
}
cyl
{
size <0.35, 0.35, 1.2>
rotate 90, <0, 1, 0>
translate <0, 0, -0.6>
material green
}
}
}
translate <0, -1.5, -1>
{
cyl
{
size <0.35, 0.35, 1.2>
translate <0, 0, -0.6>
material green
}
}
translate <1.5, 0, -1>
{
union
{
cyl
{
size <0.35, 0.35, 1.2>
rotate 90, <1, 0, 0>
translate <0, 0, -0.6>
material green
}
cyl
{
size <0.35, 0.35, 1.2>
rotate 90, <0, 1, 0>
translate <0, 0, -0.6>
material green
}
}
translate <0, -1.5, -1>
{
cyl
{
size <0.35, 0.35, 1.2>
rotate 90, <1, 0, 0>
translate <0, 0, -0.6>
material green
}
}
translate <1.5, 0, -1>
{
cyl
{
size <0.35, 0.35, 1.2>
rotate 90, <0, 1, 0>
translate <0, 0, -0.6>
material green
}
}
}
}
}
}
+84
View File
@@ -0,0 +1,84 @@
scene
{
options
{
width 800
height 600
multisample 3
}
camera
{
position <1.0, -2, 1.2>
look_at <0, 0, 0.4>
up <0, 0, 1>
}
light
{
position <10, 0, 10>
}
define material cyan
{
color <0, 1, 1>
}
plane
{
position <0, 0, 1>, 0
material
{
color <1, 1, 0>
reflectance 0.6
}
}
translate <0, 0, 0.7>
{
box
{
size <0.4, 0.4, 0.4>
material
{
color <1.0, 0.6, 0>
}
}
cyl {
size <0.2, 0, 0.3>
translate <0, 0, 0.3>
material cyan
}
cyl {
size <0.2, 0, 0.3>
rotate 90, <1, 0, 0>
translate <0, 0, 0.3>
material cyan
}
cyl {
size <0.2, 0, 0.3>
rotate -90, <1, 0, 0>
translate <0, 0, 0.3>
material cyan
}
cyl {
size <0.2, 0, 0.3>
rotate 180, <1, 0, 0>
translate <0, 0, 0.3>
material cyan
}
cyl {
size <0.2, 0, 0.3>
rotate 90, <0, 1, 0>
translate <0, 0, 0.3>
material cyan
}
cyl {
size <0.2, 0, 0.3>
rotate -90, <0, 1, 0>
translate <0, 0, 0.3>
material cyan
}
}
}
+152
View File
@@ -0,0 +1,152 @@
scene
{
options
{
multisample 3
exposure 1.2
}
camera
{
position <1.2, -2, 1>
look_at <0, 0, 0>
}
light { position <10, -12, 8> }
plane
{
position <0, 0, 1>, 0.501
material
{
color <0.4, 1, 0.4>
reflectance 0.4
}
}
plane
{
position <1, 0, 0>, 1
material
{
color <1, 0.4, 0.4>
reflectance 0.4
}
}
plane
{
position <0, -1, 0>, 1
material
{
color <0.4, 0.4, 1>
reflectance 0.4
}
}
subtract
{
union
{
box { size <1, 0.8, 0.8> }
box { size <0.8, 1, 0.8> }
box { size <0.8, 0.8, 1> }
cyl { size <0.1, 0.1, 0.8> translate <0.4, 0.4, -0.4> }
cyl { size <0.1, 0.1, 0.8> translate <0.4, -0.4, -0.4> }
cyl { size <0.1, 0.1, 0.8> translate <-0.4, 0.4, -0.4> }
cyl { size <0.1, 0.1, 0.8> translate <-0.4, -0.4, -0.4> }
cyl {
size <.1, .1, .8>
translate <.4, -.4, .4>
rotate -90, <1, 0, 0>
}
cyl {
size <.1, .1, .8>
translate <.4, -.4, -.4>
rotate -90, <1, 0, 0>
}
cyl {
size <.1, .1, .8>
translate <-.4, -.4, .4>
rotate -90, <1, 0, 0>
}
cyl {
size <.1, .1, .8>
translate <-.4, -.4, -.4>
rotate -90, <1, 0, 0>
}
cyl {
size <.1, .1, .8>
translate <.4, -.4, .4>
rotate -90, <0, 1, 0>
}
cyl {
size <.1, .1, .8>
translate <.4, -.4, -.4>
rotate -90, <0, 1, 0>
}
cyl {
size <.1, .1, .8>
translate <.4, .4, .4>
rotate -90, <0, 1, 0>
}
cyl {
size <.1, .1, .8>
translate <.4, .4, -.4>
rotate -90, <0, 1, 0>
}
sphere { radius .1 translate <.4, .4, .4> }
sphere { radius .1 translate <.4, .4, -.4> }
sphere { radius .1 translate <.4, -.4, .4> }
sphere { radius .1 translate <.4, -.4, -.4> }
sphere { radius .1 translate <-.4, .4, .4> }
sphere { radius .1 translate <-.4, .4, -.4> }
sphere { radius .1 translate <-.4, -.4, .4> }
sphere { radius .1 translate <-.4, -.4, -.4> }
material
{
color <1, 0.4, 1>
transparency 0.4
}
}
union
{
sphere { radius .1 translate <0, -.5, 0> }
sphere { radius .1 translate <-.5, .25, -.25> }
sphere { radius .1 translate <-.5, -.25, .25> }
sphere { radius .1 translate <0, 0, -.5> }
sphere { radius .1 translate <.25, -.25, -.5> }
sphere { radius .1 translate <-.25, .25, -.5> }
sphere { radius .1 translate <-.25, -.25, .5> }
sphere { radius .1 translate <-.25, .25, .5> }
sphere { radius .1 translate <.25, -.25, .5> }
sphere { radius .1 translate <.25, .25, .5> }
sphere { radius .1 translate <.5, 0, 0> }
sphere { radius .1 translate <.5, .25, .25> }
sphere { radius .1 translate <.5, .25, -.25> }
sphere { radius .1 translate <.5, -.25, .25> }
sphere { radius .1 translate <.5, -.25, -.25> }
sphere { radius .1 translate <.25, .5, 0> }
sphere { radius .1 translate <.25, .5, -.25> }
sphere { radius .1 translate <.25, .5, .25> }
sphere { radius .1 translate <-.25, .5, 0> }
sphere { radius .1 translate <-.25, .5, -.25> }
sphere { radius .1 translate <-.25, .5, .25> }
material
{
color <1, 1, 1>
}
}
}
}
+134
View File
@@ -0,0 +1,134 @@
scene
{
options
{
ambient <0.2, 0.2, 0.2>
}
define material dw_blue {
color <0.000, 0.520, 0.546>
specular <0.5, 0.5, 0.5>
}
define material dw_brown {
color <0.634, 0.628, 0.126>
specular <0.5, 0.5, 0.5>
}
define material grey_ground {
color <0.3, 0.3, 0.3>
specular <0, 0, 0>
}
define shape dw_logo union {
subtract {
intersect {
cyl {
size <3.055, 3.055, 0.5>
translate <-4.454, 0.074, -0.25>
}
box {
size <6.01, 5.94, 1>
translate <-1.782, 0, 0>
}
}
cyl {
size <0.738, 0.738, 2>
translate <-3.645, 0.041, -1>
}
box {
size <1.96, 0.456, 2>
translate <-2.212, 0.048, 0>
}
material dw_blue
}
cyl {
size <0.307, 0.307, 0.5>
translate <-3.645, 0.041, -0.25>
material dw_brown
}
subtract {
extrude {
offset 0.5
polygon {
<4.787, -2.971>
<4.787, 1.565>
<4.196, 1.565>
<2.756, -2.375>
<1.367, 1.052>
<0.007, -2.40192>
<-0.891, -0.174>
<-3, -0.174>
<-3, -2.971>
}
translate <0, 0, -0.25>
}
cyl {
size <3.488, 3.488, 2>
translate <-4.454, 0.074, -1>
}
material dw_blue
}
subtract {
extrude {
offset 0.5
polygon {
<4.787, 2.025>
<4.787, 2.971>
<-3, 2.971>
<-3, 0.283>
<-0.588, 0.283>
<0.000, -1.179>
<1.368, 2.273>
<2.728, -1.083>
<3.877, 2.025>
}
translate <0, 0, -0.25>
}
cyl {
size <3.488, 3.488, 2>
translate <-4.454, 0.074, -1>
}
material dw_brown
}
scale 0.104
}
camera
{
position <0, 0, 10>
look_at <0, 0, 0>
up <0, 1, 0>
}
light
{
position <100, -100, 100>
}
plane
{
position <0, 0, 1>, 0
material grey_ground
}
for (local $i = 0; $i < 4; $i = $i + 1)
{
local $n_logos = 2 ^ ($i + 2)
for (local $j = 0; $j < $n_logos; $j = $j + 1)
{
shape dw_logo
{
rotate $j * 360 / $n_logos, <0, 0, 1>
translate <1.5 * ($i + 1), 0, 0.4 - 0.1 * $i>
if ($i > 0 && ($j + $i) % 2 == 1)
{
rotate 90, <0, 0, 1>
}
rotate -90, <0, 0, 1>
}
}
}
shape dw_logo { translate <0, 0, 0.5> }
}
+123
View File
@@ -0,0 +1,123 @@
scene {
define material dw_blue {
color <0.000, 0.520, 0.546>
specular <0.5, 0.5, 0.5>
}
define material dw_brown {
color <0.634, 0.628, 0.126>
specular <0.5, 0.5, 0.5>
}
define material grey_ground {
color <0.3, 0.3, 0.3>
shininess 30
}
define shape dw_logo union {
subtract {
intersect {
cyl {
size <3.055, 3.055, 0.5>
translate <-4.454, 0.074, -0.25>
}
box {
size <6.01, 5.94, 1>
translate <-1.782, 0, 0>
}
}
cyl {
size <0.738, 0.738, 2>
translate <-3.645, 0.041, -1>
}
box {
size <1.96, 0.456, 2>
translate <-2.212, 0.048, 0>
}
material dw_blue
}
cyl {
size <0.307, 0.307, 0.5>
translate <-3.645, 0.041, -0.25>
material dw_brown
}
subtract {
extrude {
offset 0.5
polygon {
<4.787, -2.971>
<4.787, 1.565>
<4.196, 1.565>
<2.756, -2.375>
<1.367, 1.052>
<0.007, -2.40192>
<-0.891, -0.174>
<-3, -0.174>
<-3, -2.971>
}
translate <0, 0, -0.25>
}
cyl {
size <3.488, 3.488, 2>
translate <-4.454, 0.074, -1>
}
material dw_blue
}
subtract {
extrude {
offset 0.5
polygon {
<4.787, 2.025>
<4.787, 2.971>
<-3, 2.971>
<-3, 0.283>
<-0.588, 0.283>
<0.000, -1.179>
<1.368, 2.273>
<2.728, -1.083>
<3.877, 2.025>
}
translate <0, 0, -0.25>
}
cyl {
size <3.488, 3.488, 2>
translate <-4.454, 0.074, -1>
}
material dw_brown
}
scale 0.104
}
shape dw_logo {
translate <0, 0.387, 0.309>
rotate 90, <1, 0, 0>
}
subtract {
plane {
position <0, 0, 1>, 0
}
shape dw_logo {
translate <0, 0, -0.025>
}
material grey_ground
}
camera {
position <-0.2, -0.8, 0.4>
look_at <-0.1, 0, 0.2>
up <0, 0, 1>
}
light {
position <10, -12, 5>
radius 0.2
jitter 3
}
options {
ambient_occlusion 5
multisample 3
}
}
+53
View File
@@ -0,0 +1,53 @@
scene
{
options
{
ambient_occlusion 2
multisample 2
exposure 1.2
}
camera
{
position <0, -10, 10>
look_at <0, 0, 2>
}
light { position <10, -12, 8> }
plane
{
position <0, 0, 1>, 0
material
{
color <0, 0.5, 0.1>
}
}
subtract
{
extrude { ngon 5, 6 offset 2 }
extrude { ngon 5, 5 offset 3 translate <0, 0, -0.5> }
material { color <1, 0.7, 0> }
}
union
{
extrude
{
ngon 6, 2
offset 3 { scale 0.5 position <4, 0> }
offset 3
offset 1 { scale 0 }
}
extrude
{
ngon 6, 2
offset 3 { scale 0.5 position <-4, 0> }
offset 3
offset 1 { scale 0 }
}
material { color <0, 0.9, 0.9> }
}
}
+55
View File
@@ -0,0 +1,55 @@
scene
{
camera
{
position <0, -40, 50>
look_at <0, 100, 0>
}
light
{
position <100, -100, 50>
}
define material mat
{
color <0, 0.8, 1>
}
define material glass
{
transparency 1
refraction 1.5
}
plane
{
position <0, 0, 1>, 0
material
{
color <0, 0.7, 0>
}
}
for (local $x = -200; $x <= 200; $x = $x + 40)
{
for (local $y = 0; $y <= 4000; $y = $y + 40)
{
sphere
{
radius 10
translate <$x, $y, 10>
if ($x == 0 && $y == 0)
{
material glass
translate <0, 0, 20>
}
else
{
material mat
}
}
}
}
}
+57
View File
@@ -0,0 +1,57 @@
scene
{
camera
{
position <0, -120, 80>
look_at <0, -40, 5>
}
light
{
position <100, -100, 100>
}
define material mat { color <0, 0.8, 1> }
define material mat2 { color <1, 0.7, 0> }
define material mat3 { transparency 0.5 reflectance 0.7 }
plane
{
position <0, 0, 1>, 0
material
{
color <0, 0.7, 0>
}
}
local $m = 0
for (local $x = -100; $x <= 100; $x = $x + 40)
{
for (local $y = -100; $y <= 100; $y = $y + 40)
{
sphere
{
radius 10
translate <$x, $y, 10>
if ($m % 3 == 0)
{
material mat
}
elsif ($m % 3 == 1)
{
material mat2
}
else
{
material
{
color <1, 0, 0>
transparency abs($x / 120)
}
}
}
$m = $m + 1
}
}
}
+54
View File
@@ -0,0 +1,54 @@
scene
{
options
{
multisample 4
width 1024
height 768
max_depth 15
}
camera
{
position <0.00001, -1.9, -0.000001>
look_at <0, 0, 0>
up <0, 0, 1>
}
define material mirror
{
color <0, 0, 0>
specular <0, 0, 0>
reflectance 1.0
}
plane { position <1, 0, 0>, 2 material mirror }
plane { position <-1, 0, 0>, 2 material mirror }
plane { position <0, 1, 0>, 2 material mirror }
plane { position <0, -1, 0>, 2 material mirror }
plane { position <0, 0, 1>, 2 material mirror }
plane { position <0, 0, -1>, 2 material mirror }
sphere
{
radius 0.5
material
{
reflectance 0.2
ambient <0.5, 0.5, 0.5>
diffuse <0.5, 0.5, 0.5>
shininess 80
}
}
light
{
position <1, -1, 1>
}
light
{
position <-1, 1, -1>
}
}
+151
View File
@@ -0,0 +1,151 @@
scene
{
options
{
ambient_occlusion 3
multisample 3
exposure 1.2
}
camera
{
position <5, -13, 9>
look_at <0, 0, 2>
}
light { position <10, -12, 8> radius 0.2 jitter 4 }
plane
{
position <0, 0, 1>, 0
material
{
color <0, 0.5, 0.1>
}
}
# define a reusable Die type
define shape Die subtract
{
union
{
box { size <1, 0.8, 0.8> }
box { size <0.8, 1, 0.8> }
box { size <0.8, 0.8, 1> }
cyl { size <0.1, 0.1, 0.8> translate <0.4, 0.4, -0.4> }
cyl { size <0.1, 0.1, 0.8> translate <0.4, -0.4, -0.4> }
cyl { size <0.1, 0.1, 0.8> translate <-0.4, 0.4, -0.4> }
cyl { size <0.1, 0.1, 0.8> translate <-0.4, -0.4, -0.4> }
cyl {
size <.1, .1, .8>
translate <.4, -.4, .4>
rotate -90, <1, 0, 0>
}
cyl {
size <.1, .1, .8>
translate <.4, -.4, -.4>
rotate -90, <1, 0, 0>
}
cyl {
size <.1, .1, .8>
translate <-.4, -.4, .4>
rotate -90, <1, 0, 0>
}
cyl {
size <.1, .1, .8>
translate <-.4, -.4, -.4>
rotate -90, <1, 0, 0>
}
cyl {
size <.1, .1, .8>
translate <.4, -.4, .4>
rotate -90, <0, 1, 0>
}
cyl {
size <.1, .1, .8>
translate <.4, -.4, -.4>
rotate -90, <0, 1, 0>
}
cyl {
size <.1, .1, .8>
translate <.4, .4, .4>
rotate -90, <0, 1, 0>
}
cyl {
size <.1, .1, .8>
translate <.4, .4, -.4>
rotate -90, <0, 1, 0>
}
define shape Corner sphere { radius 0.1 }
translate <.4, .4, .4> { shape Corner }
translate <.4, .4, -.4> { shape Corner }
translate <.4, -.4, .4> { shape Corner }
translate <.4, -.4, -.4> { shape Corner }
translate <-.4, .4, .4> { shape Corner }
translate <-.4, .4, -.4> { shape Corner }
translate <-.4, -.4, .4> { shape Corner }
translate <-.4, -.4, -.4> { shape Corner }
material
{
color <1, 0.4, 1>
transparency 0.4
}
}
union
{
define shape Pip sphere { radius 0.1 }
translate <0, -.5, 0> { shape Pip }
translate <-.5, .25, -.25> { shape Pip }
translate <-.5, -.25, .25> { shape Pip }
translate <0, 0, -.5> { shape Pip }
translate <.25, -.25, -.5> { shape Pip }
translate <-.25, .25, -.5> { shape Pip }
translate <-.25, -.25, .5> { shape Pip }
translate <-.25, .25, .5> { shape Pip }
translate <.25, -.25, .5> { shape Pip }
translate <.25, .25, .5> { shape Pip }
translate <.5, 0, 0> { shape Pip }
translate <.5, .25, .25> { shape Pip }
translate <.5, .25, -.25> { shape Pip }
translate <.5, -.25, .25> { shape Pip }
translate <.5, -.25, -.25> { shape Pip }
translate <.25, .5, 0> { shape Pip }
translate <.25, .5, -.25> { shape Pip }
translate <.25, .5, .25> { shape Pip }
translate <-.25, .5, 0> { shape Pip }
translate <-.25, .5, -.25> { shape Pip }
translate <-.25, .5, .25> { shape Pip }
material
{
color <1, 1, 1>
}
}
}
# Define an individual stack of dies
define shape DieStack union
{
translate <0, 0, 1.5> { scale 3 { shape Die } }
translate <0, 0, 4> { rotate 45, <0, 0, 1> { scale 2 { shape Die } } }
translate <0, 0, 5.5> { rotate 90, <0, 1, 0> { shape Die } }
}
# Instantiate various DieStack objects
translate <-5, 0, 0> { shape DieStack }
translate <5, 0, 0> { rotate 90, <0, 0, 1> { shape DieStack } }
translate <0, 5, 0> { rotate 180, <0, 0, 1> { shape DieStack } }
translate <0, -5, 0> { rotate 270, <0, 0, 1> { shape DieStack } }
}
+27
View File
@@ -0,0 +1,27 @@
scene {
options {
width 400
height 300
}
camera {
position <5, -5, 4>
look_at <0, 0, 1>
}
light {
position <10, -10, 50>
}
plane {
position <0, 0, 1>, 0
material {
color <0, 1, 0.2>
reflectance 0.4
}
}
sphere {
radius 1
translate <0, 0, 1>
material {
color <1, 1, 0>
}
}
}
+55
View File
@@ -0,0 +1,55 @@
scene
{
options
{
multisample 3
ambient <0.2, 0.2, 0.2>
}
camera
{
position <1, -2, 1>
look_at <0, 0, 0>
}
light
{
position <-5, -15, 20>
jitter 5
}
plane
{
position <0, 0, 1>, 1
material
{
color <0, 1, 1>
}
}
subtract
{
box
{
size <1, 1, 1>
material { color <0.2, 0.2, 1> }
}
subtract
{
sphere
{
radius 0.4
material { color <1, 0, 0> }
translate <0, -0.5, 0>
}
box
{
size <1, 1, 0.2>
material { color <0, 1, 0> }
translate <0, -0.5, 0>
}
}
}
}
+46
View File
@@ -0,0 +1,46 @@
scene
{
options
{
width 800
height 600
multisample 3
}
camera
{
position <2, -2.5, 3>
look_at <-0.5, 0, 0>
up <0, 0, 1>
}
light { position <5, 0, 5> }
plane
{
position <0, 0, 1>, 0
material { color <0.8, 0.8, 0.8> }
}
box
{
size <1, 1, 1>
translate <0, -1.5, 0.6>
material { color <0, 0, 1> transparency 0.8 }
}
box
{
size <1, 1, 1>
translate <0, 0, 0.6>
material { color <0, 0, 1> transparency 0.4 }
}
box
{
size <1, 1, 1>
translate <0, 1.5, 0.6>
material { color <0, 0, 1> transparency 0.1 }
}
}
-14
View File
@@ -1,14 +0,0 @@
#pragma once
struct Color
{
double r;
double g;
double b;
double a;
Color(double r = 0.0, double g = 0.0, double b = 0.0, double a = 1.0)
: r(r), g(g), b(b), a(a)
{
}
};
-6
View File
@@ -1,6 +0,0 @@
#include <fart/Image.h>
Image::Image(size_t width, size_t height)
: width(width), height(height), pixels(width * height)
{
}
-18
View File
@@ -1,18 +0,0 @@
#pragma once
#include <fart/Color.h>
#include <stddef.h>
#include <vector>
struct Image
{
size_t width;
size_t height;
std::vector<Color> pixels;
Image(size_t width, size_t height);
Color & operator[](size_t x, size_t y)
{
return this->pixels[this->width * y + x];
}
};
-15
View File
@@ -1,15 +0,0 @@
#include <fart/ImageWriter.h>
#include <fart/PngImageWriter.h>
#include <stdio.h>
#include <filesystem>
ImageWriter * ImageWriter::build(const std::string & fname)
{
std::string ext = std::filesystem::path(fname).extension().string();
if (ext == ".png")
{
return new PngImageWriter(fname);
}
fprintf(stderr, "Unsupported output image format: '%s'\n", fname.c_str());
return nullptr;
}
-16
View File
@@ -1,16 +0,0 @@
#pragma once
#include <string>
#include <fart/Image.h>
class ImageWriter
{
public:
static ImageWriter * build(const std::string & fname);
virtual ~ImageWriter() = default;
virtual bool write(const Image & image) = 0;
protected:
ImageWriter(const std::string & fname) : fname(fname) {}
std::string fname;
};
-39
View File
@@ -1,39 +0,0 @@
#include <fart/PngImageWriter.h>
#include <png.h>
#include <stdint.h>
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <vector>
static uint8_t to_byte(double v)
{
return (uint8_t)std::lround(std::clamp(v, 0.0, 1.0) * 255.0);
}
bool PngImageWriter::write(const Image & image)
{
std::vector<uint8_t> buffer(image.width * image.height * 4u);
for (size_t i = 0u; i < image.pixels.size(); i++)
{
const Color & c = image.pixels[i];
buffer[i * 4u + 0u] = to_byte(c.r);
buffer[i * 4u + 1u] = to_byte(c.g);
buffer[i * 4u + 2u] = to_byte(c.b);
buffer[i * 4u + 3u] = to_byte(c.a);
}
png_image png = {};
png.version = PNG_IMAGE_VERSION;
png.width = image.width;
png.height = image.height;
png.format = PNG_FORMAT_RGBA;
if (!png_image_write_to_file(&png, fname.c_str(), 0, buffer.data(), 0, nullptr))
{
fprintf(stderr, "Error writing PNG file '%s': %s\n", fname.c_str(), png.message);
png_image_free(&png);
return false;
}
return true;
}
-10
View File
@@ -1,10 +0,0 @@
#pragma once
#include <fart/ImageWriter.h>
class PngImageWriter : public ImageWriter
{
public:
PngImageWriter(const std::string & fname) : ImageWriter(fname) {}
bool write(const Image & image) override;
};
+54
View File
@@ -0,0 +1,54 @@
module fart.bfile;
import std.stdio;
/**
* Struct to handle easily writing data to a binary file.
*/
public struct BFile
{
/**
* Underlying file handle.
*/
private File m_file;
/**
* Create a binary file.
*/
this(string filename)
{
m_file = File(filename, "wb");
}
/**
* Write arbitrary byte data to the file.
*/
public void write(const(void) * data, size_t length)
{
write((cast(const(ubyte) *)data)[0..length]);
}
/**
* Write an array to the file.
*/
public void write(T)(const(T)[] data)
{
m_file.rawWrite(data);
}
/**
* Write an arbitrary object to the file.
*/
public void writeObject(T)(ref const(T) obj)
{
write(&obj, obj.sizeof);
}
/**
* Close the file.
*/
public void close()
{
m_file.close();
}
}
+45
View File
@@ -0,0 +1,45 @@
module fart.color;
/**
* Structure to represent a RGBA color value.
*/
struct Color
{
/** Red color component. */
double r;
/** Green color component. */
double g;
/** Blue color component. */
double b;
/** Alpha color component. */
double a;
/**
* Convert color to a 32-bit integer RGBA value.
*
* Each color component uses one byte.
*/
public ubyte[] rgba32() const
{
return [toubyte(r), toubyte(g), toubyte(b), toubyte(a)];
}
/**
* Scale a floating point color component value to an unsigned 8-bit byte
* value.
*
* @param v
* Floating point color component value.
*
* @return Unsigned 8-bit byte value for the color component.
*/
private static ubyte toubyte(double v)
{
return cast(ubyte)(0xFF * v);
}
public static immutable Color TRANSPARENT = Color(0, 0, 0, 0);
}
+18
View File
@@ -0,0 +1,18 @@
module fart.crc32;
import std.digest.crc;
/**
* Calculate the CRC32 across the given chunk(s) of data.
*/
public uint crc32(Args...)(Args data)
{
CRC32 crc32;
crc32.start();
static foreach (arg; data)
{
crc32.put(cast(const(ubyte)[])arg);
}
auto crc = crc32.finish();
return crc[0] | (crc[1] << 8) | (crc[2] << 16) | (crc[3] << 24);
}
+35
View File
@@ -0,0 +1,35 @@
/**
* @file
*
* Host to network byte-swapping functions.
*/
module fart.hton;
version (BigEndian)
{
public uint htonl(uint v)
{
return v;
}
public uint ntohl(uint v)
{
return v;
}
}
version (LittleEndian)
{
import core.bitop;
public uint htonl(uint v)
{
return bswap(v);
}
public uint ntohl(uint v)
{
return bswap(v);
}
}
-7
View File
@@ -1,7 +0,0 @@
#include <stdio.h>
int main(int argc, char * argv[])
{
printf("Hello\n");
return 0;
}
+27
View File
@@ -0,0 +1,27 @@
module fart.main;
import fart.png;
import fart.color;
/**
* Main program entry point.
*
* @param args
* Program arguments.
*/
int main(string[] args)
{
size_t width = 800;
size_t height = 600;
string output_filename = "out.png";
Color[] pixels = [];
for (size_t y = 0; y < height; y++)
{
for (size_t x = 0; x < width; x++)
{
pixels ~= Color.TRANSPARENT;
}
}
write_png(output_filename, width, height, pixels);
return 0;
}
+158
View File
@@ -0,0 +1,158 @@
module fart.png;
import std.zlib;
import std.digest;
import fart.bfile;
import fart.crc32;
import fart.hton;
import fart.color;
/**
* PNG file header.
*/
private immutable ubyte[] HEADER = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
/**
* PNG IHDR chunk.
*/
struct IHDR
{
uint width;
uint height;
ubyte bit_depth;
ubyte color_type;
ubyte compression;
ubyte filter;
ubyte interlace;
ubyte[0] end;
this(size_t width, size_t height)
{
this.width = htonl(cast(uint)width);
this.height = htonl(cast(uint)height);
this.bit_depth = 8;
this.color_type = 6;
this.compression = 0;
this.filter = 0;
this.interlace = 0;
}
public const(void) * data()
{
return &this;
}
public size_t data_length()
{
return end.offsetof;
}
}
/**
* PNG IDAT chunk.
*/
struct IDAT
{
private const(ubyte)[] m_data;
this(ubyte[] data)
{
m_data = compress(data);
}
public const(void) * data()
{
return m_data.ptr;
}
public size_t data_length()
{
return m_data.length;
}
}
/**
* PNG IEND chunk.
*/
struct IEND
{
public const(void) * data()
{
return &this;
}
public size_t data_length()
{
return 0;
}
}
/**
* Write a PNG chunk to the output file.
*
* @param file
* Output file
* @param chunk_type
* Chunk type.
* @param chunk
* Chunk to write.
*/
private void write_chunk(Chunk)(BFile file, string chunk_type, Chunk chunk)
{
size_t chunk_data_length = chunk.data_length();
uint chunk_length_be32 = htonl(cast(uint)chunk_data_length);
file.writeObject(chunk_length_be32);
file.write(chunk_type);
const(ubyte)[] chunk_data = (cast(const(ubyte) *)chunk.data())[0..chunk_data_length];
file.write(chunk_data);
uint crc_be32 = htonl(crc32(chunk_type, chunk_data));
file.writeObject(crc_be32);
}
/**
* Write a PNG image from the given metadata and pixel data.
*
* @param filename
* Name of file to write.
* @param width
* Width of image.
* @param height
* Height of image.
* @param data
* Pixel color data.
*/
public void write_png(string filename, size_t width, size_t height, const(Color)[] data)
{
if (data.length != width * height)
return;
/* Convert Color values to 32-bit RGBA values. */
ubyte[] pixel_data;
size_t data_index;
for (size_t y = 0; y < height; y++)
{
/* Filter method 0 (None) */
pixel_data ~= 0;
for (size_t x = 0; x < width; x++)
{
pixel_data ~= data[data_index++].rgba32();
}
}
/* Open output file. */
BFile file = BFile(filename);
/* Write PNG header. */
file.write(HEADER);
/* Write IHDR chunk. */
IHDR ihdr = IHDR(width, height);
write_chunk(file, "IHDR", ihdr);
/* Write IDAT chunk. */
IDAT idat = IDAT(pixel_data);
write_chunk(file, "IDAT", idat);
/* Write IEND chunk. */
IEND iend;
write_chunk(file, "IEND", iend);
/* Close output file. */
file.close();
}
+190
View File
@@ -0,0 +1,190 @@
module fart.vector;
import std.math;
/**
* Structure to represent a 3-dimensional vector.
*/
struct Vector
{
/** Vector X coordinate. */
double x;
/** Vector Y coordinate. */
double y;
/** Vector Z coordinate. */
double z;
/**
* Compute the cross product of two vectors.
*/
public Vector cross()(auto ref const Vector other) const
{
return Vector(y * other.z - z * other.y,
z * other.x - x * other.z,
x * other.y - y * other.x);
}
/**
* Compute the dot product of two vectors.
*/
public double dot()(auto ref const Vector other) const
{
return x * other.x + y * other.y + z * other.z;
}
/**
* Get the magnitude of the vector.
*/
public double mag() const
{
return sqrt(mag2());
}
/**
* Get the squared magnitude of the vector.
*/
public double mag2() const
{
return x * x + y * y + z * z;
}
/**
* Normalize the vector to have unit length.
*/
public ref Vector normalize()
{
double mag = mag();
x /= mag;
y /= mag;
z /= mag;
return this;
}
/**
* Get a normalized vector in the same direction as this.
*/
public Vector normalized() const
{
double mag = mag();
return Vector(x / mag, y / mag, z / mag);
}
/**
* Project the vector onto a target vector.
*/
public Vector proj()(auto ref const Vector other) const
{
Vector on = other.normalized();
return on * dot(on);
}
/**
* Add two vectors.
*/
public Vector opBinary(string op : "+")(auto ref const Vector other) const
{
return Vector(x + other.x, y + other.y, z + other.z);
}
/**
* Add two vectors and assign to self.
*/
public Vector opOpAssign(string op : "+")(auto ref const Vector other)
{
x += other.x;
y += other.y;
z += other.z;
return this;
}
/**
* Negate a vector.
*/
public Vector opUnary(string op : "-")() const
{
return Vector(-x, -y, -z);
}
/**
* Subtract two vectors.
*/
public Vector opBinary(string op : "-")(auto ref const Vector other) const
{
return Vector(x - other.x, y - other.y, z - other.z);
}
/**
* Subtract two vectors and assign to self.
*/
public Vector opOpAssign(string op : "-")(auto ref const Vector other)
{
x -= other.x;
y -= other.y;
z -= other.z;
return this;
}
/**
* Scale a vector.
*/
public Vector opBinary(string op : "*")(double m) const
{
return Vector(x * m, y * m, z * m);
}
/**
* Scale a vector.
*/
public Vector opBinaryRight(string op : "*")(double m) const
{
return Vector(x * m, y * m, z * m);
}
/**
* Compute the cross product of two vectors.
*/
public Vector opBinary(string op : "*")(auto ref const Vector other) const
{
return cross(other);
}
public static immutable Vector X = Vector(1.0, 0.0, 0.0);
public static immutable Vector Y = Vector(0.0, 1.0, 0.0);
public static immutable Vector Z = Vector(0.0, 0.0, 1.0);
}
unittest
{
Vector v = Vector(1, 2, 3);
const Vector w = Vector(0, 4, 5);
Vector v_times_2 = v * 2;
assert(v_times_2.x == 2);
assert(v_times_2.y == 4);
assert(v_times_2.z == 6);
Vector v_plus_w = v + w;
assert(v_plus_w == Vector(1, 6, 8));
Vector v_minus_w = v - w;
assert(v_minus_w == Vector(1, -2, -2));
assert(v_minus_w.mag2() == 9.0);
assert(v_minus_w.mag() == 3.0);
v += v_minus_w;
assert(v == 2 * Vector.X + 0 * Vector.Y + Vector.Z);
assert(Vector.X * Vector.Y == Vector.Z);
assert(Vector.Y * Vector.Z == Vector.X);
assert(Vector.Z * Vector.X == Vector.Y);
assert(Vector.Y * Vector.X == -Vector.Z);
assert(Vector.Z * Vector.Y == -Vector.X);
assert(Vector.X * Vector.Z == -Vector.Y);
assert(w.proj(Vector.X) == Vector(0, 0, 0));
assert(w.proj(Vector.Y) == Vector(0, 4, 0));
assert(w.proj(Vector.Z) == Vector(0, 0, 5));
}
+22
View File
@@ -0,0 +1,22 @@
<<
import std.conv;
>>
token background;
token comma /,/;
token number /\d+(\.\d+)?/;
token lt /</;
token gt />/;
token semicolon /;/;
Start -> Statements;
Statements -> ;
Statements -> Statement Statements;
Statement -> BackgroundStatement;
BackgroundStatement -> background Vec3 semicolon;
Vec3 -> lt number comma number comma number gt;
File renamed without changes.
View File
File renamed without changes.