Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Review of Eolian, Eo, Bindings, Interfaces and What’s to Come
Tom Hacohen <tom.hacohen@samsung.com>
Daniel Kolesa <d.koles...
What is Eo?
Existing solutions?
Existing solutions?
GObjecct
Existing solutions?
GObjecct
libobjc
Existing solutions?
GObjecct
libobjc
systemd
Why roll our own?
How we did it?
How we did it?
A lot of prototyping → Eo1
How we did it?
A lot of prototyping → Eo1
A lot of complaints and hate-mail → Eo2
How we did it?
A lot of prototyping → Eo1
A lot of complaints and hate-mail → Eo2
Got annoyed with writing boiler-plate → ...
How we did it?
A lot of prototyping → Eo1
A lot of complaints and hate-mail → Eo2
Got annoyed with writing boiler-plate → ...
Unifying the EFL API (AKA EFL Interfaces)
Unifying the EFL API (AKA EFL Interfaces)
Before:
evas_object_image_file_set (obj , "blah.png", "key");
edje_object_file_s...
Unifying the EFL API (AKA EFL Interfaces)
Before:
evas_object_image_file_set (obj , "blah.png", "key");
edje_object_file_s...
Object lifetime
Object lifetime
eo_add() has a C friendly refcount handling
Object lifetime
eo_add() has a C friendly refcount handling
eo_add() ↔ eo_del()
Object lifetime
eo_add() has a C friendly refcount handling
eo_add() ↔ eo_del()
eo_ref() ↔ eo_unref()
Safety features
Safety features
Pointer indirection (eo id)
Safety features
Pointer indirection (eo id)
Object type checks when calling functions
Safety features
Pointer indirection (eo id)
Object type checks when calling functions
Default return values on errors
Safety features
Pointer indirection (eo id)
Object type checks when calling functions
Default return values on errors
Safety features
Pointer indirection (eo id)
Object type checks when calling functions
Default return values on errors
For ...
Class types
Class types
Normal class
Class types
Normal class
Non instantiate-able class
Class types
Normal class
Non instantiate-able class
Interface
Class types
Normal class
Non instantiate-able class
Interface
Mixin
Using Eo
Using Eo
eo_do(obj, efl_file_set("file.eet", "key"));
Using Eo
eo_do(obj, efl_file_set("file.eet", "key"));
if (eo_do(obj, elm_widget_enabled_get()))
Using Eo
eo_do(obj, efl_file_set("file.eet", "key"));
if (eo_do(obj, elm_widget_enabled_get()))
eo_do(obj, visible = elm_w...
Using Eo
eo_do(obj, efl_file_set("file.eet", "key"));
if (eo_do(obj, elm_widget_enabled_get()))
eo_do(obj, visible = elm_w...
Using Eo
eo_do(obj, efl_file_set("file.eet", "key"));
if (eo_do(obj, elm_widget_enabled_get()))
eo_do(obj, visible = elm_w...
The Eolian library
But writing objects in C is tedious!
But writing objects in C is tedious!
The answer: Eolian
But writing objects in C is tedious!
The answer: Eolian
Eolian parses Eo API declarations
But writing objects in C is tedious!
The answer: Eolian
Eolian parses Eo API declarations
Eolian allows for automated bind...
But writing objects in C is tedious!
The answer: Eolian
Eolian parses Eo API declarations
Eolian allows for automated bind...
A new format?
A new format?
Language independent → easy bindings
A new format?
Language independent → easy bindings
Familiar syntax → easy to pick up
A new format?
Language independent → easy bindings
Familiar syntax → easy to pick up
Easy to read and write
A new format?
Language independent → easy bindings
Familiar syntax → easy to pick up
Easy to read and write
Declarative an...
class Namespace.Class (inherits) {
methods { ... }
properties { ... }
events { ... }
implements { ... }
constructors { ......
methods {
method_name @class @protected {
params {
@in int x;
@out const(char) *y;
}
return: own(char *);
}
}
properties {
property_name {
keys {
list <int > *x;
}
values {
int v;
}
get {}
set {}
}
}
Generators!
Generators!
Initial generator: C
Generators!
Initial generator: C
Further generators in core EFL: C++ and Lua
Generators!
Initial generator: C
Further generators in core EFL: C++ and Lua
Third party generators: Python, efforts being ...
Generators!
Initial generator: C
Further generators in core EFL: C++ and Lua
Third party generators: Python, efforts being ...
The Eolian library
The Eolian library
C API: simple and easy to use
The Eolian library
C API: simple and easy to use
Minimum of non-standard data types → easy to bind
The Eolian library
C API: simple and easy to use
Minimum of non-standard data types → easy to bind
Not only for generators...
The Eolian library
C API: simple and easy to use
Minimum of non-standard data types → easy to bind
Not only for generators...
However...
However...
Some things still missing
However...
Some things still missing
Documentation?
However...
Some things still missing
Documentation?
Value ownership
However...
Some things still missing
Documentation?
Value ownership
And possibly others
Lua review
The Lua generator
The Lua generator
Third generator (after C and C++) → Lua
The Lua generator
Third generator (after C and C++) → Lua
Built around our Elua application runtime
The Lua generator
Third generator (after C and C++) → Lua
Built around our Elua application runtime
Itself a Lua applicati...
The Lua generator
Third generator (after C and C++) → Lua
Built around our Elua application runtime
Itself a Lua applicati...
The FFI
The FFI
LuaJIT C FFI → simple bindings
The FFI
LuaJIT C FFI → simple bindings
Simple bindings → easy debugging
The FFI
LuaJIT C FFI → simple bindings
Simple bindings → easy debugging
Also, no compiled modules
The FFI
LuaJIT C FFI → simple bindings
Simple bindings → easy debugging
Also, no compiled modules
Also, simple generation
The infrastructure
The infrastructure
Handwritten Eo bindings
The infrastructure
Handwritten Eo bindings
No object wrappers, FFI metatypes instead
The infrastructure
Handwritten Eo bindings
No object wrappers, FFI metatypes instead
Builtin method dispatch via metatables
The infrastructure
Handwritten Eo bindings
No object wrappers, FFI metatypes instead
Builtin method dispatch via metatable...
The infrastructure
Handwritten Eo bindings
No object wrappers, FFI metatypes instead
Builtin method dispatch via metatable...
local util = require("util")
... more utils follow ...
local M, __lib = ...
local __class , __body
-- init func registers ...
local elm = require("elm")
local win = elm.Window(nil , "mywin", elm.win_type.BASIC )
win.autodel = false
win.size = { 500...
Python
The Python generator
The Python generator
Handwritten Eo bindings
The Python generator
Handwritten Eo bindings
A Python script generates Cython code
The Python generator
Handwritten Eo bindings
A Python script generates Cython code
So compiled. . . :(
The Python generator
Handwritten Eo bindings
A Python script generates Cython code
So compiled. . . :(
Will be fixed. . .
The Python generator
Handwritten Eo bindings
A Python script generates Cython code
So compiled. . . :(
Will be fixed. . .
The Python generator
Handwritten Eo bindings
A Python script generates Cython code
So compiled. . . :(
Will be fixed. . . F...
The Python bindings
The Python bindings
Native Python classes and inheritance
The Python bindings
Native Python classes and inheritance
Native Python properties
The Python bindings
Native Python classes and inheritance
Native Python properties
Native Python modules
The Python bindings
Native Python classes and inheritance
Native Python properties
Native Python modules
Everything feels ...
How to use?
How to use?
Native Python. . .
How to use?
Native Python. . .
Properties
from elementary import Win
win = Win(parent , "win name", Win.ELM_WIN_BASIC)
win...
How to use?
Native Python. . .
Properties
from elementary import Win
win = Win(parent , "win name", Win.ELM_WIN_BASIC)
win...
How to use?
Native Python. . .
Properties
from elementary import Win
win = Win(parent , "win name", Win.ELM_WIN_BASIC)
win...
But what about the current bindings?
But what about the current bindings?
Incompatible. :(
But what about the current bindings?
Incompatible. :(
Kai wants to write a compatibility layer
DEMOS
What’s next?
More bindings!
Making bindings embeddable
Use Eolian to do more
Use Eolian to do more
The EFL GUI builder - already there
Use Eolian to do more
The EFL GUI builder - already there
Clouseau - not yet
Use Eolian to do more
The EFL GUI builder - already there
Clouseau - not yet
Ideas?
EFL interfaces
EFL interfaces
Eoify more of the EFL
EFL interfaces
Eoify more of the EFL
ecore_mainloop → Eo object
EFL interfaces
Eoify more of the EFL
ecore_mainloop → Eo object
ecore_animator → event on Elm Win
EFL interfaces
Eoify more of the EFL
ecore_mainloop → Eo object
ecore_animator → event on Elm Win
ecore_job → event on the...
EFL interfaces
Eoify more of the EFL
ecore_mainloop → Eo object
ecore_animator → event on Elm Win
ecore_job → event on the...
EFL interfaces
Eoify more of the EFL
ecore_mainloop → Eo object
ecore_animator → event on Elm Win
ecore_job → event on the...
EFL interfaces
Eoify more of the EFL
ecore_mainloop → Eo object
ecore_animator → event on Elm Win
ecore_job → event on the...
EFL interfaces
Eoify more of the EFL
ecore_mainloop → Eo object
ecore_animator → event on Elm Win
ecore_job → event on the...
EFL interfaces
Eoify more of the EFL
ecore_mainloop → Eo object
ecore_animator → event on Elm Win
ecore_job → event on the...
Documentation
Documentation
1st class citizen
Documentation
1st class citizen
Support Eolian features
Documentation
1st class citizen
Support Eolian features
Write once, use everywhere
Documentation
1st class citizen
Support Eolian features
Write once, use everywhere
Editable online?
Documentation
1st class citizen
Support Eolian features
Write once, use everywhere
Editable online?
Documentation
1st class citizen
Support Eolian features
Write once, use everywhere
Editable online? Comments like php.net?
Questions?
Tom Hacohen Daniel Kolesa
tom.hacohen@samsung.com d.kolesa@samsung.com
http://stosb.com http://octaforge.org
@T...
Resources Attributions
Page ??, resources/brewing_ifaces.png
Page 2, resources/expert-beerpong.jpg
Page 37, resources/one_...
Upcoming SlideShare
Loading in …5
×

[E-Dev-Day 2014][4/16] Review of Eolian, Eo, Bindings, Interfaces and What's to Come

245 views

Published on

[E-Dev-Day 2014][4/16] Review of Eolian, Eo, Bindings, Interfaces and What's to Come
at Enlightenment Developers Day 2014

https://phab.enlightenment.org/w/events/enlightenment_developer_day_2014/

Published in: Software
  • Be the first to comment

  • Be the first to like this

[E-Dev-Day 2014][4/16] Review of Eolian, Eo, Bindings, Interfaces and What's to Come

  1. 1. Review of Eolian, Eo, Bindings, Interfaces and What’s to Come Tom Hacohen <tom.hacohen@samsung.com> Daniel Kolesa <d.kolesa@samsung.com> Enlightenment Developer Day 2004
  2. 2. What is Eo?
  3. 3. Existing solutions?
  4. 4. Existing solutions? GObjecct
  5. 5. Existing solutions? GObjecct libobjc
  6. 6. Existing solutions? GObjecct libobjc systemd
  7. 7. Why roll our own?
  8. 8. How we did it?
  9. 9. How we did it? A lot of prototyping → Eo1
  10. 10. How we did it? A lot of prototyping → Eo1 A lot of complaints and hate-mail → Eo2
  11. 11. How we did it? A lot of prototyping → Eo1 A lot of complaints and hate-mail → Eo2 Got annoyed with writing boiler-plate → Eolian
  12. 12. How we did it? A lot of prototyping → Eo1 A lot of complaints and hate-mail → Eo2 Got annoyed with writing boiler-plate → Eolian Eolian didn’t cover everything we needed → Eolian (current iteration)
  13. 13. Unifying the EFL API (AKA EFL Interfaces)
  14. 14. Unifying the EFL API (AKA EFL Interfaces) Before: evas_object_image_file_set (obj , "blah.png", "key"); edje_object_file_set (obj , "blah.edj", "group"); evas_object_del (obj); ecore_timer_del (obj); ecore_animator_del (obj);
  15. 15. Unifying the EFL API (AKA EFL Interfaces) Before: evas_object_image_file_set (obj , "blah.png", "key"); edje_object_file_set (obj , "blah.edj", "group"); evas_object_del (obj); ecore_timer_del (obj); ecore_animator_del (obj); After: eo_do(obj , efl_file_set("blah.file", "key")); eo_del(obj);
  16. 16. Object lifetime
  17. 17. Object lifetime eo_add() has a C friendly refcount handling
  18. 18. Object lifetime eo_add() has a C friendly refcount handling eo_add() ↔ eo_del()
  19. 19. Object lifetime eo_add() has a C friendly refcount handling eo_add() ↔ eo_del() eo_ref() ↔ eo_unref()
  20. 20. Safety features
  21. 21. Safety features Pointer indirection (eo id)
  22. 22. Safety features Pointer indirection (eo id) Object type checks when calling functions
  23. 23. Safety features Pointer indirection (eo id) Object type checks when calling functions Default return values on errors
  24. 24. Safety features Pointer indirection (eo id) Object type checks when calling functions Default return values on errors
  25. 25. Safety features Pointer indirection (eo id) Object type checks when calling functions Default return values on errors For example: ERR <32099 >: eo eo_ptr_indirection .x:287 ← _eo_obj_pointer_get () obj_id 0x13371337 is not ← pointing to a valid object. Maybe it has already been ← freed. ERR <32124 >: eo eo_private.h:283 _eo_unref () Object ← 0xDEADBEEF already deleted.
  26. 26. Class types
  27. 27. Class types Normal class
  28. 28. Class types Normal class Non instantiate-able class
  29. 29. Class types Normal class Non instantiate-able class Interface
  30. 30. Class types Normal class Non instantiate-able class Interface Mixin
  31. 31. Using Eo
  32. 32. Using Eo eo_do(obj, efl_file_set("file.eet", "key"));
  33. 33. Using Eo eo_do(obj, efl_file_set("file.eet", "key")); if (eo_do(obj, elm_widget_enabled_get()))
  34. 34. Using Eo eo_do(obj, efl_file_set("file.eet", "key")); if (eo_do(obj, elm_widget_enabled_get())) eo_do(obj, visible = elm_widget_visibility_get(), ← elm_widget_visibility_set(!visible));
  35. 35. Using Eo eo_do(obj, efl_file_set("file.eet", "key")); if (eo_do(obj, elm_widget_enabled_get())) eo_do(obj, visible = elm_widget_visibility_get(), ← elm_widget_visibility_set(!visible)); eo_do(obj, elm_widget_visibility_set(!elm_widget_visibility_get()));
  36. 36. Using Eo eo_do(obj, efl_file_set("file.eet", "key")); if (eo_do(obj, elm_widget_enabled_get())) eo_do(obj, visible = elm_widget_visibility_get(), ← elm_widget_visibility_set(!visible)); eo_do(obj, elm_widget_visibility_set(!elm_widget_visibility_get())); static void _size_multiply (double f) { int w, h; evas_object_geometry_get (NULL , NULL , &w, &h); evas_object_geometry_set (NULL , NULL , w * f, h * f); } eo_do(obj , _size_multiply (3.5));
  37. 37. The Eolian library
  38. 38. But writing objects in C is tedious!
  39. 39. But writing objects in C is tedious! The answer: Eolian
  40. 40. But writing objects in C is tedious! The answer: Eolian Eolian parses Eo API declarations
  41. 41. But writing objects in C is tedious! The answer: Eolian Eolian parses Eo API declarations Eolian allows for automated binding generators
  42. 42. But writing objects in C is tedious! The answer: Eolian Eolian parses Eo API declarations Eolian allows for automated binding generators Eolian is meant to be familar for everyone
  43. 43. A new format?
  44. 44. A new format? Language independent → easy bindings
  45. 45. A new format? Language independent → easy bindings Familiar syntax → easy to pick up
  46. 46. A new format? Language independent → easy bindings Familiar syntax → easy to pick up Easy to read and write
  47. 47. A new format? Language independent → easy bindings Familiar syntax → easy to pick up Easy to read and write Declarative and descriptive
  48. 48. class Namespace.Class (inherits) { methods { ... } properties { ... } events { ... } implements { ... } constructors { ... } } type Type_Name: Type_Def; struct Struct_Name { ... } enum Enum_Name { ... }
  49. 49. methods { method_name @class @protected { params { @in int x; @out const(char) *y; } return: own(char *); } }
  50. 50. properties { property_name { keys { list <int > *x; } values { int v; } get {} set {} } }
  51. 51. Generators!
  52. 52. Generators! Initial generator: C
  53. 53. Generators! Initial generator: C Further generators in core EFL: C++ and Lua
  54. 54. Generators! Initial generator: C Further generators in core EFL: C++ and Lua Third party generators: Python, efforts being put into Rust, OCaml
  55. 55. Generators! Initial generator: C Further generators in core EFL: C++ and Lua Third party generators: Python, efforts being put into Rust, OCaml Future generators include JavaScript and others
  56. 56. The Eolian library
  57. 57. The Eolian library C API: simple and easy to use
  58. 58. The Eolian library C API: simple and easy to use Minimum of non-standard data types → easy to bind
  59. 59. The Eolian library C API: simple and easy to use Minimum of non-standard data types → easy to bind Not only for generators (IDEs...)
  60. 60. The Eolian library C API: simple and easy to use Minimum of non-standard data types → easy to bind Not only for generators (IDEs...) Simple database
  61. 61. However...
  62. 62. However... Some things still missing
  63. 63. However... Some things still missing Documentation?
  64. 64. However... Some things still missing Documentation? Value ownership
  65. 65. However... Some things still missing Documentation? Value ownership And possibly others
  66. 66. Lua review
  67. 67. The Lua generator
  68. 68. The Lua generator Third generator (after C and C++) → Lua
  69. 69. The Lua generator Third generator (after C and C++) → Lua Built around our Elua application runtime
  70. 70. The Lua generator Third generator (after C and C++) → Lua Built around our Elua application runtime Itself a Lua application
  71. 71. The Lua generator Third generator (after C and C++) → Lua Built around our Elua application runtime Itself a Lua application Helped the Eolian C library go forward
  72. 72. The FFI
  73. 73. The FFI LuaJIT C FFI → simple bindings
  74. 74. The FFI LuaJIT C FFI → simple bindings Simple bindings → easy debugging
  75. 75. The FFI LuaJIT C FFI → simple bindings Simple bindings → easy debugging Also, no compiled modules
  76. 76. The FFI LuaJIT C FFI → simple bindings Simple bindings → easy debugging Also, no compiled modules Also, simple generation
  77. 77. The infrastructure
  78. 78. The infrastructure Handwritten Eo bindings
  79. 79. The infrastructure Handwritten Eo bindings No object wrappers, FFI metatypes instead
  80. 80. The infrastructure Handwritten Eo bindings No object wrappers, FFI metatypes instead Builtin method dispatch via metatables
  81. 81. The infrastructure Handwritten Eo bindings No object wrappers, FFI metatypes instead Builtin method dispatch via metatables Eo inheritance and reference management
  82. 82. The infrastructure Handwritten Eo bindings No object wrappers, FFI metatypes instead Builtin method dispatch via metatables Eo inheritance and reference management No wrappers → fast, simple, no tracking
  83. 83. local util = require("util") ... more utils follow ... local M, __lib = ... local __class , __body -- init func registers the class with __body cutil.init_module (init_func , shutdown_func) ffi.cdef [[ C API definitions in C syntax ]] __body = { ... wrapper funcs over C API funcs ... } M.My_Class = function(parent , ...) ... construct the instance and return it , like C ← would ... end
  84. 84. local elm = require("elm") local win = elm.Window(nil , "mywin", elm.win_type.BASIC ) win.autodel = false win.size = { 500, 500 } win:connect("delete ,request", function () ... event ... ← end) win: resize_object_add (obj) ...
  85. 85. Python
  86. 86. The Python generator
  87. 87. The Python generator Handwritten Eo bindings
  88. 88. The Python generator Handwritten Eo bindings A Python script generates Cython code
  89. 89. The Python generator Handwritten Eo bindings A Python script generates Cython code So compiled. . . :(
  90. 90. The Python generator Handwritten Eo bindings A Python script generates Cython code So compiled. . . :( Will be fixed. . .
  91. 91. The Python generator Handwritten Eo bindings A Python script generates Cython code So compiled. . . :( Will be fixed. . .
  92. 92. The Python generator Handwritten Eo bindings A Python script generates Cython code So compiled. . . :( Will be fixed. . . FFI!
  93. 93. The Python bindings
  94. 94. The Python bindings Native Python classes and inheritance
  95. 95. The Python bindings Native Python classes and inheritance Native Python properties
  96. 96. The Python bindings Native Python classes and inheritance Native Python properties Native Python modules
  97. 97. The Python bindings Native Python classes and inheritance Native Python properties Native Python modules Everything feels native
  98. 98. How to use?
  99. 99. How to use? Native Python. . .
  100. 100. How to use? Native Python. . . Properties from elementary import Win win = Win(parent , "win name", Win.ELM_WIN_BASIC) win.size = (600, 600) win.visibility = True
  101. 101. How to use? Native Python. . . Properties from elementary import Win win = Win(parent , "win name", Win.ELM_WIN_BASIC) win.size = (600, 600) win.visibility = True Methods win. resize_object_add (obj)
  102. 102. How to use? Native Python. . . Properties from elementary import Win win = Win(parent , "win name", Win.ELM_WIN_BASIC) win.size = (600, 600) win.visibility = True Methods win. resize_object_add (obj) Callbacks obj.connect("mouse ,down", some_callable)
  103. 103. But what about the current bindings?
  104. 104. But what about the current bindings? Incompatible. :(
  105. 105. But what about the current bindings? Incompatible. :( Kai wants to write a compatibility layer
  106. 106. DEMOS
  107. 107. What’s next?
  108. 108. More bindings!
  109. 109. Making bindings embeddable
  110. 110. Use Eolian to do more
  111. 111. Use Eolian to do more The EFL GUI builder - already there
  112. 112. Use Eolian to do more The EFL GUI builder - already there Clouseau - not yet
  113. 113. Use Eolian to do more The EFL GUI builder - already there Clouseau - not yet Ideas?
  114. 114. EFL interfaces
  115. 115. EFL interfaces Eoify more of the EFL
  116. 116. EFL interfaces Eoify more of the EFL ecore_mainloop → Eo object
  117. 117. EFL interfaces Eoify more of the EFL ecore_mainloop → Eo object ecore_animator → event on Elm Win
  118. 118. EFL interfaces Eoify more of the EFL ecore_mainloop → Eo object ecore_animator → event on Elm Win ecore_job → event on the mailoop
  119. 119. EFL interfaces Eoify more of the EFL ecore_mainloop → Eo object ecore_animator → event on Elm Win ecore_job → event on the mailoop Use advance Eo features
  120. 120. EFL interfaces Eoify more of the EFL ecore_mainloop → Eo object ecore_animator → event on Elm Win ecore_job → event on the mailoop Use advance Eo features Gesture layer API can be mostly trimmed (events tracking)
  121. 121. EFL interfaces Eoify more of the EFL ecore_mainloop → Eo object ecore_animator → event on Elm Win ecore_job → event on the mailoop Use advance Eo features Gesture layer API can be mostly trimmed (events tracking) Improve existing API
  122. 122. EFL interfaces Eoify more of the EFL ecore_mainloop → Eo object ecore_animator → event on Elm Win ecore_job → event on the mailoop Use advance Eo features Gesture layer API can be mostly trimmed (events tracking) Improve existing API Common interfaces for highly redundant functions
  123. 123. EFL interfaces Eoify more of the EFL ecore_mainloop → Eo object ecore_animator → event on Elm Win ecore_job → event on the mailoop Use advance Eo features Gesture layer API can be mostly trimmed (events tracking) Improve existing API Common interfaces for highly redundant functions Correct classification by inheritance
  124. 124. Documentation
  125. 125. Documentation 1st class citizen
  126. 126. Documentation 1st class citizen Support Eolian features
  127. 127. Documentation 1st class citizen Support Eolian features Write once, use everywhere
  128. 128. Documentation 1st class citizen Support Eolian features Write once, use everywhere Editable online?
  129. 129. Documentation 1st class citizen Support Eolian features Write once, use everywhere Editable online?
  130. 130. Documentation 1st class citizen Support Eolian features Write once, use everywhere Editable online? Comments like php.net?
  131. 131. Questions? Tom Hacohen Daniel Kolesa tom.hacohen@samsung.com d.kolesa@samsung.com http://stosb.com http://octaforge.org @TomHacohen @Octaforge
  132. 132. Resources Attributions Page ??, resources/brewing_ifaces.png Page 2, resources/expert-beerpong.jpg Page 37, resources/one_syntax.jpg Page 66, resources/lua_beer.jpg Page 85, resources/python_cat.jpg Page 106, resources/pro_beer.jpg Page 107, resources/dessert.jpg

×