Last active
January 12, 2018 16:11
Revisions
-
seanlilmateus revised this gist
Feb 23, 2013 . 1 changed file with 162 additions and 52 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,123 +1,233 @@ #!/usr/bin/env macruby -wKU framework 'Foundation' module Dispatch module Futuristic def proxy Class.new(BasicObject) do def initialize(obj) @obj = obj end def method_missing(meth, *args, &blk) Future.new { @obj.send(meth, *args, &blk) } end def respond_to_missing?(meth, include_private = false) @obj.respond_to?(meth) end end end def future proxy.new(self) end end class Promise < BasicObject # MacRuby and Rubymotion BasicObject#initialize doesn't like blocks, so we have to do this def self.new(&block) ::Kernel.raise(::ArgumentError, "You cannot initalize a Dispatch::Promise without a block") unless block_given? self.alloc.initialization(block) end # setup Grand Central Dispatch concurrent Queue and Group def initialization(block) init @computation = block @arg = nil # Groups are just simple layers on top of semaphores. #Dispatch.once do @group = ::Dispatch::Group.new # Each thread gets its own FIFO queue upon which we will dispatch # the delayed computation passed in the &block variable. @promise_queue = ::Dispatch::Queue.concurrent("org.macruby.dispatch.promise-0x#{hash.to_s(16)}") # #end @value = @success = false self end def inspect __value__.inspect end def done? !!@value end alias_method :ready?, :done? private def __force__ # Asynchronously dispatch the future to the thread-local queue. @promise_queue.async(@group) { @value = @computation.call(*@arg) } end def __value__ # Wait fo the computation to finish. If it has already finished, then # just return the value in question. __force__ unless done? @group.wait @value end # like method_missing for objc # without this 'promise = Dispatch::Promise.new { NSData.dataWithContentsOfFile(file_name) }' will not work # NSString.alloc.initWithData(promise, encoding:NSUTF8StringEncoding) # since promise will not respond to NSData#bytes and return a NSInvalidArgumentException def method_missing(meth, *args, &block) __value__.send(meth, *args, &block) end def respond_to_missing?(method_name, include_private = false) __value__.respond_to?(method_name, include_private) || super end def forwardingTargetForSelector(sel) __value__ if __value__.respond_to?(sel) end end class Future < Promise # MacRuby and Rubymotion BasicObject#initialize doesn't like blocks, so we have to do this class << self def sequence(*args, &block) array = Array(args).flatten if block_given? result = [] Queue.concurrent(:high).apply(array.count) do |idx| result << Future.new { block.call(array[idx]) } end NSArray.arrayWithArray(result) else array.extend(Futuristic) array.future end end def new(arg=nil, &block) ::Kernel.raise(::ArgumentError, "You cannot initalize a Dispatch::Future without a block") unless block_given? self.alloc.initialization(arg, block) end end def when_done(&call_back) @group.notify(@promise_queue) { call_back[__value__] } self end def initialization(arg, block) super(block) @arg = arg __force__ self end def description state = done? ? :finished : :running NSString.stringWithString("<#{self.class} 0x#{hash.to_s(16)} STATE:#{state} on #@promise_queue...>") end def value; __value__; end private def method_missing(meth, *args, &block) self.send(meth, *args, &block) end def respond_to_missing?(method_name, include_private = false) self.respond_to?(method_name, include_private) end def forwardingTargetForSelector(sel) self if self.respond_to?(sel) end alias_method :inspect, :description end end class Person include Dispatch::Futuristic attr_accessor :id, :name, :email def initialize(dictionary = {}) setValuesForKeysWithDictionary(dictionary) if dictionary.is_a?(Hash) end def dance(&block) sleep 4 block.call(Dispatch::Queue.current) end def setValue(value, forUndefinedKey:key); end end person = Person.new(name: "Mateus", id:10, email:"[email protected]") # running on background queue person.future.dance do |queue| puts "running queue: #{queue}" end # running on main queue person.dance do |queue| puts "running queue: #{queue}" end urls = ["http://www.facebook.com/", "http://www.google.com/"].map { |url| NSURL.URLWithString(url) } result = Dispatch::Future.sequence(urls) do |url| NSString.stringWithContentsOfURL(url, encoding:NSUTF8StringEncoding, error:nil) end NSLog("Result: %@", result.last.value) p result.first future = Dispatch::Future.new { sleep 0.4; 10} p future.ready? p future.value p future.ready? future = Dispatch::Future.new(40) { |value| value + 2 } p future.ready? p future.value sleep 5 # Dispatch Future the_future = Dispatch::Future.new { sleep 1; 6 / 2 } the_future.when_done { |value| value = 10 } p the_future # <Dispatch::Future 0x400d4bae0 STATE:running on org.macruby.dispatch.promise-0x400d4bae0...> calculation = Dispatch::Future.new { sleep 2; 4 * 4 } p calculation # <Dispatch::Future 0x400d4bae0 STATE:running on org.macruby.dispatch.promise-0x400d4bae0...> calculation.when_done { |value| puts value + 10 } # 26 p calculation.value + 2 # 18 # Dispatch Promise promise = Dispatch::Promise.new { 12 } promise2 = Dispatch::Promise.new { sleep 2; 10 } result = promise2 + promise p result a = Dispatch::Promise.new { 10 / 2} # 10 / 2 = 5 b = Dispatch::Promise.new { a + 1 } # 5 + 1 = 6 c = Dispatch::Promise.new { a - 1 } # 5 - 1 = 4 puts b * c # 24 file_name = "/usr/share/dict/words" promise = Dispatch::Promise.new { NSData.dataWithContentsOfFile(file_name) } string = NSString.alloc.initWithData(promise, encoding:NSUTF8StringEncoding) summe = Dispatch::Future.sequence([*1..100]).inject { |sum, x| sum += x*2-1 } p summe.value futures = [*1..1000].map { |i| Dispatch::Future.new { sleep 1; i * 2 } } p futures.inject(0) { |sum, x| sum += x.value } -
seanlilmateus revised this gist
Jan 13, 2013 . 1 changed file with 3 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -11,7 +11,7 @@ def self.new(&block) end def when_done(call_back) @group.notify(@futures_queue) { call_back[@value] } end # setup Grand Central Dispatch concurrent Queue and Group @@ -22,7 +22,7 @@ def initialization(block) @group = ::Dispatch::Group.new # Each thread gets its own FIFO queue upon which we will dispatch # the delayed computation passed in the &block variable. @futures_queue ||= ::Dispatch::Queue.concurrent("org.macruby.promise-#{::Thread.current.object_id}") # @value = @success = false self end @@ -37,7 +37,7 @@ def done? def __force__ # Asynchronously dispatch the future to the thread-local queue. @futures_queue.async(@group) { @value = @computation.call } end def value -
seanlilmateus revised this gist
Jan 2, 2013 . 1 changed file with 17 additions and 17 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -35,36 +35,36 @@ def done? !!@value end def __force__ # Asynchronously dispatch the future to the thread-local queue. ::Thread.current[:futures].async(@group) { @value = @computation.call } end def value # Wait fo the computation to finish. If it has already finished, then # just return the value in question. self.__force__ unless self.done? @group.wait @value end # like method_missing for objc # without this 'promise = Dispatch::Promise.new { NSData.dataWithContentsOfFile(file_name) }' will not work # NSString.alloc.initWithData(promise, encoding:NSUTF8StringEncoding) # since promise will not respond to NSData#bytes and return a NSInvalidArgumentException alias_method :description, :inspect private def method_missing(method_name, *args, &block) self.value.send(method_name, *args, &block) if value.respond_to?(method_name) end def respond_to_missing?(method_name, include_private = false) value.respond_to?(method_name, include_private) || super end def forwardingTargetForSelector(sel) value if value.respond_to?(sel) end end class Future < BasicObject @@ -78,7 +78,7 @@ def self.new(&block) def initialization(block) init @promise = Promise.new(&block) @promise.__force__ self end -
seanlilmateus revised this gist
Jan 2, 2013 . 1 changed file with 11 additions and 8 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,5 @@ #!/usr/bin/env macruby -wKU framework 'Foundation' module Dispatch class Promise < BasicObject @@ -19,6 +18,11 @@ def when_done(call_back) def initialization(block) init @computation = block # Groups are just simple layers on top of semaphores. @group = ::Dispatch::Group.new # Each thread gets its own FIFO queue upon which we will dispatch # the delayed computation passed in the &block variable. ::Thread.current[:futures] ||= ::Dispatch::Queue.concurrent("org.macruby.promise-#{::Thread.current.object_id}") # @value = @success = false self end @@ -31,16 +35,15 @@ def done? !!@value end def resolve # Asynchronously dispatch the future to the thread-local queue. ::Thread.current[:futures].async(@group) { @value = @computation.call } end def value # Wait fo the computation to finish. If it has already finished, then # just return the value in question. self.resolve unless self.done? @group.wait @value end @@ -75,7 +78,7 @@ def self.new(&block) def initialization(block) init @promise = Promise.new(&block) @promise.resolve self end -
seanlilmateus revised this gist
Jan 2, 2013 . 1 changed file with 21 additions and 22 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,6 @@ #!/usr/bin/env macruby -wKU framework 'Foundation' module Dispatch class Promise < BasicObject @@ -18,34 +18,27 @@ def when_done(call_back) # setup Grand Central Dispatch concurrent Queue and Group def initialization(block) init @computation = block @value = @success = false self end def inspect value.inspect end def done? !!@value end def value # Each thread gets its own FIFO queue upon which we will dispatch # the delayed computation passed in the &block variable. ::Thread.current[:futures] ||= ::Dispatch::Queue.concurrent("org.macruby.promise-#{::Thread.current.object_id}") # # Groups are just simple layers on top of semaphores. @group = ::Dispatch::Group.new # Asynchronously dispatch the future to the thread-local queue. ::Thread.current[:futures].async(@group) { @value = @computation.call } # Wait fo the computation to finish. If it has already finished, then # just return the value in question. @group.wait @@ -59,6 +52,15 @@ def method_missing(method_name, *args, &block) def respond_to_missing?(method_name, include_private = false) value.respond_to?(method_name, include_private) || super end # like method_missing for objc # without this 'promise = Dispatch::Promise.new { NSData.dataWithContentsOfFile(file_name) }' will not work # NSString.alloc.initWithData(promise, encoding:NSUTF8StringEncoding) # since promise will not respond to NSData#bytes and return a NSInvalidArgumentException def forwardingTargetForSelector(sel) value if value.respond_to?(sel) end alias_method :description, :inspect end @@ -73,6 +75,7 @@ def self.new(&block) def initialization(block) init @promise = Promise.new(&block) @promise.value self end @@ -88,11 +91,7 @@ def description def value @promise.value end alias_method :inspect, :description end end -
seanlilmateus revised this gist
Dec 29, 2012 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -109,8 +109,8 @@ def method_missing(method, *args, &block) # Dispatch Promise promise = Dispatch::Promise.new { 12 } promise2 = Dispatch::Promise.new { sleep 2; 10 } result = promise2 + promise p result -
seanlilmateus revised this gist
Dec 29, 2012 . 1 changed file with 1 addition and 5 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -10,11 +10,7 @@ def self.new(&block) ::Kernel.raise(::ArgumentError, "Dispatch::Promise, wrong number of arguments (#{block.arity} for 0)") if block.arity > 0 self.alloc.initialization(block) end def when_done(call_back) @group.notify(::Thread.current[:futures]) { call_back[@value] } end -
seanlilmateus revised this gist
Dec 29, 2012 . 1 changed file with 4 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -112,10 +112,10 @@ def method_missing(method, *args, &block) p calculation.value + 2 # 18 # Dispatch Promise promise = Dispatch::Promise.new { 12 } promise2 = Dispatch::Promise.new { sleep 2; 10.to_i } result = promise2.to_int + promise.to_int p result file_name = "/usr/share/dict/words" -
seanlilmateus revised this gist
Dec 29, 2012 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -108,8 +108,8 @@ def method_missing(method, *args, &block) calculation = Dispatch::Future.new { sleep 2; 4 * 4 } p calculation # <Future: 0x400cf6ee0 running...> calculation.when_done { |value| puts value + 10 } # 26 p calculation.value + 2 # 18 # Dispatch Promise promise = Dispatch::Promise.new { 10 } -
seanlilmateus revised this gist
Dec 29, 2012 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -108,7 +108,7 @@ def method_missing(method, *args, &block) calculation = Dispatch::Future.new { sleep 2; 4 * 4 } p calculation # <Future: 0x400cf6ee0 running...> calculation.when_done { |value| puts value + 10 } # 26 p calculation + 2 # 18 # Dispatch Promise -
seanlilmateus revised this gist
Dec 29, 2012 . 1 changed file with 33 additions and 18 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,12 +1,20 @@ #!/usr/bin/env macruby -wKU framework 'Foundation' module Dispatch class Promise < BasicObject # MacRuby and Rubymotion BasicObject#initialize doesn't like blocks, so we have to do this def self.new(&block) ::Kernel.raise(::ArgumentError, "You cannot initalize a Dispatch::Promise without a block") unless block_given? ::Kernel.raise(::ArgumentError, "Dispatch::Promise, wrong number of arguments (#{block.arity} for 0)") if block.arity > 0 self.alloc.initialization(block) end def class value.class end def when_done(call_back) @group.notify(::Thread.current[:futures]) { call_back[@value] } end @@ -17,11 +25,11 @@ def initialization(block) @value = @success = false # Each thread gets its own FIFO queue upon which we will dispatch # the delayed computation passed in the &block variable. ::Thread.current[:futures] ||= ::Dispatch::Queue.concurrent("org.macruby.promise-#{::Thread.current.object_id}") # Groups are just simple layers on top of semaphores. @group = ::Dispatch::Group.new # Asynchronously dispatch the future to the thread-local queue. ::Thread.current[:futures].async(@group) { @value = block.call } self end @@ -48,23 +56,24 @@ def value @value end def method_missing(method_name, *args, &block) self.value.send(method_name, *args, &block) if value.respond_to?(method_name) end def respond_to_missing?(method_name, include_private = false) value.respond_to?(method_name, include_private) || super end alias_method :description, :inspect end class Future < BasicObject # MacRuby and Rubymotion BasicObject#initialize doesn't like blocks, so we have to do this def self.new(&block) ::Kernel.raise(::ArgumentError, "You cannot initalize a Dispatch::Future without a block") unless block_given? ::Kernel.raise(::ArgumentError, "Dispatch::Future, wrong number of arguments (#{block.arity} for 0)") if block.arity > 0 self.alloc.initialization(block) end def initialization(block) init @promise = Promise.new(&block) @@ -74,10 +83,10 @@ def initialization(block) def when_done(&block); @promise.when_done(block);end def description if @promise.done? value.inspect else NSString.stringWithString(super.gsub(/>/, ' running...>')) end end @@ -88,7 +97,6 @@ def value def method_missing(method, *args, &block) @promise.send(method, *args, &block) end alias_method :inspect, :description end end @@ -107,4 +115,11 @@ def method_missing(method, *args, &block) promise = Dispatch::Promise.new { 10 } promise2 = Dispatch::Promise.new { sleep 2 ; 10 } result = promise2 + promise p result # 20 file_name = "/usr/share/dict/words" promise = Dispatch::Promise.new { NSData.dataWithContentsOfFile(file_name) } string = NSString.alloc.initWithData(promise, encoding:NSUTF8StringEncoding) p string -
seanlilmateus revised this gist
Dec 29, 2012 . 1 changed file with 7 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -93,6 +93,7 @@ def method_missing(method, *args, &block) end end # Dispatch Future the_future = Dispatch::Future.new { sleep 1; 6 / 2 } the_future.when_done { |value| value = 10 } p the_future # <Future: 0x400cf57c0 running...> @@ -101,3 +102,9 @@ def method_missing(method, *args, &block) p calculation # <Future: 0x400cf6ee0 running...> calculation.when_done { puts calculation + 10 } # 26 p calculation + 2 # 18 # Dispatch Promise promise = Dispatch::Promise.new { 10 } promise2 = Dispatch::Promise.new { sleep 2 ; 10 } result = promise2 + promise p result # 20 -
seanlilmateus revised this gist
Dec 29, 2012 . 1 changed file with 85 additions and 42 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,16 +1,18 @@ module Dispatch class Promise < BasicObject # MacRuby and Rubymotion BasicObject#initialize doesn't like blocks, so we have to do this def self.new(&block) raise ArgumentError, "You can initalize a Future without a block" unless block_given? ::Kernel.raise(::ArgumentError, "Cannot store a Dispatch::Promise that requires an argument") if block.arity > 0 self.alloc.initialization(block) end def when_done(call_back) @group.notify(::Thread.current[:futures]) { call_back[@value] } end # setup Grand Central Dispatch concurrent Queue and Group def initialization(block) init @value = @success = false # Each thread gets its own FIFO queue upon which we will dispatch @@ -19,42 +21,83 @@ def initialization(block) # Groups are just simple layers on top of semaphores. @group = ::Dispatch::Group.new # Asynchronously dispatch the future to the thread-local queue. ::Thread.current[:futures].async(@group) { @value = block.call } self end def inspect value.inspect end # like method_missing for objc # without this 'promise = Dispatch::Promise.new { NSData.dataWithContentsOfFile(file_name) }' will not work # NSString.alloc.initWithData(promise, encoding:NSUTF8StringEncoding) # since promise will not respond to NSData#bytes and return a NSInvalidArgumentException def forwardingTargetForSelector(sel) value if value.respond_to?(sel) end def done? !!@value end def value # Wait fo the computation to finish. If it has already finished, then # just return the value in question. @group.wait @value end def method_missing(method, *args, &block) value.send(method, *args, &block) end def respond_to_missing?(method, include_private = false) value.respond_to?(method, include_private) end alias_method :description, :inspect end class Future < BasicObject def self.new(&block) raise ArgumentError, "You can initalize a Future without a block" unless block_given? ::Kernel.raise(::ArgumentError, "Cannot store a Dispatch::Future that requires an argument") if block.arity > 0 self.alloc.initialization(block) end def initialization(block) init @promise = Promise.new(&block) self end def when_done(&block); @promise.when_done(block);end def description if !@promise.done? NSString.stringWithString(super.gsub(/>/, ' running...>')) else value.inspect end end def value @promise.value end def method_missing(method, *args, &block) @promise.send(method, *args, &block) end alias_method :inspect, :description end end the_future = Dispatch::Future.new { sleep 1; 6 / 2 } the_future.when_done { |value| value = 10 } p the_future # <Future: 0x400cf57c0 running...> calculation = Dispatch::Future.new { sleep 2; 4 * 4 } p calculation # <Future: 0x400cf6ee0 running...> calculation.when_done { puts calculation + 10 } # 26 p calculation + 2 # 18 -
seanlilmateus revised this gist
Nov 23, 2012 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -27,7 +27,7 @@ def initialization(block) def inspect if !@value "#{description} still running..." else @value.inspect end -
seanlilmateus renamed this gist
Nov 23, 2012 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes. -
seanlilmateus created this gist
Nov 23, 2012 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,60 @@ class Future < BasicObject # completation callback, I don't like it either :-P def completed(&block); @success = block; end # MacRuby and Rubymotion BasicObject#initialize doesn't like blocks, so we have to do this def self.new(&block) raise ArgumentError, "You can initalize a Future without a block" unless block_given? self.alloc.initialization(block) end # setup Grand Central Dispatch concurrent Queue and Group def initialization(block) init @value = @success = false # Each thread gets its own FIFO queue upon which we will dispatch # the delayed computation passed in the &block variable. ::Thread.current[:futures] ||= ::Dispatch::Queue.concurrent("org.macruby.futures-#{::Thread.current.object_id}") # Groups are just simple layers on top of semaphores. @group = ::Dispatch::Group.new # Asynchronously dispatch the future to the thread-local queue. ::Thread.current[:futures].async(@group) { @value = block.call } @group.notify(::Thread.current[:futures]) { @success[@value] if @success } self end def inspect if !@value description.gsub(">", " running...>") else @value.inspect end end def value # Wait fo the computation to finish. If it has already finished, then # just return the value in question. @group.wait @value end def method_missing(method, *args, &block) value.send(method, *args, &block) end def respond_to_missing?(method, include_private = false) value.respond_to?(method, include_private) end end the_future = Future.new { sleep 1; 6 / 2 } the_future.completed { |value| value = 10 } p the_future # <Future: 0x400cf57c0 running...> calculation = Future.new { sleep 2; 4 * 4 } p calculation # <Future: 0x400cf6ee0 running...> calculation.completed { puts calculation + 10 } # 26 p calculation + 2 # 18