Input: def procedures ( path ) [CODESPLIT] def library ( domain , name = nil , opts = { } ) domain , name , opts = [ domain , nil , name ] if name . is_a? ( Hash ) domain , name = split_dn ( domain , name ) if m = name . match ( / \. \z / ) name = name [ 0 .. m [ 1 ] . length - 1 ] end path , _ , _ = ( Dir [ File . join ( @root , '**/*.{flo,flor}' ) ] ) . select { | f | f . index ( '/lib/' ) } . collect { | pa | [ pa , expose_dn ( pa , opts ) ] } . select { | pa , d , n | n == name && Flor . sub_domain? ( d , domain ) } . sort_by { | pa , d , n | d . count ( '.' ) } . last path ? [ Flor . relativize_path ( path ) , File . read ( path ) ] : nil end


Input: create_table : flor_timers do [CODESPLIT] def to_trigger_message d = self . data ( false ) m = d [ 'message' ] m [ 'timer_id' ] = self . id sm = d [ 'm' ] { 'point' => 'trigger' , 'exid' => self . exid , 'nid' => self . onid , 'bnid' => self . nid , 'type' => self . type , 'schedule' => self . schedule , 'timer_id' => self . id , 'message' => m , 'sm' => sm } end


Input: tasker not task since task is already a message point [CODESPLIT] def row_waiter? @serie . find { | _ , points | points . find { | po | pos = po . split ( ':' ) pos . length > 1 && ROW_PSEUDO_POINTS . include? ( pos [ 0 ] ) } } end


Input: Delete tables in the storage database that begin with flor_ and have more than 2 columns ( the Sequel schema_info table has 1 column as of this writing ) [CODESPLIT] def delete_tables @db . tables . each { | t | @db [ t ] . delete if t . to_s . match ( / / ) && @db [ t ] . columns . size > 2 } end


Input: Return a Flor :: Execution instance linked to this model [CODESPLIT] def execution ( reload = false ) exid = @values [ :exid ] ; return nil unless exid @flor_model_cache_execution = nil if reload @flor_model_cache_execution ||= unit . executions [ exid : exid ] end


Input: Returns the node hash linked to this model [CODESPLIT] def node ( reload = false ) nid = @values [ :nid ] ; return nil unless nid exe = execution ( reload ) ; return nil unless exe nodes = exe . data [ 'nodes' ] ; return nil unless nodes nodes [ nid ] end


Input: Given a nid returns a copy of all the var the node sees at that point . [CODESPLIT] def vars ( nid , vs = { } ) n = node ( nid ) ; return vs unless n ( n [ 'vars' ] || { } ) . each { | k , v | vs [ k ] = Flor . dup ( v ) unless vs . has_key? ( k ) } pnid = n [ 'parent' ] if @unit . loader && pnid == nil && n [ 'vdomain' ] != false @unit . loader . variables ( n [ 'vdomain' ] || Flor . domain ( @exid ) ) . each { | k , v | vs [ k ] = Flor . dup ( v ) unless vs . has_key? ( k ) } end if cn = n [ 'cnid' ] ; vars ( cn , vs ) ; end vars ( pnid , vs ) if pnid vs end


Input: This saves the modified trees in the parent when the node is removed it works ok except for 3 ( 2017 - 05 - 9 ) failing specs . [CODESPLIT] def leave_tags ( message , node ) ts = node [ 'tags' ] ; return [ ] unless ts && ts . any? [ { 'point' => 'left' , 'tags' => ts , 'exid' => exid , 'nid' => node [ 'nid' ] , 'payload' => message [ 'payload' ] } ] end


Input: Return an empty array of new messages . No direct effect . [CODESPLIT] def lookup_on_error_parent ( message ) nd = Flor :: Node . new ( self , nil , message ) . on_error_parent nd ? nd . to_procedure_node : nil end


Input: create_table : flor_traps do [CODESPLIT] def to_hook opts = { } opts [ :consumed ] = tconsumed opts [ :point ] = tpoints . split ( ',' ) if tpoints opts [ :tag ] = do_split ( ttags ) if ttags opts [ :heap ] = do_split ( theaps ) if theaps opts [ :heat ] = do_split ( theats ) if theats opts [ :name ] = data [ 'names' ] case trange when 'execution' opts [ :exid ] = exid when 'subdomain' opts [ :subdomain ] = Flor . domain ( exid ) when 'domain' opts [ :domain ] = Flor . domain ( exid ) else #'subnid' # default opts [ :exid ] = exid opts [ :subnid ] = true end [ "trap#{id}" , opts , self , nil ] end


Input: returns true if the trap should be removed from the execution s list of traps [CODESPLIT] def decrement c = data [ 'count' ] return false unless c c = c - 1 data [ 'count' ] = c self [ :status ] = s = ( c > 0 ) ? 'active' : 'consumed' self . update ( content : Flor :: Storage . to_blob ( @flor_model_cache_data ) , status : s ) c < 1 end


Input: Create a new Mixlib :: CLI class . If you override this make sure you call super! [CODESPLIT] def parse_options ( argv = ARGV ) argv = argv . dup opt_parser . parse! ( argv ) # Deal with any required values options . each do | opt_key , opt_value | if opt_value [ :required ] && ! config . key? ( opt_key ) reqarg = opt_value [ :short ] || opt_value [ :long ] puts "You must supply #{reqarg}!" puts @opt_parser exit 2 end if opt_value [ :in ] unless opt_value [ :in ] . kind_of? ( Array ) raise ( ArgumentError , "Options config key :in must receive an Array" ) end if config [ opt_key ] && ! opt_value [ :in ] . include? ( config [ opt_key ] ) reqarg = opt_value [ :short ] || opt_value [ :long ] puts "#{reqarg}: #{config[opt_key]} is not included in the list ['#{opt_value[:in].join("', '")}'] " puts @opt_parser exit 2 end end end @cli_arguments = argv argv end


Input: The option parser generated from the mixlib - cli DSL . + opt_parser + can be used to print a help message including the banner and any CLI options via puts opt_parser . === Returns opt_parser<OptionParser > :: The option parser object . [CODESPLIT] def opt_parser @opt_parser ||= OptionParser . new do | opts | # Set the banner opts . banner = banner # Create new options options . sort { | a , b | a [ 0 ] . to_s <=> b [ 0 ] . to_s } . each do | opt_key , opt_val | opt_args = build_option_arguments ( opt_val ) opt_method = case opt_val [ :on ] when :on :on when :tail :on_tail when :head :on_head else raise ArgumentError , "You must pass :on, :tail, or :head to :on" end parse_block = Proc . new ( ) do | c | config [ opt_key ] = if opt_val [ :proc ] if opt_val [ :proc ] . arity == 2 # New hotness to allow for reducer-style procs. opt_val [ :proc ] . call ( c , config [ opt_key ] ) else # Older single-argument proc. opt_val [ :proc ] . call ( c ) end else # No proc. c end puts opts if opt_val [ :show_options ] exit opt_val [ :exit ] if opt_val [ :exit ] end full_opt = [ opt_method ] opt_args . inject ( full_opt ) { | memo , arg | memo << arg ; memo } full_opt << parse_block opts . send ( full_opt ) end end end


Input: Calls Worker#work but after the current process is forked . The parent process will wait on the child process to exit . [CODESPLIT] def fork_and_work cpid = fork { setup_child ; work } log ( :at => :fork , :pid => cpid ) Process . wait ( cpid ) end


Input: Blocks on locking a job and once a job is locked it will process the job . [CODESPLIT] def work queue , job = lock_job if queue && job QC . log_yield ( :at => "work" , :job => job [ :id ] ) do process ( queue , job ) end end end


Input: Attempt to lock a job in the queue s table . If a job can be locked this method returns an array with 2 elements . The first element is the queue from which the job was locked and the second is a hash representation of the job . If a job is returned its locked_at column has been set in the job s row . It is the caller s responsibility to delete the job row from the table when the job is complete . [CODESPLIT] def lock_job log ( :at => "lock_job" ) job = nil while @running @queues . each do | queue | if job = queue . lock return [ queue , job ] end end @conn_adapter . wait ( @wait_interval , @queues . map { | q | q . name } ) end end


Input: A job is processed by evaluating the target code . if the job is evaluated with no exceptions then it is deleted from the queue . If the job has raised an exception the responsibility of what to do with the job is delegated to Worker#handle_failure . If the job is not finished and an INT signal is trapped this method will unlock the job in the queue . [CODESPLIT] def process ( queue , job ) start = Time . now finished = false begin call ( job ) . tap do queue . delete ( job [ :id ] ) finished = true end rescue => e handle_failure ( job , e ) finished = true ensure if ! finished queue . unlock ( job [ :id ] ) end ttp = Integer ( ( Time . now - start ) * 1000 ) QC . measure ( "time-to-process=#{ttp} source=#{queue.name}" ) end end


Input: Each job includes a method column . We will use ruby s eval to grab the ruby object from memory . We send the method to the object and pass the args . [CODESPLIT] def call ( job ) args = job [ :args ] receiver_str , _ , message = job [ :method ] . rpartition ( '.' ) receiver = eval ( receiver_str ) receiver . send ( message , args ) end


Input: enqueue ( m a ) inserts a row into the jobs table and trigger a notification . The job s queue is represented by a name column in the row . There is a trigger on the table which will send a NOTIFY event on a channel which corresponds to the name of the queue . The method argument is a string encoded ruby expression . The expression will be separated by a . character and then eval d . Examples of the method argument include : puts Kernel . puts MyObject . new . puts . The args argument will be encoded as JSON and stored as a JSON datatype in the row . ( If the version of PG does not support JSON then the args will be stored as text . The args are stored as a collection and then splatted inside the worker . Examples of args include : hello world [ hello world ] hello world . This method returns a hash with the id of the enqueued job . [CODESPLIT] def enqueue ( method , * args ) QC . log_yield ( :measure => 'queue.enqueue' ) do s = "INSERT INTO #{QC.table_name} (q_name, method, args) VALUES ($1, $2, $3) RETURNING id" conn_adapter . execute ( s , name , method , JSON . dump ( args ) ) end end


Input: enqueue_at ( t m a ) inserts a row into the jobs table representing a job to be executed not before the specified time . The time argument must be a Time object or a float timestamp . The method and args argument must be in the form described in the documentation for the #enqueue method . This method returns a hash with the id of the enqueued job . [CODESPLIT] def enqueue_at ( timestamp , method , * args ) offset = Time . at ( timestamp ) . to_i - Time . now . to_i enqueue_in ( offset , method , args ) end


Input:
enqueue_in ( t m a ) inserts a row into the jobs table representing a job to be executed not before the specified time offset . The seconds argument must be an integer . The method and args argument must be in the form described in the documentation for the #enqueue method . This method returns a hash with the id of the enqueued job . [CODESPLIT] def enqueue_in ( seconds , method , * args ) QC . log_yield ( :measure => 'queue.enqueue' ) do s = "INSERT INTO #{QC.table_name} (q_name, method, args, scheduled_at)
             VALUES ($1, $2, $3, now() + interval '#{seconds.to_i} seconds')
             RETURNING id" conn_adapter . execute ( s , name , method , JSON . dump ( args ) ) end end


Input: Net :: HTTP [CODESPLIT] def session @session ||= begin http = Net :: HTTP . new @host , @port http . use_ssl = self . use_ssl http . verify_mode = self . verify_mode http . read_timeout = self . read_timeout http . ssl_version = self . ssl_version if self . use_ssl http . start end end


Input: title : legend : xAxis : yAxis : tooltip : credits : : plotOptions [CODESPLIT] def defaults_options self . title ( { :text => nil } ) self . legend ( { :layout => "vertical" , :style => { } } ) self . xAxis ( { } ) self . yAxis ( { :title => { :text => nil } , :labels => { } } ) self . tooltip ( { :enabled => true } ) self . credits ( { :enabled => false } ) self . plotOptions ( { :areaspline => { } } ) self . chart ( { :defaultSeriesType => "line" , :renderTo => nil } ) self . subtitle ( { } ) end


Input: Pass other methods through to the javascript high_chart object . [CODESPLIT] def method_missing ( meth , opts = { } ) if meth . to_s == 'to_ary' super end if meth . to_s . end_with? '!' deep_merge_options meth [ 0 .. - 2 ] . to_sym , opts else merge_options meth , opts end end


Input: Add a simple series to the graph : [CODESPLIT] def series ( opts = { } ) if not opts . empty? @series_data << OptionsKeyFilter . filter ( opts . merge ( :name => opts [ :name ] , :data => opts [ :data ] ) ) end end


Input: Rack 2 . 0 method [CODESPLIT] def write_session ( req , sid , session_data , options ) cas_ticket = ( session_data [ 'cas' ] [ 'ticket' ] unless session_data [ 'cas' ] . nil? ) session = if ActiveRecord . respond_to? ( :version ) && ActiveRecord . version >= Gem :: Version . new ( '4.0.0' ) Session . where ( session_id : sid ) . first_or_initialize else Session . find_or_initialize_by_session_id ( sid ) end session . data = pack ( session_data ) session . cas_ticket = cas_ticket success = session . save success ? session . session_id : false end


Input: Rack 2 . 0 method [CODESPLIT] def delete_session ( req , sid , options ) Session . where ( session_id : sid ) . delete_all options [ :drop ] ? nil : generate_sid end


Input: Rack 1 . * method [CODESPLIT] def set_session ( env , sid , session_data , options ) # rack 1.x compatibilty write_session ( Rack :: Request . new ( env ) , sid , session_data , options ) end


Input: Rack 1 . * method [CODESPLIT] def destroy_session ( env , sid , options ) # rack 1.x compatibilty delete_session ( Rack :: Request . new ( env ) , sid , options ) end


Input: Rack 2 . 0 method [CODESPLIT] def find_session ( env , sid ) if sid . nil? sid = generate_sid data = nil else unless session = Session . find_by_id ( sid ) session = { } # force generation of new sid since there is no associated session sid = generate_sid end data = unpack ( session [ 'data' ] ) end [ sid , data ] end


Input: Rack 2 . 0 method [CODESPLIT] def write_session ( env , sid , session_data , options ) cas_ticket = ( session_data [ 'cas' ] [ 'ticket' ] unless session_data [ 'cas' ] . nil? ) success = Session . write ( session_id : sid , data : pack ( session_data ) , cas_ticket : cas_ticket ) success ? sid : false end


Input: params can be an array or a hash [CODESPLIT] def remove_params ( params ) self . tap do | u | u . query_values = ( u . query_values || { } ) . tap do | qv | params . each do | key , value | qv . delete key end end if u . query_values . empty? u . query_values = nil end end end


Input: initially borrowed from omniauth - cas [CODESPLIT] def parse_user_info ( node ) return nil if node . nil? { } . tap do | hash | node . children . each do | e | unless e . kind_of? ( Nokogiri :: XML :: Text ) || e . name == 'proxies' # There are no child elements if e . element_children . count == 0 if hash . has_key? ( e . name ) hash [ e . name ] = [ hash [ e . name ] ] if hash [ e . name ] . is_a? String hash [ e . name ] << e . content else hash [ e . name ] = e . content end elsif e . element_children . count # JASIG style extra attributes if e . name == 'attributes' hash . merge! ( parse_user_info ( e ) ) else hash [ e . name ] = [ ] if hash [ e . name ] . nil? hash [ e . name ] = [ hash [ e . name ] ] if hash [ e . name ] . is_a? String hash [ e . name ] . push ( parse_user_info ( e ) ) end end end end end end


Input: Rack 2 . 0 method [CODESPLIT] def find_session ( env , sid ) if sid . nil? sid = generate_sid data = nil else unless session = Session . where ( _id : sid ) . first session = { } # force generation of new sid since there is no associated session sid = generate_sid end data = unpack ( session [ 'data' ] ) end [ sid , data ] end


Input: Rack 2 . 0 method [CODESPLIT] def write_session ( env , sid , session_data , options ) cas_ticket = ( session_data [ 'cas' ] [ 'ticket' ] unless session_data [ 'cas' ] . nil? ) session = Session . find_or_initialize_by ( _id : sid ) success = session . update_attributes ( data : pack ( session_data ) , cas_ticket : cas_ticket ) success ? session . id : false end


Input: Rack 2 . 0 method [CODESPLIT] def delete_session ( env , sid , options ) Session . where ( _id : sid ) . delete options [ :drop ] ? nil : generate_sid end


Input: rubocop : disable Metrics / PerceivedComplexity [CODESPLIT] def remote_execution_proxies ( provider , authorized = true ) proxies = { } proxies [ :subnet ] = execution_interface . subnet . remote_execution_proxies . with_features ( provider ) if execution_interface && execution_interface . subnet proxies [ :fallback ] = smart_proxies . with_features ( provider ) if Setting [ :remote_execution_fallback_proxy ] if Setting [ :remote_execution_global_proxy ] proxy_scope = if Taxonomy . enabled_taxonomies . any? && User . current . present? :: SmartProxy . with_taxonomy_scope_override ( location , organization ) else :: SmartProxy . unscoped end proxy_scope = proxy_scope . authorized if authorized proxies [ :global ] = proxy_scope . with_features ( provider ) end proxies end


Input: Initiates run of the remote command and yields the data when available . The yielding doesn t happen automatically but as part of calling the refresh method . [CODESPLIT] def run_async ( command ) raise 'Async command already in progress' if @started @started = false @user_method . reset session . open_channel do | channel | channel . request_pty channel . on_data do | ch , data | publish_data ( data , 'stdout' ) unless @user_method . filter_password? ( data ) @user_method . on_data ( data , ch ) end channel . on_extended_data { | ch , type , data | publish_data ( data , 'stderr' ) } # standard exit of the command channel . on_request ( 'exit-status' ) { | ch , data | publish_exit_status ( data . read_long ) } # on signal: sending the signal value (such as 'TERM') channel . on_request ( 'exit-signal' ) do | ch , data | publish_exit_status ( data . read_string ) ch . close # wait for the channel to finish so that we know at the end # that the session is inactive ch . wait end channel . exec ( command ) do | _ , success | @started = true raise ( 'Error initializing command' ) unless success end end session . process ( 0 ) { ! run_started? } return true end


Input: when a remote server disconnects it s hard to tell if it was on purpose ( when calling reboot ) or it s an error . When it s expected we expect the script to produce restart host as its last command output [CODESPLIT] def check_expecting_disconnect last_output = @continuous_output . raw_outputs . find { | d | d [ 'output_type' ] == 'stdout' } return unless last_output if EXPECTED_POWER_ACTION_MESSAGES . any? { | message | last_output [ 'output' ] =~ / #{ message } / } @expecting_disconnect = true end end


Input: Decide if the execution should fail or not [CODESPLIT] def exit_code fail_chance = ENV . fetch ( 'REX_SIMULATE_FAIL_CHANCE' , 0 ) . to_i fail_exitcode = ENV . fetch ( 'REX_SIMULATE_EXIT' , 0 ) . to_i if fail_exitcode == 0 || fail_chance < ( Random . rand * 100 ) . round 0 else fail_exitcode end end


Input: Register a new function [CODESPLIT] def register ( name , fn = nil , & block ) self . class . new ( methods . merge ( name => fn || block ) ) end


Input: Imports proc ( s ) to the collection from another module [CODESPLIT] def import ( * args ) first = args . first return import_all ( first ) if first . instance_of? ( Module ) opts = args . pop source = opts . fetch ( :from ) rename = opts . fetch ( :as ) { first . to_sym } return import_methods ( source , args ) if args . count > 1 import_method ( source , first , rename ) end


Input: Creates new immutable collection from the current one updated with either the module s singleton method or the proc having been imported from another module . [CODESPLIT] def import_method ( source , name , new_name = name ) from = name . to_sym to = new_name . to_sym fn = source . is_a? ( Registry ) ? source . fetch ( from ) : source . method ( from ) self . class . new ( methods . merge ( to => fn ) ) end


Input: Creates new immutable collection from the current one updated with either the module s singleton methods or the procs having been imported from another module . [CODESPLIT] def import_methods ( source , names ) names . inject ( self ) { | a , e | a . import_method ( source , e ) } end


Input: Creates new immutable collection from the current one updated with all singleton methods and imported methods from the other module [CODESPLIT] def import_all ( source ) names = source . public_methods - Registry . instance_methods - Module . methods names -= [ :initialize ] # for compatibility with Rubinius names += source . store . methods . keys if source . is_a? Registry import_methods ( source , names ) end


Input: Builds the transformation [CODESPLIT] def [] ( fn , * args ) fetched = fetch ( fn ) return Function . new ( fetched , args : args , name : fn ) unless already_wrapped? ( fetched ) args . empty? ? fetched : fetched . with ( args ) end


Input: Register a new function [CODESPLIT] def register ( name , fn = nil , & block ) if contain? ( name ) raise FunctionAlreadyRegisteredError , "Function #{name} is already defined" end @store = store . register ( name , fn , block ) self end


Input: Gets the procedure for creating a transproc [CODESPLIT] def fetch ( fn ) return fn unless fn . instance_of? Symbol respond_to? ( fn ) ? method ( fn ) : store . fetch ( fn ) rescue raise FunctionNotFoundError . new ( fn , self ) end


Input: Return a simple AST representation of this function [CODESPLIT] def to_ast args_ast = args . map { | arg | arg . respond_to? ( :to_ast ) ? arg . to_ast : arg } [ name , args_ast ] end


Input: Converts a transproc to a simple proc [CODESPLIT] def to_proc if args . size > 0 proc { | * value | fn . call ( value , args ) } else fn . to_proc end end


Input: Maps replacement keys to their values [CODESPLIT] def from_pattern_match ( keys , pattern , match ) keys . each_with_index . map do | key , idx | # Check if there is any replacement specified if pattern [ key ] interpolate ( pattern [ key ] , match ) else # No replacement defined, just return correct match group match [ idx + 1 ] end end end


Input: Interpolates a string with data from matches if specified [CODESPLIT] def interpolate ( replacement , match ) group_idx = replacement . index ( '$' ) return replacement if group_idx . nil? group_nbr = replacement [ group_idx + 1 ] replacement . sub ( "$#{group_nbr}" , match [ group_nbr . to_i ] ) end


Input: Run commands prior to each tab context . [CODESPLIT] def before ( * commands , & block ) context = ( @_context [ :before ] ||= [ ] ) block_given? ? run_context ( context , block ) : context . concat ( commands ) end


Input: Run commands in the conext of a window . [CODESPLIT] def window ( * args , & block ) key = "window#{@_windows.keys.size}" options = args . extract_options! options [ :name ] = args . first unless args . empty? context = ( @_windows [ key ] = window_hash . merge ( :options => options ) ) run_context context , block end


Input: Run commands in the context of a tab . [CODESPLIT] def tab ( * args , & block ) tabs = @_context [ :tabs ] key = "tab#{tabs.keys.size}" return ( tabs [ key ] = { :commands => args } ) unless block_given? context = ( tabs [ key ] = { :commands => [ ] } ) options = args . extract_options! options [ :name ] = args . first unless args . empty? context [ :options ] = options run_context context , block @_context = @_windows [ @_windows . keys . last ] # Jump back out into the context of the last window. end


Input: Store commands to run in context . [CODESPLIT] def run ( * commands ) context = case when @_context . is_a? ( Hash ) && @_context [ :tabs ] @_context [ :tabs ] [ 'default' ] [ :commands ] when @_context . is_a? ( Hash ) @_context [ :commands ] else @_context end context << commands . map { | c | c =~ / / ? "(#{c})" : c } . join ( " && " ) end


Input: Writes the command for write operations [CODESPLIT] def set_write ( policy , operation , key , bins ) begin_cmd field_count = estimate_key_size ( key , policy ) bins . each do | bin | estimate_operation_size_for_bin ( bin ) end size_buffer write_header_with_policy ( policy , 0 , INFO2_WRITE , field_count , bins . length ) write_key ( key , policy ) bins . each do | bin | write_operation_for_bin ( bin , operation ) end end_cmd end


Input: Writes the command for delete operations [CODESPLIT] def set_delete ( policy , key ) begin_cmd field_count = estimate_key_size ( key ) size_buffer write_header_with_policy ( policy , 0 , INFO2_WRITE | INFO2_DELETE , field_count , 0 ) write_key ( key ) end_cmd end


Input: Writes the command for touch operations [CODESPLIT] def set_touch ( policy , key ) begin_cmd field_count = estimate_key_size ( key ) estimate_operation_size size_buffer write_header_with_policy ( policy , 0 , INFO2_WRITE , field_count , 1 ) write_key ( key ) write_operation_for_operation_type ( Aerospike :: Operation :: TOUCH ) end_cmd end


Input: Writes the command for exist operations [CODESPLIT] def set_exists ( policy , key ) begin_cmd field_count = estimate_key_size ( key ) size_buffer write_header ( policy , INFO1_READ | INFO1_NOBINDATA , 0 , field_count , 0 ) write_key ( key ) end_cmd end


Input: Writes the command for get operations ( all bins ) [CODESPLIT] def set_read_for_key_only ( policy , key ) begin_cmd field_count = estimate_key_size ( key ) size_buffer write_header ( policy , INFO1_READ | INFO1_GET_ALL , 0 , field_count , 0 ) write_key ( key ) end_cmd end


Input: Writes the command for get operations ( specified bins ) [CODESPLIT] def set_read ( policy , key , bin_names ) if bin_names && bin_names . length > 0 begin_cmd field_count = estimate_key_size ( key ) bin_names . each do | bin_name | estimate_operation_size_for_bin_name ( bin_name ) end size_buffer write_header ( policy , INFO1_READ , 0 , field_count , bin_names . length ) write_key ( key ) bin_names . each do | bin_name | write_operation_for_bin_name ( bin_name , Aerospike :: Operation :: READ ) end end_cmd else set_read_for_key_only ( policy , key ) end end


Input: Writes the command for getting metadata operations [CODESPLIT] def set_read_header ( policy , key ) begin_cmd field_count = estimate_key_size ( key ) estimate_operation_size_for_bin_name ( '' ) size_buffer # The server does not currently return record header data with _INFO1_NOBINDATA attribute set. # The workaround is to request a non-existent bin. # TODO: Fix this on server. #command.set_read(INFO1_READ | _INFO1_NOBINDATA); write_header ( policy , INFO1_READ , 0 , field_count , 1 ) write_key ( key ) write_operation_for_bin_name ( '' , Aerospike :: Operation :: READ ) end_cmd end


Input: Implements different command operations [CODESPLIT] def set_operate ( policy , key , operations ) begin_cmd field_count = estimate_key_size ( key , policy ) read_attr = 0 write_attr = 0 read_header = false operations . each do | operation | case operation . op_type when Aerospike :: Operation :: READ read_attr |= INFO1_READ # Read all bins if no bin is specified. read_attr |= INFO1_GET_ALL unless operation . bin_name when Aerospike :: Operation :: READ_HEADER # The server does not currently return record header data with _INFO1_NOBINDATA attribute set. # The workaround is to request a non-existent bin. # TODO: Fix this on server. # read_attr |= _INFO1_READ | _INFO1_NOBINDATA read_attr |= INFO1_READ read_header = true else write_attr = INFO2_WRITE end estimate_operation_size_for_operation ( operation ) end size_buffer if write_attr != 0 write_header_with_policy ( policy , read_attr , write_attr , field_count , operations . length ) else write_header ( policy , read_attr , write_attr , field_count , operations . length ) end write_key ( key , policy ) operations . each do | operation | write_operation_for_operation ( operation ) end write_operation_for_bin ( nil , Aerospike :: Operation :: READ ) if read_header end_cmd end


Input: Generic header write . [CODESPLIT] def write_header ( policy , read_attr , write_attr , field_count , operation_count ) read_attr |= INFO1_CONSISTENCY_ALL if policy . consistency_level == Aerospike :: ConsistencyLevel :: CONSISTENCY_ALL # Write all header data except total size which must be written last. @data_buffer . write_byte ( MSG_REMAINING_HEADER_SIZE , 8 ) # Message heade.length. @data_buffer . write_byte ( read_attr , 9 ) @data_buffer . write_byte ( write_attr , 10 ) i = 11 while i <= 25 @data_buffer . write_byte ( 0 , i ) i = i . succ end @data_buffer . write_int16 ( field_count , 26 ) @data_buffer . write_int16 ( operation_count , 28 ) @data_offset = MSG_TOTAL_HEADER_SIZE end


Input: Header write for write operations . [CODESPLIT] def write_header_with_policy ( policy , read_attr , write_attr , field_count , operation_count ) # Set flags. generation = Integer ( 0 ) info_attr = Integer ( 0 ) case policy . record_exists_action when Aerospike :: RecordExistsAction :: UPDATE when Aerospike :: RecordExistsAction :: UPDATE_ONLY info_attr |= INFO3_UPDATE_ONLY when Aerospike :: RecordExistsAction :: REPLACE info_attr |= INFO3_CREATE_OR_REPLACE when Aerospike :: RecordExistsAction :: REPLACE_ONLY info_attr |= INFO3_REPLACE_ONLY when Aerospike :: RecordExistsAction :: CREATE_ONLY write_attr |= INFO2_CREATE_ONLY end case policy . generation_policy when Aerospike :: GenerationPolicy :: NONE when Aerospike :: GenerationPolicy :: EXPECT_GEN_EQUAL generation = policy . generation write_attr |= INFO2_GENERATION when Aerospike :: GenerationPolicy :: EXPECT_GEN_GT generation = policy . generation write_attr |= INFO2_GENERATION_GT end info_attr |= INFO3_COMMIT_MASTER if policy . commit_level == Aerospike :: CommitLevel :: COMMIT_MASTER read_attr |= INFO1_CONSISTENCY_ALL if policy . consistency_level == Aerospike :: ConsistencyLevel :: CONSISTENCY_ALL write_attr |= INFO2_DURABLE_DELETE if policy . durable_delete # Write all header data except total size which must be written last. @data_buffer . write_byte ( MSG_REMAINING_HEADER_SIZE , 8 ) # Message heade.length. @data_buffer . write_byte ( read_attr , 9 ) @data_buffer . write_byte ( write_attr , 10 ) @data_buffer . write_byte ( info_attr , 11 ) @data_buffer . write_byte ( 0 , 12 ) # unused @data_buffer . write_byte ( 0 , 13 ) # clear the result code @data_buffer . write_uint32 ( generation , 14 ) @data_buffer . write_uint32 ( policy . ttl , 18 ) # Initialize timeout. It will be written later. @data_buffer . write_byte ( 0 , 22 ) @data_buffer . write_byte ( 0 , 23 ) @data_buffer . write_byte ( 0 , 24 ) @data_buffer . write_byte ( 0 , 25 ) @data_buffer . write_int16 ( field_count , 26 ) @data_buffer . write_int16 ( operation_count , 28 ) @data_offset = MSG_TOTAL_HEADER_SIZE end


Input: NewExecuteTask initializes task with fields needed to query server nodes . IsDone queries all nodes for task completion status . [CODESPLIT] def all_nodes_done? if @scan command = 'scan-list' else command = 'query-list' end nodes = @cluster . nodes done = false nodes . each do | node | conn = node . get_connection ( 0 ) responseMap , _ = Info . request ( conn , command ) node . put_connection ( conn ) response = responseMap [ command ] find = "job_id=#{@task_id}:" index = response . index ( find ) unless index # don't return on first check done = true next end b = index + find . length response = response [ b , response . length ] find = 'job_status=' index = response . index ( find ) next unless index b = index + find . length response = response [ b , response . length ] e = response . index ( ':' ) status = response [ 0 , e ] case status when 'ABORTED' raise raise Aerospike :: Exceptions :: QueryTerminated when 'IN PROGRESS' return false when 'DONE' done = true end end done end


Input: Parse all results in the batch . Add records to shared list . If the record was not found the bins will be nil . [CODESPLIT] def parse_row ( result_code ) generation = @data_buffer . read_int32 ( 6 ) expiration = @data_buffer . read_int32 ( 10 ) batch_index = @data_buffer . read_int32 ( 14 ) field_count = @data_buffer . read_int16 ( 18 ) op_count = @data_buffer . read_int16 ( 20 ) key = parse_key ( field_count ) req_key = batch . key_for_index ( batch_index ) if key . digest == req_key . digest if result_code == 0 record = parse_record ( req_key , op_count , generation , expiration ) results [ batch_index ] = record end else Aerospike . logger . warn ( "Unexpected batch key returned: #{key}" ) end end


Input: : nodoc : Parse all results in the batch . Add records to shared list . If the record was not found the bins will be nil . [CODESPLIT] def parse_row ( result_code ) batch_index = @data_buffer . read_int32 ( 14 ) field_count = @data_buffer . read_int16 ( 18 ) op_count = @data_buffer . read_int16 ( 20 ) if op_count > 0 raise Aerospike :: Exceptions :: Parse . new ( 'Received bins that were not requested!' ) end parse_key ( field_count ) results [ batch_index ] = ( result_code == 0 ) end


Input: : nodoc : Parse all results in the batch . Add records to shared list . If the record was not found the bins will be nil . [CODESPLIT] def parse_row ( result_code ) field_count = @data_buffer . read_int16 ( 18 ) op_count = @data_buffer . read_int16 ( 20 ) if op_count > 0 raise Aerospike :: Exceptions :: Parse . new ( 'Received bins that were not requested!' ) end key = parse_key ( field_count ) item = key_map [ key . digest ] if item index = item . index results [ index ] = ( result_code == 0 ) else Aerospike :: logger . debug ( "Unexpected batch key returned: #{key.namespace}, #{key.digest}" ) end end


Input: Parse all results in the batch . Add records to shared list . If the record was not found the bins will be nil . [CODESPLIT] def parse_row ( result_code ) generation = @data_buffer . read_int32 ( 6 ) expiration = @data_buffer . read_int32 ( 10 ) field_count = @data_buffer . read_int16 ( 18 ) op_count = @data_buffer . read_int16 ( 20 ) key = parse_key ( field_count ) item = key_map [ key . digest ] if item if result_code == 0 index = item . index key = item . key results [ index ] = parse_record ( key , op_count , generation , expiration ) end else Aerospike . logger . warn ( "Unexpected batch key returned: #{key}" ) end end


Input: : nodoc : [CODESPLIT] def write_bins @operations . select { | op | op . op_type == Aerospike :: Operation :: WRITE } . map ( :bin ) . compact end


Input: : nodoc : [CODESPLIT] def update_partition ( nmap , node ) amap = nil copied = false while partition = get_next node_array = nmap [ partition . namespace ] if ! node_array if ! copied # Make shallow copy of map. amap = { } nmap . each { | k , v | amap [ k ] = v } copied = true end node_array = Atomic . new ( Array . new ( Aerospike :: Node :: PARTITIONS ) ) amap [ partition . namespace ] = node_array end Aerospike . logger . debug ( "#{partition.to_s}, #{node.name}" ) node_array . update { | v | v [ partition . partition_id ] = node ; v } end copied ? amap : nil end


Input: Initialize server node with connection parameters . Get a connection to the node . If no cached connection is not available a new connection will be created [CODESPLIT] def get_connection ( timeout ) loop do conn = @connections . poll if conn . connected? conn . timeout = timeout . to_f return conn end end end


Input: : nodoc : [CODESPLIT] def write_buffer fieldCount = 0 filterSize = 0 binNameSize = 0 begin_cmd if @statement . namespace @data_offset += @statement . namespace . bytesize + FIELD_HEADER_SIZE fieldCount += 1 end if @statement . index_name @data_offset += @statement . index_name . bytesize + FIELD_HEADER_SIZE fieldCount += 1 end if @statement . set_name @data_offset += @statement . set_name . bytesize + FIELD_HEADER_SIZE fieldCount += 1 end if ! is_scan? col_type = @statement . filters [ 0 ] . collection_type if col_type > 0 @data_offset += FIELD_HEADER_SIZE + 1 fieldCount += 1 end @data_offset += FIELD_HEADER_SIZE filterSize += 1 # num filters @statement . filters . each do | filter | sz = filter . estimate_size filterSize += sz end @data_offset += filterSize fieldCount += 1 if @statement . bin_names && @statement . bin_names . length > 0 @data_offset += FIELD_HEADER_SIZE binNameSize += 1 # num bin names @statement . bin_names . each do | bin_name | binNameSize += bin_name . bytesize + 1 end @data_offset += binNameSize fieldCount += 1 end else # Calling query with no filters is more efficiently handled by a primary index scan. # Estimate scan options size. @data_offset += ( 2 + FIELD_HEADER_SIZE ) fieldCount += 1 end @statement . set_task_id @data_offset += 8 + FIELD_HEADER_SIZE fieldCount += 1 if @statement . function_name @data_offset += FIELD_HEADER_SIZE + 1 # udf type @data_offset += @statement . package_name . bytesize + FIELD_HEADER_SIZE @data_offset += @statement . function_name . bytesize + FIELD_HEADER_SIZE if @statement . function_args && @statement . function_args . length > 0 functionArgBuffer = Value . of ( @statement . function_args ) . to_bytes else functionArgBuffer = '' end @data_offset += FIELD_HEADER_SIZE + functionArgBuffer . bytesize fieldCount += 4 end if @statement . filters . nil? || @statement . filters . empty? if @statement . bin_names && @statement . bin_names . length > 0 @statement . bin_names . each do | bin_name | estimate_operation_size_for_bin_name ( bin_name ) end end end size_buffer readAttr = @policy . include_bin_data ? INFO1_READ : INFO1_READ | INFO1_NOBINDATA operation_count = ( is_scan? && ! @statement . bin_names . nil? ) ? @statement . bin_names . length : 0 write_header ( @policy , readAttr , 0 , fieldCount , operation_count ) if @statement . namespace write_field_string ( @statement . namespace , Aerospike :: FieldType :: NAMESPACE ) end unless @statement . index_name . nil? write_field_string ( @statement . index_name , Aerospike :: FieldType :: INDEX_NAME ) end if @statement . set_name write_field_string ( @statement . set_name , Aerospike :: FieldType :: TABLE ) end if ! is_scan? col_type = @statement . filters [ 0 ] . collection_type if col_type > 0 write_field_header ( 1 , Aerospike :: FieldType :: INDEX_TYPE ) @data_buffer . write_byte ( col_type , @data_offset ) @data_offset += 1 end write_field_header ( filterSize , Aerospike :: FieldType :: INDEX_RANGE ) @data_buffer . write_byte ( @statement . filters . length , @data_offset ) @data_offset += 1 @statement . filters . each do | filter | @data_offset = filter . write ( @data_buffer , @data_offset ) end # Query bin names are specified as a field (Scan bin names are specified later as operations) if @statement . bin_names && @statement . bin_names . length > 0 write_field_header ( binNameSize , Aerospike :: FieldType :: QUERY_BINLIST ) @data_buffer . write_byte ( @statement . bin_names . length , @data_offset ) @data_offset += 1 @statement . bin_names . each do | bin_name | len = @data_buffer . write_binary ( bin_name , @data_offset + 1 ) @data_buffer . write_byte ( len , @data_offset ) @data_offset += len + 1 ; end end else # Calling query with no filters is more efficiently handled by a primary index scan. write_field_header ( 2 , Aerospike :: FieldType :: SCAN_OPTIONS ) priority = @policy . priority . ord priority = priority << 4 @data_buffer . write_byte ( priority , @data_offset ) @data_offset += 1 @data_buffer . write_byte ( 100 . ord , @data_offset ) @data_offset += 1 end write_field_header ( 8 , Aerospike :: FieldType :: TRAN_ID ) @data_buffer . write_int64 ( @statement . task_id , @data_offset ) @data_offset += 8 if @statement . function_name write_field_header ( 1 , Aerospike :: FieldType :: UDF_OP ) if @statement . return_data @data_buffer . write_byte ( 1 , @data_offset ) @data_offset += 1 else @data_buffer . write_byte ( 2 , @data_offset ) @data_offset += 1 end write_field_string ( @statement . package_name , Aerospike :: FieldType :: UDF_PACKAGE_NAME ) write_field_string ( @statement . function_name , Aerospike :: FieldType :: UDF_FUNCTION ) write_field_bytes ( functionArgBuffer , Aerospike :: FieldType :: UDF_ARGLIST ) end if is_scan? && ! @statement . bin_names . nil? @statement . bin_names . each do | bin_name | write_operation_for_bin_name ( bin_name , Aerospike :: Operation :: READ ) end end end_cmd return nil end


Input: : nodoc : [CODESPLIT] def parse_group ( receive_size ) @data_offset = 0 while @data_offset < receive_size read_bytes ( MSG_REMAINING_HEADER_SIZE ) result_code = @data_buffer . read ( 5 ) . ord & 0xFF # The only valid server return codes are "ok" and "not found". # If other return codes are received, then abort the batch. case result_code when Aerospike :: ResultCode :: OK # noop when Aerospike :: ResultCode :: KEY_NOT_FOUND_ERROR # consume the rest of the input buffer from the socket read_bytes ( receive_size - @data_offset ) if @data_offset < receive_size return nil else raise Aerospike :: Exceptions :: Aerospike . new ( result_code ) end info3 = @data_buffer . read ( 3 ) . ord # If cmd is the end marker of the response, do not proceed further return false if ( info3 & INFO3_LAST ) == INFO3_LAST generation = @data_buffer . read_int32 ( 6 ) expiration = @data_buffer . read_int32 ( 10 ) field_count = @data_buffer . read_int16 ( 18 ) op_count = @data_buffer . read_int16 ( 20 ) key = parse_key ( field_count ) if result_code == 0 if @recordset . active? @recordset . records . enq ( parse_record ( key , op_count , generation , expiration ) ) else expn = @recordset . is_scan? ? SCAN_TERMINATED_EXCEPTION : QUERY_TERMINATED_EXCEPTION raise expn end end end # while true end


Input: : nodoc : [CODESPLIT] def parse_result # Read socket into receive buffer one record at a time.  Do not read entire receive size # because the receive buffer would be too big. status = true while status # Read header. read_bytes ( 8 ) size = @data_buffer . read_int64 ( 0 ) receive_size = size & 0xFFFFFFFFFFFF if receive_size > 0 status = parse_group ( receive_size ) else status = false end end end


Input: Parses the given byte buffer and populate the result object . Returns the number of bytes that were parsed from the given buffer . [CODESPLIT] def parse_record ( key , op_count , generation , expiration ) bins = op_count > 0 ? { } : nil i = 0 while i < op_count raise Aerospike :: Exceptions :: QueryTerminated . new unless valid? read_bytes ( 8 ) op_size = @data_buffer . read_int32 ( 0 ) . ord particle_type = @data_buffer . read ( 5 ) . ord name_size = @data_buffer . read ( 7 ) . ord read_bytes ( name_size ) name = @data_buffer . read ( 0 , name_size ) . force_encoding ( 'utf-8' ) particle_bytes_size = op_size - ( 4 + name_size ) read_bytes ( particle_bytes_size ) value = Aerospike . bytes_to_particle ( particle_type , @data_buffer , 0 , particle_bytes_size ) bins [ name ] = value i = i . succ end Record . new ( @node , key , bins , generation , expiration ) end


Input: : nodoc : [CODESPLIT] def update_partition ( nmap , node ) amap = nil beginning = @offset copied = false while @offset < @length if @buffer [ @offset ] == ':' # Parse namespace. namespace = @buffer [ beginning ... @offset ] . strip if namespace . length <= 0 || namespace . length >= 32 response = get_truncated_response raise Aerospike :: Exceptions :: Parse . new ( "Invalid partition namespace #{namespace}. Response=#{response}" ) end @offset += 1 beginning = @offset # Parse partition id. while @offset < @length b = @buffer [ @offset ] break if b == ';' || b == "\n" @offset += 1 end if @offset == beginning response = get_truncated_response raise Aerospike :: Exceptions :: Parse . new ( "Empty partition id for namespace #{namespace}. Response=#{response}" ) end node_array = nmap [ namespace ] if ! node_array if ! copied # Make shallow copy of map. amap = { } nmap . each { | k , v | amap [ k ] = Atomic . new ( v ) } copied = true end node_array = Atomic . new ( Array . new ( Aerospike :: Node :: PARTITIONS ) ) amap [ namespace ] = node_array end bit_map_length = @offset - beginning restore_buffer = Base64 . strict_decode64 ( @buffer [ beginning , bit_map_length ] ) i = 0 while i < Aerospike :: Node :: PARTITIONS if ( restore_buffer [ i >> 3 ] . ord & ( 0x80 >> ( i & 7 ) ) ) != 0 # Logger.Info("Map: `" + namespace + "`," + strconv.Itoa(i) + "," + node.String) node_array . update { | v | v [ i ] = node ; v } end i = i . succ end @offset += 1 beginning = @offset else @offset += 1 end end copied ? amap : nil end


Input: Converts an absolute expiration time ( in seconds from citrusleaf epoch ) to relative time - to - live ( TTL ) in seconds [CODESPLIT] def expiration_to_ttl ( secs_from_epoc ) if secs_from_epoc == 0 Aerospike :: TTL :: NEVER_EXPIRE else now = Time . now . to_i - CITRUSLEAF_EPOCH # Record was not expired at server but if it looks expired at client # because of delay or clock differences, present it as not-expired. secs_from_epoc > now ? secs_from_epoc - now : 1 end end


Input: Returns a random node on the cluster [CODESPLIT] def random_node # Must copy array reference for copy on write semantics to work. node_array = nodes length = node_array . length i = 0 while i < length # Must handle concurrency with other non-tending threads, so node_index is consistent. index = ( @node_index . update { | v | v + 1 } % node_array . length ) . abs node = node_array [ index ] return node if node . active? i = i . succ end raise Aerospike :: Exceptions :: InvalidNode end


Input: Find a node by name and returns an error if not found [CODESPLIT] def get_node_by_name ( node_name ) node = find_node_by_name ( node_name ) raise Aerospike :: Exceptions :: InvalidNode unless node node end


Input: Refresh status of all nodes in cluster . Adds new nodes and / or removes unhealty ones [CODESPLIT] def refresh_nodes cluster_config_changed = false nodes = self . nodes if nodes . empty? seed_nodes cluster_config_changed = true nodes = self . nodes end peers = Peers . new # Clear node reference count nodes . each do | node | node . refresh_reset end peers . use_peers = supports_peers_protocol? # refresh all known nodes nodes . each do | node | node . refresh_info ( peers ) end # refresh peers when necessary if peers . generation_changed? # Refresh peers for all nodes that responded the first time even if only # one node's peers changed. peers . reset_refresh_count! nodes . each do | node | node . refresh_peers ( peers ) end end nodes . each do | node | node . refresh_partitions ( peers ) if node . partition_generation . changed? end if peers . generation_changed? || ! peers . use_peers? nodes_to_remove = find_nodes_to_remove ( peers . refresh_count ) if nodes_to_remove . any? remove_nodes ( nodes_to_remove ) cluster_config_changed = true end end # Add any new nodes from peer refresh if peers . nodes . any? # peers.nodes is a Hash. Pass only values, ie. the array of nodes add_nodes ( peers . nodes . values ) cluster_config_changed = true end cluster_config_changed end


Input: ------------------------------------------------------- Write Record Operations ------------------------------------------------------- [CODESPLIT] def put ( key , bins , options = nil ) policy = create_policy ( options , WritePolicy , default_write_policy ) command = WriteCommand . new ( @cluster , policy , key , hash_to_bins ( bins ) , Aerospike :: Operation :: WRITE ) execute_command ( command ) end


Input: ------------------------------------------------------- Operations string ------------------------------------------------------- [CODESPLIT] def append ( key , bins , options = nil ) policy = create_policy ( options , WritePolicy , default_write_policy ) command = WriteCommand . new ( @cluster , policy , key , hash_to_bins ( bins ) , Aerospike :: Operation :: APPEND ) execute_command ( command ) end


Input: Prepends bin values string to existing record bin values . The policy specifies the transaction timeout record expiration and how the transaction is handled when the record already exists . [CODESPLIT] def prepend ( key , bins , options = nil ) policy = create_policy ( options , WritePolicy , default_write_policy ) command = WriteCommand . new ( @cluster , policy , key , hash_to_bins ( bins ) , Aerospike :: Operation :: PREPEND ) execute_command ( command ) end


Input: ------------------------------------------------------- Arithmetic Operations ------------------------------------------------------- [CODESPLIT] def add ( key , bins , options = nil ) policy = create_policy ( options , WritePolicy , default_write_policy ) command = WriteCommand . new ( @cluster , policy , key , hash_to_bins ( bins ) , Aerospike :: Operation :: ADD ) execute_command ( command ) end


Input: ------------------------------------------------------- Delete Operations ------------------------------------------------------- [CODESPLIT] def delete ( key , options = nil ) policy = create_policy ( options , WritePolicy , default_write_policy ) command = DeleteCommand . new ( @cluster , policy , key ) execute_command ( command ) command . existed end


Input: Removes records in the specified namespace / set efficiently . [CODESPLIT] def truncate ( namespace , set_name = nil , before_last_update = nil , options = { } ) policy = create_policy ( options , Policy , default_info_policy ) str_cmd = "truncate:namespace=#{namespace}" str_cmd << ";set=#{set_name}" unless set_name . to_s . strip . empty? if before_last_update lut_nanos = ( before_last_update . to_f * 1_000_000_000.0 ) . round str_cmd << ";lut=#{lut_nanos}" elsif supports_feature? ( Aerospike :: Features :: LUT_NOW ) # Servers >= 4.3.1.4 require lut argument str_cmd << ";lut=now" end # Send index command to one node. That node will distribute the command to other nodes. response = send_info_command ( policy , str_cmd ) . upcase return if response == 'OK' raise Aerospike :: Exceptions :: Aerospike . new ( Aerospike :: ResultCode :: SERVER_ERROR , "Truncate failed: #{response}" ) end


Input: ------------------------------------------------------- Touch Operations ------------------------------------------------------- [CODESPLIT] def touch ( key , options = nil ) policy = create_policy ( options , WritePolicy , default_write_policy ) command = TouchCommand . new ( @cluster , policy , key ) execute_command ( command ) end


Input: ------------------------------------------------------- Existence - Check Operations ------------------------------------------------------- [CODESPLIT] def exists ( key , options = nil ) policy = create_policy ( options , Policy , default_read_policy ) command = ExistsCommand . new ( @cluster , policy , key ) execute_command ( command ) command . exists end


Input: ------------------------------------------------------- Read Record Operations ------------------------------------------------------- Read record header and bins for specified key . The policy can be used to specify timeouts . [CODESPLIT] def get ( key , bin_names = nil , options = nil ) policy = create_policy ( options , Policy , default_read_policy ) command = ReadCommand . new ( @cluster , policy , key , bin_names ) execute_command ( command ) command . record end


Input: Read record generation and expiration only for specified key . Bins are not read . The policy can be used to specify timeouts . [CODESPLIT] def get_header ( key , options = nil ) policy = create_policy ( options , Policy , default_read_policy ) command = ReadHeaderCommand . new ( @cluster , policy , key ) execute_command ( command ) command . record end


Input: ------------------------------------------------------- Batch Read Operations ------------------------------------------------------- Read multiple record headers and bins for specified keys in one batch call . The returned records are in positional order with the original key array order . If a key is not found the positional record will be nil . The policy can be used to specify timeouts and protocol type . [CODESPLIT] def batch_get ( keys , bin_names = nil , options = nil ) policy = create_policy ( options , BatchPolicy , default_batch_policy ) results = Array . new ( keys . length ) info_flags = INFO1_READ case bin_names when :all , nil , [ ] info_flags |= INFO1_GET_ALL bin_names = nil when :none info_flags |= INFO1_NOBINDATA bin_names = nil end if policy . use_batch_direct key_map = BatchItem . generate_map ( keys ) execute_batch_direct_commands ( keys ) do | node , batch | BatchDirectCommand . new ( node , batch , policy , key_map , bin_names , results , info_flags ) end else execute_batch_index_commands ( keys ) do | node , batch | BatchIndexCommand . new ( node , batch , policy , bin_names , results , info_flags ) end end results end


Input: Check if multiple record keys exist in one batch call . The returned boolean array is in positional order with the original key array order . The policy can be used to specify timeouts and protocol type . [CODESPLIT] def batch_exists ( keys , options = nil ) policy = create_policy ( options , BatchPolicy , default_batch_policy ) results = Array . new ( keys . length ) if policy . use_batch_direct key_map = BatchItem . generate_map ( keys ) execute_batch_direct_commands ( keys ) do | node , batch | BatchDirectExistsCommand . new ( node , batch , policy , key_map , results ) end else execute_batch_index_commands ( keys ) do | node , batch | BatchIndexExistsCommand . new ( node , batch , policy , results ) end end results end


Input: ------------------------------------------------------- Generic Database Operations ------------------------------------------------------- Perform multiple read / write operations on a single key in one batch call . An example would be to add an integer value to an existing record and then read the result all in one database call . Operations are executed in the order they are specified . [CODESPLIT] def operate ( key , operations , options = nil ) policy = create_policy ( options , WritePolicy , default_write_policy ) command = OperateCommand . new ( @cluster , policy , key , operations ) execute_command ( command ) command . record end


Input: --------------------------------------------------------------- User defined functions ( Supported by Aerospike 3 servers only ) --------------------------------------------------------------- Register package containing user defined functions with server . This asynchronous server call will return before command is complete . The user can optionally wait for command completion by using the returned RegisterTask instance . [CODESPLIT] def register_udf_from_file ( client_path , server_path , language , options = nil ) udf_body = File . read ( client_path ) register_udf ( udf_body , server_path , language , options ) end


Input: Register package containing user defined functions with server . This asynchronous server call will return before command is complete . The user can optionally wait for command completion by using the returned RegisterTask instance . [CODESPLIT] def register_udf ( udf_body , server_path , language , options = nil ) policy = create_policy ( options , Policy , default_info_policy ) content = Base64 . strict_encode64 ( udf_body ) . force_encoding ( 'binary' ) str_cmd = "udf-put:filename=#{server_path};content=#{content};" str_cmd << "content-len=#{content.length};udf-type=#{language};" # Send UDF to one node. That node will distribute the UDF to other nodes. response_map = @cluster . request_info ( policy , str_cmd ) res = { } response_map . each do | k , response | vals = response . to_s . split ( ';' ) vals . each do | pair | k , v = pair . split ( "=" , 2 ) res [ k ] = v end end if res [ 'error' ] raise Aerospike :: Exceptions :: CommandRejected . new ( "Registration failed: #{res['error']}\nFile: #{res['file']}\nLine: #{res['line']}\nMessage: #{res['message']}" ) end UdfRegisterTask . new ( @cluster , server_path ) end


Input: RemoveUDF removes a package containing user defined functions in the server . This asynchronous server call will return before command is complete . The user can optionally wait for command completion by using the returned RemoveTask instance . [CODESPLIT] def remove_udf ( udf_name , options = nil ) policy = create_policy ( options , Policy , default_info_policy ) str_cmd = "udf-remove:filename=#{udf_name};" # Send command to one node. That node will distribute it to other nodes. # Send UDF to one node. That node will distribute the UDF to other nodes. response_map = @cluster . request_info ( policy , str_cmd ) _ , response = response_map . first if response == 'ok' UdfRemoveTask . new ( @cluster , udf_name ) else raise Aerospike :: Exceptions :: Aerospike . new ( Aerospike :: ResultCode :: SERVER_ERROR , response ) end end


Input: ListUDF lists all packages containing user defined functions in the server . This method is only supported by Aerospike 3 servers . [CODESPLIT] def list_udf ( options = nil ) policy = create_policy ( options , Policy , default_info_policy ) str_cmd = 'udf-list' # Send command to one node. That node will distribute it to other nodes. response_map = @cluster . request_info ( policy , str_cmd ) _ , response = response_map . first vals = response . split ( ';' ) vals . map do | udf_info | next if udf_info . strip! == '' udf_parts = udf_info . split ( ',' ) udf = UDF . new udf_parts . each do | values | k , v = values . split ( '=' , 2 ) case k when 'filename' udf . filename = v when 'hash' udf . hash = v when 'type' udf . language = v end end udf end end


Input: Execute user defined function on server and return results . The function operates on a single record . The package name is used to locate the udf file location : [CODESPLIT] def execute_udf ( key , package_name , function_name , args = [ ] , options = nil ) policy = create_policy ( options , WritePolicy , default_write_policy ) command = ExecuteCommand . new ( @cluster , policy , key , package_name , function_name , args ) execute_command ( command ) record = command . record return nil if ! record || record . bins . empty? result_map = record . bins # User defined functions don't have to return a value. key , obj = result_map . detect { | k , _ | k . include? ( 'SUCCESS' ) } return obj if key key , obj = result_map . detect { | k , _ | k . include? ( 'FAILURE' ) } message = key ? obj . to_s : "Invalid UDF return value" raise Aerospike :: Exceptions :: Aerospike . new ( Aerospike :: ResultCode :: UDF_BAD_RESPONSE , message ) end


Input: execute_udf_on_query applies user defined function on records that match the statement filter . Records are not returned to the client . This asynchronous server call will return before command is complete . The user can optionally wait for command completion by using the returned ExecuteTask instance . [CODESPLIT] def execute_udf_on_query ( statement , package_name , function_name , function_args = [ ] , options = nil ) policy = create_policy ( options , QueryPolicy , default_query_policy ) nodes = @cluster . nodes if nodes . empty? raise Aerospike :: Exceptions :: Aerospike . new ( Aerospike :: ResultCode :: SERVER_NOT_AVAILABLE , "Executing UDF failed because cluster is empty." ) end # TODO: wait until all migrations are finished statement . set_aggregate_function ( package_name , function_name , function_args , false ) # Use a thread per node nodes . each do | node | Thread . new do Thread . current . abort_on_exception = true begin command = QueryCommand . new ( node , policy , statement , nil ) execute_command ( command ) rescue => e Aerospike . logger . error ( e ) raise e end end end ExecuteTask . new ( @cluster , statement ) end


Input: Create secondary index . This asynchronous server call will return before command is complete . The user can optionally wait for command completion by using the returned IndexTask instance . [CODESPLIT] def create_index ( namespace , set_name , index_name , bin_name , index_type , collection_type = nil , options = nil ) if options . nil? && collection_type . is_a? ( Hash ) options , collection_type = collection_type , nil end policy = create_policy ( options , Policy , default_info_policy ) str_cmd = "sindex-create:ns=#{namespace}" str_cmd << ";set=#{set_name}" unless set_name . to_s . strip . empty? str_cmd << ";indexname=#{index_name};numbins=1" str_cmd << ";indextype=#{collection_type.to_s.upcase}" if collection_type str_cmd << ";indexdata=#{bin_name},#{index_type.to_s.upcase}" str_cmd << ";priority=normal" # Send index command to one node. That node will distribute the command to other nodes. response = send_info_command ( policy , str_cmd ) . upcase if response == 'OK' # Return task that could optionally be polled for completion. return IndexTask . new ( @cluster , namespace , index_name ) end if response . start_with? ( 'FAIL:200' ) # Index has already been created.  Do not need to poll for completion. return IndexTask . new ( @cluster , namespace , index_name , true ) end raise Aerospike :: Exceptions :: Aerospike . new ( Aerospike :: ResultCode :: INDEX_GENERIC , "Create index failed: #{response}" ) end


Input: Delete secondary index . This method is only supported by Aerospike 3 servers . [CODESPLIT] def drop_index ( namespace , set_name , index_name , options = nil ) policy = create_policy ( options , Policy , default_info_policy ) str_cmd = "sindex-delete:ns=#{namespace}" str_cmd << ";set=#{set_name}" unless set_name . to_s . strip . empty? str_cmd << ";indexname=#{index_name}" # Send index command to one node. That node will distribute the command to other nodes. response = send_info_command ( policy , str_cmd ) . upcase return if response == 'OK' # Index did not previously exist. Return without error. return if response . start_with? ( 'FAIL:201' ) raise Aerospike :: Exceptions :: Aerospike . new ( Aerospike :: ResultCode :: INDEX_GENERIC , "Drop index failed: #{response}" ) end


Input: ------------------------------------------------------- Scan Operations ------------------------------------------------------- [CODESPLIT] def scan_all ( namespace , set_name , bin_names = nil , options = nil ) policy = create_policy ( options , ScanPolicy , default_scan_policy ) # wait until all migrations are finished # TODO: implement # @cluster.WaitUntillMigrationIsFinished(policy.timeout) # Retry policy must be one-shot for scans. # copy on write for policy new_policy = policy . clone nodes = @cluster . nodes if nodes . empty? raise Aerospike :: Exceptions :: Aerospike . new ( Aerospike :: ResultCode :: SERVER_NOT_AVAILABLE , "Scan failed because cluster is empty." ) end recordset = Recordset . new ( policy . record_queue_size , nodes . length , :scan ) if policy . concurrent_nodes # Use a thread per node nodes . each do | node | Thread . new do Thread . current . abort_on_exception = true command = ScanCommand . new ( node , new_policy , namespace , set_name , bin_names , recordset ) begin execute_command ( command ) rescue => e Aerospike . logger . error ( e . backtrace . join ( "\n" ) ) unless e == SCAN_TERMINATED_EXCEPTION recordset . cancel ( e ) ensure recordset . thread_finished end end end else Thread . new do Thread . current . abort_on_exception = true nodes . each do | node | command = ScanCommand . new ( node , new_policy , namespace , set_name , bin_names , recordset ) begin execute_command ( command ) rescue => e Aerospike . logger . error ( e . backtrace . join ( "\n" ) ) unless e == SCAN_TERMINATED_EXCEPTION recordset . cancel ( e ) ensure recordset . thread_finished end end end end recordset end


Input: ScanNode reads all records in specified namespace and set from one node only . The policy can be used to specify timeouts . [CODESPLIT] def scan_node ( node , namespace , set_name , bin_names = nil , options = nil ) policy = create_policy ( options , ScanPolicy , default_scan_policy ) # wait until all migrations are finished # TODO: implement # @cluster.WaitUntillMigrationIsFinished(policy.timeout) # Retry policy must be one-shot for scans. # copy on write for policy new_policy = policy . clone new_policy . max_retries = 0 node = @cluster . get_node_by_name ( node ) unless node . is_a? ( Aerospike :: Node ) recordset = Recordset . new ( policy . record_queue_size , 1 , :scan ) Thread . new do Thread . current . abort_on_exception = true command = ScanCommand . new ( node , new_policy , namespace , set_name , bin_names , recordset ) begin execute_command ( command ) rescue => e Aerospike . logger . error ( e . backtrace . join ( "\n" ) ) unless e == SCAN_TERMINATED_EXCEPTION recordset . cancel ( e ) ensure recordset . thread_finished end end recordset end


Input: -------------------------------------------------------- Query functions ( Supported by Aerospike 3 servers only ) -------------------------------------------------------- Query executes a query and returns a recordset . The query executor puts records on a channel from separate goroutines . The caller can concurrently pops records off the channel through the record channel . [CODESPLIT] def query ( statement , options = nil ) policy = create_policy ( options , QueryPolicy , default_query_policy ) new_policy = policy . clone nodes = @cluster . nodes if nodes . empty? raise Aerospike :: Exceptions :: Aerospike . new ( Aerospike :: ResultCode :: SERVER_NOT_AVAILABLE , "Scan failed because cluster is empty." ) end recordset = Recordset . new ( policy . record_queue_size , nodes . length , :query ) # Use a thread per node nodes . each do | node | Thread . new do Thread . current . abort_on_exception = true command = QueryCommand . new ( node , new_policy , statement , recordset ) begin execute_command ( command ) rescue => e Aerospike . logger . error ( e . backtrace . join ( "\n" ) ) unless e == QUERY_TERMINATED_EXCEPTION recordset . cancel ( e ) ensure recordset . thread_finished end end end recordset end


Input: ------------------------------------------------------- User administration ------------------------------------------------------- Create user with password and roles . Clear - text password will be hashed using bcrypt before sending to server . [CODESPLIT] def create_user ( user , password , roles , options = nil ) policy = create_policy ( options , AdminPolicy , default_admin_policy ) hash = AdminCommand . hash_password ( password ) command = AdminCommand . new command . create_user ( @cluster , policy , user , hash , roles ) end


Input: Remove user from cluster . [CODESPLIT] def drop_user ( user , options = nil ) policy = create_policy ( options , AdminPolicy , default_admin_policy ) command = AdminCommand . new command . drop_user ( @cluster , policy , user ) end


Input: Change user s password . Clear - text password will be hashed using bcrypt before sending to server . [CODESPLIT] def change_password ( user , password , options = nil ) raise Aerospike :: Exceptions :: Aerospike . new ( INVALID_USER ) unless @cluster . user && @cluster . user != "" policy = create_policy ( options , AdminPolicy , default_admin_policy ) hash = AdminCommand . hash_password ( password ) command = AdminCommand . new if user == @cluster . user # Change own password. command . change_password ( @cluster , policy , user , hash ) else # Change other user's password by user admin. command . set_password ( @cluster , policy , user , hash ) end @cluster . change_password ( user , hash ) end


Input: Add roles to user s list of roles . [CODESPLIT] def grant_roles ( user , roles , options = nil ) policy = create_policy ( options , AdminPolicy , default_admin_policy ) command = AdminCommand . new command . grant_roles ( @cluster , policy , user , roles ) end


Input: Retrieve all users and their roles . [CODESPLIT] def query_users ( options = nil ) policy = create_policy ( options , AdminPolicy , default_admin_policy ) command = AdminCommand . new command . query_users ( @cluster , policy ) end


Input: : nodoc : [CODESPLIT] def authenticate ( conn , user , password ) begin set_authenticate ( user , password ) conn . write ( @data_buffer , @data_offset ) conn . read ( @data_buffer , HEADER_SIZE ) result = @data_buffer . read ( RESULT_CODE ) raise Exceptions :: Aerospike . new ( result , "Authentication failed" ) if result != 0 ensure Buffer . put ( @data_buffer ) end end


Input: fetches and return the first record from the queue if the operation is not finished and the queue is empty it blocks and waits for new records it sets the exception if it reaches the EOF mark and returns nil EOF means the operation has finished and no more records are comming from server nodes it re - raises the exception occurred in threads or which was set after reaching the EOF in the previous call [CODESPLIT] def next_record raise @thread_exception . get unless @thread_exception . get . nil? r = @records . deq set_exception if r . nil? r end


Input: fetches and returns all the records from the queue until the whole operation is finished and it reaches an EOF mark calling cancel inside the each block raises an exception to signal other consumer threads [CODESPLIT] def each ( & block ) r = true while r r = next_record # nil means EOF unless r . nil? block . call ( r ) else # reached the EOF break end end end


Input: This helper allows custom data attributes to be added to a user for the current request from within the controller . e . g . [CODESPLIT] def intercom_custom_data @_request_specific_intercom_custom_data ||= begin s = Struct . new ( :user , :company ) . new s . user = { } s . company = { } s end end


Input: Generate an intercom script tag . [CODESPLIT] def intercom_script_tag ( user_details = nil , options = { } ) controller . instance_variable_set ( IntercomRails :: SCRIPT_TAG_HELPER_CALLED_INSTANCE_VARIABLE , true ) if defined? ( controller ) options [ :user_details ] = user_details if user_details . present? options [ :find_current_user_details ] = ! options [ :user_details ] options [ :find_current_company_details ] = ! ( options [ :user_details ] && options [ :user_details ] [ :company ] ) options [ :controller ] = controller if defined? ( controller ) ScriptTag . new ( options ) end


Input: Moves this object based on the forces being applied to it and performing collision checking . [CODESPLIT] def move ( forces , obst , ramps , set_speed = false ) if set_speed @speed . x = forces . x @speed . y = forces . y else forces . x += G . gravity . x ; forces . y += G . gravity . y forces . x += @stored_forces . x ; forces . y += @stored_forces . y @stored_forces . x = @stored_forces . y = 0 forces . x = 0 if ( forces . x < 0 and @left ) or ( forces . x > 0 and @right ) forces . y = 0 if ( forces . y < 0 and @top ) or ( forces . y > 0 and @bottom ) if @bottom . is_a? Ramp if @bottom . ratio > G . ramp_slip_threshold forces . x += ( @bottom . left ? - 1 : 1 ) * ( @bottom . ratio - G . ramp_slip_threshold ) * G . ramp_slip_force / G . ramp_slip_threshold elsif forces . x > 0 && @bottom . left || forces . x < 0 && ! @bottom . left forces . x *= @bottom . factor end end @speed . x += forces . x / @mass ; @speed . y += forces . y / @mass end @speed . x = 0 if @speed . x . abs < G . min_speed . x @speed . y = 0 if @speed . y . abs < G . min_speed . y @speed . x = ( @speed . x <=> 0 ) * @max_speed . x if @speed . x . abs > @max_speed . x @speed . y = ( @speed . y <=> 0 ) * @max_speed . y if @speed . y . abs > @max_speed . y @prev_speed = @speed . clone x = @speed . x < 0 ? @x + @speed . x : @x y = @speed . y < 0 ? @y + @speed . y : @y w = @w + ( @speed . x < 0 ? - @speed . x : @speed . x ) h = @h + ( @speed . y < 0 ? - @speed . y : @speed . y ) move_bounds = Rectangle . new x , y , w , h coll_list = [ ] obst . each do | o | coll_list << o if o != self && move_bounds . intersect? ( o . bounds ) end ramps . each do | r | r . check_can_collide move_bounds end if coll_list . length > 0 up = @speed . y < 0 ; rt = @speed . x > 0 ; dn = @speed . y > 0 ; lf = @speed . x < 0 if @speed . x == 0 || @speed . y == 0 # Ortogonal if rt ; x_lim = find_right_limit coll_list elsif lf ; x_lim = find_left_limit coll_list elsif dn ; y_lim = find_down_limit coll_list elsif up ; y_lim = find_up_limit coll_list end if rt && @x + @w + @speed . x > x_lim @x = x_lim - @w @speed . x = 0 elsif lf && @x + @speed . x < x_lim @x = x_lim @speed . x = 0 elsif dn && @y + @h + @speed . y > y_lim ; @y = y_lim - @h ; @speed . y = 0 elsif up && @y + @speed . y < y_lim ; @y = y_lim ; @speed . y = 0 end else # Diagonal x_aim = @x + @speed . x + ( rt ? @w : 0 ) ; x_lim_def = x_aim y_aim = @y + @speed . y + ( dn ? @h : 0 ) ; y_lim_def = y_aim coll_list . each do | c | if c . passable ; x_lim = x_aim elsif rt ; x_lim = c . x else ; x_lim = c . x + c . w end if dn ; y_lim = c . y elsif c . passable ; y_lim = y_aim else ; y_lim = c . y + c . h end if c . passable y_lim_def = y_lim if dn && @y + @h <= y_lim && y_lim < y_lim_def elsif ( rt && @x + @w > x_lim ) || ( lf && @x < x_lim ) # Can't limit by x, will limit by y y_lim_def = y_lim if ( dn && y_lim < y_lim_def ) || ( up && y_lim > y_lim_def ) elsif ( dn && @y + @h > y_lim ) || ( up && @y < y_lim ) # Can't limit by y, will limit by x x_lim_def = x_lim if ( rt && x_lim < x_lim_def ) || ( lf && x_lim > x_lim_def ) else x_time = 1.0 * ( x_lim - @x - ( @speed . x < 0 ? 0 : @w ) ) / @speed . x y_time = 1.0 * ( y_lim - @y - ( @speed . y < 0 ? 0 : @h ) ) / @speed . y if x_time > y_time # Will limit by x x_lim_def = x_lim if ( rt && x_lim < x_lim_def ) || ( lf && x_lim > x_lim_def ) elsif ( dn && y_lim < y_lim_def ) || ( up && y_lim > y_lim_def ) y_lim_def = y_lim end end end if x_lim_def != x_aim @speed . x = 0 if lf ; @x = x_lim_def else ; @x = x_lim_def - @w end end if y_lim_def != y_aim @speed . y = 0 if up ; @y = y_lim_def else ; @y = y_lim_def - @h end end end end @x += @speed . x @y += @speed . y # Keeping contact with ramp # if @speed.y == 0 and @speed.x.abs <= G.ramp_contact_threshold and @bottom.is_a? Ramp #   @y = @bottom.get_y(self) #   puts 'aqui' # end ramps . each do | r | r . check_intersection self end check_contact obst , ramps end


Input: Moves this object as an elevator ( i . e . potentially carrying other objects ) with the specified forces or towards a given point . [CODESPLIT] def move_carrying ( arg , speed , obstacles , obst_obstacles , obst_ramps ) if speed x_d = arg . x - @x ; y_d = arg . y - @y distance = Math . sqrt ( x_d ** 2 + y_d ** 2 ) if distance == 0 @speed . x = @speed . y = 0 return end @speed . x = 1.0 * x_d * speed / distance @speed . y = 1.0 * y_d * speed / distance else arg += G . gravity @speed . x += arg . x / @mass ; @speed . y += arg . y / @mass @speed . x = 0 if @speed . x . abs < G . min_speed . x @speed . y = 0 if @speed . y . abs < G . min_speed . y @speed . x = ( @speed . x <=> 0 ) * @max_speed . x if @speed . x . abs > @max_speed . x @speed . y = ( @speed . y <=> 0 ) * @max_speed . y if @speed . y . abs > @max_speed . y end x_aim = @x + @speed . x ; y_aim = @y + @speed . y passengers = [ ] obstacles . each do | o | if @x + @w > o . x && o . x + o . w > @x foot = o . y + o . h if foot . round ( 6 ) == @y . round ( 6 ) || @speed . y < 0 && foot < @y && foot > y_aim passengers << o end end end prev_x = @x ; prev_y = @y if speed if @speed . x > 0 && x_aim >= arg . x || @speed . x < 0 && x_aim <= arg . x @x = arg . x ; @speed . x = 0 else @x = x_aim end if @speed . y > 0 && y_aim >= arg . y || @speed . y < 0 && y_aim <= arg . y @y = arg . y ; @speed . y = 0 else @y = y_aim end else @x = x_aim ; @y = y_aim end forces = Vector . new @x - prev_x , @y - prev_y prev_g = G . gravity . clone G . gravity . x = G . gravity . y = 0 passengers . each do | p | prev_speed = p . speed . clone prev_forces = p . stored_forces . clone prev_bottom = p . bottom p . speed . x = p . speed . y = 0 p . stored_forces . x = p . stored_forces . y = 0 p . instance_exec { @bottom = nil } p . move forces * p . mass , obst_obstacles , obst_ramps p . speed . x = prev_speed . x p . speed . y = prev_speed . y p . stored_forces . x = prev_forces . x p . stored_forces . y = prev_forces . y p . instance_exec ( prev_bottom ) { | b | @bottom = b } end G . gravity = prev_g end


Input: Moves this object without performing any collision checking towards a specified point or in a specified direction . [CODESPLIT] def move_free ( aim , speed ) if aim . is_a? Vector x_d = aim . x - @x ; y_d = aim . y - @y distance = Math . sqrt ( x_d ** 2 + y_d ** 2 ) if distance == 0 @speed . x = @speed . y = 0 return end @speed . x = 1.0 * x_d * speed / distance @speed . y = 1.0 * y_d * speed / distance if ( @speed . x < 0 and @x + @speed . x <= aim . x ) or ( @speed . x >= 0 and @x + @speed . x >= aim . x ) @x = aim . x @speed . x = 0 else @x += @speed . x end if ( @speed . y < 0 and @y + @speed . y <= aim . y ) or ( @speed . y >= 0 and @y + @speed . y >= aim . y ) @y = aim . y @speed . y = 0 else @y += @speed . y end else rads = aim * Math :: PI / 180 @speed . x = speed * Math . cos ( rads ) @speed . y = speed * Math . sin ( rads ) @x += @speed . x @y += @speed . y end end


Input: Causes the object to move in cycles across multiple given points ( the first point in the array is the first point the object will move towards so it doesn t need to be equal to the current / initial position ) . If obstacles are provided it will behave as an elevator ( as in + move_carrying + ) . [CODESPLIT] def cycle ( points , speed , obstacles = nil , obst_obstacles = nil , obst_ramps = nil ) @cur_point = 0 if @cur_point . nil? if obstacles move_carrying points [ @cur_point ] , speed , obstacles , obst_obstacles , obst_ramps else move_free points [ @cur_point ] , speed end if @speed . x == 0 and @speed . y == 0 if @cur_point == points . length - 1 ; @cur_point = 0 else ; @cur_point += 1 ; end end end


Input: : nodoc : Creates a new ramp . [CODESPLIT] def contact? ( obj ) obj . x + obj . w > @x && obj . x < @x + @w && obj . x . round ( 6 ) == get_x ( obj ) . round ( 6 ) && obj . y . round ( 6 ) == get_y ( obj ) . round ( 6 ) end


Input: Checks if an object is intersecting this ramp ( inside the corresponding right triangle and at the floor level or above ) . [CODESPLIT] def intersect? ( obj ) obj . x + obj . w > @x && obj . x < @x + @w && obj . y > get_y ( obj ) && obj . y <= @y + @h - obj . h end


Input: : nodoc : [CODESPLIT] def check_can_collide ( m ) y = get_y ( m ) + m . h @can_collide = m . x + m . w > @x && @x + @w > m . x && m . y < y && m . y + m . h > y end


Input: Creates a new map . [CODESPLIT] def get_absolute_size return Vector . new ( @tile_size . x * @size . x , @tile_size . y * @size . y ) unless @isometric avg = ( @size . x + @size . y ) * 0.5 Vector . new ( avg * @tile_size . x ) . to_i , ( avg * @tile_size . y ) . to_i end


Input: Returns the position in the screen corresponding to the given tile indices . [CODESPLIT] def get_screen_pos ( map_x , map_y ) return Vector . new ( map_x * @tile_size . x - @cam . x , map_y * @tile_size . y - @cam . y ) unless @isometric Vector . new ( ( map_x - map_y - 1 ) * @tile_size . x * 0.5 ) - @cam . x + @x_offset , ( ( map_x + map_y ) * @tile_size . y * 0.5 ) - @cam . y end


Input: Returns the tile in the map that corresponds to the given position in the screen as a Vector where x is the horizontal index and y the vertical index . [CODESPLIT] def get_map_pos ( scr_x , scr_y ) return Vector . new ( ( scr_x + @cam . x ) / @tile_size . x , ( scr_y + @cam . y ) / @tile_size . y ) unless @isometric # Gets the position transformed to isometric coordinates v = get_isometric_position scr_x , scr_y # divides by the square size to find the position in the matrix Vector . new ( ( v . x * @inverse_square_size ) . to_i , ( v . y * @inverse_square_size ) . to_i ) end


Input: Verifies whether a tile is inside the map . [CODESPLIT] def is_in_map ( v ) v . x >= 0 && v . y >= 0 && v . x < @size . x && v . y < @size . y end


Input: Iterates through the currently visible tiles providing the horizontal tile index the vertical tile index the x - coordinate ( in pixels ) and the y - coordinate ( in pixels ) of each tile in that order to a given block of code . [CODESPLIT] def foreach for j in @min_vis_y .. @max_vis_y for i in @min_vis_x .. @max_vis_x pos = get_screen_pos i , j yield i , j , pos . x , pos . y end end end


Input: Causes the sprite to animate through the + indices + array exactly once so that the animation stops once it reaches the last index in the array . Subsequent calls with the same parameters will have no effect but if the index or interval changes or if + set_animation + is called then a new animation cycle will begin . [CODESPLIT] def animate_once ( indices , interval ) if @animate_once_control == 2 return if indices == @animate_once_indices && interval == @animate_once_interval @animate_once_control = 0 end unless @animate_once_control == 1 @anim_counter = 0 @img_index = indices [ 0 ] @index_index = 0 @animate_once_indices = indices @animate_once_interval = interval @animate_once_control = 1 return end @anim_counter += 1 return unless @anim_counter >= interval @index_index += 1 @img_index = indices [ @index_index ] @anim_counter = 0 @animate_once_control = 2 if @index_index == indices . length - 1 end


Input: Draws the sprite in the screen [CODESPLIT] def draw ( map = nil , scale_x = 1 , scale_y = 1 , alpha = 0xff , color = 0xffffff , angle = nil , flip = nil , z_index = 0 , round = false ) if map . is_a? Hash scale_x = map . fetch ( :scale_x , 1 ) scale_y = map . fetch ( :scale_y , 1 ) alpha = map . fetch ( :alpha , 0xff ) color = map . fetch ( :color , 0xffffff ) angle = map . fetch ( :angle , nil ) flip = map . fetch ( :flip , nil ) z_index = map . fetch ( :z_index , 0 ) round = map . fetch ( :round , false ) map = map . fetch ( :map , nil ) end color = ( alpha << 24 ) | color if angle @img [ @img_index ] . draw_rot @x - ( map ? map . cam . x : 0 ) + @img [ 0 ] . width * scale_x * 0.5 , @y - ( map ? map . cam . y : 0 ) + @img [ 0 ] . height * scale_y * 0.5 , z_index , angle , 0.5 , 0.5 , ( flip == :horiz ? - scale_x : scale_x ) , ( flip == :vert ? - scale_y : scale_y ) , color else x = @x - ( map ? map . cam . x : 0 ) + ( flip == :horiz ? scale_x * @img [ 0 ] . width : 0 ) y = @y - ( map ? map . cam . y : 0 ) + ( flip == :vert ? scale_y * @img [ 0 ] . height : 0 ) @img [ @img_index ] . draw ( round ? x . round : x ) , ( round ? y . round : y ) , z_index , ( flip == :horiz ? - scale_x : scale_x ) , ( flip == :vert ? - scale_y : scale_y ) , color end end


Input: Returns whether this sprite is visible in the given map ( i . e . in the viewport determined by the camera of the given map ) . If no map is given returns whether the sprite is visible on the screen . [CODESPLIT] def visible? ( map = nil ) r = Rectangle . new @x , @y , @img [ 0 ] . width , @img [ 0 ] . height return Rectangle . new ( 0 , 0 , G . window . width , G . window . height ) . intersect? r if map . nil? map . cam . intersect? r end


Input: Adds a component to this panel . Parameters : [ c ] The component to add . [CODESPLIT] def add_component ( c ) _ , x , y = FormUtils . check_anchor ( c . anchor , c . anchor_offset_x , c . anchor_offset_y , c . w , c . h , @w , @h ) c . set_position ( @x + x , @y + y ) @controls << c end


Input: Draws the panel and all its child components . Parameters : [ alpha ] The opacity of the panel ( 0 = fully transparent 255 = fully opaque ) . [ z_index ] The z - index to draw the panel . [ color ] The color to apply as filter to the panel image and to all child components images as well . [CODESPLIT] def draw ( alpha = 255 , z_index = 0 , color = 0xffffff ) return unless @visible c = ( alpha << 24 ) | color if @img if @img . is_a? ( Array ) @img [ 0 ] . draw ( @x , @y , z_index , @scale_x , @scale_y , c ) @img [ 1 ] . draw ( @x + @tile_w , @y , z_index , @center_scale_x , @scale_y , c ) if @draw_center_x @img [ 2 ] . draw ( @x + @w - @tile_w , @y , z_index , @scale_x , @scale_y , c ) @img [ 3 ] . draw ( @x , @y + @tile_h , z_index , @scale_x , @center_scale_y , c ) if @draw_center_y @img [ 4 ] . draw ( @x + @tile_w , @y + @tile_h , z_index , @center_scale_x , @center_scale_y , c ) if @draw_center_x && @draw_center_y @img [ 5 ] . draw ( @x + @w - @tile_w , @y + @tile_h , z_index , @scale_x , @center_scale_y , c ) if @draw_center_y @img [ 6 ] . draw ( @x , @y + @h - @tile_h , z_index , @scale_x , @scale_y , c ) @img [ 7 ] . draw ( @x + @tile_w , @y + @h - @tile_h , z_index , @center_scale_x , @scale_y , c ) if @draw_center_x @img [ 8 ] . draw ( @x + @w - @tile_w , @y + @h - @tile_h , z_index , @scale_x , @scale_y , c ) else @img . draw ( @x , @y , z_index , @w . to_f / @img . width , @h . to_f / @img . height ) end end @controls . each { | k | k . draw ( alpha , z_index , color ) if k . visible } end


Input: Creates a button . [CODESPLIT] def update return unless @enabled and @visible mouse_over = Mouse . over? @x , @y , @w , @h mouse_press = Mouse . button_pressed? :left mouse_rel = Mouse . button_released? :left if @state == :up if mouse_over @img_index = 1 @state = :over else @img_index = 0 end elsif @state == :over if not mouse_over @img_index = 0 @state = :up elsif mouse_press @img_index = 2 @state = :down else @img_index = 1 end elsif @state == :down if not mouse_over @img_index = 0 @state = :down_out elsif mouse_rel @img_index = 1 @state = :over click else @img_index = 2 end else # :down_out if mouse_over @img_index = 2 @state = :down elsif mouse_rel @img_index = 0 @state = :up else @img_index = 0 end end end


Input: Draws the button in the screen . [CODESPLIT] def draw ( alpha = 0xff , z_index = 0 , color = 0xffffff ) return unless @visible color = ( alpha << 24 ) | color text_color = if @enabled if @state == :down @down_text_color else @state == :over ? @over_text_color : @text_color end else @disabled_text_color end text_color = ( alpha << 24 ) | text_color @img [ @img_index ] . draw @x , @y , z_index , @scale_x , @scale_y , color if @img if @text if @center_x or @center_y rel_x = @center_x ? 0.5 : 0 rel_y = @center_y ? 0.5 : 0 @font . draw_text_rel @text , @text_x , @text_y , z_index , rel_x , rel_y , @scale_x , @scale_y , text_color else @font . draw_text @text , @text_x , @text_y , z_index , @scale_x , @scale_y , text_color end end end


Input: Creates a new text field . [CODESPLIT] def update return unless @enabled and @visible ################################ Mouse ################################ if Mouse . over? @x , @y , @w , @h if not @active and Mouse . button_pressed? :left focus end elsif Mouse . button_pressed? :left unfocus end return unless @active if Mouse . double_click? :left if @nodes . size > 1 @anchor1 = 0 @anchor2 = @nodes . size - 1 @cur_node = @anchor2 @double_clicked = true end set_cursor_visible elsif Mouse . button_pressed? :left set_node_by_mouse @anchor1 = @cur_node @anchor2 = nil @double_clicked = false set_cursor_visible elsif Mouse . button_down? :left if @anchor1 and not @double_clicked set_node_by_mouse if @cur_node != @anchor1 ; @anchor2 = @cur_node else ; @anchor2 = nil ; end set_cursor_visible end elsif Mouse . button_released? :left if @anchor1 and not @double_clicked if @cur_node != @anchor1 ; @anchor2 = @cur_node else ; @anchor1 = nil ; end end end @cursor_timer += 1 if @cursor_timer >= 30 @cursor_visible = ( not @cursor_visible ) @cursor_timer = 0 end ############################### Keyboard ############################## shift = ( KB . key_down? ( @k [ 53 ] ) or KB . key_down? ( @k [ 54 ] ) ) if KB . key_pressed? ( @k [ 53 ] ) or KB . key_pressed? ( @k [ 54 ] ) # shift @anchor1 = @cur_node if @anchor1 . nil? elsif KB . key_released? ( @k [ 53 ] ) or KB . key_released? ( @k [ 54 ] ) @anchor1 = nil if @anchor2 . nil? end inserted = false for i in 0 .. 46 # alnum if KB . key_pressed? ( @k [ i ] ) or KB . key_held? ( @k [ i ] ) remove_interval true if @anchor1 and @anchor2 if i < 26 if shift insert_char @chars [ i + 37 ] else insert_char @chars [ i ] end elsif i < 36 if shift ; insert_char @chars [ i + 59 ] else ; insert_char @chars [ i ] ; end elsif shift insert_char ( @chars [ i + 49 ] ) else insert_char ( @chars [ i - 10 ] ) end inserted = true break end end return if inserted for i in 55 .. 65 # special if KB . key_pressed? ( @k [ i ] ) or KB . key_held? ( @k [ i ] ) remove_interval true if @anchor1 and @anchor2 if shift ; insert_char @chars [ i + 19 ] else ; insert_char @chars [ i + 8 ] ; end inserted = true break end end return if inserted for i in 66 .. 69 # numpad operators if KB . key_pressed? ( @k [ i ] ) or KB . key_held? ( @k [ i ] ) remove_interval true if @anchor1 and @anchor2 insert_char @chars [ i + 19 ] inserted = true break end end return if inserted if KB . key_pressed? ( @k [ 47 ] ) or KB . key_held? ( @k [ 47 ] ) # back if @anchor1 and @anchor2 remove_interval elsif @cur_node > 0 remove_char true end elsif KB . key_pressed? ( @k [ 48 ] ) or KB . key_held? ( @k [ 48 ] ) # del if @anchor1 and @anchor2 remove_interval elsif @cur_node < @nodes . size - 1 remove_char false end elsif KB . key_pressed? ( @k [ 49 ] ) or KB . key_held? ( @k [ 49 ] ) # left if @anchor1 if shift if @cur_node > 0 @cur_node -= 1 @anchor2 = @cur_node set_cursor_visible end elsif @anchor2 @cur_node = @anchor1 < @anchor2 ? @anchor1 : @anchor2 @anchor1 = nil @anchor2 = nil set_cursor_visible end elsif @cur_node > 0 @cur_node -= 1 set_cursor_visible end elsif KB . key_pressed? ( @k [ 50 ] ) or KB . key_held? ( @k [ 50 ] ) # right if @anchor1 if shift if @cur_node < @nodes . size - 1 @cur_node += 1 @anchor2 = @cur_node set_cursor_visible end elsif @anchor2 @cur_node = @anchor1 > @anchor2 ? @anchor1 : @anchor2 @anchor1 = nil @anchor2 = nil set_cursor_visible end elsif @cur_node < @nodes . size - 1 @cur_node += 1 set_cursor_visible end elsif KB . key_pressed? ( @k [ 51 ] ) # home @cur_node = 0 if shift ; @anchor2 = @cur_node else @anchor1 = nil @anchor2 = nil end set_cursor_visible elsif KB . key_pressed? ( @k [ 52 ] ) # end @cur_node = @nodes . size - 1 if shift ; @anchor2 = @cur_node else @anchor1 = nil @anchor2 = nil end set_cursor_visible end end


Input: Sets the text of the text field to the specified value . [CODESPLIT] def text = ( value , trigger_changed = true ) @text = value [ 0 ... @max_length ] @nodes . clear ; @nodes << @text_x x = @nodes [ 0 ] @text . chars . each { | char | x += @font . text_width ( char ) * @scale_x @nodes << x } @cur_node = @nodes . size - 1 @anchor1 = nil @anchor2 = nil set_cursor_visible @on_text_changed . call @text , @params if trigger_changed && @on_text_changed end


Input: Sets the position of the text field in the screen . [CODESPLIT] def set_position ( x , y ) d_x = x - @x d_y = y - @y @x = x ; @y = y @text_x += d_x @text_y += d_y @nodes . map! do | n | n + d_x end end


Input: Draws the text field in the screen . [CODESPLIT] def draw ( alpha = 0xff , z_index = 0 , color = 0xffffff , disabled_color = 0x808080 ) return unless @visible color = ( alpha << 24 ) | ( ( @enabled or @disabled_img ) ? color : disabled_color ) text_color = ( alpha << 24 ) | ( @enabled ? @text_color : @disabled_text_color ) img = ( ( @enabled or @disabled_img . nil? ) ? @img : @disabled_img ) img . draw @x , @y , z_index , @scale_x , @scale_y , color @font . draw_text @text , @text_x , @text_y , z_index , @scale_x , @scale_y , text_color if @anchor1 and @anchor2 selection_color = ( ( alpha / 2 ) << 24 ) | @selection_color G . window . draw_quad @nodes [ @anchor1 ] , @text_y , selection_color , @nodes [ @anchor2 ] + 1 , @text_y , selection_color , @nodes [ @anchor2 ] + 1 , @text_y + @font . height * @scale_y , selection_color , @nodes [ @anchor1 ] , @text_y + @font . height * @scale_y , selection_color , z_index end if @cursor_visible if @cursor_img @cursor_img . draw @nodes [ @cur_node ] - ( @cursor_img . width * @scale_x ) / 2 , @text_y , z_index , @scale_x , @scale_y else cursor_color = alpha << 24 G . window . draw_quad @nodes [ @cur_node ] , @text_y , cursor_color , @nodes [ @cur_node ] + 1 , @text_y , cursor_color , @nodes [ @cur_node ] + 1 , @text_y + @font . height * @scale_y , cursor_color , @nodes [ @cur_node ] , @text_y + @font . height * @scale_y , cursor_color , z_index end end end


Input: Draws the progress bar . [CODESPLIT] def draw ( alpha = 0xff , z_index = 0 , color = 0xffffff ) return unless @visible if @bg c = ( alpha << 24 ) | color @bg . draw @x , @y , z_index , @scale_x , @scale_y , c else c = ( alpha << 24 ) | @bg_color G . window . draw_quad @x , @y , c , @x + @w , @y , c , @x + @w , @y + @h , c , @x , @y + @h , c , z_index end if @fg c = ( alpha << 24 ) | color w1 = @fg . width * @scale_x w2 = ( @value . to_f / @max_value * @w ) . round x0 = @x + @fg_margin_x x = 0 while x <= w2 - w1 @fg . draw x0 + x , @y + @fg_margin_y , z_index , @scale_x , @scale_y , c x += w1 end if w2 - x > 0 img = Gosu :: Image . new ( @fg_path , tileable : true , retro : @retro , rect : [ 0 , 0 , ( ( w2 - x ) / @scale_x ) . round , @fg . height ] ) img . draw x0 + x , @y + @fg_margin_y , z_index , @scale_x , @scale_y , c end else c = ( alpha << 24 ) | @fg_color rect_r = @x + ( @value . to_f / @max_value * @w ) . round G . window . draw_quad @x , @y , c , rect_r , @y , c , rect_r , @y + @h , c , @x , @y + @h , c , z_index end if @font c = ( alpha << 24 ) | @text_color @text = @format == '%' ? "#{(@value.to_f / @max_value * 100).round}%" : "#{@value}/#{@max_value}" @font . draw_text_rel @text , @x + @w / 2 , @y + @h / 2 , z_index , 0.5 , 0.5 , @scale_x , @scale_y , c end end


Input: Creates a new drop - down list . [CODESPLIT] def update return unless @enabled and @visible if @open and Mouse . button_pressed? :left and not Mouse . over? ( @x , @y , @w , @max_h ) toggle return end @buttons . each { | b | b . update } end


Input: Sets the currently selected value of the drop - down list . It is ignored if it is not among the available options . [CODESPLIT] def value = ( val ) if @options . include? val old = @value @value = @buttons [ 0 ] . text = val @on_changed . call ( old , val ) if @on_changed end end


Input: Draws the drop - down list . [CODESPLIT] def draw ( alpha = 0xff , z_index = 0 , color = 0xffffff , over_color = 0xcccccc ) return unless @visible unless @img bottom = @y + ( @open ? @max_h : @h ) + @scale_y b_color = ( alpha << 24 ) G . window . draw_quad @x - @scale_x , @y - @scale_y , b_color , @x + @w + @scale_x , @y - @scale_y , b_color , @x + @w + @scale_x , bottom , b_color , @x - @scale_x , bottom , b_color , z_index @buttons . each do | b | c = ( alpha << 24 ) | ( b . state == :over ? over_color : color ) G . window . draw_quad b . x , b . y , c , b . x + b . w , b . y , c , b . x + b . w , b . y + b . h , c , b . x , b . y + b . h , c , z_index + 1 if b . visible end end @buttons [ 0 ] . draw ( alpha , z_index , color ) @buttons [ 1 .. - 1 ] . each { | b | b . draw alpha , z_index + 1 , color } end


Input: Creates a new label . [CODESPLIT] def draw ( alpha = 255 , z_index = 0 , color = 0xffffff ) c = @enabled ? @text_color : @disabled_text_color r1 = c >> 16 g1 = ( c & 0xff00 ) >> 8 b1 = ( c & 0xff ) r2 = color >> 16 g2 = ( color & 0xff00 ) >> 8 b2 = ( color & 0xff ) r1 *= r2 ; r1 /= 255 g1 *= g2 ; g1 /= 255 b1 *= b2 ; b1 /= 255 color = ( alpha << 24 ) | ( r1 << 16 ) | ( g1 << 8 ) | b1 @font . draw_text ( @text , @x , @y , z_index , @scale_x , @scale_y , color ) end


Input: Creates a TextHelper . [CODESPLIT] def write_line ( text , x = nil , y = nil , mode = :left , color = 0 , alpha = 0xff , effect = nil , effect_color = 0 , effect_size = 1 , effect_alpha = 0xff , z_index = 0 ) if text . is_a? Hash x = text [ :x ] y = text [ :y ] mode = text . fetch ( :mode , :left ) color = text . fetch ( :color , 0 ) alpha = text . fetch ( :alpha , 0xff ) effect = text . fetch ( :effect , nil ) effect_color = text . fetch ( :effect_color , 0 ) effect_size = text . fetch ( :effect_size , 1 ) effect_alpha = text . fetch ( :effect_alpha , 0xff ) z_index = text . fetch ( :z_index , 0 ) text = text [ :text ] end color = ( alpha << 24 ) | color rel = case mode when :left then 0 when :center then 0.5 when :right then 1 else 0 end if effect effect_color = ( effect_alpha << 24 ) | effect_color if effect == :border @font . draw_markup_rel text , x - effect_size , y - effect_size , z_index , rel , 0 , 1 , 1 , effect_color @font . draw_markup_rel text , x , y - effect_size , z_index , rel , 0 , 1 , 1 , effect_color @font . draw_markup_rel text , x + effect_size , y - effect_size , z_index , rel , 0 , 1 , 1 , effect_color @font . draw_markup_rel text , x + effect_size , y , z_index , rel , 0 , 1 , 1 , effect_color @font . draw_markup_rel text , x + effect_size , y + effect_size , z_index , rel , 0 , 1 , 1 , effect_color @font . draw_markup_rel text , x , y + effect_size , z_index , rel , 0 , 1 , 1 , effect_color @font . draw_markup_rel text , x - effect_size , y + effect_size , z_index , rel , 0 , 1 , 1 , effect_color @font . draw_markup_rel text , x - effect_size , y , z_index , rel , 0 , 1 , 1 , effect_color elsif effect == :shadow @font . draw_markup_rel text , x + effect_size , y + effect_size , z_index , rel , 0 , 1 , 1 , effect_color end end @font . draw_markup_rel text , x , y , z_index , rel , 0 , 1 , 1 , color end


Input: Draws text breaking lines when needed and when explicitly caused by the \ n character . [CODESPLIT] def write_breaking ( text , x , y , width , mode = :left , color = 0 , alpha = 0xff , z_index = 0 ) color = ( alpha << 24 ) | color text . split ( "\n" ) . each do | p | if mode == :justified y = write_paragraph_justified p , x , y , width , color , z_index else rel = case mode when :left then 0 when :center then 0.5 when :right then 1 else 0 end y = write_paragraph p , x , y , width , rel , color , z_index end end end


Input: Add a new GlobalFitMessage to the mapper and return the local message number . [CODESPLIT] def add_global ( message ) unless ( slot = @entries . index { | e | e . nil? } ) # No more free slots. We have to find the least recently used one. slot = 0 0 . upto ( 15 ) do | i | if i != slot && @entries [ slot ] . last_use > @entries [ i ] . last_use slot = i end end end @entries [ slot ] = Entry . new ( message , Time . now ) slot end


Input: Get the local message number for a given GlobalFitMessage . If there is no message number nil is returned . [CODESPLIT] def get_local ( message ) 0 . upto ( 15 ) do | i | if ( entry = @entries [ i ] ) && entry . global_message == message entry . last_use = Time . now return i end end nil end


Input: Create a new Monitoring_B object . [CODESPLIT] def check last_timestamp = ts_16_offset = nil last_ts_16 = nil # The timestamp_16 is a 2 byte time stamp value that is used instead of # the 4 byte timestamp field for monitoring records that have # current_activity_type_intensity values with an activity type of 6. The # value seems to be in seconds, but the 0 value reference does not seem # to be included in the file. However, it can be approximated using the # surrounding timestamp values. @monitorings . each do | record | if last_ts_16 && ts_16_offset && record . timestamp_16 && record . timestamp_16 < last_ts_16 # Detect timestamp_16 wrap-arounds. timestamp_16 is a 16 bit value. # In case of a wrap-around we adjust the ts_16_offset accordingly. ts_16_offset += 2 ** 16 end if ts_16_offset # We have already found the offset. Adjust all timestamps according # to 'offset + timestamp_16' if record . timestamp_16 record . timestamp = ts_16_offset + record . timestamp_16 last_ts_16 = record . timestamp_16 end else # We are still looking for the offset. if record . timestamp_16 && last_timestamp # We have a previous timestamp and found the first record with a # timestamp_16 value set. We assume that the timestamp of this # record is one minute after the previously found timestamp. # That's just a guess. Who knows what the Garmin engineers were # thinking here? ts_16_offset = last_timestamp + 60 - record . timestamp_16 record . timestamp = ts_16_offset + record . timestamp_16 last_ts_16 = record . timestamp_16 else # Just save the timestamp of the current record. last_timestamp = record . timestamp end end end end