SlideShare a Scribd company logo
1 of 76
Download to read offline
Advanced Debugging With XCode
Extending LLDB
Image by Aijaz Ansari. Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
Aijaz
@_aijaz_
(Since 1982)
šŸ˜±
Debug
Sample
Project
Session
id: String
title: String?
sessionDescription: String?
startTime: Date
endTime: Date
speaker: Speaker?
startDate: String
init?(withId id: String)
Speaker
id: String
name: String
imagePath: String?
bio: String?
twitterHandle: String?
website: String?
sessions: [Session]
init?(withId id: String)
speaker
sessions
Demo 1
Image by Aijaz Ansari. Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
Letā€™s Recap
# In ~/.lldbinit, available to all LLDB sessions
type summary add --summary-string 
"(${var._indexes[0]}, ${var._indexes[1]})" IndexPath
type summary add --summary-string 
"${var.title} by ${var.speaker.name}" MyConf.Session
Quick & Dirty Type Summaries
Summaries in Python
#!/usr/bin/python
import re
regex = re.compile('[^"]*"(.*)"n$')
sessionFormatter.py
#!/usr/bin/python
import re
regex = re.compile('[^"]*"(.*)"n$')
def stripQuotes(str):
"""Utility method to strip the first and last quote
and anything outside them"""
match = regex.match(str)
if match :
return match.group(1)
return str
sessionFormatter.py
#!/usr/bin/python
import re
regex = re.compile('[^"]*"(.*)"n$')
def stripQuotes(str):
"""Utility method to strip the first and last quote
and anything outside them"""
match = regex.match(str)
if match :
return match.group(1)
return str
sessionFormatter.py
#!/usr/bin/python
import re
regex = re.compile('[^"]*"(.*)"n$')
def stripQuotes(str):
"""Utility method to strip the first and last quote
and anything outside them"""
match = regex.match(str)
if match :
return match.group(1)
return str
def format ()
sessionFormatter.py
#!/usr/bin/python
import re
regex = re.compile('[^"]*"(.*)"n$')
def stripQuotes(str):
"""Utility method to strip the first and last quote
and anything outside them"""
match = regex.match(str)
if match :
return match.group(1)
return str
def format (valobj,internal_dict):
sessionFormatter.py
#!/usr/bin/python
import re
regex = re.compile('[^"]*"(.*)"n$')
def stripQuotes(str):
"""Utility method to strip the first and last quote
and anything outside them"""
match = regex.match(str)
if match :
return match.group(1)
return str
def format (valobj,internal_dict):
title = valobj.GetChildMemberWithName('title')
name = valobj.GetChildMemberWithName(ā€˜speakerā€™)
.GetChildMemberWithName('name')
return stripQuotes(title.GetObjectDescription())
+ " by " + 
stripQuotes(name.GetObjectDescription())
sessionFormatter.py
#!/usr/bin/python
import re
regex = re.compile('[^"]*"(.*)"n$')
def stripQuotes(str):
"""Utility method to strip the first and last quote
and anything outside them"""
match = regex.match(str)
if match :
return match.group(1)
return str
def format (valobj,internal_dict):
title = valobj.GetChildMemberWithName('title')
name = valobj.GetChildMemberWithName(ā€˜speakerā€™)
.GetChildMemberWithName('name')
return stripQuotes(title.GetObjectDescription())
+ " by " + 
stripQuotes(name.GetObjectDescription())
sessionFormatter.py
#!/usr/bin/python
import re
regex = re.compile('[^"]*"(.*)"n$')
def stripQuotes(str):
"""Utility method to strip the first and last quote
and anything outside them"""
match = regex.match(str)
if match :
return match.group(1)
return str
def format (valobj,internal_dict):
title = valobj.GetChildMemberWithName('title')
name = valobj.GetChildMemberWithName(ā€˜speakerā€™)
.GetChildMemberWithName('name')
return stripQuotes(title.GetObjectDescription())
+ " by " + 
stripQuotes(name.GetObjectDescription())
def __lldb_init_module(debugger, dict):
command = 'type summary add ā€”-python-function 
sessionFormatter.format MyConf.Session'
debugger.HandleCommand(command)
sessionFormatter.py
#!/usr/bin/python
import re
regex = re.compile('[^"]*"(.*)"n$')
def stripQuotes(str):
"""Utility method to strip the first and last quote
and anything outside them"""
match = regex.match(str)
if match :
return match.group(1)
return str
def format (valobj,internal_dict):
title = valobj.GetChildMemberWithName('title')
name = valobj.GetChildMemberWithName(ā€˜speakerā€™)
.GetChildMemberWithName('name')
return stripQuotes(title.GetObjectDescription())
+ " by " + 
stripQuotes(name.GetObjectDescription())
def __lldb_init_module(debugger, dict):
command = 'type summary add ā€”-python-function 
sessionFormatter.format MyConf.Session'
debugger.HandleCommand(command)
sessionFormatter.py
#!/usr/bin/python
import re
regex = re.compile('[^"]*"(.*)"n$')
def stripQuotes(str):
"""Utility method to strip the first and last quote
and anything outside them"""
match = regex.match(str)
if match :
return match.group(1)
return str
def format (valobj,internal_dict):
title = valobj.GetChildMemberWithName('title')
name = valobj.GetChildMemberWithName(ā€˜speakerā€™)
.GetChildMemberWithName('name')
return stripQuotes(title.GetObjectDescription())
+ " by " + 
stripQuotes(name.GetObjectDescription())
def __lldb_init_module(debugger, dict):
command = 'type summary add ā€”-python-function 
sessionFormatter.format MyConf.Session'
debugger.HandleCommand(command)
sessionFormatter.py
command script import ā€¦/sessionFormatter.py
# Add things here, like type summaries, breakpoints
# Even execute Swift or Objective-C code with 'expr'
.lldbinit-MyConf
Project-Speciļ¬c Loading
in main() or application(_:didFinishLaunchingWithOptions:)
Any
Questions?
{ "version": 1,
"speakers": [
{"id": 3,
"img": ā€œchad.jpg",
"name": ā€œChad Perk",
"twitter": "chad",
"blog": ā€œwww.example.com/chadā€,
"bio": "Chad is the co-author ofā€¦ā€
},
jq
http://feelgraļ¬x.com/data_images/out/28/973590-avatar-the-last-airbender.jpg
$ cat avatar.json
[{"name":"Aang","sex":"M","born":-12,"died":153,"bending":["Air","Water","Earth","Fire","Energy"],"identity":
{"nationality":"Southern Air Temple","ethnicity":"Air Nomad"},"spouse":"Katara","children":[{"sex":"M","name":"Bumi"},
{"sex":"F","name":"Kya"},{"sex":"M","name":"Tenzin"}]},{"name":"Katara","sex":"F","born":85,"died":null,"bending":
["Water","Blood"],"identity":{"nationality":"Southern Water Tribe","ethnicity":"Water Tribe"},"spouse":"Aang","children":
[{"sex":"M","name":"Bumi"},{"sex":"F","name":"Kya"},{"sex":"M","name":"Tenzin"}]},{"name":"Sokka","sex":"M","born":84,"died":
164,"bending":[],"identity":{"nationality":"Southern Water Tribe","ethnicity":"Water Tribe"},"spouse":null,"children":[]},
{"name":"Toph Beifong","sex":"F","born":88,"died":null,"bending":["Earth","Metal"],"identity":{"nationality":"Gaoling, Earth
Kingdom","ethnicity":"Earth Kingdom"},"spouse":null,"children":[{"sex":"F","name":"Lin Beifong"},{"sex":"F","name":"Suyin
Beifong"}]},{"name":"Iroh","sex":"M","born":null,"died":null,"bending":["Fire","Energy"],"identity":{"nationality":"Fire Nation
Capital, Fire Nation","ethnicity":"Fire Nation"},"spouse":null,"children":[{"sex":"M","name":"Lu Ten"}]},
{"name":"Zuko","sex":"M","born":83,"died":null,"bending":["Fire","Energy"],"identity":{"nationality":"Fire Nation Capital, Fire
Nation","ethnicity":"Fire Nation"},"spouse":null,"children":[{"sex":"F","name":"Izumi"}]},
{"name":"Kya","sex":"F","born":null,"died":null,"bending":["Water"],"identity":{"nationality":"Southern Water
Tribe","ethnicity":"Water Tribe, Air Nomad"},"spouse":null,"children":[]},
{"name":"Bumi","sex":"M","born":null,"died":null,"bending":["Air"],"identity":{"nationality":"United Republic","ethnicity":"Water
Tribe, Air Nomad"},"spouse":null,"children":[]},{"name":"Tenzin","sex":"M","born":null,"died":null,"bending":["Air"],"identity":
{"nationality":"Republic City, United Republic","ethnicity":"Water Tribe, Air Nomad"},"spouse":null,"children":
[{"sex":"F","name":"Jinora"},{"sex":"F","name":"Ikki"},{"sex":"M","name":"Meelo"},{"sex":"M","name":"Rohan"}]},{"name":"Lin
Beifong","sex":"F","born":120,"died":null,"bending":["Earth","Metal"],"identity":{"nationality":"Republic City, United
Republic","ethnicity":"Earth Kingdom"},"spouse":null,"children":[]},{"name":"Suyin Beifong","sex":"F","born":
126,"died":null,"bending":["Earth","Metal"],"identity":{"nationality":"Republic City, United Republic","ethnicity":"Earth
Kingdom"},"spouse":null,"children":[{"sex":"M","name":"Bataar Jr."},{"sex":"F","name":"Opal"},{"sex":"M","name":"Wei"},
{"sex":"M","name":"Wing"},{"sex":"M","name":"Huan"}]}]
$
# Pretty print the jq
$ jq '.' avatar.json
command input ļ¬leļ¬lter
# Pretty print the jq
$ jq '.' avatar.json
...
{
"sex": "M",
"name": "Huan"
}
]
}
]
$
# Pretty print the jq
$ jq '.' avatar.json
...
{
"sex": "M",
"name": "Huan"
}
]
}
]
$
# The ']' on the last line tells me this is an array
# Pretty print the jq
$ jq '.' avatar.json
...
{
"sex": "M",
"name": "Huan"
}
]
}
]
$
# The ']' on the last line tells me this is an array
# The '}' on the 2nd-last line tells me this is an array of objects
# List the keys of each object
$ jq ' .[] | keys ' avatar.json
foreach item in array print the keys of each object
pipe the output of one ļ¬lter into the input of the next
# List the keys of each object
$ jq ' .[] | keys ' avatar.json
[
"bending",
"born",
"children",
"died",
"identity",
"name",
"sex",
"spouse"
]
[
"bending",
"born",ā€¦
$
# The name of each character
$ jq ' .[] | .name ' avatar.json
foreach item in array extract the ā€˜nameā€™ ļ¬eld
# The name of each character
$ jq ā€˜.[] | .nameā€™ avatar.json
"Aang"
"Katara"
"Sokka"
"Toph Beifong"
"Iroh"
"Zuko"
"Kya"
"Bumi"
"Tenzin"
"Lin Beifong"
$
# The name of each female character
$ jq ' .[] | select(.sex == "F") | .name ' avatar.json
foreach item in array
extract the ā€˜nameā€™ ļ¬eld
where sex is F
# The name of each female character
$ jq ' .[] | select(.sex == "F") | .name ' avatar.json
"Katara"
"Toph Beifong"
"Kya"
"Lin Beifong"
"Suyin Beifongā€
$
Demo 2
Image by Aijaz Ansari. Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
(lldb) jq ā€˜.speakers[]|keysā€™ jsonString
jq ļ¬lter (program) String
1. Gather input
2. Run the jq filter on the string, saving the output
3. Print the output
#!/usr/bin/python
import commands
import lldb
import shlex
#!/usr/bin/python
import commands
import lldb
import shlex
# The actual python function that is bound to the lldb command.
def jq_command(debugger, command, result, dict):
def jq_command(debugger, command, result, dict):
def jq_command(debugger, command, result, dict):
target = debugger.GetSelectedTarget()
def jq_command(debugger, command, result, dict):
target = debugger.GetSelectedTarget()
process = target.GetProcess()
def jq_command(debugger, command, result, dict):
target = debugger.GetSelectedTarget()
process = target.GetProcess()
thread = process.GetSelectedThread()
def jq_command(debugger, command, result, dict):
target = debugger.GetSelectedTarget()
process = target.GetProcess()
thread = process.GetSelectedThread()
frame = thread.GetSelectedFrame()
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>"
command_args = shlex.split(command)
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>"
command_args = shlex.split(command)
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>"
command_args = shlex.split(command)
jq_filter = command_args[0]
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>"
command_args = shlex.split(command)
jq_filter = command_args[0]
val = frame.var(command_args[1]) # access the variable
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>"
command_args = shlex.split(command)
jq_filter = command_args[0]
val = frame.var(command_args[1]) # access the variable
val_string = eval(val.GetObjectDescription())
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>"
command_args = shlex.split(command)
jq_filter = command_args[0]
val = frame.var(command_args[1]) # access the variable
val_string = eval(val.GetObjectDescription())
# path to the jq executable.
jq_exe = "/Users/aijaz/local/bin/jq"
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>"
command_args = shlex.split(command)
jq_filter = command_args[0]
val = frame.var(command_args[1]) # access the variable
val_string = eval(val.GetObjectDescription())
# path to the jq executable.
jq_exe = "/Users/aijaz/local/bin/jq"
# We save the filter to a file so that we donā€™t have to worry
about escaping special characters.
jq_filter_file = "/tmp/jq_filter"
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>"
command_args = shlex.split(command)
jq_filter = command_args[0]
val = frame.var(command_args[1]) # access the variable
val_string = eval(val.GetObjectDescription())
# path to the jq executable.
jq_exe = "/Users/aijaz/local/bin/jq"
# We save the filter to a file so that we donā€™t have to worry
about escaping special characters.
jq_filter_file = "/tmp/jq_filter"
# the value of the NSString variable is saved in this file jq
will be invoked on the file, not using stdin
jq_json_file = ā€œ/tmp/jq_json"
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>ā€
command_args = shlex.split(command)
jq_filter = command_args[0]
val = frame.var(command_args[1]) # access the variable
val_string = eval(val.GetObjectDescription())
# path to the jq executable.
jq_exe = "/Users/aijaz/local/bin/jq"
# We save the filter to a file so that we donā€™t have to worry about escaping special characters.
jq_filter_file = "/tmp/jq_filter"
# the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin
jq_json_file = "/tmp/jq_json"
# write the json file and jq filter to temp files
f = open(jq_json_file, 'w')
f.write(val_string)
f.close()
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>ā€
command_args = shlex.split(command)
jq_filter = command_args[0]
val = frame.var(command_args[1]) # access the variable
val_string = eval(val.GetObjectDescription())
# path to the jq executable.
jq_exe = "/Users/aijaz/local/bin/jq"
# We save the filter to a file so that we donā€™t have to worry about escaping special characters.
jq_filter_file = "/tmp/jq_filter"
# the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin
jq_json_file = "/tmp/jq_json"
# write the json file and jq filter to temp files
f = open(jq_json_file, 'w')
f.write(val_string)
f.close()
f = open(jq_filter_file, 'w')
f.write(jq_filter)
f.close()
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>ā€
command_args = shlex.split(command)
jq_filter = command_args[0]
val = frame.var(command_args[1]) # access the variable
val_string = eval(val.GetObjectDescription())
# path to the jq executable.
jq_exe = "/Users/aijaz/local/bin/jq"
# We save the filter to a file so that we donā€™t have to worry about escaping special characters.
jq_filter_file = "/tmp/jq_filter"
# the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin
jq_json_file = "/tmp/jq_json"
# write the json file and jq filter to temp files
f = open(jq_json_file, 'w')
f.write(val_string)
f.close()
f = open(jq_filter_file, 'w')
f.write(jq_filter)
f.close()
# invoke jq and capture the output
output = commands.getoutput("%s -f %s %s" % (
jq_exe, jq_filter_file, jq_json_file) )
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>ā€
command_args = shlex.split(command)
jq_filter = command_args[0]
val = frame.var(command_args[1]) # access the variable
val_string = eval(val.GetObjectDescription())
# path to the jq executable.
jq_exe = "/Users/aijaz/local/bin/jq"
# We save the filter to a file so that we donā€™t have to worry about escaping special characters.
jq_filter_file = "/tmp/jq_filter"
# the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin
jq_json_file = "/tmp/jq_json"
# write the json file and jq filter to temp files
f = open(jq_json_file, 'w')
f.write(val_string)
f.close()
f = open(jq_filter_file, 'w')
f.write(jq_filter)
f.close()
# invoke jq and capture the output
output = commands.getoutput("%s -f %s %s" % (
jq_exe, jq_filter_file, jq_json_file) )
print >>result, output
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>ā€
command_args = shlex.split(command)
jq_filter = command_args[0]
val = frame.var(command_args[1]) # access the variable
val_string = eval(val.GetObjectDescription())
# path to the jq executable.
jq_exe = "/Users/aijaz/local/bin/jq"
# We save the filter to a file so that we donā€™t have to worry about escaping special characters.
jq_filter_file = "/tmp/jq_filter"
# the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin
jq_json_file = "/tmp/jq_json"
# write the json file and jq filter to temp files
f = open(jq_json_file, 'w')
f.write(val_string)
f.close()
f = open(jq_filter_file, 'w')
f.write(jq_filter)
f.close()
# invoke jq and capture the output
output = commands.getoutput("%s -f %s %s" % (
jq_exe, jq_filter_file, jq_json_file) )
print >>result, output
Gather Input
Run Command
Print Output
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>ā€
command_args = shlex.split(command)
jq_filter = command_args[0]
val = frame.var(command_args[1]) # access the variable
val_string = eval(val.GetObjectDescription())
# path to the jq executable.
jq_exe = "/Users/aijaz/local/bin/jq"
# We save the filter to a file so that we donā€™t have to worry about escaping special characters.
jq_filter_file = "/tmp/jq_filter"
# the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin
jq_json_file = "/tmp/jq_json"
# write the json file and jq filter to temp files
f = open(jq_json_file, 'w')
f.write(val_string)
f.close()
f = open(jq_filter_file, 'w')
f.write(jq_filter)
f.close()
# invoke jq and capture the output
output = commands.getoutput("%s -f %s %s" % (
jq_exe, jq_filter_file, jq_json_file) )
print >>result, output
def __lldb_init_module(debugger, dict):
# Add any commands contained in this module to LLDB
command = 'command script add -f jq.jq_command jq'
debugger.HandleCommand(command)
What have
we learned?
Validate your
hypothesis
(if youā€™re lucky enough to have a hypothesis.)
Observe
Analyze
Extend
Any
Questions?
https://github.com/aijaz/lldbPythonScripts
http://aijaz.net/2017/01/11/lldb-python/index.html
https://github.com/facebook/chisel
LLDB: https://lldb.llvm.org/
A blog post from January, where I write about most of the same stuff:
Extending LLDB: http://aijaz.net/2017/01/11/lldb-python/index.html
JQ
jq: https://stedolan.github.io/jq/
A Facebook library that adds a lot of cool extensions to LLDB
Facebook Chisel: https://github.com/facebook/chisel
WWDC Sessions:
Debugging Tips and Tricks https://developer.apple.com/videos/play/wwdc2016/417/
Whatā€™s new in LLDB: https://developer.apple.com/videos/play/wwdc2015/402/
Introduction to LLDB and the Swift REPL https://developer.apple.com/videos/play/wwdc2014/409/
Advanced Swift Debugging in LLDB https://developer.apple.com/videos/play/wwdc2014/410/
Debugging in Xcode 6 https://developer.apple.com/videos/play/wwdc2014/413/
Debugging with Xcode https://developer.apple.com/videos/play/wwdc2013/407/
* Advanced Debugging with LLDB https://developer.apple.com/videos/play/wwdc2013/413/
* Debugging in Xcode https://developer.apple.com/videos/play/wwdc2012/412/
* Debugging with Xcode https://developer.apple.com/videos/play/wwdc2012/415/
*: Contains material related to this talk
Thank You!
https://www.theodysseyonline.com/overthinking-spongebob
@_aijaz_

More Related Content

What's hot

C# 7.0 Hacks and Features
C# 7.0 Hacks and FeaturesC# 7.0 Hacks and Features
C# 7.0 Hacks and FeaturesAbhishek Sur
Ā 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with GroovyArturo Herrero
Ā 
Advanced Python, Part 1
Advanced Python, Part 1Advanced Python, Part 1
Advanced Python, Part 1Zaar Hai
Ā 
Introduction to Gremlin
Introduction to GremlinIntroduction to Gremlin
Introduction to GremlinMax De Marzi
Ā 
The Ring programming language version 1.5.4 book - Part 40 of 185
The Ring programming language version 1.5.4 book - Part 40 of 185The Ring programming language version 1.5.4 book - Part 40 of 185
The Ring programming language version 1.5.4 book - Part 40 of 185Mahmoud Samir Fayed
Ā 
From android/java to swift (3)
From android/java to swift (3)From android/java to swift (3)
From android/java to swift (3)allanh0526
Ā 
Ast transformations
Ast transformationsAst transformations
Ast transformationsHamletDRC
Ā 
Groovy
GroovyGroovy
GroovyZen Urban
Ā 
NaĆÆvetĆ© vs. Experience
NaĆÆvetĆ© vs. ExperienceNaĆÆvetĆ© vs. Experience
NaĆÆvetĆ© vs. ExperienceMike Fogus
Ā 
How to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftHow to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftGiordano Scalzo
Ā 
Designing with Groovy Traits - Gr8Conf India
Designing with Groovy Traits - Gr8Conf IndiaDesigning with Groovy Traits - Gr8Conf India
Designing with Groovy Traits - Gr8Conf IndiaNaresha K
Ā 
Madrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovyMadrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovyIvĆ”n LĆ³pez MartĆ­n
Ā 
groovy & grails - lecture 3
groovy & grails - lecture 3groovy & grails - lecture 3
groovy & grails - lecture 3Alexandre Masselot
Ā 
#ģ‚“ģ•„ģžˆė‹¤ #ģžķ”„ė§ģ™øźøø12ė…„ģ°Ø #ģ½”ķ”„ė§2ź°œģ›”ģƒģ”“źø°
#ģ‚“ģ•„ģžˆė‹¤ #ģžķ”„ė§ģ™øźøø12ė…„ģ°Ø #ģ½”ķ”„ė§2ź°œģ›”ģƒģ”“źø°#ģ‚“ģ•„ģžˆė‹¤ #ģžķ”„ė§ģ™øźøø12ė…„ģ°Ø #ģ½”ķ”„ė§2ź°œģ›”ģƒģ”“źø°
#ģ‚“ģ•„ģžˆė‹¤ #ģžķ”„ė§ģ™øźøø12ė…„ģ°Ø #ģ½”ķ”„ė§2ź°œģ›”ģƒģ”“źø°Arawn Park
Ā 
Generics and Inference
Generics and InferenceGenerics and Inference
Generics and InferenceRichard Fox
Ā 
Rust Mozlando Tutorial
Rust Mozlando TutorialRust Mozlando Tutorial
Rust Mozlando Tutorialnikomatsakis
Ā 
Dynamic C++ Silicon Valley Code Camp 2012
Dynamic C++ Silicon Valley Code Camp 2012Dynamic C++ Silicon Valley Code Camp 2012
Dynamic C++ Silicon Valley Code Camp 2012aleks-f
Ā 

What's hot (19)

C# 7.0 Hacks and Features
C# 7.0 Hacks and FeaturesC# 7.0 Hacks and Features
C# 7.0 Hacks and Features
Ā 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with Groovy
Ā 
Advanced Python, Part 1
Advanced Python, Part 1Advanced Python, Part 1
Advanced Python, Part 1
Ā 
Introduction to Gremlin
Introduction to GremlinIntroduction to Gremlin
Introduction to Gremlin
Ā 
The Ring programming language version 1.5.4 book - Part 40 of 185
The Ring programming language version 1.5.4 book - Part 40 of 185The Ring programming language version 1.5.4 book - Part 40 of 185
The Ring programming language version 1.5.4 book - Part 40 of 185
Ā 
From android/java to swift (3)
From android/java to swift (3)From android/java to swift (3)
From android/java to swift (3)
Ā 
Python lec4
Python lec4Python lec4
Python lec4
Ā 
Ast transformations
Ast transformationsAst transformations
Ast transformations
Ā 
Groovy
GroovyGroovy
Groovy
Ā 
NaĆÆvetĆ© vs. Experience
NaĆÆvetĆ© vs. ExperienceNaĆÆvetĆ© vs. Experience
NaĆÆvetĆ© vs. Experience
Ā 
How to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftHow to Clone Flappy Bird in Swift
How to Clone Flappy Bird in Swift
Ā 
Designing with Groovy Traits - Gr8Conf India
Designing with Groovy Traits - Gr8Conf IndiaDesigning with Groovy Traits - Gr8Conf India
Designing with Groovy Traits - Gr8Conf India
Ā 
Madrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovyMadrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovy
Ā 
groovy & grails - lecture 3
groovy & grails - lecture 3groovy & grails - lecture 3
groovy & grails - lecture 3
Ā 
#ģ‚“ģ•„ģžˆė‹¤ #ģžķ”„ė§ģ™øźøø12ė…„ģ°Ø #ģ½”ķ”„ė§2ź°œģ›”ģƒģ”“źø°
#ģ‚“ģ•„ģžˆė‹¤ #ģžķ”„ė§ģ™øźøø12ė…„ģ°Ø #ģ½”ķ”„ė§2ź°œģ›”ģƒģ”“źø°#ģ‚“ģ•„ģžˆė‹¤ #ģžķ”„ė§ģ™øźøø12ė…„ģ°Ø #ģ½”ķ”„ė§2ź°œģ›”ģƒģ”“źø°
#ģ‚“ģ•„ģžˆė‹¤ #ģžķ”„ė§ģ™øźøø12ė…„ģ°Ø #ģ½”ķ”„ė§2ź°œģ›”ģƒģ”“źø°
Ā 
Generics and Inference
Generics and InferenceGenerics and Inference
Generics and Inference
Ā 
C# 7
C# 7C# 7
C# 7
Ā 
Rust Mozlando Tutorial
Rust Mozlando TutorialRust Mozlando Tutorial
Rust Mozlando Tutorial
Ā 
Dynamic C++ Silicon Valley Code Camp 2012
Dynamic C++ Silicon Valley Code Camp 2012Dynamic C++ Silicon Valley Code Camp 2012
Dynamic C++ Silicon Valley Code Camp 2012
Ā 

Similar to 360|iDev

Beyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCodeBeyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCodeAijaz Ansari
Ā 
Advanced Debugging with Xcode - Extending LLDB
Advanced Debugging with Xcode - Extending LLDBAdvanced Debugging with Xcode - Extending LLDB
Advanced Debugging with Xcode - Extending LLDBAijaz Ansari
Ā 
Spring Framework - Expression Language
Spring Framework - Expression LanguageSpring Framework - Expression Language
Spring Framework - Expression LanguageDzmitry Naskou
Ā 
Grammarware Memes
Grammarware MemesGrammarware Memes
Grammarware MemesEelco Visser
Ā 
AST Transformations
AST TransformationsAST Transformations
AST TransformationsHamletDRC
Ā 
Automatically Spotting Cross-language Relations
Automatically Spotting Cross-language RelationsAutomatically Spotting Cross-language Relations
Automatically Spotting Cross-language RelationsFederico Tomassetti
Ā 
Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)HamletDRC
Ā 
Functional Scala 2020
Functional Scala 2020Functional Scala 2020
Functional Scala 2020Alexander Ioffe
Ā 
Type safe embedded domain-specific languages
Type safe embedded domain-specific languagesType safe embedded domain-specific languages
Type safe embedded domain-specific languagesArthur Xavier
Ā 
Stupid Awesome Python Tricks
Stupid Awesome Python TricksStupid Awesome Python Tricks
Stupid Awesome Python TricksBryan Helmig
Ā 
Swiftģ™€ Objective-Cė„¼ ķ•Øź»˜ ģ“°ėŠ” ė°©ė²•
Swiftģ™€ Objective-Cė„¼ ķ•Øź»˜ ģ“°ėŠ” ė°©ė²•Swiftģ™€ Objective-Cė„¼ ķ•Øź»˜ ģ“°ėŠ” ė°©ė²•
Swiftģ™€ Objective-Cė„¼ ķ•Øź»˜ ģ“°ėŠ” ė°©ė²•Jung Kim
Ā 
Clojure for Java developers - Stockholm
Clojure for Java developers - StockholmClojure for Java developers - Stockholm
Clojure for Java developers - StockholmJan Kronquist
Ā 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with ClojureDmitry Buzdin
Ā 
jRuby: The best of both worlds
jRuby: The best of both worldsjRuby: The best of both worlds
jRuby: The best of both worldsChristopher Spring
Ā 
WordCamp Portland 2018: PHP for WordPress
WordCamp Portland 2018: PHP for WordPressWordCamp Portland 2018: PHP for WordPress
WordCamp Portland 2018: PHP for WordPressAlena Holligan
Ā 
Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2Kirill Rozov
Ā 
Groovy intro for OUDL
Groovy intro for OUDLGroovy intro for OUDL
Groovy intro for OUDLJ David Beutel
Ā 

Similar to 360|iDev (20)

Beyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCodeBeyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCode
Ā 
Advanced Debugging with Xcode - Extending LLDB
Advanced Debugging with Xcode - Extending LLDBAdvanced Debugging with Xcode - Extending LLDB
Advanced Debugging with Xcode - Extending LLDB
Ā 
Spring Framework - Expression Language
Spring Framework - Expression LanguageSpring Framework - Expression Language
Spring Framework - Expression Language
Ā 
Grammarware Memes
Grammarware MemesGrammarware Memes
Grammarware Memes
Ā 
AST Transformations
AST TransformationsAST Transformations
AST Transformations
Ā 
Automatically Spotting Cross-language Relations
Automatically Spotting Cross-language RelationsAutomatically Spotting Cross-language Relations
Automatically Spotting Cross-language Relations
Ā 
Introduction to Groovy
Introduction to GroovyIntroduction to Groovy
Introduction to Groovy
Ā 
Python basic
Python basicPython basic
Python basic
Ā 
Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)
Ā 
Functional Scala 2020
Functional Scala 2020Functional Scala 2020
Functional Scala 2020
Ā 
Type safe embedded domain-specific languages
Type safe embedded domain-specific languagesType safe embedded domain-specific languages
Type safe embedded domain-specific languages
Ā 
Stupid Awesome Python Tricks
Stupid Awesome Python TricksStupid Awesome Python Tricks
Stupid Awesome Python Tricks
Ā 
Swiftģ™€ Objective-Cė„¼ ķ•Øź»˜ ģ“°ėŠ” ė°©ė²•
Swiftģ™€ Objective-Cė„¼ ķ•Øź»˜ ģ“°ėŠ” ė°©ė²•Swiftģ™€ Objective-Cė„¼ ķ•Øź»˜ ģ“°ėŠ” ė°©ė²•
Swiftģ™€ Objective-Cė„¼ ķ•Øź»˜ ģ“°ėŠ” ė°©ė²•
Ā 
Clojure for Java developers - Stockholm
Clojure for Java developers - StockholmClojure for Java developers - Stockholm
Clojure for Java developers - Stockholm
Ā 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
Ā 
jRuby: The best of both worlds
jRuby: The best of both worldsjRuby: The best of both worlds
jRuby: The best of both worlds
Ā 
WordCamp Portland 2018: PHP for WordPress
WordCamp Portland 2018: PHP for WordPressWordCamp Portland 2018: PHP for WordPress
WordCamp Portland 2018: PHP for WordPress
Ā 
Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2
Ā 
Groovy intro for OUDL
Groovy intro for OUDLGroovy intro for OUDL
Groovy intro for OUDL
Ā 
Python : Functions
Python : FunctionsPython : Functions
Python : Functions
Ā 

Recently uploaded

Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024VictoriaMetrics
Ā 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnAmarnathKambale
Ā 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...panagenda
Ā 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is insideshinachiaurasa2
Ā 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareJim McKeeth
Ā 
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benonimasabamasaba
Ā 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2
Ā 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...Jittipong Loespradit
Ā 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrainmasabamasaba
Ā 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisamasabamasaba
Ā 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisamasabamasaba
Ā 
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburgmasabamasaba
Ā 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
Ā 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...masabamasaba
Ā 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxAnnaArtyushina1
Ā 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2
Ā 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension AidPhilip Schwarz
Ā 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...chiefasafspells
Ā 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplatePresentation.STUDIO
Ā 

Recently uploaded (20)

Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Ā 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
Ā 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
Ā 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
Ā 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
Ā 
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
Ā 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
Ā 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
Ā 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
Ā 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
Ā 
Abortion Pills In Pretoria ](+27832195400*)[ šŸ„ Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ šŸ„ Women's Abortion Clinic In Pre...Abortion Pills In Pretoria ](+27832195400*)[ šŸ„ Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ šŸ„ Women's Abortion Clinic In Pre...
Ā 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
Ā 
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
Ā 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Ā 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
Ā 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Ā 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
Ā 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Ā 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Ā 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
Ā 

360|iDev

  • 1. Advanced Debugging With XCode Extending LLDB Image by Aijaz Ansari. Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
  • 3.
  • 7.
  • 8.
  • 9. Session id: String title: String? sessionDescription: String? startTime: Date endTime: Date speaker: Speaker? startDate: String init?(withId id: String) Speaker id: String name: String imagePath: String? bio: String? twitterHandle: String? website: String? sessions: [Session] init?(withId id: String) speaker sessions
  • 11. Image by Aijaz Ansari. Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
  • 13. # In ~/.lldbinit, available to all LLDB sessions type summary add --summary-string "(${var._indexes[0]}, ${var._indexes[1]})" IndexPath type summary add --summary-string "${var.title} by ${var.speaker.name}" MyConf.Session Quick & Dirty Type Summaries
  • 15. #!/usr/bin/python import re regex = re.compile('[^"]*"(.*)"n$') sessionFormatter.py
  • 16. #!/usr/bin/python import re regex = re.compile('[^"]*"(.*)"n$') def stripQuotes(str): """Utility method to strip the first and last quote and anything outside them""" match = regex.match(str) if match : return match.group(1) return str sessionFormatter.py
  • 17. #!/usr/bin/python import re regex = re.compile('[^"]*"(.*)"n$') def stripQuotes(str): """Utility method to strip the first and last quote and anything outside them""" match = regex.match(str) if match : return match.group(1) return str sessionFormatter.py
  • 18. #!/usr/bin/python import re regex = re.compile('[^"]*"(.*)"n$') def stripQuotes(str): """Utility method to strip the first and last quote and anything outside them""" match = regex.match(str) if match : return match.group(1) return str def format () sessionFormatter.py
  • 19. #!/usr/bin/python import re regex = re.compile('[^"]*"(.*)"n$') def stripQuotes(str): """Utility method to strip the first and last quote and anything outside them""" match = regex.match(str) if match : return match.group(1) return str def format (valobj,internal_dict): sessionFormatter.py
  • 20. #!/usr/bin/python import re regex = re.compile('[^"]*"(.*)"n$') def stripQuotes(str): """Utility method to strip the first and last quote and anything outside them""" match = regex.match(str) if match : return match.group(1) return str def format (valobj,internal_dict): title = valobj.GetChildMemberWithName('title') name = valobj.GetChildMemberWithName(ā€˜speakerā€™) .GetChildMemberWithName('name') return stripQuotes(title.GetObjectDescription()) + " by " + stripQuotes(name.GetObjectDescription()) sessionFormatter.py
  • 21. #!/usr/bin/python import re regex = re.compile('[^"]*"(.*)"n$') def stripQuotes(str): """Utility method to strip the first and last quote and anything outside them""" match = regex.match(str) if match : return match.group(1) return str def format (valobj,internal_dict): title = valobj.GetChildMemberWithName('title') name = valobj.GetChildMemberWithName(ā€˜speakerā€™) .GetChildMemberWithName('name') return stripQuotes(title.GetObjectDescription()) + " by " + stripQuotes(name.GetObjectDescription()) sessionFormatter.py
  • 22. #!/usr/bin/python import re regex = re.compile('[^"]*"(.*)"n$') def stripQuotes(str): """Utility method to strip the first and last quote and anything outside them""" match = regex.match(str) if match : return match.group(1) return str def format (valobj,internal_dict): title = valobj.GetChildMemberWithName('title') name = valobj.GetChildMemberWithName(ā€˜speakerā€™) .GetChildMemberWithName('name') return stripQuotes(title.GetObjectDescription()) + " by " + stripQuotes(name.GetObjectDescription()) def __lldb_init_module(debugger, dict): command = 'type summary add ā€”-python-function sessionFormatter.format MyConf.Session' debugger.HandleCommand(command) sessionFormatter.py
  • 23. #!/usr/bin/python import re regex = re.compile('[^"]*"(.*)"n$') def stripQuotes(str): """Utility method to strip the first and last quote and anything outside them""" match = regex.match(str) if match : return match.group(1) return str def format (valobj,internal_dict): title = valobj.GetChildMemberWithName('title') name = valobj.GetChildMemberWithName(ā€˜speakerā€™) .GetChildMemberWithName('name') return stripQuotes(title.GetObjectDescription()) + " by " + stripQuotes(name.GetObjectDescription()) def __lldb_init_module(debugger, dict): command = 'type summary add ā€”-python-function sessionFormatter.format MyConf.Session' debugger.HandleCommand(command) sessionFormatter.py
  • 24. #!/usr/bin/python import re regex = re.compile('[^"]*"(.*)"n$') def stripQuotes(str): """Utility method to strip the first and last quote and anything outside them""" match = regex.match(str) if match : return match.group(1) return str def format (valobj,internal_dict): title = valobj.GetChildMemberWithName('title') name = valobj.GetChildMemberWithName(ā€˜speakerā€™) .GetChildMemberWithName('name') return stripQuotes(title.GetObjectDescription()) + " by " + stripQuotes(name.GetObjectDescription()) def __lldb_init_module(debugger, dict): command = 'type summary add ā€”-python-function sessionFormatter.format MyConf.Session' debugger.HandleCommand(command) sessionFormatter.py
  • 25. command script import ā€¦/sessionFormatter.py # Add things here, like type summaries, breakpoints # Even execute Swift or Objective-C code with 'expr' .lldbinit-MyConf
  • 26. Project-Speciļ¬c Loading in main() or application(_:didFinishLaunchingWithOptions:)
  • 28. { "version": 1, "speakers": [ {"id": 3, "img": ā€œchad.jpg", "name": ā€œChad Perk", "twitter": "chad", "blog": ā€œwww.example.com/chadā€, "bio": "Chad is the co-author ofā€¦ā€ },
  • 29. jq
  • 31. $ cat avatar.json [{"name":"Aang","sex":"M","born":-12,"died":153,"bending":["Air","Water","Earth","Fire","Energy"],"identity": {"nationality":"Southern Air Temple","ethnicity":"Air Nomad"},"spouse":"Katara","children":[{"sex":"M","name":"Bumi"}, {"sex":"F","name":"Kya"},{"sex":"M","name":"Tenzin"}]},{"name":"Katara","sex":"F","born":85,"died":null,"bending": ["Water","Blood"],"identity":{"nationality":"Southern Water Tribe","ethnicity":"Water Tribe"},"spouse":"Aang","children": [{"sex":"M","name":"Bumi"},{"sex":"F","name":"Kya"},{"sex":"M","name":"Tenzin"}]},{"name":"Sokka","sex":"M","born":84,"died": 164,"bending":[],"identity":{"nationality":"Southern Water Tribe","ethnicity":"Water Tribe"},"spouse":null,"children":[]}, {"name":"Toph Beifong","sex":"F","born":88,"died":null,"bending":["Earth","Metal"],"identity":{"nationality":"Gaoling, Earth Kingdom","ethnicity":"Earth Kingdom"},"spouse":null,"children":[{"sex":"F","name":"Lin Beifong"},{"sex":"F","name":"Suyin Beifong"}]},{"name":"Iroh","sex":"M","born":null,"died":null,"bending":["Fire","Energy"],"identity":{"nationality":"Fire Nation Capital, Fire Nation","ethnicity":"Fire Nation"},"spouse":null,"children":[{"sex":"M","name":"Lu Ten"}]}, {"name":"Zuko","sex":"M","born":83,"died":null,"bending":["Fire","Energy"],"identity":{"nationality":"Fire Nation Capital, Fire Nation","ethnicity":"Fire Nation"},"spouse":null,"children":[{"sex":"F","name":"Izumi"}]}, {"name":"Kya","sex":"F","born":null,"died":null,"bending":["Water"],"identity":{"nationality":"Southern Water Tribe","ethnicity":"Water Tribe, Air Nomad"},"spouse":null,"children":[]}, {"name":"Bumi","sex":"M","born":null,"died":null,"bending":["Air"],"identity":{"nationality":"United Republic","ethnicity":"Water Tribe, Air Nomad"},"spouse":null,"children":[]},{"name":"Tenzin","sex":"M","born":null,"died":null,"bending":["Air"],"identity": {"nationality":"Republic City, United Republic","ethnicity":"Water Tribe, Air Nomad"},"spouse":null,"children": [{"sex":"F","name":"Jinora"},{"sex":"F","name":"Ikki"},{"sex":"M","name":"Meelo"},{"sex":"M","name":"Rohan"}]},{"name":"Lin Beifong","sex":"F","born":120,"died":null,"bending":["Earth","Metal"],"identity":{"nationality":"Republic City, United Republic","ethnicity":"Earth Kingdom"},"spouse":null,"children":[]},{"name":"Suyin Beifong","sex":"F","born": 126,"died":null,"bending":["Earth","Metal"],"identity":{"nationality":"Republic City, United Republic","ethnicity":"Earth Kingdom"},"spouse":null,"children":[{"sex":"M","name":"Bataar Jr."},{"sex":"F","name":"Opal"},{"sex":"M","name":"Wei"}, {"sex":"M","name":"Wing"},{"sex":"M","name":"Huan"}]}] $
  • 32. # Pretty print the jq $ jq '.' avatar.json command input ļ¬leļ¬lter
  • 33. # Pretty print the jq $ jq '.' avatar.json ... { "sex": "M", "name": "Huan" } ] } ] $
  • 34. # Pretty print the jq $ jq '.' avatar.json ... { "sex": "M", "name": "Huan" } ] } ] $ # The ']' on the last line tells me this is an array
  • 35. # Pretty print the jq $ jq '.' avatar.json ... { "sex": "M", "name": "Huan" } ] } ] $ # The ']' on the last line tells me this is an array # The '}' on the 2nd-last line tells me this is an array of objects
  • 36. # List the keys of each object $ jq ' .[] | keys ' avatar.json foreach item in array print the keys of each object pipe the output of one ļ¬lter into the input of the next
  • 37. # List the keys of each object $ jq ' .[] | keys ' avatar.json [ "bending", "born", "children", "died", "identity", "name", "sex", "spouse" ] [ "bending", "born",ā€¦ $
  • 38. # The name of each character $ jq ' .[] | .name ' avatar.json foreach item in array extract the ā€˜nameā€™ ļ¬eld
  • 39. # The name of each character $ jq ā€˜.[] | .nameā€™ avatar.json "Aang" "Katara" "Sokka" "Toph Beifong" "Iroh" "Zuko" "Kya" "Bumi" "Tenzin" "Lin Beifong" $
  • 40. # The name of each female character $ jq ' .[] | select(.sex == "F") | .name ' avatar.json foreach item in array extract the ā€˜nameā€™ ļ¬eld where sex is F
  • 41. # The name of each female character $ jq ' .[] | select(.sex == "F") | .name ' avatar.json "Katara" "Toph Beifong" "Kya" "Lin Beifong" "Suyin Beifongā€ $
  • 43. Image by Aijaz Ansari. Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
  • 44. (lldb) jq ā€˜.speakers[]|keysā€™ jsonString jq ļ¬lter (program) String 1. Gather input 2. Run the jq filter on the string, saving the output 3. Print the output
  • 46. #!/usr/bin/python import commands import lldb import shlex # The actual python function that is bound to the lldb command. def jq_command(debugger, command, result, dict):
  • 48. def jq_command(debugger, command, result, dict): target = debugger.GetSelectedTarget()
  • 49. def jq_command(debugger, command, result, dict): target = debugger.GetSelectedTarget() process = target.GetProcess()
  • 50. def jq_command(debugger, command, result, dict): target = debugger.GetSelectedTarget() process = target.GetProcess() thread = process.GetSelectedThread()
  • 51. def jq_command(debugger, command, result, dict): target = debugger.GetSelectedTarget() process = target.GetProcess() thread = process.GetSelectedThread() frame = thread.GetSelectedFrame()
  • 52. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
  • 53. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>" command_args = shlex.split(command)
  • 54. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>" command_args = shlex.split(command)
  • 55. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>" command_args = shlex.split(command) jq_filter = command_args[0]
  • 56. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>" command_args = shlex.split(command) jq_filter = command_args[0] val = frame.var(command_args[1]) # access the variable
  • 57. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>" command_args = shlex.split(command) jq_filter = command_args[0] val = frame.var(command_args[1]) # access the variable val_string = eval(val.GetObjectDescription())
  • 58. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>" command_args = shlex.split(command) jq_filter = command_args[0] val = frame.var(command_args[1]) # access the variable val_string = eval(val.GetObjectDescription()) # path to the jq executable. jq_exe = "/Users/aijaz/local/bin/jq"
  • 59. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>" command_args = shlex.split(command) jq_filter = command_args[0] val = frame.var(command_args[1]) # access the variable val_string = eval(val.GetObjectDescription()) # path to the jq executable. jq_exe = "/Users/aijaz/local/bin/jq" # We save the filter to a file so that we donā€™t have to worry about escaping special characters. jq_filter_file = "/tmp/jq_filter"
  • 60. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>" command_args = shlex.split(command) jq_filter = command_args[0] val = frame.var(command_args[1]) # access the variable val_string = eval(val.GetObjectDescription()) # path to the jq executable. jq_exe = "/Users/aijaz/local/bin/jq" # We save the filter to a file so that we donā€™t have to worry about escaping special characters. jq_filter_file = "/tmp/jq_filter" # the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin jq_json_file = ā€œ/tmp/jq_json"
  • 61. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>ā€ command_args = shlex.split(command) jq_filter = command_args[0] val = frame.var(command_args[1]) # access the variable val_string = eval(val.GetObjectDescription()) # path to the jq executable. jq_exe = "/Users/aijaz/local/bin/jq" # We save the filter to a file so that we donā€™t have to worry about escaping special characters. jq_filter_file = "/tmp/jq_filter" # the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin jq_json_file = "/tmp/jq_json" # write the json file and jq filter to temp files f = open(jq_json_file, 'w') f.write(val_string) f.close()
  • 62. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>ā€ command_args = shlex.split(command) jq_filter = command_args[0] val = frame.var(command_args[1]) # access the variable val_string = eval(val.GetObjectDescription()) # path to the jq executable. jq_exe = "/Users/aijaz/local/bin/jq" # We save the filter to a file so that we donā€™t have to worry about escaping special characters. jq_filter_file = "/tmp/jq_filter" # the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin jq_json_file = "/tmp/jq_json" # write the json file and jq filter to temp files f = open(jq_json_file, 'w') f.write(val_string) f.close() f = open(jq_filter_file, 'w') f.write(jq_filter) f.close()
  • 63. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>ā€ command_args = shlex.split(command) jq_filter = command_args[0] val = frame.var(command_args[1]) # access the variable val_string = eval(val.GetObjectDescription()) # path to the jq executable. jq_exe = "/Users/aijaz/local/bin/jq" # We save the filter to a file so that we donā€™t have to worry about escaping special characters. jq_filter_file = "/tmp/jq_filter" # the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin jq_json_file = "/tmp/jq_json" # write the json file and jq filter to temp files f = open(jq_json_file, 'w') f.write(val_string) f.close() f = open(jq_filter_file, 'w') f.write(jq_filter) f.close() # invoke jq and capture the output output = commands.getoutput("%s -f %s %s" % ( jq_exe, jq_filter_file, jq_json_file) )
  • 64. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>ā€ command_args = shlex.split(command) jq_filter = command_args[0] val = frame.var(command_args[1]) # access the variable val_string = eval(val.GetObjectDescription()) # path to the jq executable. jq_exe = "/Users/aijaz/local/bin/jq" # We save the filter to a file so that we donā€™t have to worry about escaping special characters. jq_filter_file = "/tmp/jq_filter" # the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin jq_json_file = "/tmp/jq_json" # write the json file and jq filter to temp files f = open(jq_json_file, 'w') f.write(val_string) f.close() f = open(jq_filter_file, 'w') f.write(jq_filter) f.close() # invoke jq and capture the output output = commands.getoutput("%s -f %s %s" % ( jq_exe, jq_filter_file, jq_json_file) ) print >>result, output
  • 65. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>ā€ command_args = shlex.split(command) jq_filter = command_args[0] val = frame.var(command_args[1]) # access the variable val_string = eval(val.GetObjectDescription()) # path to the jq executable. jq_exe = "/Users/aijaz/local/bin/jq" # We save the filter to a file so that we donā€™t have to worry about escaping special characters. jq_filter_file = "/tmp/jq_filter" # the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin jq_json_file = "/tmp/jq_json" # write the json file and jq filter to temp files f = open(jq_json_file, 'w') f.write(val_string) f.close() f = open(jq_filter_file, 'w') f.write(jq_filter) f.close() # invoke jq and capture the output output = commands.getoutput("%s -f %s %s" % ( jq_exe, jq_filter_file, jq_json_file) ) print >>result, output Gather Input Run Command Print Output
  • 66. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>ā€ command_args = shlex.split(command) jq_filter = command_args[0] val = frame.var(command_args[1]) # access the variable val_string = eval(val.GetObjectDescription()) # path to the jq executable. jq_exe = "/Users/aijaz/local/bin/jq" # We save the filter to a file so that we donā€™t have to worry about escaping special characters. jq_filter_file = "/tmp/jq_filter" # the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin jq_json_file = "/tmp/jq_json" # write the json file and jq filter to temp files f = open(jq_json_file, 'w') f.write(val_string) f.close() f = open(jq_filter_file, 'w') f.write(jq_filter) f.close() # invoke jq and capture the output output = commands.getoutput("%s -f %s %s" % ( jq_exe, jq_filter_file, jq_json_file) ) print >>result, output def __lldb_init_module(debugger, dict): # Add any commands contained in this module to LLDB command = 'command script add -f jq.jq_command jq' debugger.HandleCommand(command)
  • 69. (if youā€™re lucky enough to have a hypothesis.)
  • 75. LLDB: https://lldb.llvm.org/ A blog post from January, where I write about most of the same stuff: Extending LLDB: http://aijaz.net/2017/01/11/lldb-python/index.html JQ jq: https://stedolan.github.io/jq/ A Facebook library that adds a lot of cool extensions to LLDB Facebook Chisel: https://github.com/facebook/chisel WWDC Sessions: Debugging Tips and Tricks https://developer.apple.com/videos/play/wwdc2016/417/ Whatā€™s new in LLDB: https://developer.apple.com/videos/play/wwdc2015/402/ Introduction to LLDB and the Swift REPL https://developer.apple.com/videos/play/wwdc2014/409/ Advanced Swift Debugging in LLDB https://developer.apple.com/videos/play/wwdc2014/410/ Debugging in Xcode 6 https://developer.apple.com/videos/play/wwdc2014/413/ Debugging with Xcode https://developer.apple.com/videos/play/wwdc2013/407/ * Advanced Debugging with LLDB https://developer.apple.com/videos/play/wwdc2013/413/ * Debugging in Xcode https://developer.apple.com/videos/play/wwdc2012/412/ * Debugging with Xcode https://developer.apple.com/videos/play/wwdc2012/415/ *: Contains material related to this talk