irb
than to google for the answer.ruby
interpreter evaluates a fileirb
Interactive Ruby Shellpry
advanced ruby shell
# This is a ruby comment
##
# We'll use #=> to represent the output of an expression,
# as if it were evaluated in the Interactive Ruby Shell (irb)
##
3/4.0
#=> 0.75
=begin
You might also come across this style for multi-line comments,
but using # is more prevalent.
=end
true
false
!false
#=> true
true && false
#=> false
true || false
#=> true
# avoid using "not", "and", and "or"
1 # FixNum
1.5 # Float
Math::PI
Math::E
2000000
2_000_000 # same as 2000000, easier to read
# single quotes are for literal strings
'Hello'
# double quotes allow special characters
# and variable interpolation
"pi is:\t#{Math::PI}"
# escaping quotes isn't fun, let ruby do that for us
%{That's a "quoted" string}
#=> "That's a \"quoted\" string"
# we often need to trim whitespace off of a string
"hello \n".strip
#=> "hello"
a_number = 3
some_string = 'I am a string'
another_string = "My number is #{a_number}"
$my_global_variable = "Try to avoid using global variables"
$my_global_variable = "whenever possible"
MY_GLOBAL_CONSTANT = "I am a constant"
MY_GLOBAL_CONSTANT = "warning if you try to change me"
$stdin
, $stdout
, $stderr
$0
- name of file containing current script$:
- ruby load path$DEBUG
- true if launched with -d
flagENV
- environment variablesARGV
- arguments passed to the script
# These look like strings to us,
# but are really just simple human-readable constant values.
:red
# Sometimes we'll use them to represent enumerable things,
# like days of the week.
:monday
# We use them the most as lookup keys
:some_key
# define an array
arr = ["I", "am", "a", 6, "element", "array"]
# call Array#length or Array#count
arr.length
#=> 6
# retrieve an element of an array
arr[0]
#=> "I"
# retrieve the first element
arr.first
#=> "I"
# nicer way to create an array of Strings
arr = %w[I am a six string array]
#=> ["I", "am", "a", "six", "string", "array"]
# we can assign multiple variables at once
one, two = [1, 2]
%w
. The most common you’ll see are %w(...)
, %w{...}
, and %w[...]
.
# older syntax (pre-1.9)
map = {:monday => 1, :tuesday => 2,
:wednesday => 3, :thursday => 4, :friday => 5}
map[:monday]
#=> 1
map[:saturday] = 6
#=> 6
# newer javascript-like syntax (preferred)
map = {monday: 1, tuesday: 2,
wednesday: 3, thursday: 4, friday: 5}
# non-symbol keys use old syntax
map = {1 => "monday"}
(1..5).to_a
#=> [1, 2, 3, 4, 5]
(1...5).to_a
#=> [1, 2, 3, 4]
["ls", "-a", "-l", "-R", "/tmp"][0..2]
#=> ["ls", "-a", "-l"]
%w(ls -a -l -R /tmp)[1..-1]
#=> ["-a", "-l", "-R", "/tmp"]
ssh
into the VMirb
You should see a prompt like
2.3.3 :001 >
Exit irb
by typing exit
, quit
, or CTRL+d
(End of File)
Launch irb
again for the next several sections of this lab
true
=> true
false
=> false
true && true
=> true
true || false
=> true
!true
=> false
!nil
=> true
!!nil
=> false
1+2
=> 3
8/4
=> 2
3/4
=> 0
3/4.0
=> 0.75
1_000_000
=> 1000000
2**3
=> 8
'hello, IRb'
=> "hello, IRb"
"hello, #{$0}"
=> "hello, irb"
'hello, #{$0}'
=> "hello, \#${0}"
name = 'Ben'
=> "Ben"
age = years = 36
=> 36
age + 1
=> 37
age
=> 37
age = age + 1
=> 37
age
=> 37
years
=> 36
years += 1
=> 37
days = [:mon, :tue, :wed, :thurs, :fri]
=> [:mon, :tues, :wed, :thurs, :fri]
days[3]
=> :thurs
days << :sat
=> [:mon, :tues, :wed, :thurs, :fri, :sat]
days.push(:sun)
=> [:mon, :tues, :wed, :thurs, :fri, :sat, :sun]
days.shift
=> :mon
days.first
=> :tues
days.methods.count
=> 172
days = {mon: "Monday", tues: "Tuesday"}
=> {:mon=>"Monday", :tues=>"Tuesday"}
days[:mon]
=> "Monday"
days["mon"]
=> nil
days[:wed] = "Wednesday"
=> "Wednesday"
days.length
=> 3
days.keys.first
=> :mon
irb
, do the following:
name
that holds a person’s name
name = 'Ben'
age
that holds a person’s age
age = 35
"Hi, I'm #{name}. I'm #{age} years old."
double_age
that’s twice age
double_age = age * 2
"Hi, I'm twice #{name}'s age. I'm #{double_age} years old."
irb
, do the following:
scores
with values [8, 9, 10, 6, 8]
scores = [8, 9, 10, 6, 8]
Array#last
method on scores
to get the last element
scores.last #=> 8
Array#max
method to get the max element in the list
scores.max #=> 10
[]
operator to get the third element in the array
scores[2] #=> 10
irb
, do the following:
colors
that maps from a color name to a number, using the table below
colors = {red: 1, green: 2, yellow: 3, blue: 4, magenta: 5, cyan: 6, white: 7}
colors[:yellow] #=> 3
colors[:black] = 0
| Color | Value |
|---|---|
| red | 1 |
| green | 2 |
| yellow | 3 |
| blue | 4 |
| magenta | 5 |
| cyan | 6 |
| white | 7 |
$stdin
, $stdout
, $stderr
are IO
objectsputs
, print
, printf
gets
write
, putc
, <<
getc
, read
, readbyte
, readchar
puts(str)
System.out.println
print(str)
puts
, but no newline
> puts "Hello"
Hello
=> nil
> print "Hello"
Hello => nil
puts
and print
don’t return anything, so they evaluate to nilprintf
in C%[flags][width][.precision]type
> printf '%s, %s!', 'hello', 'shell'
hello, shell! => nil
> printf '%10s, %10s!', 'hello', 'shell'
hello, shell! => nil
> printf '%-10s, %-10s!', 'hello', 'shell'
hello , shell ! => nil
> printf '%d / %d is %.2f', 10, 3, 10/3.0
10 / 3 is 33.33 => nil
irb
shell.
pick.rb
and inside it put a single command to print the string "Q♠"
ruby ./pick.rb
ruby
all the timepick.rb
file again#!/usr/bin/env ruby
chmod 755 ./pick.rb
./pick.rb
The full file contents of pick.rb
should be
#!/usr/bin/env ruby
puts "Q♠"
Array#shuffle
or Array#sample
to pick one at random
if true
puts "I knew it!"
else
puts "not gonna happen"
end
temp = 95
if temp < 40
puts "brrrr!"
elsif temp < 60
puts "cold"
elsif temp == 74
puts "perfect"
elsif temp < 80
puts "nice"
elsif temp < 90
puts "warm"
else
puts "scorcher"
end
# 'unless' is the opposite of 'if'
cloudy = false
unless cloudy
puts "I should bring some sunblock"
else
puts "maybe I should bring an umbrella"
end
if
and unless
, but we can also put these keywords at the end of a line
puts "Hi" if should_introduce
puts "Time to go" unless having_fun
first_name = nil
puts "Hello, #{first_name}" if first_name
temp = 95
case temp
when -100...40
puts "brrrr!"
when 40...60
puts "cold"
when 74
puts "perfect"
when 60...80
puts "nice"
when 80...90
puts "warm"
else
puts "scorcher"
end
cmd = 'ls'
case cmd
when 'help'
puts 'help requested'
when 'ls'
puts 'listing files'
else
puts 'unknown command'
end
if
/elsif
/elsif
/… blocks, but it often makes for more readable code.when
statements; for example, a class (e.g. String
) will match if the object is of that type, and a regular expression (e.g. /[a-zA-Z]+/
) will match any string that the regex matches.
file = 'exe/pick'
case file
when %r{^exe/}
puts 'executable'
when %r{^lib/}
puts 'library'
else
puts 'unknown'
end
loop do
puts "type CTRL+c to stop this"
end
while true
while rand < 0.9
puts "I win"
end
# since this was only one line,
# we can use the simpler
puts "I win" while rand < 0.9
list = []
until list.length > 10
list << Time.now
sleep 1
end
for day in [:mon, :tues, :thurs]
day = day.to_s.capitalize
day << "day"
puts day
end
pick_5.rb
pick.rb
selected one random card, this time we want to pick a random card 5 times.
pick_5
script.break
will get out of the current loop, orexit
will exit the scriptputs "got an ace" if card =~ /A./
puts card.split("").first == 'A'
if
/ unless
/ while
do
… end
or {
… }
| block_param1, block_param2 |
Array#each
and Array#map
are two of the most commonly-used functions that take blocks.
# We already saw one way to iterate through an array
for day in [:mon, :tues, :wed]
puts "#{day}"
end
# We can also do this by passing Array#each a block
[:mon, :tues, :wed].each do |day|
puts "#{day}"
end
each
instead of for
may feel awkward at first when coming from another language, but stick with it and you’ll find yourself among the ruby programmers who find it enjoyable to read.
# we can also use each to
# loop through a hash's key/value pairs
map = {mon: 1, tues: 2, wed: 3}
map.each do |name, day|
puts "#{name}is day #{day}of the week"
end
# We often want to create an array from another array
# by transforming the elements somehow.
# without blocks
squares = []
nums = [1, 2, 3, 4]
for i in nums
squares << i*i
end
# with Array#each
squares = []
nums = [1, 2, 3, 4]
nums.each do |i|
squares << i*i
end
# with Array#map
nums = [1, 2, 3, 4]
squares = nums.map do |i|
i*i
end
# it's short, so this is okay
nums = [1, 2, 3, 4]
squares = nums.map{ |i| i*i }
SUITS = %w(♠ ♥ ♦ ♣)
VALUES = %w(2 3 4 5 6 7 8 9 10 J Q K A)
cards = []
VALUES.each do |val|
SUITS.each do |suit|
cards << "#{val}#{suit}"
end
end
SUITS = %w(♠ ♥ ♦ ♣)
VALUES = %w(2 3 4 5 6 7 8 9 10 J Q K A)
cards = VALUES.map{|v| SUITS.map{|s| "#{v}#{s}"}}.flatten
SUITS = %w(♠ ♥ ♦ ♣)
VALUES = %w(2 3 4 5 6 7 8 9 10 J Q K A)
cards = VALUES.product(SUITS).map(&:join)
&:join
business? It’s shorthand for .map{|arr| arr.join}
puts
, each
, length
, capitalize
, []
# functions can take 0 or more arguments
def increment(number)
# they evaluate to the last line executed
# so no need for an explicit 'return'
number + 1
end
# if there are no arguments, we can leave off the parentheses
def print_help
puts "This is not a helpful message."
end
# arguments can have default values
# in case we don't specify them
def decrement(number, decrement_by = 1)
number - decrement_by
end
# arguments can be any type, like arrays or hashes.
# how we check for valid inputs is up to us
def lookup(needles = [], haystack = {})
# needles could be a non-array,
# or haystack could be a non-hash,
# in which case this will raise an exception
needles.map do |needle|
haystack.has_value?(needle)
end
end
# we can leave off the parentheses
# as long as the code is still readable
# and not ambiguous
new_val = decrement(10, 5)
new_val = decrement 10, 5
puts('Hello, Shell!')
puts 'Hello, Shell!'
# When a hash is the last argument,
# we can leave off the curly braces
lookup([1, 2, 3], one: 1, two: 2, three: 3)
# this is often used to send options to a function
echo(["hello", "world"], capitalize: true, delimiter: '-')
take_n.rb
(or update one of the previous ones)take(n = 1)
ARGV[0].to_i
to the function
module Commands
VERSION = "1.0.1"
HELP_TEXT = "Sorry, no help."
end
puts Commands::VERSION
puts Commands::HELP_TEXT
module Commands
def Commands.echo(*args)
puts args.join(' ')
end
end
Commands.echo "hello", "world"
module Commands
FILES = "~/.zshrc /etc/passwd"
def ls
puts FILES
end
end
include Commands
ls
class <ClassName> ... end
initialize
is the Constructornew
@name
is an instance variable
class MyFile
def initialize(name)
@name = name
end
def to_s
@name
end
end
my_file = MyFile.new "data.txt"
puts "I just created #{my_file}"
class MyFile
# empty constructor, can leave out
def initialize; end
# Setter, method name is "name="
# In Java, we'd call this setName
def name=(arg)
@name = arg
end
def name
@name
end
end
my_file = MyFile.new
my_file.name = "data.txt"
puts my_file.name
myfile.rb
with the code from the previous page@contents
to be an empty stringcontents
class MyFile
def initialize
@contents = ''
end
def contents=(contents)
@contents = contents
end
def contents
@contents
end
end
my_file = MyFile.new
my_file.contents = "hello, file"
puts my_file.contents
attr_reader
- generates a default getterattr_writer
- generates a default setterattr_accessor
- generates both a getter and a setterattr_*
class MyFile
attr_accessor :name, :contents
end
my_file = MyFile.new
my_file.name = 'data.txt'
my_file.contents = 'Hello, File!'
puts "#{my_file.name}: #{my_file.contents}"
my_file.methods.sort
class MyFile
attr_reader :name
def name=(filename)
@name = filename.upcase
end
end
my_file = MyFile.new
my_file.name = "data.txt"
puts "I just created #{my_file.name}"
MyFile
instead of File
? It turns out that ruby already has a class named File
, so this could have been confusing. We could have put this file into a module (e.g. RubyShell
) and referenced it as RubyShell::File
to get around this.
class MyDir < MyFile
attr_reader :files
def add(file)
@files ||= []
@files << file
end
def contents
@files.join("\n")
end
end
dir = MyDir.new
dir.is_a?(MyDir) #=> true
dir.is_a?(MyFile) #=> true
Script
- represents some executable code and provides an execute
methodMyFile
- represents a file with a name and contentsScriptFile
that represents a file whose content is a script that can be executed.class ScriptFile < Script, MyFile
?
class ScriptFile < MyFile
attr_reader :script
def initialize(script)
@script = script
end
# delegate the execute functionality to the Script
def execute
@script.execute
end
end
delegate :execute, to: :script
, and Ruby has similar functionality via the Forwardable
module
module Script
def execute
# assumes whoever mixes this in will have a method `contents`
eval(contents) # caution: eval can be dangerous!
end
end
class ScriptFile < MyFile
include Script
end
ScriptFile.ancestors
# => [ScriptFile, Script, MyFile, Object, Kernel, BasicObject]
script = ScriptFile.new
script.contents = "1+1"
script.execute #=> 2
script.is_a?(Script) #=> true
public
(default) - can be called from anywhereprivate
- can only be called from within this classprotected
- can only be called where self
is of the same type
class MyTextFile
def initialize
@current_line = 0
@lines = []
10.times{ |i| @lines << "line #{i}" }
end
def readline
return '' if end_of_file?
line = @lines[@current_line]
increment_line
line
end
private
def increment_line
@current_line += 1
end
def end_of_file?
@current_line + 1 > @lines.length
end
end
Card
class that holds a value and a suitDeck
class that holds our cardslab07
), create a file card.rb
Card
class.
class Card
end
initialize
method) to the Card
classto_s
method to print out the Card
irb
, load the file via require './card'
or load './card.rb'
require
can only be called once, so you must exit the irb
session and restart it after making changesload
can be called multiple times, but can create an inconsistent state, so be careful.deck.rb
that defines a Deck
Deck
has a property @cards
, but it doesn’t expose this
initializer
@cards
, it provides methods take(n)
and shuffle
require './card'
to the top of the file if you need to reference the Card
classDeck
print nicely by defining a to_s
method
irb
and pry
call .inspect
when printing objectsinspect
, or call alias_method :inspect, :to_s
within the class definition to make it the same as to_s
Card
class, include Comparable
def <=>(otherCard)
, that
nil
if the other object isn’t really a Card
0
if the cards are of equal face value-1
if self
has a lower value than otherCard
1
if self
has a greater value than otherCard
<
, >
, <=
, ==
Deck#each
like we call Array#each
?Deck
, if we call include Enumerable
and then define a method #each
, we’ll get a bunch of functions like #map
, and even #minmax
(because our Cards
are Comparable
)
def each
return enum_for(:each) unless block_given?
@cards.each{ |c| yield c }
self
end
highcard.rb
that picks one card for each player and reports what those cards are and who won.assert_equal(expected, actual)
and spec-style tests
require 'minitest/autorun'
class Example < Minitest::Test
def test_integer_division
assert_equal 3, 10/3
end
end
ruby minitest_example.rb
gem install rspec
require 'rspec'
describe 'Integer Division' do
it 'divides 10 by 3 and gets 3' do
expect(10/3).to eq(3)
end
end
rspec rspec_example.rb
rspec --color --format documentation ./rspec_example.rb
.rspec
file.
require 'minitest/autorun'
describe 'Integer Division' do
it 'divides 10 by 3 and gets 3' do
expect(10/3).must_equal 3
end
end
ruby minitest_example_spec.rb
require_relative '../card'
require 'minitest/autorun'
class CardTest < MiniTest::Unit::TestCase
def test_face_card_is_face_card
assert Card.new('K', 'S').is_face_card?
end
def test_non_face_card_is_not_face_card
assert !Card.new('8', 'H').is_face_card?
end
end
class Card
# ...
def is_face_card?
return self.value == 'K'
end
end
def test_face_card_is_face_card
['J', 'Q', 'K', 'A'].each do |value|
assert Card.new(value, 'H').is_face_card?
end
end
class Card
def is_face_card?
%w(J Q K A).include?(self.value)
end
end
assert_performance_linear
)Deck.new.take(5)
should return 5 cards, and then the rest of the deck should only have 47 cards left.gem install rspec
installs the rspec rubygem so we can require it from our codegem install rspec -v 3.5.0
for specifying the versiongem search
searches through remote gems for ones to installgem list
lists locally installed gemsgem uninstall
uninstalls gems
source 'https://rubygems.org'
gem 'highline'
gem 'rspec-core', '= 3.5.2' # exact version
gem 'rspec', '~> 3.5.0' # highest version between 3.5.0 and 3.6
gem 'nokogiri', github: 'sparklemotion/nokogiri'
.gemspec
file)bundler
manages dependencies between gemsGemfile
lists gems and general versionsGemfile.lock
lists specific versionsbundle install
resolves dependencies and installs the gemssinatra
, to make add a server around our deck.gem install sinatra
/card
returns the next card in the deck (it’s string representation)/shuffle
shuffles the deck
#!/usr/bin/env ruby
require 'sinatra'
require './deck'
class DeckServer < Sinatra::Base
set :deck, Deck.new
set :magic_number, 42
get '/' do
"Try going to /card"
end
get '/number' do
settings.magic_number.to_s
end
end
DeckServer.run!
chmod 755 ./deck_server.rb
./deck_server.rb
curl http://localhost:4567/card
curl http://localhost:4567/shuffle
curl http://localhost:4567/card
OpenURI
ruby module:
require 'open-uri'
open("<some url>").read
deck_client.rb
filebundle gem rubygames
rubygames.gemspec
and remove the TODOsgem build
gem install
gem contents rubygames
lib/rubygames
test/
exe/
require
linesrake test
still worksgit add .
deckserver
)
$ rails new notes
$ cd notes
$ bundle install
$ rails db:create
$ rails db:migrate
$ rails server
$ rails generate scaffold note title:string body:text completed:boolean
$ rails db:migrate
$ rails server
ActiveRecord
ActionView
ActionController
app/
controllers/
application_controller.rb
notes_controller.rb
models/
note.rb
views/
layouts/application.html.erb
notes/index.html.erb
# app/models/note.rb
class Note < ApplicationRecord
def title
# not really defined,
# but acts like it!
end
end
Note
-> notes
db/migrate
has_one
, has_many
, belongs_to
, habtm
)body
must exist, title
must be shorter than 140 characters)create
, create!
, new
-> save!
find
, where
, where.not
save
, save!
, update_attribute
, update
delete
, destroy
, delete_all
, destroy_all
Note.create! title: "First Post", body: "w00t"
# same as
Note.new(title: "First Post", body: "w00t").save!
# fetch everything
Note.all
# get the most recent 5 notes
Note.order(created_at: :desc).limit(5)
# fetch all that match a criteria
Note.where(title: "First Post")
# fetch one by its primary key (id)
Note.find(1)
# get the count of all that don't match a criteria
Note.where.not(title: "First Post").count
# get the first matching record
Note.where(title: "First Post").first
| Prefix | Verb | URI Pattern | Controller#Action |
|---|---|---|---|
| notes | GET | /notes(.:format) | notes#index |
| POST | /notes(.:format) | notes#create | |
| new_note | GET | /notes/new(.:format) | notes#new |
| edit_note | GET | /notes/:id/edit(.:format) | notes#edit |
| note | GET | /notes/:id(.:format) | notes#show |
| PATCH | /notes/:id(.:format) | notes#update | |
| PUT | /notes/:id(.:format) | notes#update | |
| DELETE | /notes/:id(.:format) | notes#destroy |
GET /notes
New
GET /notes/new
Create
POST /notes/
GET /notes/5
GET /notes
Edit
on oneGET /notes/6/edit
Update
PATCH /notes/6
GET /notes/6
:html
, :json
, :xml
, :js
)
class NotesController < ApplicationController
def index
@notes = Note.all
end
def show
@note = Note.find(params[:id])
end
def new
@note = Note.new
end
def edit
@note = Note.find(params[:id])
end
# Not shown: create, update, destroy
end
class NotesController < ApplicationController
before_action :set_note, only: [:show, :edit, :update, :destroy]
def index
@notes = Note.all
end
def show; end
def new
@note = Note.new
end
def edit; end
# (Not shown: create, update, destroy)
private
def set_note
@note = Note.find(params[:id])
end
end
yield
the main contentcontent_for
<!DOCTYPE html>
<!-- app/views/layouts/application.html.erb -->
<html>
<head>
<title>FridgeDoor</title>
<%= stylesheet_link_tag 'application' %>
<%= javascript_include_tag 'application' %>
<%= csrf_meta_tags %>
</head>
<body>
<%= yield %>
</body>
</html>
<!-- app/views/notes/show.html.erb -->
<p>
<strong>Title:</strong>
<%= @note.title %>
</p>
<p>
<strong>Body:</strong>
<%= @note.body %>
</p>
<%= link_to 'Edit', edit_note_path(@note) %> |
<%= link_to 'Back', notes_path %>
/ notes/show.html.haml
/ would replace notes/show.html.erb -->
%p
%strong Title<EMAIL_ADDRESS>%p
%strong Body<EMAIL_ADDRESS>= link_to 'Edit', edit_note_path(@note)
|
= link_to 'Back', notes_path
/! notes/show.html.slim would replace notes/show.html.erb
p
strong<EMAIL_ADDRESS>p
strong<EMAIL_ADDRESS>= link_to 'Edit', edit_note_path(@note)
|
= link_to 'Back', notes_path
demo
?
rails new demo
demo
?
cd demo
bundle install
rails db:create
rails db:migrate
rails server
rails s
localhost:3000
rails g scaffold todo desc:string
, where would we go to create a new todo?
/todos (and follow the link)
/todos/new
todos
or your own idea)
rails new fridge_door
rails g scaffold todo title:string completed:boolean
rails db:migrate
rails s
rails test
# test/controllers/notes_controller_test.rb
require 'test_helper'
class NotesControllerTest < ActionController::TestCase
setup do
@note = notes(:one)
end
test "should get index" do
get :index
assert_response :success
assert_not_nil assigns(:notes)
end
# ....
end
# test/fixtures/notes.yml
one:
title: MyString
body: MyText
notes(:one)
Note
objectcreated_at: <%= Time.now %>
# test/models/note_test.rb
test "notes require a body" do
assert_not Note.new(title: "Title", body: "").valid?
end
rails test test/models/note_test.rb
rails test test/models/note_test.rb:5
validates :terms_of_service, acceptance: true
validates :email, confirmation: true
validates :email, exclusion: {in<EMAIL_ADDRESS>validates :display_name, format: /\A[a-zA-Z]{3,12}\z/
validates :display_name, length: { in: 3..12 }
validates :age, numericality: true
validates :email, :display_name, presence: true
length
and presence
both sound like they could work!Add the validation to app/models/note.rb
class Note < ApplicationRecord
validates :body, presence: true
end
Re-run the test to see it pass
rails test test/models/note_test.rb
$ rails console
cd
and ls
our objects!binding.pry
pry-byebug
(Ruby 2+)pry-debugger
(Ruby 1.9.2+)
# Gemfile
group :development, :test do
gem 'pry-rails'
gem 'pry-byebug'
end
belongs_to
on the other sidebelongs_to
means “I have their id
” in my database tablerailsgames
rails new railsgames
rails g scaffold user name:string
rails g scaffold game name:string description:text user:references
rails console
to create some datarails server
app/views/games/index.html.erb
to show the user’s nameapp/views/games/show.html.erb
to show the user’s nameapp/views/games/_form.html.erb
to have a dropdown to select the user
form.collection_select(:user_id, User.all, :id, :name)
configs
table with the following properties:
server_url
server_port
game_type
(make this an integer)app/models/config.rb
, add the line:
enum game_type: { highcard: 10, five_card_draw: 20 }
rails console
run the following a few times
Config.where(server_url: "http://localhost", server_port: 3000, game_type :highcard).first_or_create
sudo mkdir -p /etc/puppet/code/hiera
after_save
hook to our Config model to update hiera
class Config < ApplicationRecord
after_save :update_puppet_facts
def update_puppet_facts
game_servers = Config.all.map do |config|
{ "server" => "#{config.server_url}:#{config.server_port}",
"game_type" => config.game_type }
end
yml = {"game_servers" => game_servers}.to_yaml
File.open('/etc/puppet/code/hiera/common.yaml', 'w') do |f|
f.puts yml
end
end
end
rails console
and try Config.first.save
sudo touch /etc/puppet/code/hiera/common.yaml
sudo chown $USER /etc/puppet/code/hiera/common.yaml
Config.first.save
hiera game_servers
require 'hiera'
hiera = Hiera.new(config: '/etc/puppet/hiera.yaml')
puts hiera.lookup('game_servers', [], nil)
mkdir -p lab15/lib
cd lab15/lib
export FACTERLIB=$(pwd)
# lib15/lib/ips.rb
Facter.add(:ips) do
setcode do
['<IP_ADDRESS>']
end
end
# lib15/lib/ips.rb
Facter.add(:ips) do
setcode do
ifaces = Facter.fact('interfaces').value.split(',')
ips = ifaces.map do |iface|
Facter.fact("ipaddress_#{iface}").value
end
end
end
!
version as well. The convention is that the !
version will modify the string you call it on, whereas the non-!
version returns a new string.+
concatenate two strings (e.g. "thank " + "you" #=> "thank you"
)==
equality operator=~
matching operator (e.g. "thank you" =~ /thank/
)capitalize
converts the first character to upper casechomp
removes trailing whitespacestrip
removes leading and trailing whitespaceupcase
converts the string to all capsdowncase
converts the string to all lowercaseempty?
returns if the string has zero lengthgsub
replaces all occurrences of a pattern with a replacementsub
replaces the first occurrence of a pattern with a replacementinclude?
determines if the string contains the given substringlength
the character length of the stringreverse
the backwards version of the stringsplit
splits the string based on the given pattern into an array of strings separated by that patternto_i
converts the string into an integer of the given base (if possible)to_sym
converts the string into a symbol+
joins two arrays-
is the difference between two arrays&
is the intersection of two arrays<<
, push
adds to the end of an arrayunshift
adds to the beginning of the arrayinsert
adds an element to a specific place in the array<=>
is the comparison operator[index]
retrieves the element at index
[start, length]
and [start..end]
retrieves a subarrayany? {|obj| block}
returns true if the block returns true for any elementselect {|obj| block}
returns the elements for which the block returns truemap {|obj| block}
returns a new array with the block being performed on each elementcount
, length
returns the number of elements in the arraytake(n)
returns the first n
elements of the arraydrop(n)
returns the tail of the array after skipping the first n
elementseach {|obj| block}
performs the block on each element of the arrayeach_with_index {|obj, idx| block}
same as each
but also gives access to the indexinclude?
returns if the given element is in the arraypop
removes the last element from the array and returns itshift
removes the first element from the array and returns itreverse
returns the array backwardssample
returns a random element (or n
random elements) from the arrayshuffle
randomizes the arraysort
sorts the array using <=>
on each of the elementsjoin
builds a string from the array elementsexpect(actual).to eq(expected)
expect(actual).not_to eq(expected)
expect(actual).to be(expected)
expect(actual).to equal(expected)
expect(actual).to be > expected
expect(actual).to be <= expected
expect(actual).to be_within(delta).of(expected)
expect(actual).to match(/expression/)
expect("hello, world!").to match(/[a-z]+, [a-z]+!/)
expect("hello").to be_an_instance_of(String)
expect(3).to be_a(Numeric)
expect(3).to be_an(Integer)
expect(3).to be_truthy
expect(true).to be_true
expect(nil).to be_falsy
expect(false).to be_false
expect(nil).to be_nil
expect(3).to_not be_nil
expect { raise NotImplementedError }.to raise_error(NotImplementedError)
expect(actual).to be_xxx
# passes if actual.xxx?expect(actual).to have_xxx(:arg)
# passes if actual.has_xxx?(:arg)expect(actual).to include(expected)
expect(actual).to start_with(expected)
expect(actual).to end_with(expected)
gem search
searches through remote ruby gems
gem search ^rails
gem search ^rails$ -d
gem install
downloads and installs a gem and its dependencies
gem install highline
gem install highline -v 1.7.8
gem install highline -v '>= 1.7'
gem install highline -v '~> 1.7.0'
gem uninstall
removes a gem from the systemgem list
lists locally installed gemsgem build
builds a gem from a gemspecgem update
updates gems to the latest versiongem which
shows where the gem is locatedgem push
publish a gem to a remote gemserverbundle install
use bundler to install all the gems specified in a Gemfile
bundle show
similar to gem which
, shows where a gem is installedbundle update
updates versions of gems specified by the Gemfile
, ignoring the Gemfile.lock
bundle exec
executes a command, making all the gems listed in the Gemfile
available via require
bundle gem
creates the files and directory structure for a new gem| Command | Description |
|---|---|
| rails new | Creates a new rails app. rails new MyBlog |
| rails server | Runs rails (default port 3000, Ctrl+C to exit) |
rails s -b <IP_ADDRESS> to bind to all network interfaces |
|
| rails console | Launch an interactive ruby console for the rails app rails c |
| rails generate | Show the available generators. rails g |
| rails g scaffold | Creates model, view, controller, route, tests, and migration |
| bundle install | Installs the dependencies specified in the Gemfile |
| Command | Description |
|---|---|
| rails db:create | Sets up a new database |
| rails db:migrate | Runs any pending migrations |
RAILS_ENV=test rails db:migrate |
|
| to update the test database schemas | |
| rails db:reset | Clears the database and updates it |
| to the latest migration | |
| rails db:seed | sets up initial “seed” data in the |
database, based on db/seeds.rb |
| Command | Description |
|---|---|
| rails test | Runs all the tests |
whole file: rails test test/models/model_test.rb |
|
one test: rails test test/models/model_test.rb:12 |
|
| rails -T | Shows all available rails commands |
rails g scaffold author name:string birthdate:datetime
rails g scaffold post title:string body:text likes:integer
rails g scaffold product description:text cost:"decimal{10,2}"
# if we want to destroy that last one
rails d scaffold product
rails g migration add_rating_to_authors rating:float
rails g scaffold
)validates :terms_of_service, acceptance: true
validates :email, confirmation: true
validates :email, exclusion: { in<EMAIL_ADDRESS>}
validates :display_name, format: /\A[a-zA-Z]{3,12}\z/
validates :display_name, length: { in: 3..12 }
validates :age, numericality: true
validates :email, display_name, presence: true
<button class="btn btn-primary col-xs-12 col-md-6">
First Button
</button>
<button class="btn btn-secondary col-xs-12 col-md-6">
Second Button
</button>


The Great Metal Survey
Help us find what makes metalheads worldwide tick.
Go to the survey
Full Name
E-mail
Age
Who of the following do you consider to be the best metal vocalist?
Select the best vocalist of all time
Maynard James Keenan
Mike Patton
Bruce Dickinson
Rob Halford
Ronnie James Dio
What is the most important instrument in a metal band:
Guitar
Bass
Drums
Vocals
Choose one or more metal genres that you enjoy
Alternative
Black
Glam
Grunge
Power
Anything you'd like to tell our magazine's editors?


Raise
{{pendingOfferService.getMessage() || 'Your fundraising offer is being processed by the Ethereum blockchain.'}}
Your Wallet address: {{walletAddress}}
Now you can follow your fundraising offer on: Manage


toggleFullScreen() is a JavaScript function which toggle the full screen and monitors current full screen state triggering callback on change of fullscreen state.
<button class="toggle-fullscreen" title="Full screen" data-toggle="tooltip"> <img src="images/expand.svg" alt="Full screen" /> </button>JavaScript
var $fullScreenTogglers = $(".toggle-fullscreen"); $fullScreenTogglers.click(function(e) { e.preventDefault(); // in case if toggler is an anchor toggleFullScreen(function(isFullScreen) { $fullScreenTogglers.find("img").attr("src", isFullScreen ? "images/compress.svg" : "images/expand.svg"); }); });
NOTE: This quick example uses jQuery. But the function itself written in vanilla JavaScript, so jQuery doesn't required.
Click button below to toggle full screen mode


Tendermint P2P Layer¶
This article explains the Tendermint P2P Layer and many of its gotchas. Understanding the P2P Layer has been very important to us, since it has important systems architecture implications.
Intro¶
The Tendermint P2P implementation is based on a relatively simple concept.
Types of peers¶
Each node in the network is configured to dial a set of seed
and
persistentPeers
when it is first started. Both of these parameters
can be set in the config.
- Persistent peers
- The Tendermint node will try to maintain a permanent connection with this peer during its runtime. That also means that it will persistently try to redial the node if the connection fails. This is for example useful for the connection between Validator and Sentry nodes, because they will immediately try to reconnect after a connection failure, and there is no scenario where they could be stuck in a unreasonably long backoff or generally be removed from the peers addressbook which could cause unforeseen issues in a Sentry architecture.
- Seeds
- Seed nodes are only there to provide an up-to-date list of peers of the network. If a node is configured to run as a seed node, it will actively search the network for new peers and store them in its addressbook. However, it will not maintain active connections with the peers it queries. Connections from a seed node are meant to be short-lived in order to just query the other peers addressbook, learn about its new peers and then disconnect again. If you specify a seed node in the config of your node it will try to dial it on startup to retrieve an up-to-date addressbook as well as a list of peers on the network to bootstrap its connections.
Addressbook¶
From the moment the node has acquired a list of peers on the network it will store them in a weighted addressbook.
This addressbook stores all peers the client has ever learned about (and possibly connected to). When a connection to a peer fails, this is marked in the addressbook and will lead to a backoff before the next reconnection attempt is made. If a peer connection fails for more than x times (where x is a constant hardcoded in Tendermint at the moment), the peer is marked as bad and removed from the addressbook.
Connection Types¶
- Inbound connection
- Every connection that was initiated by another peer
which contacted our node from the outside is called an inbound
connection. The number of maximum inbound connections can be specified
with
max_num_inbound_peers
. In order for another peer to create a connection to our node our P2P port (26656 by default) has to be publicly exposed. - Outbound connection
- Every connection that was initiated by our peer (because of persistent peers, manual dialing or the PEX reactor) is an outbound connection. In order to establish an outbound connection the P2P port does not have to be opened as long as outbound connections are allowed by firewall rules.
The peer reactor¶
Depending on whether you have a normal or seed node, the PEX (peer exchange) reactor will execute the following loop regularly.
Normal peer¶
Startup¶
The node will check its addressbook for valid peers to connect to and connect to all of the persistent peers specified. If the addressbook is empty, it will try to connect to one of the specified seed nodes.
Loop¶
In the peer exchange routine the node will try to connect to new nodes
from its addressbook until it has reached the max_num_outbound_peers
(as of tendermint commit 6fad8eaf5).
It will also query a random peer for its addressbook if the addressbook of itself is not yet “full” (currently 1000 entries).
Seed node¶
Startup¶
as with a normal node
Loop¶
The node will try to clean up its connections by closing every connection that has been found to be healthy.
Then, it will attempt to connect to all its known peers from the addressbook and ask them for their addressbook.
This behaviour intends to get a picture of the network that contains almost every public node available in order to allow new nodes to easily bootstrap using an up-to-date addressbook.
Operation Notes¶
Knowing all of this, there are a number of different ways to improve your network’s resilience by taking advantage of how the P2P reactor works.
Running outbound only nodes¶
In order to reduce your DDoS attack surface you might want to run outbound only sentry nodes.
Outbound only nodes behind a stateful firewall - that is, any firewall that isn’t a simple router ACL - allow you to completely drop incoming connections, permitting only packets belonging to existing sessions. That way, your node is not publicly reachable from the internet except for the TCP sessions that you have established with your peers. This greatly reduces the attack surface for network-layer attacks. Depending on your peer selection policy, it can also reduce the attack surface for L7 (application layer) attacks by only connecting to trusted nodes.
With global TCP load balancers like Google Cloud and CloudFlare Spectrum, the stateful firewall is moved closer to the providers edge points of presence (PoPs), allowing you to absorb large denial-of-service attacks (the provider will drop unknown packets right when they enter their network, distributing attack traffic across their PoPs rather than congesting the single availability zone your application is running in).
Additional safety measures could be to announce a wrong IP using PEX, which confuses nodes other than those those you are connecting to. That way, only the peers you have established connections with will know your true IP.
However, this also increases the importance of having uncompromised peers because other peers of potentially good actors on the network won’t be able to connect to you and if your maximum number of outbound peers is filled with compromised peers, you will only see these nodes and no others as we have learned above. Such a compromise may allow an attacker to alter your view of the network, rendering you unable to catch up with the network or even cause your node to exhibit byzantine behaviour, if it’s in a vulnerable state.
So it’s very important to (either):
- Set a high number of outgoing peers
- Add at least some trusted persistent peers
- Implement additional measures to either select peers or rotate peers on a regular basis
Warning
If your firewall is misconfigured or you are announcing a wrong public IP (e.g. your internal Docker IP) your node will be outbound-only unintentionally since no other nodes can connect from the outside (assuming you are not configured as persistent peer using your true IP). This can result in slow syncing and missed blocks due to delays in consensus message gossip, unless you apply the optimizations noted above.
Note
Outbound-only peers are meant as an additional measure to protect your validator from DDoS and similar attacks. However, running only outbound peers can cause network partitioning, slow bootstrapping for new network participants and general network destabilization. Plase make sure that you run only a small portion of your sentries in an outbound-only configuration to ensure the overall quality of the network.
Running “full-duplex” nodes¶
Full-Duplex or inbound/outbound nodes are the default configuration for nodes. They allow both inbound connections to be established from the outside as well as outbound connections.
In order to run a full-duplex node your firewall needs to be opened for both in- and outbound traffic on the relevant port (26656 by default).
Since the host can be reached from the public internet, the risk for DDoS is higher. However, this configuration allows new peers to establish connections with them and thereby increases the overall network’s resilience.
You should run most of your sentries as “full-duplex” nodes.
Please keep in mind to set your number of maximum inbound peers in the config file to an appropriate value to get a better view of the network.
Private nodes¶
Private nodes communicate via VPN or other private networks and allow only selected peers to establish connections with them. Such a configuration could be used for validator-validator private peerings.
In order to not leak any information about the node, it can be run with PEX disabled and the peering with the other nodes hardcoded as persistent peer.
The Sentry architecture¶
In order to deploy multiple different kinds of nodes, as described above, in our network and combine their strengths we need an additional layer besides our single validator node (or multiple validator nodes).
In order to effectively mitigate DDoS attacks we also don’t want to publicly expose our validator nodes (IPs) to the internet.
This is implemented in an architecture developed by the Tendermint/Cosmos team called Sentry node architecture.
While the validators reside in a Virtual Private Network (like it’s e.g. offered by many cloud providers) or actual private network that is disconnected from the internet our Sentries basically build a proxy layer between this network and the public internet / cosmos network.
Sentry nodes are full cosmos nodes whose only task it is to relay messages and blocks to the validator nodes.
This is done by assigning the Sentry nodes both a public and private interface and hardcoding the validator nodes as persistent peers. The PEX reactor is limited in a way to not broadcast the validator nodes to the other public peers in the network.
As a result no network participant will ever have a direct connection with one of our validator nodes and will therefore also not be able to DDoS these directly. The Sentry nodes form a shielding layer and are not limited in their number since they only act as a proxy and have no special stateful task like signing. New nodes can be added and removed at any time as long as a minimum amount is kept online.
To learn more about the Sentry architecture and how to configure your nodes accordingly look at the Cosmos Docs.
Sentry-Auto-Scaling¶
Actually… Sentry Auto Scaling isn’t the best way to protect yourself against DDoS attacks, and Certus One is investing in proper DDoS protection rather than sentry scale-out.
Autoscaling is a common and successful defense against application-layer DDoS in webservers and APIs - you just outnumber the attacker by responding to every single of their requests.
It might seem obvious to apply the same approach to sentry nodes, however, it’s less effective and more expensive than you might expect.
Let’s first take a look at potential DDoS vectors of your validator:
- L7 - Application Layer:
- Vulnerabilities in Tendermint or the Cosmos SDK can allow an attacker to slow or take your nodes down with little effort and bandwidth. Traditional DDoS solutions will mostly not be able to mitigate this since they lack protocol-level insight.
- L4 - Protocol Layer:
- SYN floods and similar attacks which aim to overwhelm your load balancer or operating system or fill up its flow tracking tables.
- L2/3 - Network Layer
- Large-scale high-bandwidth reflection attacks which aim to saturate the network interface of your hosts, or provider, or even your provider’s provider (it happens).
Now, how does autoscaling mitigate these?
L7 attacks cannot be mitigated by creating more nodes. Since there are no high bandwidth requirements on the attacker side, they can just continue attacking each new node, taking it down as well which would trigger the creation of more new nodes in an auto-scaling environment. It’s not much of a difference to them whether they need to attack 100 or 200 nodes, but it makes a huge difference to you. It won’t get you anywhere, but will get really expensive, really fast (which might be all the attacker wants, anyway).
To prevent this, one would need sophisticated auto-scaling algorithms which stops scaling up if new nodes quickly stop responding.
So what about L2/3/4 attacks?
If your sentry nodes are getting attacked by large amplification attacks (which are easily in the >100 Gpbs range), they will be down immediately - all it takes is 1-2 Gbits. Your provider is probably going to nullroute your IP, preventing the attacker from taking down the provider’s network, sacrificing your IP for the greater good. On the other hand, if your provider is experienced in mitigating DDoS attacks and has sufficient bandwidth, he will easily be able to mitigate the attacks. They are straight-forward to filter (fixed source port).
The same goes for SYN floods - they either kill your node right away, or are easily defeated or rate limited to insignificance by a competent provider or even a cloud provider’s TCP proxy (see above - GCP and CloudFlare can both proxy TCP connections).
Auto scaling of sentries can help with volumetric attacks, as you would just spawn more sentries until the attacker no longer has sufficient capacities to attack all of them.
The issue is that this requires a lot of resources on your side. Spawning up nodes to match the bandwidth of the attacker can be quite expensive, especially over longer periods of time. While you might remain online during the attack, the attacker is still having the financial upper hand and could potentially blackmail you (he’s not paying for the compromised servers he’s using!).
In order to quickly scale up Cosmos nodes you need to have snapshots of the blockchain data in place because it would otherwise take very long for it to sync with the network. That is another point of failure in case of such an attack especially considering the growing size of the blockchain and the extra infrastructure you need. Additionally, even with recent snapshots, it will take a while for you new node to catch up.
What else to do?
One of the very obvious alternatives and additional security measures is outbound-only nodes as described above, in combination with a global TCP proxy like GCP’s global LB or CloudFlare Spectrum. These can handle bandwidths in excess of most realistic DDoS attacks, without any of the traffic reaching your sentry node. Additionally, chances are that your attacker do not even know the IP address of the node since it only initiates a limited amount of outbound connections. This can even be stripped down to a selected set of peers to further increase security which ultimately leads us to private peers.
With private peers in place, you have got nodes that are not publicly known and in the best case (with potential direct in-cloud peerings or private network interconnects) expose almost no external attack surface. An attacker would have to take down all of the other validators you peer with to prevent them from relaying your messages.
This eliminates most of the DDoS threat - an attacker would have to overwhelm Google’s TCP proxy or CloudFlare spectrum as well as all of your private peers. If he even misses a single node, your validator will still be functional.
We recommend you invest your time into advanced DDoS mitigation setups, good relationships with other validators and a diverse set of sentries running at different providers rather than building a less effective, but complex cloud autoscaling mechanism.


Drones
Sometimes we are like drones. Bringing others down won’t make you fly higher.
Sometimes we are like drones. Bringing others down won’t make you fly higher.
We will have leveled up when this is all over.
Year 2020 has NOT been off to a good start for most of the world, which is why I am now more motivated than ever to squeeze my finite time on Earth to create...
Data science is now a lot more mature than it was back in 2003 (the year when the SARS epidemic struck).
Coal, petroleum, natural gas… You probably guessed it: I am naming common examples of finite energy resources — finite being the operative word.
Just how long is 50 meters?
I am not a historian, but I read every now and then.
Today’s late-night ramblings are in regard to something that one cannot see, but undoubtedly exists nonetheless.
I could tell something must have gone wrong. The last stretches of the highway leading up to Tai Lam Tunnel — including the 3.8-kilometer tunnel itself — wer...
In the tail end of 2018, I built a prototype for a robot photographer. The goal was for it to one day serve as a photographer’s stunt double, so that photojo...


Home
About
Services
Contact Us
Name
Phone Number
Type of service
Location
Select location
Kilimani
Kasarani
Thika
Bahati
Muthaiga
Starehe
Upload your image


Help
This is an application for managing token authentication to a Sonatype Nexus artifact repository. If you are able to authenticate to the Nexus server which this token manager is pointed at, you can manage your own tokens. If you have admin privileges on that Nexus server, you will also be able to manage other user's tokens from this application as well.


Integer Division
Calculate the number of times a given integer fully goes into another given integer.
Counting Up
Write values from 1 to a given value to a memory location, overwriting as the value is incremented.
Multiplication
Multiply two given positive integers together.
Factorial
Calculate the factorial of a given value.
Greatest common factor
Calculate the greatest common factor of 2 integers (AQA A Level 2019 paper 2)


| Top |
You may wish to begin by reading the text widget conceptual overview which gives an overview of all the objects and data types related to the text widget and how they work together.
GtkTextBuffer *
gtk_text_iter_get_buffer (const GtkTextIter *iter
);
Returns the GtkTextBuffer this iterator is associated with.
GtkTextIter *
gtk_text_iter_copy (const GtkTextIter *iter
);
Creates a dynamically-allocated copy of an iterator. This function
is not useful in applications, because iterators can be copied with a
simple assignment (GtkTextIter i = j;
). The
function is used by language bindings.
void gtk_text_iter_assign (GtkTextIter *iter
,const GtkTextIter *other
);
Assigns the value of other
to iter
. This function
is not useful in applications, because iterators can be assigned
with GtkTextIter i = j;
. The
function is used by language bindings.
Since: 3.2
void
gtk_text_iter_free (GtkTextIter *iter
);
Free an iterator allocated on the heap. This function is intended for use in language bindings, and is not especially useful for applications, because iterators can simply be allocated on the stack.
gint
gtk_text_iter_get_offset (const GtkTextIter *iter
);
Returns the character offset of an iterator.
Each character in a GtkTextBuffer has an offset,
starting with 0 for the first character in the buffer.
Use gtk_text_buffer_get_iter_at_offset()
to convert an
offset back into an iterator.
gint
gtk_text_iter_get_line (const GtkTextIter *iter
);
Returns the line number containing the iterator. Lines in a GtkTextBuffer are numbered beginning with 0 for the first line in the buffer.
gint
gtk_text_iter_get_line_offset (const GtkTextIter *iter
);
Returns the character offset of the iterator, counting from the start of a newline-terminated line. The first character on the line has offset 0.
gint
gtk_text_iter_get_line_index (const GtkTextIter *iter
);
Returns the byte index of the iterator, counting from the start of a newline-terminated line. Remember that GtkTextBuffer encodes text in UTF-8, and that characters can require a variable number of bytes to represent.
gint
gtk_text_iter_get_visible_line_index (const GtkTextIter *iter
);
Returns the number of bytes from the start of the
line to the given iter
, not counting bytes that
are invisible due to tags with the “invisible” flag
toggled on.
gint
gtk_text_iter_get_visible_line_offset (const GtkTextIter *iter
);
Returns the offset in characters from the start of the
line to the given iter
, not counting characters that
are invisible due to tags with the “invisible” flag
toggled on.
gunichar
gtk_text_iter_get_char (const GtkTextIter *iter
);
The Unicode character at this iterator is returned. (Equivalent to
operator* on a C++ iterator.) If the element at this iterator is a
non-character element, such as an image embedded in the buffer, the
Unicode “unknown” character 0xFFFC is returned. If invoked on
the end iterator, zero is returned; zero is not a valid Unicode character.
So you can write a loop which ends when gtk_text_iter_get_char()
returns 0.
gchar * gtk_text_iter_get_slice (const GtkTextIter *start
,const GtkTextIter *end
);
Returns the text in the given range. A “slice” is an array of characters encoded in UTF-8 format, including the Unicode “unknown” character 0xFFFC for iterable non-character elements in the buffer, such as images. Because images are encoded in the slice, byte and character offsets in the returned array will correspond to byte offsets in the text buffer. Note that 0xFFFC can occur in normal text as well, so it is not a reliable indicator that a pixbuf or widget is in the buffer.
gchar * gtk_text_iter_get_text (const GtkTextIter *start
,const GtkTextIter *end
);
Returns text in the given range. If the range
contains non-text elements such as images, the character and byte
offsets in the returned string will not correspond to character and
byte offsets in the buffer. If you want offsets to correspond, see
gtk_text_iter_get_slice()
.
gchar * gtk_text_iter_get_visible_slice (const GtkTextIter *start
,const GtkTextIter *end
);
Like gtk_text_iter_get_slice()
, but invisible text is not included.
Invisible text is usually invisible because a GtkTextTag with the
“invisible” attribute turned on has been applied to it.
gchar * gtk_text_iter_get_visible_text (const GtkTextIter *start
,const GtkTextIter *end
);
Like gtk_text_iter_get_text()
, but invisible text is not included.
Invisible text is usually invisible because a GtkTextTag with the
“invisible” attribute turned on has been applied to it.
GdkPixbuf *
gtk_text_iter_get_pixbuf (const GtkTextIter *iter
);
If the element at iter
is a pixbuf, the pixbuf is returned
(with no new reference count added). Otherwise,
NULL
is returned.
GSList *
gtk_text_iter_get_marks (const GtkTextIter *iter
);
Returns a list of all GtkTextMark at this location. Because marks are not iterable (they don’t take up any "space" in the buffer, they are just marks in between iterable locations), multiple marks can exist in the same place. The returned list is not in any meaningful order.
GSList * gtk_text_iter_get_toggled_tags (const GtkTextIter *iter
,gboolean toggled_on
);
Returns a list of GtkTextTag that are toggled on or off at this
point. (If toggled_on
is TRUE
, the list contains tags that are
toggled on.) If a tag is toggled on at iter
, then some non-empty
range of characters following iter
has that tag applied to it. If
a tag is toggled off, then some non-empty range following iter
does not have the tag applied to it.
GtkTextChildAnchor *
gtk_text_iter_get_child_anchor (const GtkTextIter *iter
);
If the location at iter
contains a child anchor, the
anchor is returned (with no new reference count added). Otherwise,
NULL
is returned.
gboolean gtk_text_iter_starts_tag (const GtkTextIter *iter
,GtkTextTag *tag
);
Returns TRUE
if tag
is toggled on at exactly this point. If tag
is NULL
, returns TRUE
if any tag is toggled on at this point.
Note that if gtk_text_iter_starts_tag()
returns TRUE
, it means that iter
is
at the beginning of the tagged range, and that the
character at iter
is inside the tagged range. In other
words, unlike gtk_text_iter_ends_tag()
, if gtk_text_iter_starts_tag()
returns
TRUE
, gtk_text_iter_has_tag()
will also return TRUE
for the same
parameters.
Since: 3.20
gboolean gtk_text_iter_begins_tag (const GtkTextIter *iter
,GtkTextTag *tag
);
gtk_text_iter_begins_tag
has been deprecated since version 3.20 and should not be used in newly-written code.
Use gtk_text_iter_starts_tag()
instead.
Returns TRUE
if tag
is toggled on at exactly this point. If tag
is NULL
, returns TRUE
if any tag is toggled on at this point.
Note that if gtk_text_iter_begins_tag()
returns TRUE
, it means that iter
is
at the beginning of the tagged range, and that the
character at iter
is inside the tagged range. In other
words, unlike gtk_text_iter_ends_tag()
, if gtk_text_iter_begins_tag()
returns
TRUE
, gtk_text_iter_has_tag()
will also return TRUE
for the same
parameters.
gboolean gtk_text_iter_ends_tag (const GtkTextIter *iter
,GtkTextTag *tag
);
Returns TRUE
if tag
is toggled off at exactly this point. If tag
is NULL
, returns TRUE
if any tag is toggled off at this point.
Note that if gtk_text_iter_ends_tag()
returns TRUE
, it means that iter
is
at the end of the tagged range, but that the character
at iter
is outside the tagged range. In other words,
unlike gtk_text_iter_starts_tag()
, if gtk_text_iter_ends_tag()
returns TRUE
,
gtk_text_iter_has_tag()
will return FALSE
for the same parameters.
gboolean gtk_text_iter_toggles_tag (const GtkTextIter *iter
,GtkTextTag *tag
);
This is equivalent to (gtk_text_iter_starts_tag()
||
gtk_text_iter_ends_tag()
), i.e. it tells you whether a range with
tag
applied to it begins or ends at iter
.
gboolean gtk_text_iter_has_tag (const GtkTextIter *iter
,GtkTextTag *tag
);
Returns TRUE
if iter
points to a character that is part of a range tagged
with tag
. See also gtk_text_iter_starts_tag()
and gtk_text_iter_ends_tag()
.
GSList *
gtk_text_iter_get_tags (const GtkTextIter *iter
);
Returns a list of tags that apply to iter
, in ascending order of
priority (highest-priority tags are last). The GtkTextTag in the
list don’t have a reference added, but you have to free the list
itself.
gboolean gtk_text_iter_editable (const GtkTextIter *iter
,gboolean default_setting
);
Returns whether the character at iter
is within an editable region
of text. Non-editable text is “locked” and can’t be changed by the
user via GtkTextView. This function is simply a convenience
wrapper around gtk_text_iter_get_attributes()
. If no tags applied
to this text affect editability, default_setting
will be returned.
You don’t want to use this function to decide whether text can be
inserted at iter
, because for insertion you don’t want to know
whether the char at iter
is inside an editable range, you want to
know whether a new character inserted at iter
would be inside an
editable range. Use gtk_text_iter_can_insert()
to handle this
case.
gboolean gtk_text_iter_can_insert (const GtkTextIter *iter
,gboolean default_editability
);
Considering the default editability of the buffer, and tags that
affect editability, determines whether text inserted at iter
would
be editable. If text inserted at iter
would be editable then the
user should be allowed to insert text at iter
.
gtk_text_buffer_insert_interactive()
uses this function to decide
whether insertions are allowed at a given position.
gboolean
gtk_text_iter_starts_word (const GtkTextIter *iter
);
Determines whether iter
begins a natural-language word. Word
breaks are determined by Pango and should be correct for nearly any
language (if not, the correct fix would be to the Pango word break
algorithms).
gboolean
gtk_text_iter_ends_word (const GtkTextIter *iter
);
Determines whether iter
ends a natural-language word. Word breaks
are determined by Pango and should be correct for nearly any
language (if not, the correct fix would be to the Pango word break
algorithms).
gboolean
gtk_text_iter_inside_word (const GtkTextIter *iter
);
Determines whether the character pointed by iter
is part of a
natural-language word (as opposed to say inside some whitespace). Word
breaks are determined by Pango and should be correct for nearly any language
(if not, the correct fix would be to the Pango word break algorithms).
Note that if gtk_text_iter_starts_word()
returns TRUE
, then this function
returns TRUE
too, since iter
points to the first character of the word.
gboolean
gtk_text_iter_starts_line (const GtkTextIter *iter
);
Returns TRUE
if iter
begins a paragraph,
i.e. if gtk_text_iter_get_line_offset()
would return 0.
However this function is potentially more efficient than
gtk_text_iter_get_line_offset()
because it doesn’t have to compute
the offset, it just has to see whether it’s 0.
gboolean
gtk_text_iter_ends_line (const GtkTextIter *iter
);
Returns TRUE
if iter
points to the start of the paragraph
delimiter characters for a line (delimiters will be either a
newline, a carriage return, a carriage return followed by a
newline, or a Unicode paragraph separator character). Note that an
iterator pointing to the \n of a \r\n pair will not be counted as
the end of a line, the line ends before the \r. The end iterator is
considered to be at the end of a line, even though there are no
paragraph delimiter chars there.
gboolean
gtk_text_iter_starts_sentence (const GtkTextIter *iter
);
Determines whether iter
begins a sentence. Sentence boundaries are
determined by Pango and should be correct for nearly any language
(if not, the correct fix would be to the Pango text boundary
algorithms).
gboolean
gtk_text_iter_ends_sentence (const GtkTextIter *iter
);
Determines whether iter
ends a sentence. Sentence boundaries are
determined by Pango and should be correct for nearly any language
(if not, the correct fix would be to the Pango text boundary
algorithms).
gboolean
gtk_text_iter_inside_sentence (const GtkTextIter *iter
);
Determines whether iter
is inside a sentence (as opposed to in
between two sentences, e.g. after a period and before the first
letter of the next sentence). Sentence boundaries are determined
by Pango and should be correct for nearly any language (if not, the
correct fix would be to the Pango text boundary algorithms).
gboolean
gtk_text_iter_is_cursor_position (const GtkTextIter *iter
);
See gtk_text_iter_forward_cursor_position()
or PangoLogAttr or
pango_break()
for details on what a cursor position is.
gint
gtk_text_iter_get_chars_in_line (const GtkTextIter *iter
);
Returns the number of characters in the line containing iter
,
including the paragraph delimiters.
gint
gtk_text_iter_get_bytes_in_line (const GtkTextIter *iter
);
Returns the number of bytes in the line containing iter
,
including the paragraph delimiters.
gboolean gtk_text_iter_get_attributes (const GtkTextIter *iter
,GtkTextAttributes *values
);
Computes the effect of any tags applied to this spot in the
text. The values
parameter should be initialized to the default
settings you wish to use if no tags are in effect. You’d typically
obtain the defaults from gtk_text_view_get_default_attributes()
.
gtk_text_iter_get_attributes() will modify values
, applying the
effects of any tags present at iter
. If any tags affected values
,
the function returns TRUE
.
PangoLanguage *
gtk_text_iter_get_language (const GtkTextIter *iter
);
A convenience wrapper around gtk_text_iter_get_attributes()
,
which returns the language in effect at iter
. If no tags affecting
language apply to iter
, the return value is identical to that of
gtk_get_default_language()
.
gboolean
gtk_text_iter_is_end (const GtkTextIter *iter
);
Returns TRUE
if iter
is the end iterator, i.e. one past the last
dereferenceable iterator in the buffer. gtk_text_iter_is_end()
is
the most efficient way to check whether an iterator is the end
iterator.
gboolean
gtk_text_iter_is_start (const GtkTextIter *iter
);
Returns TRUE
if iter
is the first iterator in the buffer, that is
if iter
has a character offset of 0.
gboolean
gtk_text_iter_forward_char (GtkTextIter *iter
);
Moves iter
forward by one character offset. Note that images
embedded in the buffer occupy 1 character slot, so
gtk_text_iter_forward_char()
may actually move onto an image instead
of a character, if you have images in your buffer. If iter
is the
end iterator or one character before it, iter
will now point at
the end iterator, and gtk_text_iter_forward_char()
returns FALSE
for
convenience when writing loops.
gboolean
gtk_text_iter_backward_char (GtkTextIter *iter
);
Moves backward by one character offset. Returns TRUE
if movement
was possible; if iter
was the first in the buffer (character
offset 0), gtk_text_iter_backward_char()
returns FALSE
for convenience when
writing loops.
gboolean gtk_text_iter_forward_chars (GtkTextIter *iter
,gint count
);
Moves count
characters if possible (if count
would move past the
start or end of the buffer, moves to the start or end of the
buffer). The return value indicates whether the new position of
iter
is different from its original position, and dereferenceable
(the last iterator in the buffer is not dereferenceable). If count
is 0, the function does nothing and returns FALSE
.
gboolean gtk_text_iter_backward_chars (GtkTextIter *iter
,gint count
);
Moves count
characters backward, if possible (if count
would move
past the start or end of the buffer, moves to the start or end of
the buffer). The return value indicates whether the iterator moved
onto a dereferenceable position; if the iterator didn’t move, or
moved onto the end iterator, then FALSE
is returned. If count
is 0,
the function does nothing and returns FALSE
.
gboolean
gtk_text_iter_forward_line (GtkTextIter *iter
);
Moves iter
to the start of the next line. If the iter is already on the
last line of the buffer, moves the iter to the end of the current line.
If after the operation, the iter is at the end of the buffer and not
dereferencable, returns FALSE
. Otherwise, returns TRUE
.
gboolean
gtk_text_iter_backward_line (GtkTextIter *iter
);
Moves iter
to the start of the previous line. Returns TRUE
if
iter
could be moved; i.e. if iter
was at character offset 0, this
function returns FALSE
. Therefore if iter
was already on line 0,
but not at the start of the line, iter
is snapped to the start of
the line and the function returns TRUE
. (Note that this implies that
in a loop calling this function, the line number may not change on
every iteration, if your first iteration is on line 0.)
gboolean gtk_text_iter_forward_lines (GtkTextIter *iter
,gint count
);
Moves count
lines forward, if possible (if count
would move
past the start or end of the buffer, moves to the start or end of
the buffer). The return value indicates whether the iterator moved
onto a dereferenceable position; if the iterator didn’t move, or
moved onto the end iterator, then FALSE
is returned. If count
is 0,
the function does nothing and returns FALSE
. If count
is negative,
moves backward by 0 - count
lines.
gboolean gtk_text_iter_backward_lines (GtkTextIter *iter
,gint count
);
Moves count
lines backward, if possible (if count
would move
past the start or end of the buffer, moves to the start or end of
the buffer). The return value indicates whether the iterator moved
onto a dereferenceable position; if the iterator didn’t move, or
moved onto the end iterator, then FALSE
is returned. If count
is 0,
the function does nothing and returns FALSE
. If count
is negative,
moves forward by 0 - count
lines.
gboolean gtk_text_iter_forward_word_ends (GtkTextIter *iter
,gint count
);
Calls gtk_text_iter_forward_word_end()
up to count
times.
gboolean gtk_text_iter_backward_word_starts (GtkTextIter *iter
,gint count
);
Calls gtk_text_iter_backward_word_start()
up to count
times.
gboolean
gtk_text_iter_forward_word_end (GtkTextIter *iter
);
Moves forward to the next word end. (If iter
is currently on a
word end, moves forward to the next one after that.) Word breaks
are determined by Pango and should be correct for nearly any
language (if not, the correct fix would be to the Pango word break
algorithms).
gboolean
gtk_text_iter_backward_word_start (GtkTextIter *iter
);
Moves backward to the previous word start. (If iter
is currently on a
word start, moves backward to the next one after that.) Word breaks
are determined by Pango and should be correct for nearly any
language (if not, the correct fix would be to the Pango word break
algorithms).
gboolean
gtk_text_iter_forward_cursor_position (GtkTextIter *iter
);
Moves iter
forward by a single cursor position. Cursor positions
are (unsurprisingly) positions where the cursor can appear. Perhaps
surprisingly, there may not be a cursor position between all
characters. The most common example for European languages would be
a carriage return/newline sequence. For some Unicode characters,
the equivalent of say the letter “a” with an accent mark will be
represented as two characters, first the letter then a "combining
mark" that causes the accent to be rendered; so the cursor can’t go
between those two characters. See also the PangoLogAttr and
pango_break()
function.
gboolean
gtk_text_iter_backward_cursor_position
(GtkTextIter *iter
);
Like gtk_text_iter_forward_cursor_position()
, but moves backward.
gboolean gtk_text_iter_forward_cursor_positions (GtkTextIter *iter
,gint count
);
Moves up to count
cursor positions. See
gtk_text_iter_forward_cursor_position()
for details.
gboolean gtk_text_iter_backward_cursor_positions (GtkTextIter *iter
,gint count
);
Moves up to count
cursor positions. See
gtk_text_iter_forward_cursor_position()
for details.
gboolean
gtk_text_iter_backward_sentence_start (GtkTextIter *iter
);
Moves backward to the previous sentence start; if iter
is already at
the start of a sentence, moves backward to the next one. Sentence
boundaries are determined by Pango and should be correct for nearly
any language (if not, the correct fix would be to the Pango text
boundary algorithms).
gboolean gtk_text_iter_backward_sentence_starts (GtkTextIter *iter
,gint count
);
Calls gtk_text_iter_backward_sentence_start()
up to count
times,
or until it returns FALSE
. If count
is negative, moves forward
instead of backward.
gboolean
gtk_text_iter_forward_sentence_end (GtkTextIter *iter
);
Moves forward to the next sentence end. (If iter
is at the end of
a sentence, moves to the next end of sentence.) Sentence
boundaries are determined by Pango and should be correct for nearly
any language (if not, the correct fix would be to the Pango text
boundary algorithms).
gboolean gtk_text_iter_forward_sentence_ends (GtkTextIter *iter
,gint count
);
Calls gtk_text_iter_forward_sentence_end()
count
times (or until
gtk_text_iter_forward_sentence_end()
returns FALSE
). If count
is
negative, moves backward instead of forward.
gboolean gtk_text_iter_forward_visible_word_ends (GtkTextIter *iter
,gint count
);
Calls gtk_text_iter_forward_visible_word_end()
up to count
times.
Since: 2.4
gboolean gtk_text_iter_backward_visible_word_starts (GtkTextIter *iter
,gint count
);
Calls gtk_text_iter_backward_visible_word_start()
up to count
times.
Since: 2.4
gboolean
gtk_text_iter_forward_visible_word_end
(GtkTextIter *iter
);
Moves forward to the next visible word end. (If iter
is currently on a
word end, moves forward to the next one after that.) Word breaks
are determined by Pango and should be correct for nearly any
language (if not, the correct fix would be to the Pango word break
algorithms).
Since: 2.4
gboolean
gtk_text_iter_backward_visible_word_start
(GtkTextIter *iter
);
Moves backward to the previous visible word start. (If iter
is currently
on a word start, moves backward to the next one after that.) Word breaks
are determined by Pango and should be correct for nearly any
language (if not, the correct fix would be to the Pango word break
algorithms).
Since: 2.4
gboolean
gtk_text_iter_forward_visible_cursor_position
(GtkTextIter *iter
);
Moves iter
forward to the next visible cursor position. See
gtk_text_iter_forward_cursor_position()
for details.
Since: 2.4
gboolean
gtk_text_iter_backward_visible_cursor_position
(GtkTextIter *iter
);
Moves iter
forward to the previous visible cursor position. See
gtk_text_iter_backward_cursor_position()
for details.
Since: 2.4
gboolean gtk_text_iter_forward_visible_cursor_positions (GtkTextIter *iter
,gint count
);
Moves up to count
visible cursor positions. See
gtk_text_iter_forward_cursor_position()
for details.
Since: 2.4
gboolean gtk_text_iter_backward_visible_cursor_positions (GtkTextIter *iter
,gint count
);
Moves up to count
visible cursor positions. See
gtk_text_iter_backward_cursor_position()
for details.
Since: 2.4
gboolean
gtk_text_iter_forward_visible_line (GtkTextIter *iter
);
Moves iter
to the start of the next visible line. Returns TRUE
if there
was a next line to move to, and FALSE
if iter
was simply moved to
the end of the buffer and is now not dereferenceable, or if iter
was
already at the end of the buffer.
Since: 2.8
gboolean
gtk_text_iter_backward_visible_line (GtkTextIter *iter
);
Moves iter
to the start of the previous visible line. Returns TRUE
if
iter
could be moved; i.e. if iter
was at character offset 0, this
function returns FALSE
. Therefore if iter
was already on line 0,
but not at the start of the line, iter
is snapped to the start of
the line and the function returns TRUE
. (Note that this implies that
in a loop calling this function, the line number may not change on
every iteration, if your first iteration is on line 0.)
Since: 2.8
gboolean gtk_text_iter_forward_visible_lines (GtkTextIter *iter
,gint count
);
Moves count
visible lines forward, if possible (if count
would move
past the start or end of the buffer, moves to the start or end of
the buffer). The return value indicates whether the iterator moved
onto a dereferenceable position; if the iterator didn’t move, or
moved onto the end iterator, then FALSE
is returned. If count
is 0,
the function does nothing and returns FALSE
. If count
is negative,
moves backward by 0 - count
lines.
Since: 2.8
gboolean gtk_text_iter_backward_visible_lines (GtkTextIter *iter
,gint count
);
Moves count
visible lines backward, if possible (if count
would move
past the start or end of the buffer, moves to the start or end of
the buffer). The return value indicates whether the iterator moved
onto a dereferenceable position; if the iterator didn’t move, or
moved onto the end iterator, then FALSE
is returned. If count
is 0,
the function does nothing and returns FALSE
. If count
is negative,
moves forward by 0 - count
lines.
Since: 2.8
void gtk_text_iter_set_offset (GtkTextIter *iter
,gint char_offset
);
Sets iter
to point to char_offset
. char_offset
counts from the start
of the entire text buffer, starting with 0.
void gtk_text_iter_set_line (GtkTextIter *iter
,gint line_number
);
Moves iterator iter
to the start of the line line_number
. If
line_number
is negative or larger than the number of lines in the
buffer, moves iter
to the start of the last line in the buffer.
void gtk_text_iter_set_line_offset (GtkTextIter *iter
,gint char_on_line
);
Moves iter
within a line, to a new character
(not byte) offset. The given character offset must be less than or
equal to the number of characters in the line; if equal, iter
moves to the start of the next line. See
gtk_text_iter_set_line_index()
if you have a byte index rather than
a character offset.
void gtk_text_iter_set_line_index (GtkTextIter *iter
,gint byte_on_line
);
Same as gtk_text_iter_set_line_offset()
, but works with a
byte index. The given byte index must be at
the start of a character, it can’t be in the middle of a UTF-8
encoded character.
void gtk_text_iter_set_visible_line_index (GtkTextIter *iter
,gint byte_on_line
);
Like gtk_text_iter_set_line_index()
, but the index is in visible
bytes, i.e. text with a tag making it invisible is not counted
in the index.
void gtk_text_iter_set_visible_line_offset (GtkTextIter *iter
,gint char_on_line
);
Like gtk_text_iter_set_line_offset()
, but the offset is in visible
characters, i.e. text with a tag making it invisible is not
counted in the offset.
void
gtk_text_iter_forward_to_end (GtkTextIter *iter
);
Moves iter
forward to the “end iterator,” which points one past the last
valid character in the buffer. gtk_text_iter_get_char()
called on the
end iterator returns 0, which is convenient for writing loops.
gboolean
gtk_text_iter_forward_to_line_end (GtkTextIter *iter
);
Moves the iterator to point to the paragraph delimiter characters,
which will be either a newline, a carriage return, a carriage
return/newline in sequence, or the Unicode paragraph separator
character. If the iterator is already at the paragraph delimiter
characters, moves to the paragraph delimiter characters for the
next line. If iter
is on the last line in the buffer, which does
not end in paragraph delimiters, moves to the end iterator (end of
the last line), and returns FALSE
.
gboolean gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter
,GtkTextTag *tag
);
Moves forward to the next toggle (on or off) of the
GtkTextTag tag
, or to the next toggle of any tag if
tag
is NULL
. If no matching tag toggles are found,
returns FALSE
, otherwise TRUE
. Does not return toggles
located at iter
, only toggles after iter
. Sets iter
to
the location of the toggle, or to the end of the buffer
if no toggle is found.
gboolean gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter
,GtkTextTag *tag
);
Moves backward to the next toggle (on or off) of the
GtkTextTag tag
, or to the next toggle of any tag if
tag
is NULL
. If no matching tag toggles are found,
returns FALSE
, otherwise TRUE
. Does not return toggles
located at iter
, only toggles before iter
. Sets iter
to the location of the toggle, or the start of the buffer
if no toggle is found.
gboolean gtk_text_iter_forward_find_char (GtkTextIter *iter
,GtkTextCharPredicate pred
,gpointer user_data
,const GtkTextIter *limit
);
Advances iter
, calling pred
on each character. If
pred
returns TRUE
, returns TRUE
and stops scanning.
If pred
never returns TRUE
, iter
is set to limit
if
limit
is non-NULL
, otherwise to the end iterator.
iter |
||
pred |
a function to be called on each character. |
[scope call] |
user_data |
user data for |
|
limit |
search limit, or |
[allow-none] |
gboolean gtk_text_iter_backward_find_char (GtkTextIter *iter
,GtkTextCharPredicate pred
,gpointer user_data
,const GtkTextIter *limit
);
Same as gtk_text_iter_forward_find_char()
, but goes backward from iter
.
iter |
||
pred |
function to be called on each character. |
[scope call] |
user_data |
user data for |
|
limit |
search limit, or |
[allow-none] |
gboolean gtk_text_iter_forward_search (const GtkTextIter *iter
,const gchar *str
,GtkTextSearchFlags flags
,GtkTextIter *match_start
,GtkTextIter *match_end
,const GtkTextIter *limit
);
Searches forward for str
. Any match is returned by setting
match_start
to the first character of the match and match_end
to the
first character after the match. The search will not continue past
limit
. Note that a search is a linear or O(n) operation, so you
may wish to use limit
to avoid locking up your UI on large
buffers.
match_start
will never be set to a GtkTextIter located before iter
, even if
there is a possible match_end
after or at iter
.
iter |
start of search |
|
str |
a search string |
|
flags |
flags affecting how the search is done |
|
match_start |
return location for start of match, or |
[out caller-allocates][allow-none] |
match_end |
return location for end of match, or |
[out caller-allocates][allow-none] |
limit |
location of last possible |
[allow-none] |
gboolean gtk_text_iter_backward_search (const GtkTextIter *iter
,const gchar *str
,GtkTextSearchFlags flags
,GtkTextIter *match_start
,GtkTextIter *match_end
,const GtkTextIter *limit
);
Same as gtk_text_iter_forward_search()
, but moves backward.
match_end
will never be set to a GtkTextIter located after iter
, even if
there is a possible match_start
before or at iter
.
iter |
a GtkTextIter where the search begins |
|
str |
search string |
|
flags |
bitmask of flags affecting the search |
|
match_start |
return location for start of match, or |
[out caller-allocates][allow-none] |
match_end |
return location for end of match, or |
[out caller-allocates][allow-none] |
limit |
location of last possible |
[allow-none] |
gboolean gtk_text_iter_equal (const GtkTextIter *lhs
,const GtkTextIter *rhs
);
Tests whether two iterators are equal, using the fastest possible
mechanism. This function is very fast; you can expect it to perform
better than e.g. getting the character offset for each iterator and
comparing the offsets yourself. Also, it’s a bit faster than
gtk_text_iter_compare()
.
gint gtk_text_iter_compare (const GtkTextIter *lhs
,const GtkTextIter *rhs
);
A qsort()
-style function that returns negative if lhs
is less than
rhs
, positive if lhs
is greater than rhs
, and 0 if they’re equal.
Ordering is in character offset order, i.e. the first character in the buffer
is less than the second character in the buffer.
gboolean gtk_text_iter_in_range (const GtkTextIter *iter
,const GtkTextIter *start
,const GtkTextIter *end
);
Checks whether iter
falls in the range [start
, end
).
start
and end
must be in ascending order.
void gtk_text_iter_order (GtkTextIter *first
,GtkTextIter *second
);
Swaps the value of first
and second
if second
comes before
first
in the buffer. That is, ensures that first
and second
are
in sequence. Most text buffer functions that take a range call this
automatically on your behalf, so there’s no real reason to call it yourself
in those cases. There are some exceptions, such as gtk_text_iter_in_range()
,
that expect a pre-sorted range.
typedef struct { /* GtkTextIter is an opaque datatype; ignore all these fields. * Initialize the iter with gtk_text_buffer_get_iter_* * functions */ } GtkTextIter;
Flags affecting how a search is done.
If neither GTK_TEXT_SEARCH_VISIBLE_ONLY nor GTK_TEXT_SEARCH_TEXT_ONLY are enabled, the match must be exact; the special 0xFFFC character will match embedded pixbufs or child widgets.


{{#each products as |result key|}}
{{#each custom_fields}}
{{#if name '==' 'Razors'}}
-
{{>components/common/custom/card product=result settings=../settings show_rating=../settings.show_product_rating theme_settings=../theme_settings customer=../customer event=../event position=(add @index 1)}}
{{/if}}
{{/each}}
{{/each}}
{{#each products as |result key|}}
{{#each custom_fields}}
{{#if name '==' 'Body'}}
-
{{>components/common/custom/card product=result settings=../settings show_rating=../settings.show_product_rating theme_settings=../theme_settings customer=../customer event=../event position=(add @index 1)}}
{{/if}}
{{/each}}
{{/each}}
{{#each products as |result key|}}
{{#each custom_fields}}
{{#if name '==' 'Face'}}
-
{{>components/common/custom/card product=result settings=../settings show_rating=../settings.show_product_rating theme_settings=../theme_settings customer=../customer event=../event position=(add @index 1)}}
{{/if}}
{{/each}}
{{/each}}
{{#each products as |result key|}}
{{#each custom_fields}}
{{#if name '==' 'Gifts & Kits'}}
-
{{>components/common/custom/card product=result settings=../settings show_rating=../settings.show_product_rating theme_settings=../theme_settings customer=../customer event=../event position=(add @index 1)}}
{{/if}}
{{/each}}
{{/each}}


[ht::head {NLAS Harvesters}] One way to add LiDAR data sets to RAMADDA is to set up a LiDAR Collection harvester in RAMADDA. This is a special purpose instance of the general purpose File Harvester facility that RAMADDA provides.
A Harvester is configured to scan a specified server-side file system directory tree. A pattern can be provided to determine what files should be harvested. The harvester will automatically detect new LiDAR files and load them into RAMADDA. You have the option of leaving the files in place or moving them into RAMADDA's data store.
mcgowan:ls lvis LVIS_Antarctica_2009/ LVIS_Costa_Rica/ LVIS_Arkansas/ LVIS_Greenland/ LVIS_California/ LVIS_NH_Bartlett_Forest/ mcgowan:ls lvis/LVIS_Arkansas/ LVIS_US_AR_2006_20080819.lceThat we want to map into the RAMADDA repository so that the LVIS_... directories are represented with RAMADDA LiDAR Collections and the files are LiDAR Data as shown here.
The Harvester we have set up points to the top-level lvis directory. When it scans it walks the tree down and discovers a file (e.g., LVIS_US_AR_2006_20080819.lce). The harvester creates a LiDAR Collection folder from the parent directory of the file (e.g., LVIS_Arkansas). It replaces any underscore "_" with a space " " and uses that as the name of the collection entry. The file is then ingested and scanned to extract spatial metadata. The new LiDAR Data entry is then created with the parent collection entry.
The NLAS plugin provides a special purpose LiDAR Collection harvester. This harvester type creates the right kind of folder and entry types for the harvested data. To create a harvester you need to be a site administrator. From the [ht::menu Admin Harvesters] page select the New Harvester button. Enter a name for your harvester and for Type select "LiDAR Collection" in the form: [ht::cimg images/newharvester.png {New Harvester Form} {border=0 width=600}] The Harvester edit form is the same as for the general purpose File Harvester facility in RAMADDA. The only difference is the Entry Types are just the LiDAR Data entry types.
Enter the server file system directory, the destination RAMADDA folder and, optionally, select a LiDAR entry type. The harvester can be configured to automatically run on a specified schedule. [ht::foot]


:navtop
+callout-info
We are going to use an example [https://ramadda.org/repository/a/example_map_file IMDV entry]
that shows the below map.
To explore this example
import the
https://ramadda.org/repository/a/userguide_boulder_county_outdoors file.
-callout
:heading Adding a Map
The IMDV supports adding a number of map file formats - GeoJson, GPX, KML/KMZ and Shapefile.
To add a map file to an IMDV entry first upload the file to RAMADDA.
The IMDV entry can act as a folder so you can upload the file under the IMDV or elsewhere
in your RAMADDA.
:p
From the IMDV New menu, select "Map File". The Map Entry selector will be shown:
Navigate through your RAMADDA entry hierarchy and select the map file.
You can also drag-and-drop the map file directly onto the IMDV map.
Note: by storing the map file as a child entry of the IMDV entry then you
can export the IMDV entry and the map file will be included in the export.
Once added the IMDV will zoom to the map area.
If there are properties defined in your map file
then a Filters area will shown. These allow you to toggle on/off the map features.
:p
We're going to go through the set of steps to create the below map display.
The configuration includes:
* Configuring the popup display
* Changing the label of the "Own Type Name" to "Ownership"
* Only showing the Acreage and Ownership filters
* Add a "Closed" Style Group
* Color coding based on Ownership type
* Adding a label to the top of the legend
* Adding a color bar header
:heading Popup Text
The Properties dialog for the map file can be
brought up with the
link.
:p
The Popup Text can contain arbitrary HTML as well as macros
corresponding to the properties in the map file.
Note: the source names of the source properties are cleaned
up and lower-cased to get the property IDs
used in these settings.
:p
For example, the below image shows the Popup Text that creates the displayed
popup. The "prop_name" property is used as a header and the ownership, acquired year
and acreage properties are shown.
:heading Feature Flags
The Feature Flags section allows you to configure the labels used for the map properties,
what search properties are shown, etc. Clicking on one of the links under "Add Property"
will add that flag to the list.
:p
The below Flags changes the label of the own_type_name to "Ownership".
The filter.show=false flag hides all filters but the <property>.filter.show=true
flags causes those two filters to be shown.
The IMDV guesses as to what type of data is a property and provides an appropriate search widget.
If you want to force the search widget to be a different type you can enter:
some_property.filter.type=enumeration
:heading Map Styles
The
Style section of the settings dialog lets you specify the standard set of map styles, e.g.,
stroke color, stroke width, fill color, etc.
In our example we've changed the Stroke Color to be gray and the Stroke Width to be 1.
:p
The
Style Rules section allows you to specify how to style each individual feature based on
the feature properties.
With
Fill Colors checked the map polygons will be colored with a set of categorical colors.
The
Map value to fill color and
Map value to stroke color allows you to specify
a property that is mapped into a colortable. If it is a numeric property then you can also
specify a min/max range.
:p
The
Style Rules allows you to specify specific property value tests mapped to a set of styles.
In our example we color any feature with
Ownership="County Conservation Easement" with green and Ownership="County Owned Open Space" with blue.
Mouse over the styles to see the format, e.g.:
fillColor:red
fillOpacity:0.5
strokeColor:blue
strokeWidth:2
strokeDashstyle:solid|dot|dash|dashdot|longdash|longdashdot
externalGraphic:/repository/map/marker-blue.png
:p
The
Style Groups section allows you to specify one or more groups and the corresponding styles
for those groups. This enables you to "paint" specific polygons in the map.
These groups will show up in the legend. Selecting a group in the legend and then selecting
a polygon in the map will add that polygon to the group.
:p
In our example we've defined a style group called "Closed" with fill color red and diagonal striping.
The
Labels section allows you to specify a template (similar to the popup text) for a label
for each polygon.
:heading Other Configuration
The top-level properties for the IMDV entry are available through the File->Properties menu item.
:p
The color legend bar at the top of the map is defined with the Header under the Header/Footer tab.
This can be arbitrary wiki text. In this case we are using the display_legend wiki tag.
The "Explore the trails map with the below filters" top-level legend label and the
legend width are defined in the Other Properties section.


--- layout: post title: 'World Telemedia Day 2: High Resolution 3D and the future of mobile content, Phil Atkin, nVidia' date: 2005-11-17 00:00:00 categories: business interfaces-&-interaction mobile play ---
World Telemedia Day 2: High Resolution 3D and the future of mobile content, Phil Atkin, nVidia
"A short history of NVIDIA... through real-time hair"
A history of PC games. Turning point was GLQuake with rendered lighting behaviours.
So what happened? Low-cost 3D accelerators. OpenGL, the first cross-platform standard. High-performance CPUs became available.
Games need: powerful CPUs. Standardised 3D APIs. Affordable 3D acceleration. I'd disagree with all these for mobile.
Java is not the best solution for gaming; it's interpreted, unresponsive, etc. JSRs help out here (JSR-184). BREW is good. Still no GLQuake yet.
Demo of Quake on a handset.
3D titles scale better to different resolutions so are more portable (sounds tenuous to me but hey I'm not a game developer).
"Phones are more like arcade machines than consoles": short play sessions.
Why 3D necessarily - just cos that's what console games did?


If you have a question that's not addressed in the FAQ, or you simply want to get in touch with us, use one of the tabs below:
We use discord as our primary method of communication. Join our live, interactive chat during the show, or simply pop in to tell us about your latest development project. We're a friendly bunch!
No tech project's web presence is complete without social media channels. We're plugged in to a few - check them out below:


Here you can upload your Digicam Business Card
About WiiLink24
WiiLink24 is a revival service for the now-defunct Japanese exclusive Wii channels. This service will (soon) allow you to use Wii no Ma, Demae Channel, and Digicam Print Channel.
2020-2021 WiiLink24 Team
We are not associated with Nintendo nor its affiliates. We are also not associated with the staff of any other online services for the Wii.


-------------------------------------------------------------------------------- -- light52_muldiv.vhdl -- Simple multiplier/divider module. -------------------------------------------------------------------------------- -- The 8051 mul and div instructions are both unsigned and operands are 8 bit. -- -- This module implements the division as a sequential state machine which takes -- 8 cycles to complete. -- The multiplier can be implemented as sequential or as combinational, in which -- case it will use a DSP block in those architectures that support it. -- No attempt has been made to make this module generic or reusable. -- -- If you want a combinational multiplier but don't want to waste a DSP block -- in this module, you need to modify this file adding whatever synthesis -- pragmas your tool of choice needs. -- -- Note that unlike the division state machine, the combinational product logic -- is always operating: when SEQUENTIAL_MULTIPLIER=true, prod_out equals -- data_a * data_b with a latency of 1 clock cycle, and mul_ready is hardwired -- to '1'. -- -- FIXME explain division algorithm. -------------------------------------------------------------------------------- -- GENERICS: -- -- SEQUENTIAL_MULTIPLIER -- Sequential vs. combinational multiplier. -- When true, a sequential implementation will be used for the multiplier, -- which will usually save a lot of logic or a dedicated multiplier. -- When false, a combinational registered multiplier will be used. -- -------------------------------------------------------------------------------- -- INTERFACE SIGNALS: -- -- clk : Clock, active rising edge. -- reset : Synchronous reset. Clears only the control registers not -- visible to the programmer -- not the output registers. -- -- data_a : Numerator input, should be connected to the ACC register. -- data_b : Denominator input, should be connected to the B register. -- start : Assert for 1 cycle to start the division state machine -- (and the product if SEQUENTIAL_MULTIPLIER=true); -- -- prod_out : Product output, valid only when mul_ready='1'. -- quot_out : Quotient output, valid only when div_ready='1'. -- rem_out : Remainder output, valid only when div_ready='1'. -- div_ov_out : Division overflow flag, valid only when div_ready='1'. -- mul_ov_out : Product overflow flag, valid only when mul_ready='1'. -- -- mul_ready : Asserted permanently if SEQUENTIAL_MULTIPLIER=false. -- div_ready : Deasserted the cycle after start is asserted. -- Asserted when the division has completed. -- -------------------------------------------------------------------------------- -- Copyright (C) 2012 Jose A. Ruiz -- -- This source file may be used and distributed without -- restriction provided that this copyright statement is not -- removed from the file and that any derivative work contains -- the original copyright notice and the associated disclaimer. -- -- This source file is free software; you can redistribute it -- and/or modify it under the terms of the GNU Lesser General -- Public License as published by the Free Software Foundation; -- either version 2.1 of the License, or (at your option) any -- later version. -- -- This source is distributed in the hope that it will be -- useful, but WITHOUT ANY WARRANTY; without even the implied -- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR -- PURPOSE. See the GNU Lesser General Public License for more -- details. -- -- You should have received a copy of the GNU Lesser General -- Public License along with this source; if not, download it -- from http://www.opencores.org/lgpl.shtml -------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.light52_pkg.all; use work.light52_ucode_pkg.all; entity light52_muldiv is generic ( SEQUENTIAL_MULTIPLIER : boolean := false ); port( clk : in std_logic; reset : in std_logic; data_a : in t_byte; data_b : in t_byte; start : in std_logic; prod_out : out t_word; quot_out : out t_byte; rem_out : out t_byte; div_ov_out : out std_logic; mul_ov_out : out std_logic; mul_ready : out std_logic; div_ready : out std_logic ); end entity light52_muldiv; architecture sequential of light52_muldiv is signal bit_ctr : integer range 0 to 8; signal b_shift_reg : t_word; signal den_ge_256 : std_logic; signal num_ge_den : std_logic; signal sub_num : std_logic; signal denominator : t_byte; signal rem_reg : t_byte; signal quot_reg : t_byte; signal prod_reg : t_word; signal ready : std_logic; signal load_regs : std_logic; begin -- Control logic --------------------------------------------------------------- control_counter: process(clk) begin if clk'event and clk='1' then if reset='1' then bit_ctr <= 8; else if load_regs='1' then bit_ctr <= 0; elsif bit_ctr /= 8 then bit_ctr <= bit_ctr + 1; end if; end if; end if; end process control_counter; -- Internal signal ready is asserted after 8 cycles. -- The sequential multiplier will use this signal too, IF it takes 8 cycles. ready <= '1' when bit_ctr >= 8 else '0'; ---- Divider logic ------------------------------------------------------------- -- What we do is a simple base-2 'shift-and-subtract' algorithm that takes -- 8 cycles to complete. We can get away with this because we deal with unsigned -- numbers only. divider_registers: process(clk) begin if clk'event and clk='1' then -- denominator shift register if load_regs='1' then b_shift_reg <= "0" & data_b & "0000000"; -- Division overflow can be determined upon loading B reg data. -- OV will be raised only on div-by-zero. if data_b=X"00" then div_ov_out <= '1'; else div_ov_out <= '0'; end if; else b_shift_reg <= "0" & b_shift_reg(b_shift_reg'high downto 1); end if; -- numerator register if load_regs='1' then rem_reg <= data_a; elsif bit_ctr/=8 and sub_num='1' then rem_reg <= rem_reg - denominator; end if; --- quotient register if load_regs='1' then quot_reg <= (others => '0'); elsif bit_ctr/=8 then quot_reg <= quot_reg(quot_reg'high-1 downto 0) & sub_num; end if; load_regs <= start; end if; end process divider_registers; denominator <= b_shift_reg(7 downto 0); -- The 16-bit comparison between b_shift_reg (denominator) and the zero-extended -- rem_reg (numerator) can be simplified by splitting it in 2: -- If the shifted denominator high byte is not zero, it is >=256... den_ge_256 <= '1' when b_shift_reg(15 downto 8) /= X"00" else '0'; -- ...otherwise we need to compare the low bytes. num_ge_den <= '1' when rem_reg >= denominator else '0'; sub_num <= '1' when den_ge_256='0' and num_ge_den='1' else '0'; quot_out <= quot_reg; prod_out <= prod_reg; rem_out <= rem_reg; div_ready <= ready; ---- Multiplier logic ---------------------------------------------------------- ---- Combinational multiplier ----------------------------- multiplier_combinational: if not SEQUENTIAL_MULTIPLIER generate registered_combinational_multiplier:process(clk) begin if clk'event and clk='1' then prod_reg <= data_a * data_b; -- t_byte is unsigned end if; end process registered_combinational_multiplier; -- The multiplier output is valid in the cycle after the operands are loaded, -- so by the time MUL is executed it's already done. mul_ready <= '1'; mul_ov_out <= '1' when prod_reg(15 downto 8)/=X"00" else '0'; prod_out <= prod_reg; end generate multiplier_combinational; ---- Sequential multiplier -------------------------------- multiplier_sequential: if SEQUENTIAL_MULTIPLIER generate assert false report "Sequential multiplier implementation not done yet."& " Use combinational implementation." severity failure; end generate multiplier_sequential; end sequential;


On 9 March 2020, 7 new articles were published in 5 journals.
New Times, New Crimes: Notes on the Depillarization of the Criminal Justice System
Book Review: Victimology: A Canadian Perspective
Book Review: Victim Support and the Welfare State
Prevalence and Correlates of Sexual Revictimization in Middle and High School Youth
Cyber Sextortion: An Exploratory Analysis of Different Perpetrators Engaging in A Similar Crime