Input: Create a new FitDataRecord . [CODESPLIT] def new_fit_data_record ( record_type , field_values = { } ) case record_type when 'file_id' @file_id = ( record = FileId . new ( field_values ) ) when 'software' @software = ( record = Software . new ( field_values ) ) when 'device_info' @device_infos << ( record = DeviceInfo . new ( field_values ) ) when 'monitoring_info' @monitoring_infos << ( record = MonitoringInfo . new ( field_values ) ) when 'monitoring' @monitorings << ( record = Monitoring . new ( field_values ) ) else record = nil end record end


Input: Create a new FieldDescription object . [CODESPLIT] def create_global_definition ( fit_entity ) messages = fit_entity . developer_fit_messages unless ( gfm = GlobalFitMessages [ @native_mesg_num ] ) Log . error "Developer field description references unknown global " + "message number #{@native_mesg_num}" return end if @developer_data_index >= fit_entity . top_level_record . developer_data_ids . size Log . error "Developer data index #{@developer_data_index} is too large" return end msg = messages [ @native_mesg_num ] || messages . message ( @native_mesg_num , gfm . name ) unless ( @fit_base_type_id & 0x7F ) < FIT_TYPE_DEFS . size Log . error "fit_base_type_id #{@fit_base_type_id} is too large" return end options = { } options [ :scale ] = @scale if @scale options [ :offset ] = @offset if @offset options [ :array ] = @array if @array options [ :unit ] = @units msg . field ( @field_definition_number , FIT_TYPE_DEFS [ @fit_base_type_id & 0x7F ] [ 1 ] , "_#{@developer_data_index}_#{@field_name}" , options ) end


Input: Ensure that FitDataRecords have a deterministic sequence . Device infos are sorted by device_index . [CODESPLIT] def check ( index ) unless @device_index Log . fatal 'device info record must have a device_index' end if @device_index == 0 unless @manufacturer Log . fatal 'device info record 0 must have a manufacturer field set' end if @manufacturer == 'garmin' unless @garmin_product Log . fatal 'device info record 0 must have a garman_product ' + 'field set' end else unless @product Log . fatal 'device info record 0 must have a product field set' end end if @serial_number . nil? Log . fatal 'device info record 0 must have a serial number set' end end end


Input: Redirect all log messages to the given IO . [CODESPLIT] def open ( io ) begin @@logger = Logger . new ( io ) rescue => e @@logger = Logger . new ( $stderr ) Log . fatal "Cannot open log file: #{e.message}" end end


Input: Create a new FitDataRecord . [CODESPLIT] def new_fit_data_record ( record_type , field_values = { } ) case record_type when 'file_id' @file_id = ( record = FileId . new ( field_values ) ) when 'file_creator' @software = ( record = FileCreator . new ( field_values ) ) when 'device_info' @device_infos << ( record = DeviceInfo . new ( field_values ) ) when 'training_status' @training_statuses << ( record = TrainingStatus . new ( field_values ) ) else record = nil end record end


Input: Create a FitFileEntity . Set what kind of FIT file we are dealing with . [CODESPLIT] def set_type ( type ) if @top_level_record Log . fatal "FIT file type has already been set to " + "#{@top_level_record.class}" end case type when 4 , 'activity' @top_level_record = Activity . new @type = 'activity' when 32 , 'monitoring_b' @top_level_record = Monitoring_B . new @type = 'monitoring_b' when 44 , 'metrics' @top_level_record = Metrics . new @type = 'metrics' else Log . error "Unsupported FIT file type #{type}" return nil end @top_level_record end


Input: Create a new Activity object . [CODESPLIT] def check unless @timestamp && @timestamp >= Time . parse ( '1990-01-01T00:00:00+00:00' ) Log . fatal "Activity has no valid timestamp" end unless @total_timer_time Log . fatal "Activity has no valid total_timer_time" end unless @device_infos . length > 0 Log . fatal "Activity must have at least one device_info section" end @device_infos . each . with_index { | d , index | d . check ( index ) } @sensor_settings . each . with_index { | s , index | s . check ( index ) } unless @num_sessions == @sessions . count Log . fatal "Activity record requires #{@num_sessions}, but " "#{@sessions.length} session records were found in the " "FIT file." end # Records must have consecutively growing timestamps and distances. ts = Time . parse ( '1989-12-31' ) distance = nil invalid_records = [ ] @records . each_with_index do | r , idx | Log . fatal "Record has no timestamp" unless r . timestamp if r . timestamp < ts Log . fatal "Record has earlier timestamp than previous record" end if r . distance if distance && r . distance < distance # Normally this should be a fatal error as the FIT file is clearly # broken. Unfortunately, the Skiing/Boarding app in the Fenix3 # produces such broken FIT files. So we just warn about this # problem and discard the earlier records. Log . error "Record #{r.timestamp} has smaller distance " + "(#{r.distance}) than an earlier record (#{distance})." # Index of the list record to be discarded. ( idx - 1 ) . downto ( 0 ) do | i | if ( ri = @records [ i ] ) . distance > r . distance # This is just an approximation. It looks like the app adds # records to the FIT file for runs that it meant to discard. # Maybe the two successive time start events are a better # criteria. But this workaround works for now. invalid_records << ri else # All broken records have been found. break end end end distance = r . distance end ts = r . timestamp end unless invalid_records . empty? # Delete all the broken records from the @records Array. Log . warn "Discarding #{invalid_records.length} earlier records" @records . delete_if { | r | invalid_records . include? ( r ) } end # Laps must have a consecutively growing message index. @laps . each . with_index do | lap , index | lap . check ( index ) # If we have heart rate zone records, there should be one for each # lap @heart_rate_zones [ index ] . check ( index ) if @heart_rate_zones [ index ] end @sessions . each { | s | s . check ( self ) } end


Input: Total distance convered by this activity purely computed by the GPS coordinates . This may differ from the distance computed by the device as it can be based on a purely calibrated footpod . [CODESPLIT] def total_gps_distance timer_stops = [ ] # Generate a list of all timestamps where the timer was stopped. @events . each do | e | if e . event == 'timer' && e . event_type == 'stop_all' timer_stops << e . timestamp end end # The first record of a FIT file can already have a distance associated # with it. The GPS location of the first record is not where the start # button was pressed. This introduces a slight inaccurcy when computing # the total distance purely on the GPS coordinates found in the records. d = 0.0 last_lat = last_long = nil last_timestamp = nil # Iterate over all the records and accumlate the distances between the # neiboring coordinates. @records . each do | r | if ( lat = r . position_lat ) && ( long = r . position_long ) if last_lat && last_long distance = Fit4Ruby :: GeoMath . distance ( last_lat , last_long , lat , long ) d += distance end if last_timestamp speed = distance / ( r . timestamp - last_timestamp ) end if timer_stops [ 0 ] == r . timestamp # If a stop event was found for this record timestamp we clear the # last_* values so that the distance covered while being stopped # is not added to the total. last_lat = last_long = nil last_timestamp = nil timer_stops . shift else last_lat = lat last_long = long last_timestamp = r . timestamp end end end d end


Input: Returns the computed VO2max value . This value is computed by the device based on multiple previous activities . [CODESPLIT] def vo2max # First check the event log for a vo2max reporting event. @events . each do | e | return e . vo2max if e . event == 'vo2max' end # Then check the user_data entries for a metmax entry. METmax * 3.5 # is same value as VO2max. @user_data . each do | u | return u . metmax * 3.5 if u . metmax end nil end


Input: Write the Activity data to a file . [CODESPLIT] def write ( io , id_mapper ) @file_id . write ( io , id_mapper ) @file_creator . write ( io , id_mapper ) ( @field_descriptions + @developer_data_ids + @device_infos + @sensor_settings + @data_sources + @user_profiles + @physiological_metrics + @events + @sessions + @laps + @records + @heart_rate_zones + @personal_records ) . sort . each do | s | s . write ( io , id_mapper ) end super end


Input: Check if the current Activity is equal to the passed Activity . [CODESPLIT] def new_fit_data_record ( record_type , field_values = { } ) case record_type when 'file_id' @file_id = ( record = FileId . new ( field_values ) ) when 'field_description' @field_descriptions << ( record = FieldDescription . new ( field_values ) ) when 'developer_data_id' @developer_data_ids << ( record = DeveloperDataId . new ( field_values ) ) when 'epo_data' @epo_data = ( record = EPO_Data . new ( field_values ) ) when 'file_creator' @file_creator = ( record = FileCreator . new ( field_values ) ) when 'device_info' @device_infos << ( record = DeviceInfo . new ( field_values ) ) when 'sensor_settings' @sensor_settings << ( record = SensorSettings . new ( field_values ) ) when 'data_sources' @data_sources << ( record = DataSources . new ( field_values ) ) when 'user_data' @user_data << ( record = UserData . new ( field_values ) ) when 'user_profile' @user_profiles << ( record = UserProfile . new ( field_values ) ) when 'physiological_metrics' @physiological_metrics << ( record = PhysiologicalMetrics . new ( field_values ) ) when 'event' @events << ( record = Event . new ( field_values ) ) when 'session' unless @cur_lap_records . empty? # Copy selected fields from section to lap. lap_field_values = { } [ :timestamp , :sport ] . each do | f | lap_field_values [ f ] = field_values [ f ] if field_values . include? ( f ) end # Ensure that all previous records have been assigned to a lap. record = create_new_lap ( lap_field_values ) end @num_sessions += 1 @sessions << ( record = Session . new ( @cur_session_laps , @lap_counter , field_values ) ) @cur_session_laps = [ ] when 'lap' record = create_new_lap ( field_values ) when 'record' @cur_lap_records << ( record = Record . new ( field_values ) ) @records << record when 'hrv' @hrv << ( record = HRV . new ( field_values ) ) when 'heart_rate_zones' @heart_rate_zones << ( record = HeartRateZones . new ( field_values ) ) when 'personal_records' @personal_records << ( record = PersonalRecords . new ( field_values ) ) else record = nil end record end


Input: Create a new Session object . [CODESPLIT] def check ( activity ) unless @first_lap_index Log . fatal 'first_lap_index is not set' end unless @num_laps Log . fatal 'num_laps is not set' end @first_lap_index . upto ( @first_lap_index - @num_laps ) do | i | if ( lap = activity . lap [ i ] ) @laps << lap else Log . fatal "Session references lap #{i} which is not contained in " "the FIT file." end end end


Input: Create a new GlobalFitMessage definition . [CODESPLIT] def field ( number , type , name , opts = { } ) field = Field . new ( type , name , opts ) register_field_by_name ( field , name ) register_field_by_number ( field , number ) end


Input: Define a new set of Field alternatives for this message definition . [CODESPLIT] def alt_field ( number , ref_field , & block ) unless @fields_by_name . include? ( ref_field ) raise "Unknown ref_field: #{ref_field}" end field = AltField . new ( self , ref_field , block ) register_field_by_number ( field , number ) end


Input: In development raises an error if the captcha field is not blank . This is is good to remember that the field should be hidden with CSS and shown only to robots . [CODESPLIT] def spam? self . class . mail_captcha . each do | field | next if send ( field ) . blank? if defined? ( Rails ) && Rails . env . development? raise ScriptError , "The captcha field #{field} was supposed to be blank" else return true end end false end


Input: Deliver the resource without running any validation . [CODESPLIT] def deliver! mailer = MailForm :: Notifier . contact ( self ) if mailer . respond_to? ( :deliver_now ) mailer . deliver_now else mailer . deliver end end


Input: Returns a hash of attributes according to the attributes existent in self . class . mail_attributes . [CODESPLIT] def mail_form_attributes self . class . mail_attributes . each_with_object ( { } ) do | attr , hash | hash [ attr . to_s ] = send ( attr ) end end


Input: Start Solr and wait for it to become available [CODESPLIT] def start extract_and_configure if config . managed? exec ( 'start' , p : port , c : config . cloud ) # Wait for solr to start unless status sleep config . poll_interval end after_start end end


Input: Stop Solr and wait for it to finish exiting [CODESPLIT] def restart if config . managed? && started? exec ( 'restart' , p : port , c : config . cloud ) end end


Input: Check the status of a managed Solr service [CODESPLIT] def status return true unless config . managed? out = exec ( 'status' ) . read out =~ / #{ port } / rescue false end


Input: Create a new collection in solr [CODESPLIT] def create ( options = { } ) options [ :name ] ||= SecureRandom . hex create_options = { p : port } create_options [ :c ] = options [ :name ] if options [ :name ] create_options [ :n ] = options [ :config_name ] if options [ :config_name ] create_options [ :d ] = options [ :dir ] if options [ :dir ] Retriable . retriable do raise "Not started yet" unless started? end # short-circuit if we're using persisted data with an existing core/collection return if options [ :persist ] && create_options [ :c ] && client . exists? ( create_options [ :c ] ) exec ( "create" , create_options ) options [ :name ] end


Input: Update the collection configuration in zookeeper [CODESPLIT] def upconfig ( options = { } ) options [ :name ] ||= SecureRandom . hex options [ :zkhost ] ||= zkhost upconfig_options = { upconfig : true , n : options [ :name ] } upconfig_options [ :d ] = options [ :dir ] if options [ :dir ] upconfig_options [ :z ] = options [ :zkhost ] if options [ :zkhost ] exec 'zk' , upconfig_options options [ :name ] end


Input: Copy the collection configuration from zookeeper to a local directory [CODESPLIT] def downconfig ( options = { } ) options [ :name ] ||= SecureRandom . hex options [ :zkhost ] ||= zkhost downconfig_options = { downconfig : true , n : options [ :name ] } downconfig_options [ :d ] = options [ :dir ] if options [ :dir ] downconfig_options [ :z ] = options [ :zkhost ] if options [ :zkhost ] exec 'zk' , downconfig_options options [ :name ] end


Input: Create a new collection run the block and then clean up the collection [CODESPLIT] def with_collection ( options = { } ) options = config . collection_options . merge ( options ) return yield if options . empty? name = create ( options ) begin yield name ensure delete name unless options [ :persist ] end end


Input: Clean up any files solr_wrapper may have downloaded [CODESPLIT] def clean! stop remove_instance_dir! FileUtils . remove_entry ( config . download_dir , true ) if File . exist? ( config . download_dir ) FileUtils . remove_entry ( config . tmp_save_dir , true ) if File . exist? config . tmp_save_dir checksum_validator . clean! FileUtils . remove_entry ( config . version_file ) if File . exist? config . version_file end


Input: rubocop : disable Lint / RescueException extract a copy of solr to instance_dir Does noting if solr already exists at instance_dir [CODESPLIT] def extract return config . instance_dir if extracted? zip_path = download begin Zip :: File . open ( zip_path ) do | zip_file | # Handle entries one by one zip_file . each do | entry | dest_file = File . join ( config . tmp_save_dir , entry . name ) FileUtils . remove_entry ( dest_file , true ) entry . extract ( dest_file ) end end rescue Exception => e abort "Unable to unzip #{zip_path} into #{config.tmp_save_dir}: #{e.message}" end begin FileUtils . remove_dir ( config . instance_dir , true ) FileUtils . cp_r File . join ( config . tmp_save_dir , File . basename ( config . download_url , ".zip" ) ) , config . instance_dir self . extracted_version = config . version FileUtils . chmod 0755 , config . solr_binary rescue Exception => e abort "Unable to copy #{config.tmp_save_dir} to #{config.instance_dir}: #{e.message}" end config . instance_dir ensure FileUtils . remove_entry config . tmp_save_dir if File . exist? config . tmp_save_dir end


Input: Run a bin / solr command [CODESPLIT] def exec ( cmd , options = { } ) stringio = StringIO . new # JRuby uses Popen4 command_runner = IO . respond_to? ( :popen4 ) ? Popen4Runner : PopenRunner runner = command_runner . new ( cmd , options , config ) exit_status = runner . run ( stringio ) if exit_status != 0 && cmd != 'status' raise "Failed to execute solr #{cmd}: #{stringio.read}. Further information may be available in #{instance_dir}/server/logs" end stringio end


Input: Delete the underlying C ++ instance after exec returns Otherwise rb_gc_call_finalizer_at_exit () can delete stuff that Qt :: Application still needs for its cleanup . [CODESPLIT] def exec result = method_missing ( :exec ) disable_threading ( ) self . dispose Qt :: Internal . application_terminated = true result end


Input: Add three methods propertyNames () slotNames () and signalNames () from Qt3 as they are very useful when debugging [CODESPLIT] def propertyNames ( inherits = false ) res = [ ] if inherits for p in 0 ... propertyCount ( ) res . push property ( p ) . name end else for p in propertyOffset ( ) ... propertyCount ( ) res . push property ( p ) . name end end return res end


Input: Return a list of signals including inherited ones [CODESPLIT] def get_signals all_signals = [ ] current = @klass while current != Qt :: Base meta = Meta [ current . name ] if ! meta . nil? all_signals . concat meta . signals end current = current . superclass end return all_signals end


Input: Adds another Duration or a Numeric to this Duration . Numeric values are treated as seconds . [CODESPLIT] def + ( other ) if Duration === other Duration . new ( value + other . value , @parts + other . parts ) else Duration . new ( value + other , @parts + [ [ :seconds , other ] ] ) end end


Input: Returns a new date / time at the end of the quarter . Example : 31st March 30th June 30th September . DateTime objects will have a time set to 23 : 59 : 59 . [CODESPLIT] def end_of_quarter last_quarter_month = [ 3 , 6 , 9 , 12 ] . detect { | m | m >= month } beginning_of_month . change ( :month => last_quarter_month ) . end_of_month end


Input: Returns a new date / time representing the given day in the next week . Week is assumed to start on + start_day + default is + Date . beginning_of_week + or + config . beginning_of_week + when set . DateTime objects have their time set to 0 : 00 . [CODESPLIT] def next_week ( start_day = Date . beginning_of_week ) first_hour { weeks_since ( 1 ) . beginning_of_week . days_since ( days_span ( start_day ) ) } end


Input: Returns a new date / time representing the given day in the previous week . Week is assumed to start on + start_day + default is + Date . beginning_of_week + or + config . beginning_of_week + when set . DateTime objects have their time set to 0 : 00 . [CODESPLIT] def prev_week ( start_day = Date . beginning_of_week ) first_hour { weeks_ago ( 1 ) . beginning_of_week . days_since ( days_span ( start_day ) ) } end


Input: Returns the number of days to the start of the week on the given day . Week is assumed to start on + start_day + default is + Date . beginning_of_week + or + config . beginning_of_week + when set . [CODESPLIT] def days_to_week_start ( start_day = Date . beginning_of_week ) start_day_number = DAYS_INTO_WEEK [ start_day ] current_day_number = wday != 0 ? wday - 1 : 6 ( current_day_number - start_day_number ) % 7 end


Input: Formats a + number + into a US phone number ( e . g . ( 555 ) 123 - 9876 ) . You can customize the format in the + options + hash . [CODESPLIT] def number_to_phone ( number , options = { } ) return unless number options = options . symbolize_keys number = number . to_s . strip area_code = options [ :area_code ] delimiter = options [ :delimiter ] || "-" extension = options [ :extension ] country_code = options [ :country_code ] if area_code number . gsub! ( / \d \d \d / , "(\\1) \\2#{delimiter}\\3" ) else number . gsub! ( / \d \d \d / , "\\1#{delimiter}\\2#{delimiter}\\3" ) number . slice! ( 0 , 1 ) if number . start_with? ( delimiter ) && ! delimiter . blank? end str = '' str << "+#{country_code}#{delimiter}" unless country_code . blank? str << number str << " x #{extension}" unless extension . blank? str end


Input: Create progress bar [CODESPLIT] def reset @width = 0 if no_width @render_period = frequency == 0 ? 0 : 1.0 / frequency @current = 0 @last_render_time = Time . now @last_render_width = 0 @done = false @stopped = false @start_at = Time . now @started = false @tokens = { } @meter . clear end


Input: Advance the progress bar [CODESPLIT] def advance ( progress = 1 , tokens = { } ) return if done? synchronize do emit ( :progress , progress ) if progress . respond_to? ( :to_hash ) tokens , progress = progress , 1 end @start_at = Time . now if @current . zero? && ! @started @current += progress @tokens = tokens @meter . sample ( Time . now , progress ) if ! no_width && @current >= total finish && return end now = Time . now return if ( now - @last_render_time ) < @render_period render end end


Input: Iterate over collection either yielding computation to block or provided Enumerator . If the bar s total was not set it would be taken from collection . count otherwise previously set total would be used . This allows using the progressbar with infinite lazy or slowly - calculated enumerators . [CODESPLIT] def iterate ( collection , progress = 1 , & block ) update ( total : collection . count * progress ) unless total progress_enum = Enumerator . new do | iter | collection . each do | elem | advance ( progress ) iter . yield ( elem ) end end block_given? ? progress_enum . each ( block ) : progress_enum end


Input: Update configuration options for this bar [CODESPLIT] def update ( options = { } ) synchronize do options . each do | name , val | if @configuration . respond_to? ( "#{name}=" ) @configuration . public_send ( "#{name}=" , val ) end end end end


Input: Render progress to the output [CODESPLIT] def render return if done? if hide_cursor && @last_render_width == 0 && ! ( @current >= total ) write ( TTY :: Cursor . hide ) end if @multibar characters_in = @multibar . line_inset ( self ) update ( inset : self . class . display_columns ( characters_in ) ) end formatted = @formatter . decorate ( self , @format ) @tokens . each do | token , val | formatted = formatted . gsub ( ":#{token}" , val ) end padded = padout ( formatted ) write ( padded , true ) @last_render_time = Time . now @last_render_width = self . class . display_columns ( formatted ) end


Input: Move cursor to a row of the current bar if the bar is rendered under a multibar . Otherwise do not move and yield on current row . [CODESPLIT] def move_to_row if @multibar CURSOR_LOCK . synchronize do if @first_render @row = @multibar . next_row yield if block_given? output . print "\n" @first_render = false else lines_up = ( @multibar . rows + 1 ) - @row output . print TTY :: Cursor . save output . print TTY :: Cursor . up ( lines_up ) yield if block_given? output . print TTY :: Cursor . restore end end else yield if block_given? end end


Input: Write out to the output [CODESPLIT] def write ( data , clear_first = false ) return unless tty? # write only to terminal move_to_row do output . print ( TTY :: Cursor . column ( 1 ) ) if clear_first characters_in = @multibar . line_inset ( self ) if @multibar output . print ( "#{characters_in}#{data}" ) output . flush end end


Input: End the progress [CODESPLIT] def finish return if done? @current = total unless no_width render clear ? clear_line : write ( "\n" , false ) ensure @meter . clear @done = true # reenable cursor if it is turned off if hide_cursor && @last_render_width != 0 write ( TTY :: Cursor . show , false ) end emit ( :done ) end


Input: Stop and cancel the progress at the current position [CODESPLIT] def stop # reenable cursor if it is turned off if hide_cursor && @last_render_width != 0 write ( TTY :: Cursor . show , false ) end return if done? render clear ? clear_line : write ( "\n" , false ) ensure @meter . clear @stopped = true emit ( :stopped ) end


Input: Log message above the current progress bar [CODESPLIT] def log ( message ) sanitized_message = message . gsub ( / \r \n / , ' ' ) if done? write ( sanitized_message + "\n" , false ) return end sanitized_message = padout ( sanitized_message ) write ( sanitized_message + "\n" , true ) render end


Input: Pad message out with spaces [CODESPLIT] def padout ( message ) message_length = self . class . display_columns ( message ) if @last_render_width > message_length remaining_width = @last_render_width - message_length message += ' ' * remaining_width end message end


Input: Reschedule the job in the future ( when a job fails ) . Uses an exponential scale depending on the number of failed attempts . [CODESPLIT] def reschedule ( message , backtrace = [ ] , time = nil ) if self . attempts < MAX_ATTEMPTS time ||= Job . db_time_now + ( attempts ** 4 ) + 5 self . attempts += 1 self . run_at = time self . last_error = message + "\n" + backtrace . join ( "\n" ) self . unlock save! else logger . info "* [JOB] PERMANENTLY removing #{self.name} because of #{attempts} consequetive failures." destroy_failed_jobs ? destroy : update_attribute ( :failed_at , Delayed :: Job . db_time_now ) end end


Input: Try to run one job . Returns true / false ( work done / work failed ) or nil if job can t be locked . [CODESPLIT] def run_with_lock ( max_run_time , worker_name ) logger . info "* [JOB] aquiring lock on #{name}" unless lock_exclusively! ( max_run_time , worker_name ) # We did not get the lock, some other worker process must have logger . warn "* [JOB] failed to aquire exclusive lock for #{name}" return nil # no work done end begin runtime = Benchmark . realtime do invoke_job # TODO: raise error if takes longer than max_run_time destroy end # TODO: warn if runtime > max_run_time ? logger . info "* [JOB] #{name} completed after %.4f" % runtime return true # did work rescue Exception => e reschedule e . message , e . backtrace log_exception ( e ) return false # work failed end end


Input: Lock this job for this worker . Returns true if we have the lock false otherwise . [CODESPLIT] def lock_exclusively! ( max_run_time , worker = worker_name ) now = self . class . db_time_now affected_rows = if locked_by != worker # We don't own this job so we will update the locked_by name and the locked_at self . class . update_all ( [ "locked_at = ?, locked_by = ?" , now , worker ] , [ "id = ? and (locked_at is null or locked_at < ?)" , id , ( now - max_run_time . to_i ) ] ) else # We already own this job, this may happen if the job queue crashes. # Simply resume and update the locked_at self . class . update_all ( [ "locked_at = ?" , now ] , [ "id = ? and locked_by = ?" , id , worker ] ) end if affected_rows == 1 self . locked_at = now self . locked_by = worker return true else return false end end


Input: loads all of our tracery files into our + files + hash if a file is named default then we load that into + grammar + [CODESPLIT] def setup_tracery dir_path raise "Provided path not a directory" unless Dir . exist? ( dir_path ) @grammar = { } Dir . open ( dir_path ) do | dir | dir . each do | file | # skip our current and parent dir next if file =~ / \. \. / # read the rule file into the files hash @grammar [ file . split ( '.' ) . first ] = createGrammar ( JSON . parse ( File . read ( "#{dir_path}/#{file}" ) ) ) end end # go ahead and makes a default mention-handler #  if we have a reply rule file unless @grammar [ 'reply' ] . nil? on_reply { | bot | bot . reply_with_mentions ( '#default#' , rules : 'reply' ) } end end


Input: a shortcut fuction for expanding text with tracery before posting [CODESPLIT] def expand_and_post ( text , * options ) opts = Hash [ options ] rules = opts . fetch ( :rules , 'default' ) actually_post ( @grammar [ rules ] . flatten ( text ) , ** opts . reject { | k | k == :rules } ) end


Input: Starts a loop that checks for any notifications for the authenticated user running the appropriate stored proc when needed [CODESPLIT] def run_interact @streamer . user do | update | if update . kind_of? Mastodon :: Notification case update . type when 'mention' # this makes it so .content calls strip instead  update . status . class . module_eval { alias_method :content , :strip } if @strip_html store_mention_data update . status @on_reply . call ( self , update . status ) unless @on_reply . nil? when 'reblog' @on_boost . call ( self , update ) unless @on_boost . nil? when 'favourite' @on_fave . call ( self , update ) unless @on_fave . nil? when 'follow' @on_follow . call ( self , update ) unless @on_follow . nil? end end end end


Input: Replies to the last mention the bot recieved using the mention s visibility and spoiler with + text + [CODESPLIT] def reply ( text , * options ) options = Hash [ options ] post ( "@#{@mention_data[:account].acct} #{text}" , ** @mention_data . merge ( options ) . reject { | k | k == :mentions or k == :account } ) end


Input: Replies to the last post and tags everyone who was mentioned ( this function respects #NoBot ) [CODESPLIT] def reply_with_mentions ( text , * options ) # build up a string of all accounts mentioned in the post #  unless that account is our own, or the tagged account #  has #NoBot mentions = @mention_data [ :mentions ] . collect do | m | "@#{m.acct}" unless m . acct == @username or no_bot? m . id end . join ' ' reply ( "#{mentions.strip} #{text}" , options ) end


Input: Starts a loop that checks for mentions from the authenticated user account running a supplied block or if a block is not provided on_reply [CODESPLIT] def run_reply @streamer . user do | update | next unless update . kind_of? Mastodon :: Notification and update . type == 'mention' # this makes it so .content calls strip instead  update . status . class . module_eval { alias_method :content , :strip } if @strip_html store_mention_data update . status if block_given? yield ( self , update . status ) else @on_reply . call ( self , update . status ) end end end


Input: Stores select data about a post into a hash for later use [CODESPLIT] def store_mention_data ( mention ) @mention_data = { reply_id : mention . id , visibility : mention . visibility , spoiler : mention . spoiler_text , hide_media : mention . sensitive? , mentions : mention . mentions , account : mention . account } end


Input: Creates the stream client [CODESPLIT] def setup_streaming stream_uri = @client . instance ( ) . attributes [ 'urls' ] [ 'streaming_api' ] . gsub ( / / , 'https' ) @streamer = Mastodon :: Streaming :: Client . new ( base_url : stream_uri , bearer_token : ENV [ 'TOKEN' ] ) end


Input: Adds the command and block into the bot to process later also sets up the command regex [CODESPLIT] def add_command cmd , & block @commands . append cmd unless @commands . include? cmd @cmd_hash [ cmd . to_sym ] = block # build up our regex (this regex should be fine, i guess :shrug:) @cmd_regex = / \A #{ @prefix } #{ @commands . join ( '|' ) } \b /m end


Input: Starts loop to process any mentions running command procs set up earlier [CODESPLIT] def run_commands @streamer . user do | update | next unless update . kind_of? Mastodon :: Notification and update . type == 'mention' # set up the status to strip html, if needed update . status . class . module_eval { alias_method :content , :strip } if @strip_html store_mention_data update . status # strip our username out of the status post = update . status . content . gsub ( / #{ @username } / , '' ) # see if the post matches our regex, running the stored proc if it does matches = @cmd_regex . match ( post ) unless matches . nil? @cmd_hash [ matches [ :cmd ] . to_sym ] . call ( self , matches [ :data ] . strip , update . status ) else if block_given? yield ( self , update . status ) else @not_found . call ( self , update . status ) unless @not_found . nil? end end end end


Input: Parse the service name from a path . Look at the last component of the path ignoring some common names . [CODESPLIT] def parse_service_name ( path ) parts = Pathname . new ( path ) . each_filename . to_a . reverse! # Find the last segment not in common segments, fall back to the last segment. parts . find { | seg | ! COMMON_SEGMENTS [ seg ] } || parts . first end


Input: Create a new TCP Client connection [CODESPLIT] def connect start_time = Time . now retries = 0 close # Number of times to try begin connect_to_server ( servers , policy ) logger . info ( message : "Connected to #{address}" , duration : ( Time . now - start_time ) * 1000 ) if respond_to? ( :logger ) rescue ConnectionFailure , ConnectionTimeout => exception cause = exception . is_a? ( ConnectionTimeout ) ? exception : exception . cause # Retry-able? if self . class . reconnect_on_errors . include? ( cause . class ) && ( retries < connect_retry_count . to_i ) retries += 1 logger . warn "#connect Failed to connect to any of #{servers.join(',')}. Sleeping:#{connect_retry_interval}s. Retry: #{retries}" if respond_to? ( :logger ) sleep ( connect_retry_interval ) retry else message = "#connect Failed to connect to any of #{servers.join(',')} after #{retries} retries. #{exception.class}: #{exception.message}" logger . benchmark_error ( message , exception : exception , duration : ( Time . now - start_time ) ) if respond_to? ( :logger ) raise ConnectionFailure . new ( message , address . to_s , cause ) end end end


Input: Write data to the server [CODESPLIT] def write ( data , timeout = write_timeout ) data = data . to_s if respond_to? ( :logger ) payload = { timeout : timeout } # With trace level also log the sent data payload [ :data ] = data if logger . trace? logger . benchmark_debug ( '#write' , payload : payload ) do payload [ :bytes ] = socket_write ( data , timeout ) end else socket_write ( data , timeout ) end rescue Exception => exc close if close_on_error raise exc end


Input: Returns a response from the server [CODESPLIT] def read ( length , buffer = nil , timeout = read_timeout ) if respond_to? ( :logger ) payload = { bytes : length , timeout : timeout } logger . benchmark_debug ( '#read' , payload : payload ) do data = socket_read ( length , buffer , timeout ) # With trace level also log the received data payload [ :data ] = data if logger . trace? data end else socket_read ( length , buffer , timeout ) end rescue Exception => exc close if close_on_error raise exc end


Input: Write and / or receive data with automatic retry on connection failure [CODESPLIT] def retry_on_connection_failure retries = 0 begin connect if closed? yield ( self ) rescue ConnectionFailure => exception exc_str = exception . cause ? "#{exception.cause.class}: #{exception.cause.message}" : exception . message # Re-raise exceptions that should not be retried if ! self . class . reconnect_on_errors . include? ( exception . cause . class ) logger . info "#retry_on_connection_failure not configured to retry: #{exc_str}" if respond_to? ( :logger ) raise exception elsif retries < @retry_count retries += 1 logger . warn "#retry_on_connection_failure retry #{retries} due to #{exception.class}: #{exception.message}" if respond_to? ( :logger ) connect retry end logger . error "#retry_on_connection_failure Connection failure: #{exception.class}: #{exception.message}. Giving up after #{retries} retries" if respond_to? ( :logger ) raise ConnectionFailure . new ( "After #{retries} retries to host '#{server}': #{exc_str}" , server , exception . cause ) end end


Input: Close the socket only if it is not already closed [CODESPLIT] def close socket . close if socket && ! socket . closed? @socket = nil @address = nil true rescue IOError => exception logger . warn "IOError when attempting to close socket: #{exception.class}: #{exception.message}" if respond_to? ( :logger ) false end


Input: Returns whether the connection to the server is alive [CODESPLIT] def alive? return false if socket . nil? || closed? if IO . select ( [ socket ] , nil , nil , 0 ) ! socket . eof? rescue false else true end rescue IOError false end


Input: Connect to one of the servers in the list per the current policy Returns [ Socket ] the socket connected to or an Exception [CODESPLIT] def connect_to_server ( servers , policy ) # Iterate over each server address until it successfully connects to a host last_exception = nil Policy :: Base . factory ( policy , servers ) . each do | address | begin return connect_to_address ( address ) rescue ConnectionTimeout , ConnectionFailure => exception last_exception = exception end end # Raise Exception once it has failed to connect to any server last_exception ? raise ( last_exception ) : raise ( ArgumentError , "No servers supplied to connect to: #{servers.join(',')}" ) end


Input: Returns [ Socket ] connected to supplied address address [ Net :: TCPClient :: Address ] Host name ip address and port of server to connect to Connect to the server at the supplied address Returns the socket connection [CODESPLIT] def connect_to_address ( address ) socket = if proxy_server :: SOCKSSocket . new ( "#{address.ip_address}:#{address.port}" , proxy_server ) else :: Socket . new ( Socket :: AF_INET , Socket :: SOCK_STREAM , 0 ) end unless buffered socket . sync = true socket . setsockopt ( Socket :: IPPROTO_TCP , Socket :: TCP_NODELAY , 1 ) end socket . setsockopt ( Socket :: SOL_SOCKET , Socket :: SO_KEEPALIVE , true ) if keepalive socket_connect ( socket , address , connect_timeout ) @socket = ssl ? ssl_connect ( socket , address , ssl_handshake_timeout ) : socket @address = address # Invoke user supplied Block every time a new connection has been established @on_connect . call ( self ) if @on_connect end


Input: Connect to server [CODESPLIT] def socket_connect ( socket , address , timeout ) socket_address = Socket . pack_sockaddr_in ( address . port , address . ip_address ) # Timeout of -1 means wait forever for a connection return socket . connect ( socket_address ) if timeout == - 1 deadline = Time . now . utc + timeout begin non_blocking ( socket , deadline ) { socket . connect_nonblock ( socket_address ) } rescue Errno :: EISCONN # Connection was successful. rescue NonBlockingTimeout raise ConnectionTimeout . new ( "Timed out after #{timeout} seconds trying to connect to #{address}" ) rescue SystemCallError , IOError => exception message = "#connect Connection failure connecting to '#{address.to_s}': #{exception.class}: #{exception.message}" logger . error message if respond_to? ( :logger ) raise ConnectionFailure . new ( message , address . to_s , exception ) end end


Input: Write to the socket [CODESPLIT] def socket_write ( data , timeout ) if timeout < 0 socket . write ( data ) else deadline = Time . now . utc + timeout length = data . bytesize total_count = 0 non_blocking ( socket , deadline ) do loop do begin count = socket . write_nonblock ( data ) rescue Errno :: EWOULDBLOCK retry end total_count += count return total_count if total_count >= length data = data . byteslice ( count .. - 1 ) end end end rescue NonBlockingTimeout logger . warn "#write Timeout after #{timeout} seconds" if respond_to? ( :logger ) raise WriteTimeout . new ( "Timed out after #{timeout} seconds trying to write to #{address}" ) rescue SystemCallError , IOError => exception message = "#write Connection failure while writing to '#{address.to_s}': #{exception.class}: #{exception.message}" logger . error message if respond_to? ( :logger ) raise ConnectionFailure . new ( message , address . to_s , exception ) end


Input: Try connecting to a single server Returns the connected socket [CODESPLIT] def ssl_connect ( socket , address , timeout ) ssl_context = OpenSSL :: SSL :: SSLContext . new ssl_context . set_params ( ssl . is_a? ( Hash ) ? ssl : { } ) ssl_socket = OpenSSL :: SSL :: SSLSocket . new ( socket , ssl_context ) ssl_socket . hostname = address . host_name ssl_socket . sync_close = true begin if timeout == - 1 # Timeout of -1 means wait forever for a connection ssl_socket . connect else deadline = Time . now . utc + timeout begin non_blocking ( socket , deadline ) { ssl_socket . connect_nonblock } rescue Errno :: EISCONN # Connection was successful. rescue NonBlockingTimeout raise ConnectionTimeout . new ( "SSL handshake Timed out after #{timeout} seconds trying to connect to #{address.to_s}" ) end end rescue SystemCallError , OpenSSL :: SSL :: SSLError , IOError => exception message = "#connect SSL handshake failure with '#{address.to_s}': #{exception.class}: #{exception.message}" logger . error message if respond_to? ( :logger ) raise ConnectionFailure . new ( message , address . to_s , exception ) end # Verify Peer certificate ssl_verify ( ssl_socket , address ) if ssl_context . verify_mode != OpenSSL :: SSL :: VERIFY_NONE ssl_socket end


Input: Raises Net :: TCPClient :: ConnectionFailure if the peer certificate does not match its hostname [CODESPLIT] def ssl_verify ( ssl_socket , address ) unless OpenSSL :: SSL . verify_certificate_identity ( ssl_socket . peer_cert , address . host_name ) domains = extract_domains_from_cert ( ssl_socket . peer_cert ) ssl_socket . close message = "#connect SSL handshake failed due to a hostname mismatch. Request address was: '#{address.to_s}'" + "  Certificate valid for hostnames: #{domains.map { |d| "'#{d}'"}.join(',')}" logger . error message if respond_to? ( :logger ) raise ConnectionFailure . new ( message , address . to_s ) end end


Input: Party Mode! Join all speakers into a single group . [CODESPLIT] def party_mode new_master = nil return nil unless speakers . length > 1 new_master = find_party_master if new_master . nil? party_over speakers . each do | slave | next if slave . uid == new_master . uid slave . join new_master end rescan @topology end


Input: Look for Sonos devices on the network and return the first IP address found [CODESPLIT] def discover result = SSDP :: Consumer . new . search ( service : 'urn:schemas-upnp-org:device:ZonePlayer:1' , first_only : true , timeout : @timeout , filter : lambda { | r | r [ :params ] [ "ST" ] . match ( / / ) } ) @first_device_ip = result [ :address ] end


Input: Find all of the Sonos devices on the network [CODESPLIT] def topology self . discover unless @first_device_ip return [ ] unless @first_device_ip doc = Nokogiri :: XML ( open ( "http://#{@first_device_ip}:#{Sonos::PORT}/status/topology" ) ) doc . xpath ( '//ZonePlayers/ZonePlayer' ) . map do | node | TopologyNode . new ( node ) end end


Input: Find a single resource by the resource id [CODESPLIT] def find ( id ) response = RestClient . get ( "#{@type.Resource}/#{id}" ) singular_resource = @type . Resource [ 0 ... - 1 ] if response . body [ singular_resource ] . nil? raise ArgumentError , 'Resource not found' end type . new . from_json ( response . body [ singular_resource ] . to_json ) end


Input: Get all resources from a query by paging through data [CODESPLIT] def all list = [ ] page = 1 fetch_all = true if @query . has_key? ( :page ) page = @query [ :page ] fetch_all = false end while true response = RestClient . get ( @type . Resource , @query ) data = response . body [ @type . Resource ] if ! data . empty? data . each { | item | list << @type . new . from_json ( item . to_json ) } if ! fetch_all break else where ( page : page += 1 ) end else break end end return list end


Input: when calling validates it should create the Vali instance already and set [CODESPLIT] def validate ( form ) property = attributes . first # here is the thing: why does AM::UniquenessValidator require a filled-out record to work properly? also, why do we need to set # the class? it would be way easier to pass #validate a hash of attributes and get back an errors hash. # the class for the finder could either be infered from the record or set in the validator instance itself in the call to ::validates. record = form . model_for_property ( property ) record . send ( "#{property}=" , form . send ( property ) ) @klass = record . class # this is usually done in the super-sucky #setup method. super ( record ) . tap do | res | form . errors . add ( property , record . errors . first . last ) if record . errors . present? end end


Input: DISCUSS : can we achieve that somehow via features in build_inline? [CODESPLIT] def property ( * ) super . tap do | dfn | return dfn unless dfn [ :nested ] _name = dfn [ :name ] dfn [ :nested ] . instance_eval do @_name = _name . singularize . camelize # this adds Form::name for AM::Validations and I18N. def name @_name end end end end


Input: moved from reform as not applicable to dry [CODESPLIT] def validates ( * args , & block ) validation ( name : :default , inherit : true ) { validates args , block } end


Input: : nodoc : Updates the attribute in the given XML block to the value provided . [CODESPLIT] def update_xml ( xml , values ) if array? values . each do | value | wrap ( xml , :always_create => true ) . tap do | node | XML . set_attribute ( node , name , value . to_s ) end end else wrap ( xml ) . tap do | xml | XML . set_attribute ( xml , name , values . to_s ) end end end


Input: Updates the text in the given _xml_ block to the _value_ provided . [CODESPLIT] def update_xml ( xml , value ) wrap ( xml ) . tap do | xml | if content? add ( xml , value ) elsif name? xml . name = value elsif array? value . each do | v | add ( XML . add_node ( xml , name ) , v ) end else add ( XML . add_node ( xml , name ) , value ) end end end


Input: Updates the composed XML object in the given XML block to the value provided . [CODESPLIT] def update_xml ( xml , value ) wrap ( xml ) . tap do | xml | value . each_pair do | k , v | node = XML . add_node ( xml , hash . wrapper ) @key . update_xml ( node , k ) @value . update_xml ( node , v ) end end end


Input: Updates the composed XML object in the given XML block to the value provided . [CODESPLIT] def update_xml ( xml , value ) wrap ( xml ) . tap do | xml | params = { :name => name , :namespace => opts . namespace } if array? value . each do | v | XML . add_child ( xml , v . to_xml ( params ) ) end elsif value . is_a? ( ROXML ) XML . add_child ( xml , value . to_xml ( params ) ) else XML . add_node ( xml , name ) . tap do | node | XML . set_content ( node , value . to_xml ) end end end end


Input: : nodoc : Returns an XML object representing this object [CODESPLIT] def to_xml ( params = { } ) params . reverse_merge! ( :name => self . class . tag_name , :namespace => self . class . roxml_namespace ) params [ :namespace ] = nil if [ '*' , 'xmlns' ] . include? ( params [ :namespace ] ) XML . new_node ( [ params [ :namespace ] , params [ :name ] ] . compact . join ( ':' ) ) . tap do | root | refs = ( self . roxml_references . present? ? self . roxml_references : self . class . roxml_attrs . map { | attr | attr . to_ref ( self ) } ) refs . each do | ref | value = ref . to_xml ( self ) unless value . nil? ref . update_xml ( root , value ) end end if params [ :namespaces ] params [ :namespaces ] . each { | prefix , url | root . add_namespace_definition ( prefix , url ) } end end end


Input: Calculates the payment on interest for an investment based on constant - amount periodic payments and a constant interest rate . [CODESPLIT] def ipmt ( rate , per , nper , pv , fv = 0 , end_or_beginning = 0 ) pmt = self . pmt ( rate , nper , pv , fv , end_or_beginning ) fv = self . fv ( rate , ( per - 1 ) , pmt , pv , end_or_beginning ) * rate temp = end_or_beginning == 1 ? fv / ( 1 + rate ) : fv ( per == 1 && end_or_beginning == 1 ) ? 0.0 : temp end


Input: Calculates the number of payment periods for an investment based on constant - amount periodic payments and a constant interest rate . [CODESPLIT] def nper ( rate , pmt , pv , fv = 0 , end_or_beginning = 0 ) z = pmt * ( 1 + rate * end_or_beginning ) / rate temp = Math . log ( ( - fv + z ) / ( pv + z ) ) temp / Math . log ( 1 + rate ) end


Input: Calculates the periodic payment for an annuity investment based on constant - amount periodic payments and a constant interest rate . [CODESPLIT] def pmt ( rate , nper , pv , fv = 0 , end_or_beginning = 0 ) temp = ( 1 + rate ) ** nper fact = ( 1 + rate * end_or_beginning ) * ( temp - 1 ) / rate - ( fv + pv * temp ) / fact end


Input: Calculates the interest rate of an annuity investment based on constant - amount periodic payments and the assumption of a constant interest rate . [CODESPLIT] def rate ( nper , pmt , pv , fv = 0 , end_or_beginning = 0 , rate_guess = 0.10 ) guess = rate_guess tolerancy = 1e-6 close = false begin temp = newton_iter ( guess , nper , pmt , pv , fv , end_or_beginning ) next_guess = ( guess - temp ) . round ( 20 ) diff = ( next_guess - guess ) . abs close = diff < tolerancy guess = next_guess end while ! close next_guess end


Input: Calculates the net present value of an investment based on a series of periodic cash flows and a discount rate . [CODESPLIT] def npv ( discount , cashflows ) total = 0 cashflows . each_with_index do | cashflow , index | total += ( cashflow . to_f / ( 1 + discount . to_f ) ** ( index + 1 ) ) end total end


Input: Calculates the internal rate of return on an investment based on a series of periodic cash flows . [CODESPLIT] def irr ( values ) func = Helpers :: IrrHelper . new ( values ) guess = [ func . eps ] nlsolve ( func , guess ) guess [ 0 ] end


Input: This method was borrowed from the NumPy rate formula which was generated by Sage [CODESPLIT] def newton_iter ( r , n , p , x , y , w ) t1 = ( r + 1 ) ** n t2 = ( r + 1 ) ** ( n - 1 ) ( ( y + t1 x + p ( t1 - 1 ) * ( r w + 1 ) / r ) / ( n t2 x - p ( t1 - 1 ) * ( r w + 1 ) / ( r ** 2 ) + n p t2 ( r w + 1 ) / r + p ( t1 - 1 ) * w / r ) ) end


Input: Simple mean formula : sum elements and / by length [CODESPLIT] def mean ( numbers_ary ) numbers_ary . inject ( 0 ) { | sum , i | sum + i } . to_f / numbers_ary . size end


Input: Median formula @param numbers_ary [ array ] an array of numbers [CODESPLIT] def median ( numbers_ary ) numbers_ary . sort! len = numbers_ary . length ( numbers_ary [ ( len - 1 ) / 2 ] + numbers_ary [ len / 2 ] ) / 2.0 end


Input: Helpers and filters . [CODESPLIT] def event_summary ( trim_at = 100 ) summary = @event [ 'check' ] [ 'notification' ] || @event [ 'check' ] [ 'description' ] if summary . nil? source = @event [ 'check' ] [ 'source' ] || @event [ 'client' ] [ 'name' ] event_context = [ source , @event [ 'check' ] [ 'name' ] ] . join ( '/' ) output = @event [ 'check' ] [ 'output' ] . chomp output = output . length > trim_at ? output [ 0 .. trim_at ] + '...' : output summary = [ event_context , output ] . join ( ' : ' ) end summary end


Input: geckoboard - ruby gem s dataset . find_or_create id attribute e . g . peoplefinder - staging . total_profiles_report [CODESPLIT] def id Rails . application . class . parent_name . underscore + '-' + ( ENV [ 'ENV' ] || Rails . env ) . downcase + '.' + self . class . name . demodulize . underscore end


Input: = begin # revisit this def apply io if truncate? io . truncate 0 elsif append? io . seek IO :: SEEK_END 0 end end = end [CODESPLIT] def inspect names = NAMES . map { | name | name if ( flags & IOMode . const_get ( name . upcase ) ) != 0 } names . unshift 'rdonly' if ( flags & 0x3 ) == 0 "#<#{self.class} #{names.compact * '|'}>" end


Input: tries to get a dirent for path . return nil if it doesn t exist ( change it ) [CODESPLIT] def dirent_from_path path dirent = @root path = file . expand_path ( path ) . split ( '/' ) until path . empty? part = path . shift next if part . empty? return nil if dirent . file? return nil unless dirent = dirent / part end dirent end


Input: load document from file . [CODESPLIT] def load # we always read 512 for the header block. if the block size ends up being different, # what happens to the 109 fat entries. are there more/less entries? @io . rewind header_block = @io . read 512 @header = Header . new header_block # create an empty bbat. @bbat = AllocationTable :: Big . new self bbat_chain = header_block [ Header :: SIZE .. - 1 ] . unpack 'V*' mbat_block = @header . mbat_start @header . num_mbat . times do blocks = @bbat . read ( [ mbat_block ] ) . unpack 'V*' mbat_block = blocks . pop bbat_chain += blocks end # am i using num_bat in the right way? @bbat . load @bbat . read ( bbat_chain [ 0 , @header . num_bat ] ) # get block chain for directories, read it, then split it into chunks and load the # directory entries. semantics changed - used to cut at first dir where dir.type == 0 @dirents = @bbat . read ( @header . dirent_start ) . to_enum ( :each_chunk , Dirent :: SIZE ) . map { | str | Dirent . new self , str } # now reorder from flat into a tree # links are stored in some kind of balanced binary tree # check that everything is visited at least, and at most once # similarly with the blocks of the file. # was thinking of moving this to Dirent.to_tree instead. class << @dirents def to_tree idx = 0 return [ ] if idx == Dirent :: EOT d = self [ idx ] to_tree ( d . child ) . each { | child | d << child } raise FormatError , "directory #{d.inspect} used twice" if d . idx d . idx = idx to_tree ( d . prev ) + [ d ] + to_tree ( d . next ) end end @root = @dirents . to_tree . first @dirents . reject! { | d | d . type_id == 0 } # silence this warning by default, its not really important (issue #5). # fairly common one appears to be "R" (from office OS X?) which smells # like some kind of UTF16 snafu, but scottwillson also has had some kanji... #Log.warn "root name was #{@root.name.inspect}" unless @root.name == 'Root Entry' unused = @dirents . reject ( :idx ) . length Log . warn "#{unused} unused directories" if unused > 0 # FIXME i don't currently use @header.num_sbat which i should # hmm. nor do i write it. it means what exactly again? # which mode to use here? @sb_file = RangesIOResizeable . new @bbat , :first_block => @root . first_block , :size => @root . size @sbat = AllocationTable :: Small . new self @sbat . load @bbat . read ( @header . sbat_start ) end


Input: the flush method is the main save method . all file contents are always written directly to the file by the RangesIO objects all this method does is write out all the file meta data - dirents allocation tables file header etc . [CODESPLIT] def flush # update root dirent, and flatten dirent tree @root . name = 'Root Entry' @root . first_block = @sb_file . first_block @root . size = @sb_file . size @dirents = @root . flatten # serialize the dirents using the bbat RangesIOResizeable . open @bbat , 'w' , :first_block => @header . dirent_start do | io | io . write @dirents . map { | dirent | dirent . to_s } . join padding = ( io . size / @bbat . block_size . to_f ) . ceil * @bbat . block_size - io . size io . write 0 . chr * padding @header . dirent_start = io . first_block end # serialize the sbat # perhaps the blocks used by the sbat should be marked with BAT? RangesIOResizeable . open @bbat , 'w' , :first_block => @header . sbat_start do | io | io . write @sbat . to_s @header . sbat_start = io . first_block @header . num_sbat = @bbat . chain ( @header . sbat_start ) . length end # create RangesIOResizeable hooked up to the bbat. use that to claim bbat blocks using # truncate. then when its time to write, convert that chain and some chunk of blocks at # the end, into META_BAT blocks. write out the chain, and those meta bat blocks, and its # done. # this is perhaps not good, as we reclaim all bat blocks here, which # may include the sbat we just wrote. FIXME @bbat . map! do | b | b == AllocationTable :: BAT || b == AllocationTable :: META_BAT ? AllocationTable :: AVAIL : b end # currently we use a loop. this could be better, but basically, # the act of writing out the bat, itself requires blocks which get # recorded in the bat. # # i'm sure that there'd be some simpler closed form solution to this. solve # recursive func: # #   num_mbat_blocks = ceil(max((mbat_len - 109) * 4 / block_size, 0)) #   bbat_len = initial_bbat_len + num_mbat_blocks #   mbat_len = ceil(bbat_len * 4 / block_size) # # the actual bbat allocation table is itself stored throughout the file, and that chain # is stored in the initial blocks, and the mbat blocks. num_mbat_blocks = 0 io = RangesIOResizeable . new @bbat , 'w' , :first_block => AllocationTable :: EOC # truncate now, so that we can simplify size calcs - the mbat blocks will be appended in a # contiguous chunk at the end. # hmmm, i think this truncate should be matched with a truncate of the underlying io. if you # delete a lot of stuff, and free up trailing blocks, the file size never shrinks. this can # be fixed easily, add an io truncate @bbat . truncate! @io . truncate @bbat . block_size * ( @bbat . length + 1 ) while true # get total bbat size. equivalent to @bbat.to_s.length, but for the factoring in of # the mbat blocks. we can't just add the mbat blocks directly to the bbat, as as this iteration # progresses, more blocks may be needed for the bat itself (if there are no more gaps), and the # mbat must remain contiguous. bbat_data_len = ( ( @bbat . length + num_mbat_blocks ) * 4 / @bbat . block_size . to_f ) . ceil * @bbat . block_size # now storing the excess mbat blocks also increases the size of the bbat: new_num_mbat_blocks = ( [ bbat_data_len / @bbat . block_size - 109 , 0 ] . max * 4 / ( @bbat . block_size . to_f - 4 ) ) . ceil if new_num_mbat_blocks != num_mbat_blocks # need more space for the mbat. num_mbat_blocks = new_num_mbat_blocks elsif io . size != bbat_data_len # need more space for the bat # this may grow the bbat, depending on existing available blocks io . truncate bbat_data_len else break end end # now extract the info we want: ranges = io . ranges bbat_chain = @bbat . chain io . first_block io . close bbat_chain . each { | b | @bbat [ b ] = AllocationTable :: BAT } # tack on the mbat stuff @header . num_bat = bbat_chain . length mbat_blocks = ( 0 ... num_mbat_blocks ) . map do block = @bbat . free_block @bbat [ block ] = AllocationTable :: META_BAT block end @header . mbat_start = mbat_blocks . first || AllocationTable :: EOC # now finally write the bbat, using a not resizable io. # the mode here will be 'r', which allows write atm.  RangesIO . open ( @io , :ranges => ranges ) { | f | f . write @bbat . to_s } # this is the mbat. pad it out. bbat_chain += [ AllocationTable :: AVAIL ] * [ 109 - bbat_chain . length , 0 ] . max @header . num_mbat = num_mbat_blocks if num_mbat_blocks != 0 # write out the mbat blocks now. first of all, where are they going to be? mbat_data = bbat_chain [ 109 .. - 1 ] # expand the mbat_data to include the linked list forward pointers. mbat_data = mbat_data . to_enum ( :each_slice , @bbat . block_size / 4 - 1 ) . to_a . zip ( mbat_blocks [ 1 .. - 1 ] + [ nil ] ) . map { | a , b | b ? a + [ b ] : a } # pad out the last one. mbat_data . last . push ( ( [ AllocationTable :: AVAIL ] * ( @bbat . block_size / 4 - mbat_data . last . length ) ) ) RangesIO . open @io , :ranges => @bbat . ranges ( mbat_blocks ) do | f | f . write mbat_data . flatten . pack ( 'V*' ) end end # now seek back and write the header out @io . seek 0 @io . write @header . to_s + bbat_chain [ 0 , 109 ] . pack ( 'V*' ) @io . flush end


Input: could be useful with mis - behaving ole documents . or to just clean them up . [CODESPLIT] def repack temp = :file case temp when :file Tempfile . open 'ole-repack' do | io | io . binmode repack_using_io io end when :mem ; StringIO . open ( '' . dup , method ( :repack_using_io ) ) else raise ArgumentError , "unknown temp backing #{temp.inspect}" end end


Input: https : // www . snip2code . com / Snippet / 71914 / Parse - link - headers - from - Github - API - in - Ru [CODESPLIT] def parse_link_header ( header , params = { } ) links = Hash . new return links unless header parts = header . split ( ',' ) parts . each do | part , index | section = part . split ( ';' ) url = section [ 0 ] [ / / , 1 ] name = section [ 1 ] [ / / , 1 ] . to_sym links [ name ] = url end return links end


Input: try to load an embedded object ; call out to the API if not [CODESPLIT] def load_relation ( relationship , position = nil ) if objects = @resource . dig ( "_embedded" , relationship ) location = position ? objects [ position ] : objects begin WpApiClient :: Collection . new ( location ) rescue WpApiClient :: ErrorResponse load_from_links ( relationship , position ) end else load_from_links ( relationship , position ) end end


Input: requests come in as url / params pairs [CODESPLIT] def get_concurrently ( requests ) responses = [ ] @conn . in_parallel do requests . map do | r | responses << get ( r [ 0 ] , r [ 1 ] ) end end responses end


Input: Take the API response and figure out what it is [CODESPLIT] def native_representation_of ( response_body ) # Do we have a collection of objects? if response_body . is_a? Array WpApiClient :: Collection . new ( response_body , @headers ) else WpApiClient :: Entities :: Base . build ( response_body ) end end


Input: call contract functions by rpc call method [CODESPLIT] def call_func ( method : , params : [ ] , tx : { } ) # rubocop:disable Naming/UncommunicativeMethodParamName data , output_types = function_data_with_ot ( method , params ) resp = @rpc . call_rpc ( :call , params : [ tx . merge ( data : data , to : address ) , "latest" ] ) result = resp [ "result" ] data = [ Utils . remove_hex_prefix ( result ) ] . pack ( "H*" ) return if data . nil? re = decode_abi output_types , data re . length == 1 ? re . first : re end


Input: call contract functions by sendRawTransaction [CODESPLIT] def send_func ( tx : , private_key : , method : , params : [ ] ) # rubocop:disable Naming/UncommunicativeMethodParamName data , _output_types = function_data_with_ot ( method , params ) transaction = if tx . is_a? ( Hash ) Transaction . from_hash ( tx ) else tx end transaction . data = data resp = @rpc . send_transaction ( transaction , private_key ) resp &. dig ( "result" ) end


Input: parse url to host port and scheme [CODESPLIT] def parse_url uri = URI . parse ( @url ) @host = uri . host @port = uri . port @scheme = uri . scheme end


Input: wrapper Web3 :: Eth abi encoder for encoded data [CODESPLIT] def function_data_with_ot ( method_name , * params ) web3 = Web3 :: Eth :: Rpc . new host : @host , port : @port , connect_options : { use_ssl : https? } contract = web3 . eth . contract ( abi ) . at ( address ) contract . function_data ( method_name , params ) end


Input: wrapper for call rpc method [CODESPLIT] def call_rpc ( method , jsonrpc : DEFAULT_JSONRPC , params : DEFAULT_PARAMS , id : DEFAULT_ID ) conn . post ( "/" , rpc_params ( method , jsonrpc : jsonrpc , params : params , id : id ) ) end


Input: wrapper for rpc params [CODESPLIT] def rpc_params ( method , jsonrpc : DEFAULT_JSONRPC , params : DEFAULT_PARAMS , id : DEFAULT_ID ) { jsonrpc : jsonrpc , id : id , method : method , params : params } . to_json end


Input: wrapper faraday object with CITA URL and Content - Type [CODESPLIT] def conn Faraday . new ( url : url ) do | faraday | faraday . headers [ "Content-Type" ] = "application/json" faraday . request :url_encoded # form-encode POST params faraday . adapter Faraday . default_adapter # make requests with Net::HTTP end end


Input: easy to transfer tokens [CODESPLIT] def transfer ( to : , private_key : , value : , quota : 30_000 ) valid_until_block = block_number [ "result" ] . hex + 88 meta_data = get_meta_data ( "latest" ) [ "result" ] version = meta_data [ "version" ] chain_id = if version . zero? meta_data [ "chainId" ] elsif version == 1 meta_data [ "chainIdV1" ] end transaction = Transaction . new ( nonce : Utils . nonce , valid_until_block : valid_until_block , chain_id : chain_id , to : to , value : value , quota : quota , version : version ) send_transaction ( transaction , private_key ) end


Input: Replace the current storage with the given one . [CODESPLIT] def replace ( new ) if String === new @data . replace ( JSON . parse ( new ) ) else @data . replace ( new ) end end


Input: Call the block between a [ #reload ] and [ #save ] . [CODESPLIT] def commit ( & block ) autosave = @autosave @autosave = false result = nil reload begin result = block . call save rescue reload raise ensure @autosave = autosave end result end


Input: Convert the storage to JSON . [CODESPLIT] def to_json io = StringIO . new ( "{" ) io << JSON . create_id . to_json << ":" << self . class . name . to_json << "," @data . each { | key , value | io << key . to_json . to_s << ":" << value . to_json << "," } io . seek ( - 1 , IO :: SEEK_CUR ) io << "}" io . string end


Input: Time the given block with the given label . [CODESPLIT] def time ( label , & block ) raise ArgumentError , "no block given" unless block ` ` begin if block . arity == 0 instance_exec ( block ) else block . call ( self ) end ensure ` ` end end


Input: Group the given block . [CODESPLIT] def group ( * args , & block ) raise ArgumentError , "no block given" unless block ` ` begin if block . arity == 0 instance_exec ( block ) else block . call ( self ) end ensure ` ` end end


Input: Group the given block but collapse it . [CODESPLIT] def group! ( * args , & block ) return unless block_given? ` ` begin if block . arity == 0 instance_exec ( block ) else block . call ( self ) end ensure ` ` end end


Input: Create a new { Cookies } wrapper . [CODESPLIT] def [] ( name ) matches = ` ` . scan ( / #{ Regexp . escape ( name . encode_uri_component ) } / ) return if matches . empty? result = matches . flatten . map { | value | JSON . parse ( value . decode_uri_component ) } result . length == 1 ? result . first : result end


Input: Set a cookie . [CODESPLIT] def []= ( name , value , options = { } ) string = value . is_a? ( String ) ? value : JSON . dump ( value ) encoded_value = encode ( name , string , @options . merge ( options ) ) ` #{ encoded_value } ` end


Input: rubocop : disable Metrics / MethodLength rubocop : disable Metrics / CyclomaticComplexity rubocop : disable Metrics / PerceivedComplexity [CODESPLIT] def scan raise IOError , "There's a invalid or missing file" if @file . nil? unmarked_group_found = false multiple_marked_found = false result = Hash . new { | hash , key | hash [ key ] = [ ] } result . tap do | effect | begin Timeout . timeout ( @config . scan_timeout ) do detect_groups unless @groups_detected end rescue Timeout :: Error raise_watcher :timed_out_watcher return effect end @groups . each_pair do | _label , group | marks = Hash . new { | hash , key | hash [ key ] = [ ] } group . marks . each_pair do | line , value | value . each do | mark | marks [ line ] << mark . value if mark . marked? ( config . intensity_percentual ) && mark . value end multiple_marked_found = true if marks [ line ] . size > 1 unmarked_group_found = true if marks [ line ] . empty? end effect [ group . label . to_sym ] = marks end raise_watcher :scan_unmarked_watcher , effect if unmarked_group_found raise_watcher :scan_multiple_marked_watcher , effect if multiple_marked_found if unmarked_group_found || multiple_marked_found raise_watcher :scan_mark_watcher , effect , unmarked_group_found , multiple_marked_found end end end


Input: rubocop : enable Metrics / MethodLength rubocop : enable Metrics / CyclomaticComplexity rubocop : enable Metrics / PerceivedComplexity rubocop : disable Metrics / MethodLength rubocop : disable Metrics / CyclomaticComplexity rubocop : disable Metrics / PerceivedComplexity rubocop : disable Metrics / BlockNesting [CODESPLIT] def detect_groups if @config . scan_mode == :grid scanner = FloodScan . new ( @file . dup ) @groups . each_pair do | _label , group | group_center = group . expected_coordinates . center x = group_center [ :x ] y = group_center [ :y ] width = group . expected_coordinates . width height = group . expected_coordinates . height block = scanner . scan ( Magick :: Point . new ( x , y ) , width , height ) if ! block . empty? group . coordinates = Coordinates . new ( block ) marks_blocks = find_marks_grid ( group ) marks_blocks . each do | mark | mark_width = ImageUtils . calc_width ( mark [ :x1 ] , mark [ :x2 ] ) mark_height = ImageUtils . calc_height ( mark [ :y1 ] , mark [ :y2 ] ) mark_file = @original_file . crop ( mark [ :x1 ] , mark [ :y1 ] , mark_width , mark_height ) o_mark = Mark . new group : group , coordinates : coordinate ( mark ) , image_str : ImageUtils . export_file_to_str ( mark_file ) , line : mark [ :line ] group . marks [ mark [ :line ] ] << o_mark end else @groups_not_detected << group . label end end else file_str = ImageUtils . export_file_to_str ( @file ) original_file_str = ImageUtils . export_file_to_str ( @original_file ) incorrect_bubble_line_found = Hash . new { | hash , key | hash [ key ] = [ ] } bubbles_adjusted = [ ] incorrect_expected_lines = false @groups . each_pair do | _label , group | next unless group . expected_coordinates . any? line = 0 group_center = group . expected_coordinates . center block = find_block_marks ( file_str , group_center [ :x ] , group_center [ :y ] , group ) next unless block group . coordinates = Coordinates . new ( block ) marks_blocks = find_marks ( original_file_str , group ) marks_blocks . sort! { | a , b | a [ :y1 ] <=> b [ :y1 ] } mark_ant = nil marks_blocks . each do | mark | mark_width = ImageUtils . calc_width ( mark [ :x1 ] , mark [ :x2 ] ) mark_height = ImageUtils . calc_height ( mark [ :y1 ] , mark [ :y2 ] ) next unless mark_width >= group . mark_width_with_down_tolerance && mark_height >= group . mark_height_with_down_tolerance mark_positions = mark [ :y1 ] - 10 .. mark [ :y1 ] + 10 line += 1 unless mark_ant && mark_positions . include? ( mark_ant [ :y1 ] ) mark [ :line ] = line mark_ant = mark end marks_blocks . delete_if { | m | m [ :line ] . nil? } marks_blocks . sort_by! { | a | [ a [ :line ] , a [ :x1 ] ] } mark_ant = nil marks_blocks . each do | mark | if mark_ant && mark_ant [ :line ] == mark [ :line ] mark_ant_center = ImageUtils . image_center ( mark_ant ) mark_center = ImageUtils . image_center ( mark ) if ( mark_ant_center [ :x ] - mark_center [ :x ] ) . abs < 10 mark [ :conflict ] = true mark [ :conflicting_mark ] = mark_ant else mark_ant = mark end else mark_ant = mark end end marks_blocks . delete_if { | m | m [ :conflict ] } first_position = 0 elements_position_count = 0 marks_blocks . map { | m | m [ :line ] } . each do | dash | marks = marks_blocks . select { | m | m [ :line ] == dash } if marks . count == group . marks_options . count first_position += marks . first [ :x1 ] elements_position_count += 1 end end if elements_position_count . positive? first_position /= elements_position_count distance = group . distance_between_marks * ( group . marks_options . count - 1 ) last_position = first_position + distance marks_blocks . delete_if do | mark | mark [ :x1 ] < first_position - 10 || mark [ :x1 ] > last_position + 10 end marks_blocks . map { | m | m [ :line ] } . each do | dash | loop do reprocess = false marks = marks_blocks . select { | m | m [ :line ] == dash } marks . each_with_index do | current_mark , index | if index . zero? first_mark_position = first_position - 5 .. first_position + 5 unless first_mark_position . include? ( current_mark [ :x1 ] ) new_mark = { x1 : first_position , x2 : first_position + group . mark_width , y1 : current_mark [ :y1 ] , y2 : current_mark [ :y1 ] + group . mark_height , line : dash } marks_blocks << new_mark marks_blocks . sort_by! { | a | [ a [ :line ] , a [ :x1 ] ] } bubbles_adjusted << new_mark reprocess = true break end end next_mark = marks [ index + 1 ] distance = 0 distance = next_mark [ :x1 ] - current_mark [ :x1 ] if next_mark next unless distance > group . distance_between_marks + 10 || next_mark . nil? && index + 1 < group . marks_options . count new_x1 = current_mark [ :x1 ] + group . distance_between_marks new_mark = { x1 : new_x1 , x2 : new_x1 + group . mark_width , y1 : current_mark [ :y1 ] , y2 : current_mark [ :y1 ] + group . mark_height , line : dash } marks_blocks << new_mark marks_blocks . sort_by! { | a | [ a [ :line ] , a [ :x1 ] ] } bubbles_adjusted << new_mark reprocess = true break end break unless reprocess end end end marks_blocks . each do | mark | mark_width = ImageUtils . calc_width ( mark [ :x1 ] , mark [ :x2 ] ) mark_height = ImageUtils . calc_height ( mark [ :y1 ] , mark [ :y2 ] ) mark_file = @original_file . crop ( mark [ :x1 ] , mark [ :y1 ] , mark_width , mark_height ) o_mark = Mark . new group : group , coordinates : coordinate ( mark ) , image_str : ImageUtils . export_file_to_str ( mark_file ) , line : mark [ :line ] group . marks [ mark [ :line ] ] << o_mark if mark [ :line ] <= group . expected_lines end incorrect_expected_lines = group . incorrect_expected_lines group . marks . each_pair do | dash , marks | if marks . count != group . marks_options . count incorrect_bubble_line_found [ group . label . to_sym ] << dash end end end @groups_detected = true if incorrect_bubble_line_found . any? || bubbles_adjusted . any? || incorrect_expected_lines raise_watcher :incorrect_group_watcher , incorrect_expected_lines , incorrect_bubble_line_found , bubbles_adjusted . flatten end end end


Input: rubocop : enable Metrics / MethodLength rubocop : enable Metrics / CyclomaticComplexity rubocop : enable Metrics / PerceivedComplexity rubocop : enable Metrics / BlockNesting rubocop : disable Metrics / CyclomaticComplexity rubocop : disable Metrics / MethodLength rubocop : disable Metrics / PerceivedComplexity rubocop : disable Metrics / BlockNesting [CODESPLIT] def find_block_marks ( image , x , y , group ) expected_coordinates = group . expected_coordinates found_blocks = [ ] expected_width = expected_coordinates . width expected_height = expected_coordinates . height block = nil while x <= expected_coordinates . x2 && y <= expected_coordinates . y2 if image [ y ] && image [ y ] [ x ] == ' ' block = find_in_blocks ( found_blocks , x , y ) unless block block = find_block ( image , x , y ) found_blocks << block block [ :width ] = ImageUtils . calc_width ( block [ :x1 ] , block [ :x2 ] ) block [ :height ] = ImageUtils . calc_height ( block [ :y1 ] , block [ :y2 ] ) if @config . scan_mode == :grid unless block [ :width ] <= ( expected_width + group . block_width_tolerance ) && block [ :width ] >= ( expected_width - group . block_width_tolerance ) if block [ :width ] > expected_width + group . block_width_tolerance ajust_width = block [ :width ] - expected_width if @config . auto_ajust_block_width == :left block [ :x2 ] = ( block [ :x2 ] - ajust_width ) + @config . edge_level block [ :width ] = expected_width + @config . edge_level elsif @config . auto_ajust_block_width == :right block [ :x1 ] = ( block [ :x1 ] + ajust_width ) - @config . edge_level block [ :width ] = expected_width + @config . edge_level end else block [ :width ] = 0 end end unless block [ :height ] <= ( expected_height + group . block_height_tolerance ) && block [ :height ] >= ( expected_height - group . block_height_tolerance ) if block [ :height ] > expected_height + group . block_height_tolerance ajust_width = block [ :height ] - expected_height if @config . auto_ajust_block_height == :top block [ :y2 ] = ( block [ :y2 ] - ajust_height ) + @config . edge_level block [ :height ] = expected_height + @config . edge_level elsif @config . auto_ajust_block_height == :bottom block [ :y1 ] = ( block [ :y1 ] + ajust_height ) - @config . edge_level block [ :height ] = expected_height + @config . edge_level end else block [ :height ] = 0 end end end block_width_with_tolerance = block [ :width ] + group . block_width_tolerance block_height_with_tolerance = block [ :height ] + group . block_height_tolerance return block if block_width_with_tolerance >= expected_width && block_height_with_tolerance >= expected_height end end x += 1 y += 1 end end


Input: rubocop : enable Metrics / CyclomaticComplexity rubocop : enable Metrics / MethodLength rubocop : enable Metrics / PerceivedComplexity rubocop : enable Metrics / BlockNesting [CODESPLIT] def find_marks_grid ( group ) block = group . coordinates blocks = [ ] blocks . tap do | chunks | lines = group . expected_lines columns = group . marks_options . size distance_lin = group . mark_height distance_col = group . mark_width lines . times do | lin | columns . times do | col | chunks << { x1 : block . x1 + ( col * distance_col ) , y1 : block . y1 + ( lin * distance_lin ) , x2 : block . x1 + ( col * distance_col ) + distance_col , y2 : block . y1 + ( lin * distance_lin ) + distance_lin , line : lin + 1 } end end end end


Input: rubocop : disable Metrics / CyclomaticComplexity rubocop : disable Metrics / MethodLength rubocop : disable Metrics / PerceivedComplexity rubocop : disable Metrics / BlockNesting [CODESPLIT] def find_marks ( image , group ) block = group . coordinates y = block . y1 blocks = [ ] blocks . tap do | chunks | while y < block . y2 x = block . x1 while x < block . x2 if image [ y ] [ x ] == ' ' x += 1 next end result = find_in_blocks ( chunks , x , y ) unless result result = find_block ( image , x , y , '.' , block ) mark_width = ImageUtils . calc_width ( result . values_at ( :x1 , :x2 ) ) mark_height = ImageUtils . calc_height ( result . values_at ( :y1 , :y2 ) ) if mark_width > group . mark_width_with_up_tolerance distance_x1 = x - result [ :x1 ] distance_x2 = result [ :x2 ] - x if distance_x1 <= distance_x2 result [ :x2 ] = result [ :x1 ] + group . mark_width else result [ :x1 ] = result [ :x2 ] - group . mark_width end end if mark_height > group . mark_height_with_up_tolerance distance_y1 = y - result [ :y1 ] distance_y2 = result [ :y2 ] - y if distance_y1 <= distance_y2 result [ :y2 ] = result [ :y1 ] + group . mark_height else result [ :y1 ] = result [ :y2 ] - group . mark_height end end chunks << result unless chunks . any? { | b | b == result } end x += 1 end y += 1 end end end


Input: rubocop : enable Metrics / CyclomaticComplexity rubocop : enable Metrics / MethodLength rubocop : enable Metrics / PerceivedComplexity rubocop : enable Metrics / BlockNesting [CODESPLIT] def flag_position ( position ) raise IOError , "There's a invalid or missing file" if @file . nil? files = @original_file . dup files . tap do | file | add_mark ( file , position ) end end


Input: rubocop : disable Metrics / MethodLength [CODESPLIT] def flag_all_marks raise IOError , "There's a invalid or missing file" if @file . nil? @original_file . dup . tap do | file | begin Timeout . timeout ( @config . scan_timeout ) do detect_groups unless @groups_detected end rescue Timeout :: Error raise_watcher :timed_out_watcher return file end @groups . each_pair do | _label , group | dr = Magick :: Draw . new dr . stroke_width = 5 dr . stroke ( COLORS [ 3 ] ) dr . line ( group . expected_coordinates . values_at ( :x1 , :y1 , :x2 , :y1 ) ) dr . line ( group . expected_coordinates . values_at ( :x2 , :y1 , :x2 , :y2 ) ) dr . line ( group . expected_coordinates . values_at ( :x2 , :y2 , :x1 , :y2 ) ) dr . line ( group . expected_coordinates . values_at ( :x1 , :y2 , :x1 , :y1 ) ) dr . draw ( file ) next unless group . coordinates dr = Magick :: Draw . new dr . stroke_width = 5 dr . stroke ( COLORS [ 5 ] ) dr . line ( group . coordinates . values_at ( :x1 , :y1 , :x2 , :y1 ) ) dr . line ( group . coordinates . values_at ( :x2 , :y1 , :x2 , :y2 ) ) dr . line ( group . coordinates . values_at ( :x2 , :y2 , :x1 , :y2 ) ) dr . line ( group . coordinates . values_at ( :x1 , :y2 , :x1 , :y1 ) ) dr . draw ( file ) end end end


Input: rubocop : disable Metrics / MethodLength [CODESPLIT] def add_mark ( file , position , mark = nil ) dr = Magick :: Draw . new if @config . scan_mode == :grid x = position [ :x ] - 9 y = position [ :y ] + 5 intensity = mark . intensity ? mark . intensity . ceil . to_s : '+' dr . annotate ( file , 0 , 0 , x , y , intensity ) do self . pointsize = 15 self . fill = COLORS [ 2 ] end dr = Magick :: Draw . new dr . stroke_width = 2 dr . stroke ( COLORS [ 1 ] ) dr . line ( mark . coordinates . values_at ( :x1 , :y1 , :x2 , :y1 ) ) dr . line ( mark . coordinates . values_at ( :x2 , :y1 , :x2 , :y2 ) ) dr . line ( mark . coordinates . values_at ( :x2 , :y2 , :x1 , :y2 ) ) dr . line ( mark . coordinates . values_at ( :x1 , :y2 , :x1 , :y1 ) ) else dr . annotate ( file , 0 , 0 , position [ :x ] - 9 , position [ :y ] + 11 , '+' ) do self . pointsize = 30 self . fill = '#900000' end dr = Magick :: Draw . new dr . fill = '#FF0000' dr . point ( position [ :x ] , position [ :y ] ) dr . point ( position [ :x ] , position [ :y ] + 1 ) dr . point ( position [ :x ] + 1 , position [ :y ] ) dr . point ( position [ :x ] + 1 , position [ :y ] + 1 ) end dr . draw ( file ) end


Input: Internal : The Savon client to send SOAP requests with . [CODESPLIT] def client @client ||= Savon . client ( wsdl ) do | wsdl | wsdl . endpoint = endpoint end . tap do | client | client . config . soap_header = soap_headers client . http . auth . ssl . verify_mode = :none end end


Input: Internal : Performs a SOAP request . If the session is invalid it will attempt to reauthenticate by called the reauthentication handler if present . [CODESPLIT] def request ( * args , & block ) authenticate! unless session_id retries = authentication_retries begin perform_request ( args , block ) rescue Savon :: SOAP :: Fault => e if e . message =~ / / && authentication_handler && retries > 0 authenticate! retries -= 1 retry end raise end end


Input: Internal Calls the authentication handler which should set [CODESPLIT] def authenticate! options = authentication_handler . call ( self , @options ) @options . merge! ( options ) client . config . soap_header = soap_headers end


Input: Public : Unzips the returned zip file to the location . [CODESPLIT] def extract_to ( destination ) return on_complete { | job | job . extract_to ( destination ) } unless started? with_tmp_zip_file do | file | unzip ( file , destination ) end self end


Input: Internal : Unzips source to destination . [CODESPLIT] def unzip ( source , destination ) Zip :: File . open ( source ) do | zip | zip . each do | f | path = File . join ( destination , f . name ) FileUtils . mkdir_p ( File . dirname ( path ) ) zip . extract ( f , path ) { true } end end end


Input: Internal : Writes the zip file content to a temporary location so it can be extracted . [CODESPLIT] def with_tmp_zip_file file = Tempfile . new ( 'retrieve' ) begin file . binmode file . write ( zip_file ) file . rewind yield file ensure file . close file . unlink end end


Input: Internal : Starts a heart beat in a thread which polls the job status until it has completed or timed out . [CODESPLIT] def start_heart_beat if threading? Thread . abort_on_exception = true @heart_beat ||= Thread . new run_loop else run_loop . call end end


Input: Internal : Starts the run loop and blocks until the job has completed or failed . [CODESPLIT] def run_loop proc { delay = DELAY_START loop do @status = nil sleep ( delay = delay * DELAY_MULTIPLIER ) trigger :on_poll if completed? || error? trigger callback_type Thread . stop if threading? break end end } end


Input: Public : Perform the login request . [CODESPLIT] def login response = client . request ( :login ) do soap . body = { :username => username , :password => password } end response . body [ :login_response ] [ :result ] end


Input: Internal : Savon client . [CODESPLIT] def client @client ||= Savon . client ( Metaforce . configuration . partner_wsdl ) do | wsdl | wsdl . endpoint = Metaforce . configuration . endpoint end . tap { | client | client . http . auth . ssl . verify_mode = :none } end


Input: Public : Initializes a new instance of a manifest ( package . xml ) file . [CODESPLIT] def to_xml xml_builder = Nokogiri :: XML :: Builder . new do | xml | xml . Package ( 'xmlns' => 'http://soap.sforce.com/2006/04/metadata' ) { self . each do | key , members | xml . types { members . each do | member | xml . members member end xml . name key . to_s . camelize } end xml . version Metaforce . configuration . api_version } end xml_builder . to_xml end


Input: Public : Parses a package . xml file [CODESPLIT] def parse ( file ) document = Nokogiri :: XML ( file ) . remove_namespaces! document . xpath ( '//types' ) . each do | type | name = type . xpath ( 'name' ) . first . content key = name . underscore . to_sym type . xpath ( 'members' ) . each do | member | self [ key ] << member . content end end self end


Input: Internal : Creates a zip file with the contents of the directory . [CODESPLIT] def zip_file path = Dir . mktmpdir File . join ( path , 'deploy.zip' ) . tap do | path | Zip :: File . open ( path , Zip :: File :: CREATE ) do | zip | Dir [ "#{@path}/**/**" ] . each do | file | zip . add ( file . sub ( "#{File.dirname(@path)}/" , '' ) , file ) end end end end


Input: Creates a new object with given UUID . [CODESPLIT] def new_with_uuid ( klass , uuid ) if klass . is_a? ( String ) klass = Object . const_get ( klass ) end object = klass . new ( self , uuid ) object . initialize_defaults object end


Input: Creates a new group with given UUID . [CODESPLIT] def new_group_with_uuid ( name , uuid , path = nil , source_tree = :group ) main_group . new_group_with_uuid ( name , uuid , path , source_tree ) end


Input: Creates a new group with given UUID . [CODESPLIT] def new_group_with_uuid ( name , uuid , path = nil , source_tree = :group ) group = project . new_with_uuid ( PBXGroup , uuid ) children << group group . name = name group . set_source_tree ( source_tree ) group . set_path ( path ) group end


Input: Creates a file reference with given UUID . [CODESPLIT] def new_reference_with_uuid ( path , uuid , source_tree = :group ) # customize `FileReferencesFactory.new_file_reference` path = Pathname . new ( path ) ref = self . project . new_with_uuid ( PBXFileReference , uuid ) self . children << ref GroupableHelper . set_path_with_source_tree ( ref , path , source_tree ) ref . set_last_known_file_type # customize `FileReferencesFactory.configure_defaults_for_file_reference` if ref . path . include? ( '/' ) ref . name = ref . path . split ( '/' ) . last end if File . extname ( ref . path ) . downcase == '.framework' ref . include_in_index = nil end ref end


Input: Adds the file reference with given UUID . [CODESPLIT] def add_file_reference_with_uuid ( file_ref , uuid , avoid_duplicates = false ) if avoid_duplicates && existing = build_file ( file_ref ) existing else build_file = project . new_with_uuid ( PBXBuildFile , uuid ) build_file . file_ref = file_ref files . insert ( 0 , build_file ) build_file end end


Input: @param [ String ] root_path The path provided will be used for detecting Xcode project and Seedfile . [CODESPLIT] def install self . prepare_requirements self . analyze_dependencies self . execute_seedfile self . remove_seeds self . install_seeds self . configure_project self . configure_phase self . project . save self . build_lockfile @seeds = { } @locks = { } @targets = { } @source_files = { } @file_references = [ ] @swift_seedname_prefix = false end


Input: Read Xcode project Seedfile and lockfile . An exception will be raised if there is no . xcodeproj file or Seedfile in the { #root_path } . [CODESPLIT] def prepare_requirements # .xcodeproj project_filename = Dir . glob ( "#{root_path}/*.xcodeproj" ) [ 0 ] if project_filename self . project = Xcodeproj :: Project . open ( project_filename ) end # Seedfile begin self . seedfile = File . read ( self . seedfile_path ) rescue Errno :: ENOENT raise Seeds :: Exception . new "Couldn't find Seedfile." end # Seedfile.lock - optional begin self . lockfile = File . read ( self . lockfile_path ) rescue Errno :: ENOENT end end


Input: Parses Seedfile . lockfile into { #lockfile } . [CODESPLIT] def analyze_dependencies say "Anaylizing dependencies" # Seedfile.lock if self . lockfile locks = YAML . load ( self . lockfile ) locks [ "SEEDS" ] . each do | lock | seed = Seeds :: Seed . new seed . name = lock . split ( ' (' ) [ 0 ] seed . version = lock . split ( '(' ) [ 1 ] . split ( ')' ) [ 0 ] if seed . version . start_with? '$' seed . commit = seed . version [ 1 .. - 1 ] seed . version = nil end self . locks [ seed . name ] = seed end end end


Input: Executes { #seedfile } using eval [CODESPLIT] def execute_seedfile @current_target_name = nil # Sets `@swift_seedname_prefix` as `true`. # # @!scope method # @!visibility private # def swift_seedname_prefix! ( ) @swift_seedname_prefix = true end # Set current Xcode project with given path. # # @!scope method # @!visibility private # def xcodeproj ( path ) proejct_filename = File . join ( self . root_path , path ) self . project = Xcodeproj :: Project . open ( proejct_filename ) self . validate_project end # Sets `@current_target_name` and executes code block. # # @param [String] names The name of target. # # @!scope method # @!visibility private # def target ( * names , & code ) self . validate_project names . each do | name | name = name . to_s # use string instead of symbol target = self . project . target_named ( name ) if not target raise Seeds :: Exception . new "#{self.project.path.basename} doesn't have a target `#{name}`" end @current_target_name = name code . call ( ) end @current_target_name = nil end def local ( name , source_dir , options = { } ) self . validate_project if not @current_target_name target self . project . targets . map ( :name ) do send ( __callee__ , name , source_dir , options ) end else seed = Seeds :: Seed :: LocalSeed . new if not name raise Seeds :: Exception . new "Need a name to identifier." else seed . name = name end if not source_dir raise Seeds :: Exception . new "Need a source dir." else seed . source_dir = source_dir end seed . files = options [ :files ] || '**/*.{h,m,mm,swift}' if seed . files . kind_of? String seed . files = [ seed . files ] end seed . exclude_files = options [ :exclude_files ] || [ ] self . seeds [ seed . name ] = seed self . targets [ seed . name ] ||= [ ] self . targets [ seed . name ] << @current_target_name . to_s end end # Creates a new instance of {#Seeds::Seed::GitHub} and adds to {#seeds}. # # @see #Seeds::Seed::GitHub # # @!scope method # @!visibility private # def github ( repo , tag , options = { } ) self . validate_project if not @current_target_name # apply to all targets target self . project . targets . map ( :name ) do send ( __callee__ , repo , tag , options ) end elsif repo . split ( '/' ) . count != 2 raise Seeds :: Exception . new "#{repo}: GitHub should have both username and repo name.\n" "    (e.g. `devxoul/JLToast`)" else seed = Seeds :: Seed :: GitHub . new seed . url = "https://github.com/#{repo}" seed . name = repo . split ( '/' ) [ 1 ] if tag . is_a? ( String ) if options [ :commit ] raise Seeds :: Exception . new "#{repo}: Version and commit are both specified." end seed . version = tag seed . files = options [ :files ] || '**/*.{h,m,mm,swift}' seed . exclude_files = options [ :exclude_files ] || [ ] elsif tag . is_a? ( Hash ) options . merge! ( tag ) seed . commit = options [ :commit ] [ 0 .. 6 ] seed . files = options [ :files ] || '**/*.{h,m,mm,swift}' seed . exclude_files = options [ :exclude_files ] || [ ] end if seed . files . kind_of? ( String ) seed . files = [ seed . files ] end if seed . exclude_files . kind_of? ( String ) seed . exclude_files = [ seed . exclude_files ] end self . seeds [ seed . name ] = seed self . targets [ seed . name ] ||= [ ] self . targets [ seed . name ] << @current_target_name . to_s end end # Creates a new instance of {#Seeds::Seed::BitBucket} and adds to # {#seeds}. # # @see #Seeds::Seed::BitBucket # # @!scope method # @!visibility private # def bitbucket ( repo , tag , options = { } ) self . validate_project if not @current_target_name # apply to all targets target self . project . targets . map ( :name ) do send ( __callee__ , repo , tag , options ) end elsif repo . split ( '/' ) . count != 2 raise Seeds :: Exception . new "#{repo}: BitBucket should have both username and repo name.\n" "    (e.g. `devxoul/JLToast`)" else seed = Seeds :: Seed :: BitBucket . new seed . url = "https://bitbucket.org/#{repo}" seed . name = repo . split ( '/' ) [ 1 ] if tag . is_a? ( String ) if options [ :commit ] raise Seeds :: Exception . new "#{repo}: Version and commit are both specified." end seed . version = tag seed . files = options [ :files ] || '**/*.{h,m,mm,swift}' seed . exclude_files = options [ :exclude_files ] || [ ] elsif tag . is_a? ( Hash ) options . merge! ( tag ) seed . commit = options [ :commit ] [ 0 .. 6 ] seed . files = options [ :files ] || '**/*.{h,m,mm,swift}' seed . exclude_files = options [ :exclude_files ] || [ ] end if seed . files . kind_of? ( String ) seed . files = [ seed . files ] end if seed . exclude_files . kind_of? ( String ) seed . exclude_files = [ seed . exclude_files ] end self . seeds [ seed . name ] = seed self . targets [ seed . name ] ||= [ ] self . targets [ seed . name ] << @current_target_name . to_s end end def git ( repo , tag , options = { } ) self . validate_project if not @current_target_name target self . project . targets . map ( :name ) do send ( __callee__ , repo , tag , options ) end elsif not repo . end_with? ".git" raise Seeds :: Exception . new "#{repo}: is not a valid git repo.\n" else seed = Seeds :: Seed :: CustomSeed . new seed . url = repo seed . name = repo . split ( '/' ) . last . sub / / , '' if tag . is_a? String if options [ :commit ] raise Seeds :: Exception . new "#{repo}: Version and commit are both specified." end seed . version = tag seed . files = options [ :files ] || '**/*.{h,m,mm,swift}' seed . exclude_files = options [ :exclude_files ] || [ ] elsif tag . is_a? Hash seed . commit = tag [ :commit ] [ 0 .. 6 ] seed . files = tag [ :files ] || '**/*.{h,m,mm,swift}' seed . exclude_files = options [ :exclude_files ] || [ ] end if seed . files . kind_of? String seed . files = [ seed . files ] end if seed . exclude_files . kind_of? String seed . exclude_files = [ seed . exclude_files ] end self . seeds [ seed . name ] = seed self . targets [ seed . name ] ||= [ ] self . targets [ seed . name ] << @current_target_name . to_s end end eval seedfile end


Input: Removes disused seeds . [CODESPLIT] def remove_seeds removings = self . locks . keys - self . seeds . keys removings . each do | name | say "Removing #{name} (#{self.locks[name].version})" . red dirname = File . join ( self . root_path , "Seeds" , name ) FileUtils . rm_rf ( dirname ) end end


Input: Installs new seeds or updates existing seeds . [CODESPLIT] def install_seeds seed_dir = File . join self . root_path , "Seeds" if not Dir . exist? seed_dir Dir . mkdir seed_dir end self . seeds . sort . each do | name , seed | dirname = File . join ( self . root_path , "Seeds" , seed . name ) if seed . instance_of? Seeds :: Seed :: LocalSeed self . install_local_seed ( seed , dirname ) else self . install_seed ( seed , dirname ) end next if not seed . files # add seed files to `source_files` self . source_files [ name ] = [ ] seed . files . each do | file | paths = Dir . glob ( File . join ( dirname , file ) ) # exclude files seed . exclude_files . each do | exclude_file | exclude_paths = Dir . glob ( File . join ( dirname , exclude_file ) ) exclude_paths . each do | exclude_path | paths . delete ( exclude_path ) end end paths . each do | path | path = self . path_with_prefix ( seed . name , path ) self . source_files [ name ] . push ( path ) end end end end


Input:
Installs new seed or updates existing seed in { #dirname } . [CODESPLIT] def install_seed ( seed , dirname ) # if remote url has changed, remove directory and clone again remote_url = ` #{ Shellwords . escape ( dirname ) } ` . strip if remote_url != seed . url FileUtils . rm_rf ( dirname ) end # clone and return if not exists if not File . exist? ( dirname ) say "Installing #{seed.name} (#{seed.version or seed.commit})" . green command = "git clone #{seed.url}" command += " -b #{seed.version}" if seed . version command += " #{Shellwords.escape(dirname)} 2>&1" output = ` #{ command } ` unable_to_access = output . include? ( "unable to access" ) if unable_to_access and output . include? ( "Failed to connect to" ) raise Seeds :: Exception . new "#{seed.name}: Failed to connect to #{seed.url}. \n#{output}" end not_found = output . include? ( "not found" ) if not_found and output . include? ( "repository" ) raise Seeds :: Exception . new "#{seed.name}: Couldn't find the repository." elsif not_found and output . include? ( "upstream" ) raise Seeds :: Exception . new "#{seed.name}: Couldn't find the tag `#{seed.version}`." end if seed . commit and not seed . version # checkout to commit output = ` #{ Shellwords . escape ( dirname ) } \
 #{ seed . commit } ` if output . include? ( "did not match any" ) raise Seeds :: Exception . new "#{seed.name}: Couldn't find the commit `#{seed.commit}`." end end return end # discard local changes ` #{ Shellwords . escape ( dirname ) } \
 \
 \
 ` if lock = self . locks [ seed . name ] lock_version = lock . version lock_commit = lock . commit end if seed . version == lock_version and seed . commit == lock_commit say "Using #{seed.name} (#{lock_version or lock_commit})" return end if seed . version say "Installing #{seed.name} #{seed.version}" " (was #{lock_version or lock_commit})" . green output = ` #{ Shellwords . escape ( dirname ) } \
 #{ seed . version } \
 #{ seed . version } ` if output . include? ( "Couldn't find" ) raise Seeds :: Exception . new "#{seed.name}: Couldn't find the tag or branch `#{seed.version}`." end elsif seed . commit say "Installing #{seed.name} #{seed.commit}" " (was #{lock_version or lock_commit})" . green output = ` #{ Shellwords . escape ( dirname ) } #{ seed . commit } ` if output . include? ( "did not match any" ) raise Seeds :: Exception . new "#{seed.name}: Couldn't find the commit `#{seed.commit}`." . red end end end


Input: Append seed name as a prefix to file name and returns the path . [CODESPLIT] def path_with_prefix ( seedname , path ) if @swift_seedname_prefix components = path . split ( "/" ) prefix = seedname + "_" # Alamofire_ filename = components [ - 1 ] # Alamofire.swift extension = File . extname ( filename ) # .swift # only swift files can have prefix in filename if extension == '.swift' and not filename . start_with? prefix filename = prefix + filename # Alamofire_Alamofire.swift newpath = components [ 0 ... - 1 ] . join ( '/' ) + '/' + filename File . rename ( path , newpath ) # rename real files path = newpath end end path end