Posts filled under: ruby

WordSquared bot

Looks like i wrote a good enough bot for http://wordsquared.com/

Version 0.1b at youtube: http://www.youtube.com/watch?v=NilCjtRIvng
It was more laggy, than current :)

As below log shows, its completing words with 2-4w per 1s, but this affected only by my current internet connection.
Later i’ll move it to dedicated server in hetzner.de to test European’s speed.

P.S. from 3k point to 10k in 10 mins :) P.S.S. Still using http://wordsolver.net/ word’s database -.-

Logged as Bubonic Pestilence
Loading game .. OK
@ws.tiles: 1.678851842880249 parse: 0.00460505485534668
9958 6998 A DIRECTION: bottom SIZE: 11 WORD: ALB
9918 6997 H DIRECTION: left SIZE: 11 WORD: LECH
9958 6997 L DIRECTION: left SIZE: 11 WORD: EXCEL
9958 6996 B DIRECTION: right SIZE: 11 WORD: BECK
9959 6996 E DIRECTION: bottom SIZE: 11 WORD: EMEU
9961 6996 K DIRECTION: bottom SIZE: 11 WORD: KAYO
9921 6995 O DIRECTION: bottom SIZE: 11 WORD: OAT
9923 6995 E DIRECTION: top SIZE: 3 WORD: DYE
9961 6995 A DIRECTION: right SIZE: 11 WORD: AFT
9963 6995 T DIRECTION: bottom SIZE: 11 WORD: TAXI
9921 6994 A DIRECTION: left SIZE: 11 WORD: RAJA
9950 6994 J DIRECTION: right SIZE: 8 WORD: JAWS
9951 6994 A DIRECTION: top SIZE: 9 WORD: HANSA
9952 6994 W DIRECTION: top SIZE: 8 WORD: SHAW
9953 6994 S DIRECTION: bottom SIZE: 5 WORD: SAINS
9959 6994 E DIRECTION: left SIZE: 5 WORD: HAME
9963 6994 A DIRECTION: right SIZE: 11 WORD: AHI
9921 6993 T DIRECTION: right SIZE: 2 WORD: TI
9922 6993 I DIRECTION: bottom SIZE: 3 WORD: IRE
9945 6993 R DIRECTION: left SIZE: 3 WORD: PUR
9950 6993 A DIRECTION: left SIZE: 3 WORD: BA
9953 6993 A DIRECTION: right SIZE: 3 WORD: AVE
9955 6993 E DIRECTION: bottom SIZE: 6 WORD: EDS
9953 6992 I DIRECTION: left SIZE: 2 WORD: TI
9963 6992 I DIRECTION: right SIZE: 11 WORD: IN
9922 6991 E DIRECTION: left SIZE: 11 WORD: RE
9925 6990 E DIRECTION: bottom SIZE: 11 WORD: EF
9926 6990 A DIRECTION: bottom SIZE: 11 WORD: ADZ
9951 6985 E DIRECTION: bottom SIZE: 11 WORD: EF
9957 7029 I DIRECTION: left SIZE: 11 WORD: QI
9959 7029 I DIRECTION: right SIZE: 11 WORD: IF
9891 7028 R DIRECTION: right SIZE: 2 WORD: RE
9897 7028 B DIRECTION: bottom SIZE: 2 WORD: BE
9940 7028 E DIRECTION: right SIZE: 4 WORD: ED
9897 7027 E DIRECTION: left SIZE: 5 WORD: DICE
9897 7025 E DIRECTION: left SIZE: 11 WORD: WE
9942 7025 O DIRECTION: bottom SIZE: 3 WORD: OS
9961 7025 D DIRECTION: right SIZE: 11 WORD: DIG
9962 7025 I DIRECTION: top SIZE: 11 WORD: QI
9963 7025 G DIRECTION: bottom SIZE: 11 WORD: GINKS
9954 7024 Y DIRECTION: top SIZE: 11 WORD: BY

Dofus first AI… Roaming between wheet :) That later it will farm…

Ruby & Binary data… My way of parsing:

Wrote class, that help me reading binary data:

Usage

"\x11\x5f\x14".log # show hexdump
"\x40\x40".readShort # & etc

Code

module NetString
  LITTLE_ENDIAN = 1
  BIG_ENDIAN = 2

  SYS_ENDIAN = ([42].pack('i')[0].ord == 42) ? LITTLE_ENDIAN : BIG_ENDIAN

  def endian
    #@endian = SYS_ENDIAN if @endian.nil?
    @endian = BIG_ENDIAN if @endian.nil?
    @endian
  end

  def endianess=(endian)
    unless [BIG_ENDIAN, LITTLE_ENDIAN].include? endian
      raise 'Endianess should be set with const: NetString::LITTLE_ENDIAN or NetString::BIG_ENDIAN'
      exit
    end

    @endian = endian
  end

  def endianess data
    endian

    if @endian != SYS_ENDIAN
      data.reverse!
    end
  end

  def nsRead l, endian = true
    case self
    when String
      self.force_encoding 'ASCII-8BIT' if self.encoding.to_s == 'UTF-8'
      data = slice!(0, l)
    when File, StringIO
      data = read(l)
    end

    unless data.bytes.to_a.size == l
      self.log "self"
      pp l
      data.log "data"
    end

    raise 'NetString: incorrect length data read' unless data.bytes.to_a.size == l

    endianess(data) if endian
    data
  end

  def readByte; nsRead(1, false).unpack('c').first.to_i; end ## signed
  def readUByte; nsRead(1, false).unpack('C').first.to_i; end

  def readBoolean; !(readByte == 0); end

  def readShort; nsRead(2).unpack('s').first.to_i; end ## signed
  def readUShort; nsRead(2).unpack('S').first.to_i; end

  def readInt; nsRead(4).unpack('l').first.to_i; end ## signed
  def readUInt; nsRead(4).unpack('L').first.to_i; end

  def readDouble; nsRead(8, false).unpack('G').first.to_i; end ## Double-precision float
  def readFloat; puts '----------- CHECK ME READ FLOAT -----------'; nsRead(8).unpack('g').first.to_i; end ## Single-precision float

  def readQuad; nsRead(8).unpack('Q').first.to_i; end
  def readLongLong; a = readInt; b = readInt; a | (b << 32); end

  def readBytesAsString l; nsRead(l, false); end
  def readString; str = ''; while (char = readBytesAsString(1)) != "\x00"; str << char; end; str; end
  def readUTFString; s = readShort; readBytesAsString s; end

  alias_method :readUnsignedByte, :readUByte
  alias_method :readUnsignedShort, :readUShort
  alias_method :readUnsignedInt, :readUInt
  alias_method :readUTF, :readUTFString

  def nsWrite data, endian = true
    endianess(data) if endian

    case self.class.to_s
    when 'String'
      concat(data)
    when 'File'
      print data
    end

    self
  end

  def writeByte data; nsWrite([data].pack('c'), false); end
  def writeUByte data; nsWrite([data].pack('C'), false); end

  def writeBoolean data; nsWrite([data.to_i].pack('C'), false); end

  def writeShort data; nsWrite([data].pack('s')); end
  def writeUShort data; nsWrite([data].pack('S')); end

  def writeInt data; nsWrite([data].pack('l')); end
  def writeUInt data; nsWrite([data].pack('L')); end

  def writeDouble; puts '----------- CHECK ME WRITE DOUBLE -----------', nsWrite([data].pack('G')); end ## Double-precision float
  def writeFloat; puts '----------- CHECK ME WRITE FLOAT -----------', nsWrite([data].pack('g')); end ## Single-precision float

  def writeQuad data; nsWrite([data].pack('Q')); end

  def writeBytesAsString data; nsWrite(data, false); end
  def writeString data; nsWrite(data + "\x00", false); end
  def writeUTFString data; writeUShort(data.size); nsWrite(data, false); end

  def hexed(short = false)
    f = '%02X'
    j = ' '

    if short
      f = '%02x'
      j = ''
    end

    h = bytes.to_a.collect { |c| f % c }

    h.join j
  end

  def to_ansi
    string = ''

    t = bytes.to_a.each do |byte|
      byte = 46 if byte < 33 or byte > 126

      string += '  ' + byte.chr
    end

    string.strip
  end

  def log(name = nil, short = false)
    puts rlog(name, short)
  end

  def rlog(name, short = false)
    name = 'DATA DUMP' if name.nil?
    pad = '-' * 25

    firstline = "#{pad} #{name} (#{length}) #{pad}"
    endline = '-' * firstline.length 

    firstline << "\n" <<
      to_ansi << "\n" <<
      hexed(short) << "\n" <<
    endline
  end

  def to_block(l = 50, params = {})
    l /= 2

    self.strip!

    puts "#{'-' * l} #{self} #{'-' * l}\n"

    params.each { |k, v| puts "#{k}: #{v}" } if params.size
    yield

    puts "#{'-' * (2 * l + length + 2)}"
  end
end

class String
  include NetString
end

class IO
  include NetString
end

class StringIO
  include NetString
end

Btw, it’s in beta currently, because i didn’t check float/double methods enough :)

Flickr & Ruby…

Simple ruby script, for downloading flickr’s photosets

Requirements

sudo gem install flickraw mechanize

Usage

ruby flickr.rb

Code

#!/usr/local/rvm/ruby
# encoding: utf-8

require "fileutils"
require "flickraw"
require "mechanize"

m = Mechanize.new

FlickRaw.api_key = "<YOU_API_KEY>"
FlickRaw.shared_secret = "<YOR_API_SECRET>"

photosets = %w{<PHOTOSTREAM_ID> <PHOTOSTREAM_ID> <PHOTOSTREAM_ID> <PHOTOSTREAM_ID>}
photosets.each do |photoset_id|
  list = flickr.photosets.getPhotos(photoset_id: photoset_id, extras: 'url_o, url_l, url_m')
  h = list.to_hash

  h["photo"].each do |p|
    url = p["url_o"] || p["url_l"] || p["url_m"]

    filedir = "flickr/#{photoset_id}"
    filename = File.basename(url)
    filepath = "#{filedir}/#{filename}"

    next if File.exists?(filepath)

    file = m.get(url)

    FileUtils.mkdir_p(filedir)
    file.save_as(filepath)
  end
end

Oh yeah!

Now it can login, move, and say through console :)

Dofus bot can speak

[ INFO] [D2I] Parsing i18n_en.d2i
[ INFO] [D2O] Parsing InfoMessages.d2o
[ INFO] [D2O] Parsing Servers.d2o
[ INFO] [D2O] Parsing ChatChannels.d2o
[ INFO] Connected
[   OK] Authentification successful
[ INFO] Connected
[   OK] Ticket accepted
[ INFO] Position in character selection queue: 1 / 1
[ INFO] Position in character selection queue: 0 / 0
[ INFO] Position in character selection queue: 0 / 0
[ INFO] Character weight: 14 / 1000
[   OK] Welcome to DOFUS, and welcome to the World of Twelve! Remember that it is <b>strictly forbidden</b> to disclose your account name or password.
[   OK] This account was last accessed on 13/07/2011 at 05:02.
[CHAT] [GENERAL]               : oops
[CHAT] [GENERAL]               : like i didn't did it wrong?!
[CHAT] [GENERAL]               : heh
[CHAT] [PRIVATE]               : asd
[CHAT] [PRIVATE]               : wanna join me ? )
say hellow world )
[CHAT] [GENERAL]          : hellow world )
say bla bla bla
[CHAT] [GENERAL]          : bla bla bla

Dofus «login -> game» sequence

Just got it…

def check_connection
  recv # receive packets

  case @state
  when STATE_NOT_CONNECTED
    reconnect
  when STATE_CONNECTED_TO_LOGIN
    @packets.pop do |packet|
      case packet
      when Com::AnkamaGames::Dofus::Network::Messages::Handshake::ProtocolRequired
        if packet.requiredVersion > $config.protocol_build
          log("Current protocol build: #{$config.protocol_build}, required build: #{packet.requiredVersion}", Logger::FATAL)
        end

        if packet.currentVersion < $config.protocol_required_build
          log("Current protocol build: #{$config.protocol_required_build}, is too new for the server version: #{packet.currentVersion}", Logger::FATAL)
        end
      when HelloConnectMessage
        $config.session_key = packet.sessionKey

        im = IdentificationMessage.new
        bytes = im.build!({
          username: $config.username,
          password: $config.password,
          version: $config.version,
          session_key: $config.session_key
        })

        send_data bytes
      when Com::AnkamaGames::Dofus::Network::Messages::Queues::LoginQueueStatusMessage
        l("Position in login queue: #{packet.position} / #{packet.total}")
      when IdentificationSuccessMessage
        l('Authentification successful', Logger::OK)
        @state = STATE_SERVERS_LIST
      else
        l("Incorrect packet at $net.STATE_CONNECTED_TO_LOGIN: #{packet.class}", Logger::FATAL)
      end
    end
  when STATE_SERVERS_LIST
    @packets.pop do |packet|
      case packet
      when ServersListMessage
        if !$config.server_id
          "Select server:".to_block(10) {
            packet.servers.select { |s| s.status == s.class::STATUS_ONLINE }.each do |s|
              printf("%5d %s %d %s\n", s.id, "-", s.charactersCount, s.status_t)
            end
          }

          while line = gets do
            line.strip!
            next if line.empty?

            exit if line.to_i == 0

            server = packet.servers.find { |s| s.id == line.to_i }
            next unless server

            $config.server_id = server.id
            break
          end
        end

        ssm = ServerSelectionMessage.new.build!($config.server_id)
        send_data ssm
      when SelectedServerDataMessage
        @ip = packet.address
        @port = packet.port
        $config.ticket = packet.ticket

        reconnect

        @state = STATE_CONNECTED_TO_GAME
      else
        l("Incorrect packet at $net.STATE_SERVERS_LIST: #{packet.class}", Logger::FATAL)
      end
    end
  when STATE_CONNECTED_TO_GAME
    @packets.pop do |packet|
      case packet
      when Com::AnkamaGames::Dofus::Network::Messages::Handshake::ProtocolRequired
        if packet.requiredVersion > $config.protocol_build
          log("Current protocol build: #{$config.protocol_build}, required build: #{packet.requiredVersion}", Logger::FATAL)
        end

        if packet.currentVersion < $config.protocol_required_build
          log("Current protocol build: #{$config.protocol_required_build}, is too new for the server version: #{packet.currentVersion}", Logger::FATAL)
        end
      when HelloGameMessage
        atm = AuthenticationTicketMessage.new.build!('en', $config.ticket)
        send_data atm
      when AuthenticationTicketAcceptedMessage
        l("Ticket accepted", Logger::OK)
      when Com::AnkamaGames::Dofus::Network::Messages::Game::Basic::BasicTimeMessage
        # nothing to do, just ignore
      when Com::AnkamaGames::Dofus::Network::Messages::Game::Approach::AccountCapabilitiesMessage
        $config.account_id = packet.account_id

        clrm = Com::AnkamaGames::Dofus::Network::Messages::Game::Character::Choice::CharactersListRequestMessage.new.build!
        send_data clrm

        @state = STATE_CHARACTER_SELECTION
      else
        l("Incorrect packet at $net.STATE_CONNECTED_TO_GAME: #{packet.class}", Logger::FATAL)
      end
    end
  when STATE_CHARACTER_SELECTION
    @packets.pop do |packet|
      case packet
      when Com::AnkamaGames::Dofus::Network::Messages::Queues::QueueStatusMessage
        l("Position in character selection queue: #{packet.position} / #{packet.total}")
      when Com::AnkamaGames::Dofus::Network::Messages::Secure::TrustStatusMessage,
           Com::AnkamaGames::Dofus::Network::Messages::Game::Basic::BasicNoOperationMessage
        # nothing to do, ignore
      when Com::AnkamaGames::Dofus::Network::Messages::Game::Character::Choice::CharactersListMessage
        characters = packet.characters

        if !$config.character_id && characters.size > 0
          puts "Choose your character:"

          fields = sprintf("%20s | %5s | %5s | %6s", 'Name', 'Level', 'Class', 'Sex')
          puts fields, '-' * fields.size

          characters.each do |c|
            puts sprintf("%20s | %5d | %5d | %6s", c.name, c.level, c.breed, c.sex ? 'Male' : 'Female')
          end

          while line = gets do
            line.strip!
            break if line.empty?

            character = characters.find { |c| c.name.downcase == line.downcase }
            next unless character

            $config.character_id = character.id
            break
          end

          csm = Com::AnkamaGames::Dofus::Network::Messages::Game::Character::Choice::CharacterSelectionMessage.new.build!($config.character_id)
          send_data csm

          @state = STATE_IN_GAME
        elsif characters.size == 0
          l("No character created", Logger::FATAL)
          exit
        end
      else
        l("Incorrect packet at $net.STATE_CHARACTER_SELECTION: #{packet.class}", Logger::FATAL)
      end
    end
  when STATE_IN_GAME
  else
    l("Unknown state #{state} for $net", Logger::FATAL);
    exit
  end
end

Output

[user host-122 ~/Documents/Projects/dofus] ./run.rb
[ INFO] [D2O] Parsing Servers.d2o
[ INFO] Connected
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Handshake::ProtocolRequired
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Connection::HelloConnectMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Connection::IdentificationMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Connection::IdentificationSuccessMessage
[   OK] Authentification successful
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Connection::ServersListMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Connection::ServerSelectionMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Connection::SelectedServerDataMessage
[ INFO] Connected
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Handshake::ProtocolRequired
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Approach::HelloGameMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Approach::AuthenticationTicketMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Approach::AuthenticationTicketAcceptedMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Basic::BasicTimeMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Approach::AccountCapabilitiesMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Secure::TrustStatusMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Basic::BasicNoOperationMessage
[   OK] Ticket accepted
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Character::Choice::CharactersListRequestMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Queues::QueueStatusMessage
[ INFO] Position in character selection queue: 1 / 1
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Queues::QueueStatusMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Basic::BasicNoOperationMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Queues::QueueStatusMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Character::Choice::CharactersListMessage
[ INFO] Position in character selection queue: 0 / 0
[ INFO] Position in character selection queue: 0 / 0
Choose your character:
                Name | Level | Class |    Sex
---------------------------------------------
               Char1 |     2 |     5 |   Male
               Char2 |     4 |     3 | Female
               Char3 |    19 |     9 | Female
Char1
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Character::Choice::CharacterSelectionMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Basic::BasicNoOperationMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Context::Notification::NotificationListMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Character::Choice::CharacterSelectedSuccessMessage
[ INFO] Selected character: [------] Char1 (2)
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Inventory::Items::InventoryContentMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Inventory::Items::SetUpdateMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Shortcut::ShortcutBarContentMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Shortcut::ShortcutBarContentMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Context::Roleplay::Emote::EmoteListMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Pvp::AlignmentRankUpdateMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Pvp::AlignmentSubAreasListMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Chat::Channel::EnabledChannelsMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Inventory::Spells::SpellListMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Shortcut::ShortcutBarContentMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Initialization::SetCharacterRestrictionsMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Inventory::Items::InventoryWeightMessage
[ INFO] Character weight: 14 / 1000
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Friend::FriendWarnOnConnectionStateMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Friend::GuildMemberWarnOnConnectionStateMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Friend::FriendWarnOnLevelGainStateMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Basic::TextInformationMessage
[ WARN] Check Com::AnkamaGames::Dofus::Network::Messages::Game::Basic::TextInformationMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Basic::TextInformationMessage
[ WARN] Check Com::AnkamaGames::Dofus::Network::Messages::Game::Basic::TextInformationMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Initialization::ServerExperienceModificatorMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Friend::SpouseStatusMessage

P.S. Please don’t blame my ugly code :)

YouTube Video Uploader

Wrote script to upload bunch of videos to youtube through YouTube API:

To get developer’s key, visit: http://code.google.com/apis/youtube/dashboard/gwt/index.html

Thanks to kylejginavan@github for this cool gem: YouTube It

Usage:

ruby youtube-it.rb --user <user@gmail.com> --password <password_for_gmail> --key <your_dev_key> *.avi

Before run

gem install youtube_it -r

Code:

# encoding: utf-8

require "rubygems"
require "openssl"
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
require "youtube_it"
require "fileutils"
require "ostruct"
require "optparse"

$stdout.sync = true

options = OpenStruct.new

optparse = OptionParser.new do |opts|
  opts.banner = "Usage: #{$0} [options] file1[ file2 ...]"

  opts.on("-u", "--user USERNAME", "[REQUIRED] Specify username for youtube account") do |username|
    options.username = username
  end

  opts.on(:REQUIRED, "-p", "--password PASSWORD", "[REQUIRED] Specify password for youtube account") do |password|
    options.password = password
  end

  opts.on("-k", "--key KEY", "[REQUIRED] Specify developer's key for youtube account") do |dev_key|
    options.dev_key = dev_key
  end

  opts.on_tail("-h", "--help", "Display this screen") do
    puts opts
    exit
  end
end

optparse.parse!

if options.username.nil? || options.password.nil? || options.dev_key.nil? || ARGV.size == 0
  puts optparse
  exit
end

client = YouTubeIt::Client.new({
  :username => options.username,
  :password => options.password,
  :dev_key => options.dev_key
})

ARGV.each do |filepath|
  (puts "File #{filepath} doesn't exists. Skipping."; next) unless File.exists?(filepath)

  begin
    print filepath

    title = File.basename(filepath, File.extname(filepath))
    title[0] = title[0, 1].upcase
    title.gsub!(/\s*(\-|_)\s*/iu, ' ')

    client.video_upload(File.open(filepath), {
      :title => title,
      :description => title,
      :category => "Travel"
    })

    puts " .. OK!"
  rescue Exception => e
    puts "", e, "Sleeping 30s", ""
    sleep 30
    retry
  end
end

Awful “command” for TextMate

Are anyone capable to explain usage of this script?

#!/opt/local/bin/ruby

DOFUS_DIR = File.expand_path("~/Documents/Projects/DofusApp/source")

def tabs size = 3
  "  " * size
end

filepath_rb = ENV["TM_FILEPATH"]

filepath_as = filepath_rb.gsub(File.expand_path('~/Documents/Projects/dofus/includes'), '')
filepath_as = DOFUS_DIR + File.join(File.dirname(filepath_as).downcase, File.basename(filepath_as, File.extname(filepath_as)) + ".as")

raise unless File.exists?(filepath_as)

File.open(filepath_as) do |f|
  data = f.read

  as_tabs, code = data.scan(/([ \t]+)public function deserializeAs_.+?:void\s*\{\s+(.+?)\s+return.+\1\}/miu).first

  new_code = code.lines.
    map { |l| l.strip!; tabs + l }.
    join("\n").
    gsub("this.", "@").
    gsub("();", "").
    gsub(/var loc\d+:\*=(0|null);\s*/ium, "").
    gsub(/super\.deserialize\(arg1\);/ium, "super data\n#{tabs}").
    gsub(/com\.ankamagames\.jerakine\.network\.utils\.BooleanByteWrapper\.getFlag\(loc\d+,\s*(\d+)\);/iu, "BBW.get(byte, \\1)").
    gsub(/if \([^\(\)]+\) \{\s+throw new Error[^\n]+\s+\}[\s\n\t]*/ium, "").
    gsub(/[ \t]+var loc\d+:\*=\s*arg\d+\.readUnsignedShort\s+while.+\s+loc\d+ = arg1.(\w+)\s+(@\w+).+\s+.+\s+\}/u, <<-EOD).
#{tabs}
#{tabs}\\2 = []
#{tabs}data.readUShort.times {
#{tabs}  \\2 << data.\\1
#{tabs}}
    EOD
    gsub(/[ \t]+var loc\d+:\*=\s*arg\d+\.readUnsignedShort\s+while.+\s+\(loc\d+ = new com[^A-Z]+(\w+).+\s+(@\w+).+\s+.+\s+\}/u, <<-EOD).
#{tabs}
#{tabs}\\2 = []
#{tabs}data.readUShort.times {
#{tabs}  (obj = \\1.new).deserialize(data)
#{tabs}  \\2 << obj
#{tabs}}
    EOD
    gsub(/[ \t]+var loc\d+:\*=\s*arg\d+\.readUnsignedShort\s+while.+\s*{\s*if \(\(loc\d+ = \w+.(read\w+).+\s*throw new Error.+\s+\}\s.+(@\w+).+\s+\+\+loc\d.+\s.+/iu, <<-EOD).
#{tabs}
#{tabs}\\2 = []
#{tabs}data.readUShort.times {
#{tabs}  \\2 << data.\\1
#{tabs}}
    EOD
    gsub(/[^\n]+var loc\d+:\*=\s*arg\d+\.readUnsignedShort\s+while\s*\([^)]+\)\s*{\s*loc\d+ = \w+\.readUnsignedShort\s\s*\(loc\d+ = [\w\.]+ProtocolTypeManager\.getInstance.+\.deserialize\((.+)\)[^@]+(@\w+)[^}]+}\n/iu, <<-EOD).
#{tabs}
#{tabs}\\2 = []
#{tabs}data.readUShort.times {
#{tabs}  type_id = data.readUShort
#{tabs}  (obj = Types.get(type_id)).deserialize(\\1)
#{tabs}  \\2 << obj
#{tabs}}
#{tabs}
    EOD
    gsub(/var loc\d:\*=arg1.readUnsignedShort\s+(@\w+) = .+ProtocolTypeManager.getInstance[^A-Z]+(\w+).+\s+\1.+/u, <<-EOD).
#{tabs}
#{tabs}type_id = data.readUShort
#{tabs}(\\1 = Types.get(type_id)).deserialize(data)
#{tabs}
    EOD
    gsub(/\s+(\S+) = new com.ankamagames[^A-Z]+(\w+)/u, "\n#{tabs}\n#{tabs}\\1 = \\2.new").
    gsub(".deserialize(arg1);", ".deserialize(arg1)\n#{tabs}").
    gsub("arg1", "data").
    strip

  print "#{new_code}
#{tabs}
#{tabs}false"
end

Халява MLGame ячейки!

Oops, найдена бага, последняя координата +1 надо :)
i.e. 68-1-51 => 68-1-52

Может быть кому нужны ячейки для городов > 38 клеток? )

[68-1-51]        DEADLAND   41
[68-3-15]        DEADLAND   41
[68-3-16]        DEADLAND   39
[68-3-22]        DEADLAND   42
[68-4-13]    CURSEDFOREST   40
[69-4-62]        HOLYLAND   39
[70-3-03]          FOREST   39
[70-4-31]        HOLYLAND   43
[70-5-15]     MAGICFOREST   43
[72-1-32]        DEADLAND   39
[72-2-16]        MOUNTAIN   40
[72-2-38]        HOLYLAND   41
[72-4-11]          STEPPE   42
[73-2-02]          FOREST   40
[73-2-33]          FOREST   40
[73-2-44]          FOREST   41

Ещё один добрый человек поделился:

[53-21-53]          STEPPE   39
[56-22-22]    CURSEDFOREST   40
[56-22-26]          FOREST   41
[57-20-51]        DEADLAND   42
[57-22-52]     MAGICFOREST   42
[58-21-44]          STEPPE   39
[58-22-46]          FOREST   42
[59-21-01]        MOUNTAIN   39
[59-22-12]          FOREST   40
[59-22-14]     MAGICFOREST   43
[59-22-36]     MAGICFOREST   43
[59-22-60]        DEADLAND   39
[60-20-45]        DEADLAND   43
[60-21-49]    CURSEDFOREST   39
[61-20-22]        HOLYLAND   42

Сканер “уже открытых” ячеек на карте

Сборщик уже исследованных ячеек… точнее его вывод:

[65-3-39]          DESERT   29
[65-3-47]          DESERT   29
[65-3-48]          DESERT   22
[65-4-01]    CURSEDFOREST   29
[65-4-03]    CURSEDFOREST   37
[68-1-10]    CURSEDFOREST   32
[68-1-11]    CURSEDFOREST   22
[68-1-12]    CURSEDFOREST   34
[68-1-13]    CURSEDFOREST   37
[68-1-14]    CURSEDFOREST   22
[68-4-12]          STEPPE   24
[68-4-13]    CURSEDFOREST   40
[68-4-14]        DEADLAND   35
[68-4-15]        DEADLAND   28
[69-2-60]        HOLYLAND   28
[69-2-61]        HOLYLAND   22
[69-3-00]        MOUNTAIN   28
[69-3-01]        MOUNTAIN   22
[70-1-49]        HOLYLAND   23
[70-1-51]        HOLYLAND   22
[70-1-52]        HOLYLAND   37
[70-1-54]          FOREST   27
[70-1-56]     MAGICFOREST   38
[70-1-58]     MAGICFOREST   24
[70-1-62]        HOLYLAND   34
[70-5-12]     MAGICFOREST   23
[70-5-13]     MAGICFOREST   31
[70-5-15]     MAGICFOREST   43
[70-5-17]     MAGICFOREST   23
[70-5-18]          STEPPE   28
[70-5-19]          STEPPE   33
[70-5-20]          STEPPE   26
[71-3-03]     MAGICFOREST   23
[71-3-05]     MAGICFOREST   36
[71-3-06]     MAGICFOREST   26
[71-3-08]     MAGICFOREST   22
[71-3-09]        HOLYLAND   27
[72-2-32]     MAGICFOREST   26
[72-2-33]          STEPPE   33
[72-2-34]     MAGICFOREST   22
Top of Page