diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ad7fcec --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +data/config.josn \ No newline at end of file diff --git a/data/.gitkeep b/data/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/config.json b/data/config.json new file mode 100644 index 0000000..4ae889d --- /dev/null +++ b/data/config.json @@ -0,0 +1 @@ +{"config":{"spec_version":2,"hostname":"192.168.49.1","port":8962,"presets":[]},"data":{"groups":[],"actions":[],"values":[]}} \ No newline at end of file diff --git a/lib/backend.rb b/lib/backend.rb new file mode 100644 index 0000000..c4dafd9 --- /dev/null +++ b/lib/backend.rb @@ -0,0 +1,49 @@ +module TAC + class Backend + attr_reader :config, :tacnet + def initialize + @config = load_config + @tacnet = TACNET.new + end + + def load_config + if File.exist?(TAC::CONFIG_PATH) + JSON.parse(File.read( TAC::CONFIG_PATH )) + else + write_default_config + load_config + end + end + + def write_default_config + File.open(TAC::CONFIG_PATH, "w") do |f| + f.write JSON.dump( + { + config: { + spec_version: TAC::CONFIG_SPEC_VERSION, + hostname: TACNET::DEFAULT_HOSTNAME, + port: TACNET::DEFAULT_PORT, + presets: [], + }, + data: { + groups: [], + actions: [], + values: [], + }, + } + ) + end + end + + def refresh_config + load_config + + $window.states.clear + $window.push_state(Editor) + end + + def refresh_tacnet_status + $window.current_state.refresh_tacnet_status + end + end +end \ No newline at end of file diff --git a/lib/dialog.rb b/lib/dialog.rb new file mode 100644 index 0000000..8a1943e --- /dev/null +++ b/lib/dialog.rb @@ -0,0 +1,66 @@ +module TAC + class Dialog < CyberarmEngine::GuiState + def setup + theme(THEME) + background Gosu::Color.new(0x88_000000) + + @title = @options[:title] ? @options[:title] : "#{self.class}" + @window_width, @window_height = window.width, window.height + + @dialog_root = stack width: 250, height: 400, border_thickness: 2, border_color: [TAC::Palette::TIMECRAFTERS_PRIMARY, TAC::Palette::TIMECRAFTERS_SECONDARY] do + # Title bar + flow width: 1.0, height: 0.1 do + background [TAC::Palette::TIMECRAFTERS_PRIMARY, TAC::Palette::TIMECRAFTERS_SECONDARY] + + # title + flow width: 0.9 do + label @title + end + + # Buttons + flow width: 0.1 do + button "X", text_size: 24 do + close + end + end + end + + # Dialog body + stack width: 1.0, height: 0.9 do + build + end + end + + center_dialog + end + + def build + end + + def center_dialog + @dialog_root.style.x = window.width / 2 - @dialog_root.style.width / 2 + @dialog_root.style.y = window.height / 2 - @dialog_root.style.height / 2 + end + + def draw + $window.previous_state.draw + Gosu.flush + + super + end + + def update + super + + if window.width != @window_width or window.height != @window_height + center_dialog + + @window_width, @window_height = window.width, window.height + end + end + + def close + $window.pop_state + end + end +end \ No newline at end of file diff --git a/lib/dialogs/name_prompt_dialog.rb b/lib/dialogs/name_prompt_dialog.rb new file mode 100644 index 0000000..9f14c1e --- /dev/null +++ b/lib/dialogs/name_prompt_dialog.rb @@ -0,0 +1,25 @@ +module TAC + class Dialog + class NamePromptDialog < Dialog + def build + background Gosu::Color::GRAY + label @options[:subtitle] + + flow width: 1.0 do + label "Name", width: 0.25 + edit_line "", width: 0.70 + end + + flow width: 1.0 do + button "Cancel", width: 0.475 do + close + end + + button @options[:submit_label], width: 0.475 do + @options[:callback].call(self) + end + end + end + end + end +end \ No newline at end of file diff --git a/lib/palette.rb b/lib/palette.rb index 43beab0..c88b09b 100644 --- a/lib/palette.rb +++ b/lib/palette.rb @@ -6,6 +6,7 @@ module TAC TIMECRAFTERS_PRIMARY = Gosu::Color.new(0xff008000) TIMECRAFTERS_SECONDARY = Gosu::Color.new(0xff006000) + TIMECRAFTERS_TERTIARY = Gosu::Color.new(0xff00d000) TACNET_PRIMARY = Gosu::Color.new(0xff000080) TACNET_SECONDARY = Gosu::Color.new(0xff000060) diff --git a/lib/states/editor.rb b/lib/states/editor.rb index da430df..72f1afc 100644 --- a/lib/states/editor.rb +++ b/lib/states/editor.rb @@ -2,6 +2,8 @@ module TAC class States class Editor < CyberarmEngine::GuiState def setup + theme(THEME) + stack width: 1.0, height: 1.0 do stack width: 1.0, height: 0.1 do background [TAC::Palette::TIMECRAFTERS_PRIMARY, TAC::Palette::TIMECRAFTERS_SECONDARY] @@ -11,21 +13,29 @@ module TAC label TAC::NAME, color: Gosu::Color::BLACK, bold: true flow do - [:add, :delete, :clone, :create, :simulate].each do |b| - button b.capitalize, text_size: 18 + button "Add Group", text_size: 18 do + push_state(TAC::Dialog::NamePromptDialog, title: "Create Group", subtitle: "Add Group", submit_label: "Add", callback: proc {|instance| instance.close }) + end + button "Add Action", text_size: 18 do + push_state(TAC::Dialog::NamePromptDialog, title: "Create Action", subtitle: "Add Action", submit_label: "Add", callback: proc {|instance| instance.close }) + end + button "Add Value", text_size: 18 do + push_state(TAC::Dialog::NamePromptDialog, title: "Create Value", subtitle: "Add Value", submit_label: "Add", callback: proc {|instance| instance.close }) end end end flow width: 0.299 do stack width: 0.5 do - label "TACNET", color: TAC::Palette::TACNET_PRIMARY - @tacnet_ip_address = label "192.168.49.1", color: TAC::Palette::TACNET_SECONDARY + label "TACNET v#{TACNET::Packet::PROTOCOL_VERSION}", color: TAC::Palette::TACNET_PRIMARY + @tacnet_ip_address = label "#{TACNET::DEFAULT_HOSTNAME}:#{TACNET::DEFAULT_PORT}", color: TAC::Palette::TACNET_SECONDARY end stack width: 0.499 do @tacnet_status = label "Connection Error", background: TAC::Palette::TACNET_CONNECTION_ERROR, text_size: 18, padding: 5, margin_top: 2 - @tacnet_connection_button = button "Connect", text_size: 18 + @tacnet_connection_button = button "Connect", text_size: 18 do + window.backend.tacnet.connect + end end end end diff --git a/lib/tac.rb b/lib/tac.rb new file mode 100644 index 0000000..dcf3f79 --- /dev/null +++ b/lib/tac.rb @@ -0,0 +1,6 @@ +module TAC + ROOT_PATH = File.expand_path("../..", __FILE__) + CONFIG_PATH = "#{ROOT_PATH}/data/config.json" + + CONFIG_SPEC_VERSION = 2 +end \ No newline at end of file diff --git a/lib/tacnet.rb b/lib/tacnet.rb new file mode 100644 index 0000000..4f0c365 --- /dev/null +++ b/lib/tacnet.rb @@ -0,0 +1,22 @@ +module TAC + class TACNET + DEFAULT_HOSTNAME = "192.168.49.1" + DEFAULT_PORT = 8962 + + SYNC_INTERVAL = 250 # ms + HEARTBEAT_INTERVAL = 1_500 # ms + + def initialize + @connection = nil + @server = nil + end + + def connect(hostname = DEFAULT_HOSTNAME, port = DEFAULT_PORT, error_callback = proc {}) + return if @connection && @connect.connected? + + @connection = Connection.new(hostname, port) + puts "Connecting..." + @connection.connect(error_callback) + end + end +end \ No newline at end of file diff --git a/lib/tacnet/client.rb b/lib/tacnet/client.rb new file mode 100644 index 0000000..5ab6131 --- /dev/null +++ b/lib/tacnet/client.rb @@ -0,0 +1,122 @@ +module TAC + class TACNET + class Client + CHUNK_SIZE = 4096 + + attr_reader :uuid, :read_queue, :write_queue, :socket, + :packets_sent, :packets_received, + :data_sent, :data_received + attr_accessor :sync_interval + def initialize + @uuid = SecureRandom.uuid + @read_queue = [] + @write_queue = [] + + @sync_interval = 100 + + @packets_sent, @packets_received = 0, 0 + @data_sent, @data_received = 0, 0 + end + + def socket=(socket) + @socket = socket + + listen + end + + def listen + Thread.new do + while connected? + # Read from socket + while message_in = read + if message_in.empty? + break + else + @read_queue << message_in + + @packets_received += 1 + @data_received += message_in.length + end + end + + # Write to socket + while message_out = @write_queue.shift + write(message_out) + + @packets_sent += 1 + @data_sent += message_out.length + end + + sleep @sync_interval / 1000.0 + end + end + end + + def sync(&block) + block.call + end + + def handle_read_queue + message = gets + + while message + puts(message) + + message = gets + end + end + + def connected? + !closed? + end + + def bound? + @socket.bound? if @socket + end + + def closed? + @socket.closed? if @socket + end + + def write(message) + @socket.puts("#{message}\r\n\n") + end + + def read + message = "" + + begin + data = @socket.readpartial(CHUNK_SIZE) + message += message + end until message.end_with?("\r\n\n") + + return message + end + + def puts(message) + @write_queue << message + end + + def gets + @read_queue.shift + end + + def encode(message) + return message + end + + def decode(blob) + return blob + end + + def flush + @socket.flush if socket + end + + def close(reason = nil) + write(reason) if reason + @socket.close if @socket + end + end + end +end \ No newline at end of file diff --git a/lib/tacnet/connection.rb b/lib/tacnet/connection.rb new file mode 100644 index 0000000..dd20249 --- /dev/null +++ b/lib/tacnet/connection.rb @@ -0,0 +1,58 @@ +module TAC + class TACNET + class Connection + def initialize(hostname = DEFAULT_HOSTNAME, port = DEFAULT_PORT) + @hostname = hostname + @port = port + + @last_sync_time = 0 + @sync_interval = SYNC_INTERVAL + + @last_heartbeat_sent = 0 + @heartbeat_interval = HEARTBEAT_INTERVAL + + @connection_handler = proc do + handle_connection + end + end + + def connect(error_callback) + return if @client + + @client = Client.new + + Thread.new do + begin + @client.socket = Socket.tcp(@hostname, @port, connect_timeout: 5) + + while @client && @client.connected? + if Gosu.milliseconds > @last_sync_time + @sync_interval + @last_sync_time = Gosu.milliseconds + + @client.sync(@connection_handler) + end + end + + rescue => error + p error + error_callback.call(error) + end + end + end + + def handle_connection + if @client && @client.connected? + message = @client.gets + + PacketHandler.handle(message) if message + + if Gosu.milliseconds > @last_heartbeat_sent + @heartbeat_interval + last_heartbeat_sent = Gosu.milliseconds + + client.puts(PacketHandler.packet_heartbeat) + end + end + end + end + end +end \ No newline at end of file diff --git a/lib/tacnet/packet.rb b/lib/tacnet/packet.rb new file mode 100644 index 0000000..ae7ab1f --- /dev/null +++ b/lib/tacnet/packet.rb @@ -0,0 +1,89 @@ +module TAC + class TACNET + class Packet + PROTOCOL_VERSION = "0" + PROTOCOL_HEADER_SEPERATOR = "|" + PROTOCOL_HEARTBEAT = "heartbeat" + + PACKET_TYPES = { + handshake: 0, + heartbeat: 1, + dump_config: 2, + + add_group: 3, + update_group: 4, + delete_group: 5, + + add_action: 6, + update_action: 7, + delete_action: 8, + + add_variable: 9, + update_variable: 10, + delete_variable: 11, + } + + def self.from_stream(message) + slice = message.split("|", 4) + + if slice.size < 4 + warn "Failed to split packet along first 4 " + PROTOCOL_HEADER_SEPERATOR + ". Raw return: " + Arrays.toString(slice) + return nil + end + + if slice.first != PROTOCOL_VERSION + warn "Incompatible protocol version received, expected: " + PROTOCOL_VERSION + " got: " + slice.first + return nil + end + + unless valid_packet_type?(Integer(slice[1])) + warn "Unknown packet type detected: #{slice[1]}" + return nil + end + + version = slice[0] + type = PACKET_TYPES.key(Integer(slice[1])) + content_length = Integer(slice[2]) + content = slice[3] + + return Packet.new(version, type, content_length, body) + end + + def self.create(packet_type, body) + Packet.new(PROTOCOL_VERSION, packet_type, body.length, body) + end + + def self.valid_packet_type?(packet_type) + PACKET_TYPES.values.find { |t| t == packet_type } + end + + attr_reader :version, :type, :content_length, :body + def initialize(version, type, content_length, body) + @version = version + @type = type + @content_length = content_length + @body = body + end + + def encode_header + string = "" + string += PROTOCOL_VERSION + string += PROTOCOL_HEADER_SEPERATOR + string += packet_type + string += PROTOCOL_HEADER_SEPERATOR + string += content_length + string += PROTOCOL_HEADER_SEPERATOR + + return string + end + + def valid? + true + end + + def to_s + "#{encode_header}#{body}" + end + end + end +end \ No newline at end of file diff --git a/lib/tacnet/packet_handler.rb b/lib/tacnet/packet_handler.rb new file mode 100644 index 0000000..03420dc --- /dev/null +++ b/lib/tacnet/packet_handler.rb @@ -0,0 +1,65 @@ +module TAC + class TACNET + class PacketHandler + def initialize(host_is_a_connection: false) + @host_is_a_connection = host_is_a_connection + end + + def handle(message) + packet = Packet.from_stream(message) + + if packet + hand_off(packet) + else + warn "Rejected raw packet: #{message}" + end + end + + def hand_off(packet) + case packet.type + when :handshake + handle_handshake(packet) + when :heartbeat + handle_heartbeat(packet) + when :dump_config + handle_dump_config(packet) + else + warn "No hand off available for packet type: #{packet.type}" + end + end + + def handle_handshake(packet) + end + + def handle_heartbeat(packet) + end + + def handle_dump_config(packet) + begin + hash = JSON.parse(packet.body) + + if @host_is_a_connection + File.open("#{TAC::ROOT_PATH}/data/config.json", "w") { |f| f.write packet.body } + + $window.backend.update_config + end + rescue JSON::ParserError + end + end + + def self.packet_handshake(client_uuid) + Packet.create(Packet::PACKET_TYPES[:handshake], client_uuid) + end + + def self.packet_heartbeat + Packet.create(Packet::PACKET_TYPES[:heartbeat], Packet::PROTOCOL_VERSION) + end + + def self.packet_dump_config(string) + string = string.gsub("\n", " ") + + Packet.create(Packet::PACKET_TYPES[:dump_config], string) + end + end + end +end \ No newline at end of file diff --git a/lib/tacnet/server.rb b/lib/tacnet/server.rb new file mode 100644 index 0000000..118c49e --- /dev/null +++ b/lib/tacnet/server.rb @@ -0,0 +1,129 @@ +module TAC + class TACNET + class Server + attr_reader :active_client, + :packets_sent, :packets_received, :data_sent, :data_received, + :client_last_packets_sent, :client_last_packets_received, :client_last_data_sent, :client_last_data_received + def initialize(port = DEFAULT_PORT) + @port = port + + @socket = nil + @active_client = nil + @connection_attempts = 0 + @max_connection_attempts = 10 + + @packets_sent, @packets_received, @client_last_packets_sent, @client_last_packets_received = 0, 0, 0, 0 + @data_sent, @data_received, @client_last_data_sent, @client_last_data_received = 0, 0, 0, 0 + + @last_sync_time = 0 + @sync_interval = SYNC_INTERVAL + + @last_heartbeat_sent = 0 + @heartbeat_interval = HEARTBEAT_INTERVAL + + @client_handler_proc = proc do + handle_client + end + + @packet_handler = PacketHandler.new + end + + def start + Thread.new do + while !@socket && @connection_attempts < @max_connection_attempts + begin + @socket = TCPServer.new(@port) + rescue => error + p error + + @connection_attempts += 1 + retry + end + end + + while !@socket.closed? + begin + run_server + rescue => error + p error + @socket.close + end + end + end + end + + def run_server + while !@socket.closed? + client = Client.new + client.sync_interval = @sync_interval + client.socket = @socket.accept + + unless @active_client && @active_client.closed? + warn "Too many clients, already have one connected!" + client.close("Too many clients!") + else + @active_client = client + # TODO: Backup local config + # SEND CONFIG + config = File.read(TAC::CONFIG_PATH) + + @active_client.puts(PacketHandler.packet_handshake(@active_client.uuid)) + @active_client.puts(PacketHandler.packet_dump_config(config)) + + Thread.new do + while @active_client && @active_client.connected? + if Gosu.milliseconds > @last_sync_time + @sync_interval + @last_sync_time = Gosu.milliseconds + + @active_client.sync(@client_handler_proc) + update_stats + end + end + + update_stats + @active_client = nil + + @client_last_packets_sent = 0 + @client_last_packets_received = 0 + @client_last_data_sent = 0 + @client_last_data_received = 0 + end + end + end + end + + def handle_client + if @active_client && @active_client.connected? + message = @active_client.gets + + unless message.empty? + @packet_handler.handle(message) + end + + if Gosu.milliseconds > @last_heartbeat_sent + @heartbeat_interval + @last_heartbeat_sent = Gosu.milliseconds + + @active_client.puts(PacketHandler.packet_heartbeart) + end + end + end + + private def update_stats + if @active_client + # NOTE: Sent and Received are reversed for Server stats + + @packets_sent += @active_client.packets_received - @client_last_packets_received + @packets_received += @active_client.packets_sent - @client_last_packets_sent + + @data_sent += @active_client.data_received - @client_last_data_received + @data_received += @active_client.data_sent - @client_last_data_sent + + @client_last_packets_sent = @active_client.packets_sent + @client_last_packets_received = @active_client.packets_received + @client_last_data_sent = @active_client.data_sent + @client_last_data_received = @active_client.data_received + end + end + end + end +end \ No newline at end of file diff --git a/lib/theme.rb b/lib/theme.rb new file mode 100644 index 0000000..2980143 --- /dev/null +++ b/lib/theme.rb @@ -0,0 +1,19 @@ +module TAC + THEME = { + Label: { + font: "#{TAC::ROOT_PATH}/media/DejaVuSansCondensed.ttf", + text_size: 28 + }, + Button: { + background: TAC::Palette::TIMECRAFTERS_PRIMARY, + border_thickness: 1, + border_color: Gosu::Color.new(0xff_111111), + hover: { + background: TAC::Palette::TIMECRAFTERS_SECONDARY, + }, + active: { + background: TAC::Palette::TIMECRAFTERS_TERTIARY + } + } + } +end \ No newline at end of file diff --git a/lib/window.rb b/lib/window.rb index a092a41..2b8a7bd 100644 --- a/lib/window.rb +++ b/lib/window.rb @@ -1,9 +1,11 @@ module TAC class Window < CyberarmEngine::Window + attr_reader :backend def initialize(**args) super(**args) self.caption = "#{TAC::NAME} v#{TAC::VERSION} (#{TAC::RELEASE_NAME})" + @backend = Backend.new push_state(TAC::States::Editor) end diff --git a/media/DejaVuSansCondensed.ttf b/media/DejaVuSansCondensed.ttf new file mode 100644 index 0000000..3259bc2 Binary files /dev/null and b/media/DejaVuSansCondensed.ttf differ diff --git a/media/LICENSE b/media/LICENSE new file mode 100644 index 0000000..df52c17 --- /dev/null +++ b/media/LICENSE @@ -0,0 +1,187 @@ +Fonts are (c) Bitstream (see below). DejaVu changes are in public domain. +Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below) + + +Bitstream Vera Fonts Copyright +------------------------------ + +Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is +a trademark of Bitstream, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of the fonts accompanying this license ("Fonts") and associated +documentation files (the "Font Software"), to reproduce and distribute the +Font Software, including without limitation the rights to use, copy, merge, +publish, distribute, and/or sell copies of the Font Software, and to permit +persons to whom the Font Software is furnished to do so, subject to the +following conditions: + +The above copyright and trademark notices and this permission notice shall +be included in all copies of one or more of the Font Software typefaces. + +The Font Software may be modified, altered, or added to, and in particular +the designs of glyphs or characters in the Fonts may be modified and +additional glyphs or characters may be added to the Fonts, only if the fonts +are renamed to names not containing either the words "Bitstream" or the word +"Vera". + +This License becomes null and void to the extent applicable to Fonts or Font +Software that has been modified and is distributed under the "Bitstream +Vera" names. + +The Font Software may be sold as part of a larger software package but no +copy of one or more of the Font Software typefaces may be sold by itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, +TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME +FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING +ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE +FONT SOFTWARE. + +Except as contained in this notice, the names of Gnome, the Gnome +Foundation, and Bitstream Inc., shall not be used in advertising or +otherwise to promote the sale, use or other dealings in this Font Software +without prior written authorization from the Gnome Foundation or Bitstream +Inc., respectively. For further information, contact: fonts at gnome dot +org. + +Arev Fonts Copyright +------------------------------ + +Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the fonts accompanying this license ("Fonts") and +associated documentation files (the "Font Software"), to reproduce +and distribute the modifications to the Bitstream Vera Font Software, +including without limitation the rights to use, copy, merge, publish, +distribute, and/or sell copies of the Font Software, and to permit +persons to whom the Font Software is furnished to do so, subject to +the following conditions: + +The above copyright and trademark notices and this permission notice +shall be included in all copies of one or more of the Font Software +typefaces. + +The Font Software may be modified, altered, or added to, and in +particular the designs of glyphs or characters in the Fonts may be +modified and additional glyphs or characters may be added to the +Fonts, only if the fonts are renamed to names not containing either +the words "Tavmjong Bah" or the word "Arev". + +This License becomes null and void to the extent applicable to Fonts +or Font Software that has been modified and is distributed under the +"Tavmjong Bah Arev" names. + +The Font Software may be sold as part of a larger software package but +no copy of one or more of the Font Software typefaces may be sold by +itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL +TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +Except as contained in this notice, the name of Tavmjong Bah shall not +be used in advertising or otherwise to promote the sale, use or other +dealings in this Font Software without prior written authorization +from Tavmjong Bah. For further information, contact: tavmjong @ free +. fr. + +TeX Gyre DJV Math +----------------- +Fonts are (c) Bitstream (see below). DejaVu changes are in public domain. + +Math extensions done by B. Jackowski, P. Strzelczyk and P. Pianowski +(on behalf of TeX users groups) are in public domain. + +Letters imported from Euler Fraktur from AMSfonts are (c) American +Mathematical Society (see below). +Bitstream Vera Fonts Copyright +Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera +is a trademark of Bitstream, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of the fonts accompanying this license (“Fonts”) and associated +documentation +files (the “Font Software”), to reproduce and distribute the Font Software, +including without limitation the rights to use, copy, merge, publish, +distribute, +and/or sell copies of the Font Software, and to permit persons to whom +the Font Software is furnished to do so, subject to the following +conditions: + +The above copyright and trademark notices and this permission notice +shall be +included in all copies of one or more of the Font Software typefaces. + +The Font Software may be modified, altered, or added to, and in particular +the designs of glyphs or characters in the Fonts may be modified and +additional +glyphs or characters may be added to the Fonts, only if the fonts are +renamed +to names not containing either the words “Bitstream” or the word “Vera”. + +This License becomes null and void to the extent applicable to Fonts or +Font Software +that has been modified and is distributed under the “Bitstream Vera” +names. + +The Font Software may be sold as part of a larger software package but +no copy +of one or more of the Font Software typefaces may be sold by itself. + +THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, +TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME +FOUNDATION +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, +SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN +ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR +INABILITY TO USE +THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. +Except as contained in this notice, the names of GNOME, the GNOME +Foundation, +and Bitstream Inc., shall not be used in advertising or otherwise to promote +the sale, use or other dealings in this Font Software without prior written +authorization from the GNOME Foundation or Bitstream Inc., respectively. +For further information, contact: fonts at gnome dot org. + +AMSFonts (v. 2.2) copyright + +The PostScript Type 1 implementation of the AMSFonts produced by and +previously distributed by Blue Sky Research and Y&Y, Inc. are now freely +available for general use. This has been accomplished through the +cooperation +of a consortium of scientific publishers with Blue Sky Research and Y&Y. +Members of this consortium include: + +Elsevier Science IBM Corporation Society for Industrial and Applied +Mathematics (SIAM) Springer-Verlag American Mathematical Society (AMS) + +In order to assure the authenticity of these fonts, copyright will be +held by +the American Mathematical Society. This is not meant to restrict in any way +the legitimate use of the fonts, such as (but not limited to) electronic +distribution of documents containing these fonts, inclusion of these fonts +into other public domain or commercial font collections or computer +applications, use of the outline data to create derivative fonts and/or +faces, etc. However, the AMS does require that the AMS copyright notice be +removed from any derivative versions of the fonts which have been altered in +any way. In addition, to ensure the fidelity of TeX documents using Computer +Modern fonts, Professor Donald Knuth, creator of the Computer Modern faces, +has requested that any alterations which yield different font metrics be +given a different name. + +$Id$ diff --git a/timecrafters_action_configurator.rb b/timecrafters_action_configurator.rb index 9ccabd9..1227b3f 100644 --- a/timecrafters_action_configurator.rb +++ b/timecrafters_action_configurator.rb @@ -4,10 +4,23 @@ require "json" require "faker" +require_relative "lib/tac" require_relative "lib/palette" require_relative "lib/window" require_relative "lib/version" require_relative "lib/storage" +require_relative "lib/backend" require_relative "lib/states/editor" +require_relative "lib/theme" +require_relative "lib/dialog" +require_relative "lib/dialogs/name_prompt_dialog" +require_relative "lib/tacnet" +require_relative "lib/tacnet/packet" +require_relative "lib/tacnet/packet_handler" +require_relative "lib/tacnet/client" +require_relative "lib/tacnet/connection" +require_relative "lib/tacnet/server" + +Thread.abort_on_exception = true TAC::Window.new(width: (Gosu.screen_width * 0.8).round, height: (Gosu.screen_height * 0.8).round, resizable: true).show \ No newline at end of file