SlideShare ist ein Scribd-Unternehmen logo
1 von 108
Downloaden Sie, um offline zu lesen
Rust JavaScript
Ingvar Stepanyan
@RReverser
Wait but why
JavaScript:
true cross-platform target
JavaScript:
true cross-platform target
JavaScript:
true cross-platform target
JavaScript:
true cross-platform target
JavaScript:
true cross-platform target
JavaScript:
true cross-platform target
JavaScript:
true cross-platform target
JavaScript:
true cross-platform target
JavaScript:
true cross-platform target
Wait but how
C/C++ CFG/SSA
LLVM
bitcode
Native
objects
Native
executable
Clang (LLVM)
C/C++ CFG/SSA 
LLVM
bitcode
JavaScript /
WASM
Emscripten (LLVM)
Rust CFG/SSA
LLVM
bitcode
Native
objects
Native
executable
Rust (LLVM)
Emscripten + Rust
Rust CFG/SSA
LLVM
bitcode
Native
objects
Native
executable
C/C++ CFG/SSA 
LLVM
bitcode
JavaScript /
WASM
Emscripten + Rust
Rust CFG/SSA
LLVM
bitcode
Native
objects
Native
executable
C/C++ CFG/SSA 
LLVM
bitcode
JavaScript /
WASM
Emscripten + Rust
Rust CFG/SSA
LLVM
bitcode
C/C++ CFG/SSA 
LLVM
bitcode
JavaScript /
WASM
Hell o'world
// hello.rs
fn main() {
println!("Hello, world");
}
$ rustc --target=asmjs-unknown-emscripten hello.rs
$ node hello.js
Hello, world
Exporting functions
#[no_mangle]
pub extern fn add_integers(x: i32, y: i32) -> i32 {
return x + y;
}
Exporting functions
#[no_mangle]
pub extern fn add_integers(x: i32, y: i32) -> i32 {
return x + y;
}
fn main() {}
$ rustc --target=asmjs-unknown-emscripten hello.rs
$ node
> require('./hello')
$
Exporting functions
#![feature(link_args)]
#[no_mangle]
pub extern fn add_integers(x: i32, y: i32) -> i32 {
return x + y;
}
#[link_args = "-s NO_EXIT_RUNTIME=1"]
extern {}
fn main() {}
Exporting functions
#[no_mangle]
pub extern fn add_integers(x: i32, y: i32) -> i32 {
return x + y;
}
extern {
fn emscripten_exit_with_live_runtime();
}
fn main() {
unsafe {
emscripten_exit_with_live_runtime();
}
}
$ rustc --target=asmjs-unknown-emscripten hello.rs
$ node
> require('./hello')
exit(0) implicitly called by end of main(), but
noExitRuntime, so not exiting the runtime (you can
use emscripten_force_exit, if you want to force a
true shutdown)
[Emscripten Module object]
> require('./hello')._add_integers(10, 20)
30
Exporting functions
$ emcc ... "hello.0.o" "-o" "hello.js" "-s"
"EXPORTED_FUNCTIONS=["_add_integers","_main",
"_rust_eh_personality"]" ...
Exporting functions
var real__add_integers = asm["_add_integers"];
asm["_add_integers"] = function() {
assert(runtimeInitialized, 'you need to wait for the runtime
to be ready (e.g. wait for main() to be called)');
assert(!runtimeExited, 'the runtime was exited (use
NO_EXIT_RUNTIME to keep it alive after main() exits)');
return real__add_integers.apply(null, arguments);
};
Generated code (asm.js)
function _add_integers($0,$1) {
$0 = $0|0;
$1 = $1|0;
var $$arith = 0, $$ispos = 0, $$negcheck = 0, $$negtemp = 0, $$poscheck = 0, $
$postemp = 0, $$select = 0, $2 = 0, label = 0, sp = 0;
sp = STACKTOP;
$$arith = (($0) + ($1))|0;
$$postemp = (($0) + -2147483648)|0;
$$negtemp = (($0) + 2147483647)|0;
$$poscheck = ($$arith|0)<($$postemp|0);
$$negcheck = ($$arith|0)>($$negtemp|0);
$$ispos = ($0|0)>=(0);
$$select = $$ispos ? $$poscheck : $$negcheck;
$2 = $$select;
if ($2) {
__ZN4core9panicking5panic17h0c8c35aaab94c092E(2160);
// unreachable;
} else {
return ($$arith|0);
}
return (0)|0;
}
Optimized code (asm.js)
function _add_integers($0, $1) {
$0 = $0 | 0;
$1 = $1 | 0;
return $1 + $0 | 0; //@line 47
}
Optimized code (WASM)
(func $_add_integers (param $0 i32) (param $1 i32)
(result i32)
(i32.add
(get_local $1)
(get_local $0)
)
)
asm.js <-> wasm
x+y|0
(i32.add (get_local $x)
(get_local $y))
+(x+y)
(i32.add (get_local $x)
(get_local $y))
f()|0 (call $f)
HEAP32[ptr>>2]|0
(i32.load (get_local
$ptr))
Memory model
var HEAP8 = new global.Int8Array(buffer);
var HEAP16 = new global.Int16Array(buffer);
var HEAP32 = new global.Int32Array(buffer);
var HEAPU8 = new global.Uint8Array(buffer);
var HEAPU16 = new global.Uint16Array(buffer);
var HEAPU32 = new global.Uint32Array(buffer);
var HEAPF32 = new global.Float32Array(buffer);
var HEAPF64 = new global.Float64Array(buffer);
Memory model
Calling JavaScript
#include <emscripten.h>
int main() {
EM_ASM(
alert("who doesn't like popups?");
);
return 0;
}
Calling JavaScript
// system/include/emscripten/em_asm.h
#define EM_ASM(...) emscripten_asm_const(#__VA_ARGS__)
#define EM_ASM_(code, ...)
emscripten_asm_const_int(#code, __VA_ARGS__)
...
Calling JavaScript
emscripten_asm_const: true,
emscripten_asm_const_int: true,
emscripten_asm_const_double: true,
Calling JavaScript
function _main() {
var label = 0, sp = 0;
sp = STACKTOP;
_emscripten_asm_const_v(0);
return 0;
}
Calling JavaScript
var ASM_CONSTS = [function() {
alert("who doesn't like popups?");
}];
function _emscripten_asm_const_v(code) {
return ASM_CONSTS[code]();
}
Calling JavaScript
extern {
fn emscripten_asm_const(code: &str, ...);
}
Calling JavaScript
extern {
fn emscripten_asm_const(code: *const u8, ...);
}
Calling JavaScript
unsafe {
emscripten_asm_const_int(b"alert("who doesn't like
popups?");");
}
Calling JavaScript
unsafe {
emscripten_asm_const_int(b"alert("who doesn't like
popups?");".as_ptr());
}
Calling JavaScript
unsafe {
emscripten_asm_const_int(b"alert("who doesn't like
popups?");" as *const u8);
}
Calling JavaScript
unsafe {
emscripten_asm_const_int(b"alert("who doesn't like
popups?");0" as *const u8);
}
Calling JavaScript
macro_rules! js {
($expr:expr $(,$arg:expr)*) => (unsafe {
emscripten_asm_const(
concat!(stringify!($expr), "0")
as *const str
as *const u8
)
})
}
Calling JavaScript
js! {
alert("who doesn't like popups?");
}
Calling JavaScript
But what about fancy types
Embind
C++ magic
#include <emscripten/bind.h>
using namespace emscripten;
class MyClass {
public:
MyClass(int x) : x(x) {}
int getX() const { return x; }
void setX(int x_) { x = x_; }
private:
int x;
};
// Binding code
EMSCRIPTEN_BINDINGS(my_class_example) {
class_<MyClass>("MyClass")
.constructor<int>()
.property("x", &MyClass::getX, &MyClass::setX)
;
}
$ emcc --bind hello.cpp -o hello.js
> module = require('./hello')
[Emscripten Module object]
> myObj = new module.MyClass(10)
MyClass {}
> myObj.x
10
> myObj.$$.ptr
5247384
> module.HEAP32[myObj.$$.ptr >> 2]
10
Embind
C++ magic
EMSCRIPTEN_ALWAYS_INLINE explicit class_(const char* name) {
using namespace internal;
BaseSpecifier::template verify<ClassType>();
auto _getActualType = &getActualType<ClassType>;
auto upcast = BaseSpecifier::template getUpcaster<ClassType>();
auto downcast = BaseSpecifier::template getDowncaster<ClassType>();
auto destructor = &raw_destructor<ClassType>;
_embind_register_class(
TypeID<ClassType>::get(),
TypeID<AllowedRawPointer<ClassType>>::get(),
TypeID<AllowedRawPointer<const ClassType>>::get(),
BaseSpecifier::get(),
getSignature(_getActualType),
reinterpret_cast<GenericFunction>(_getActualType),
getSignature(upcast),
reinterpret_cast<GenericFunction>(upcast),
getSignature(downcast),
reinterpret_cast<GenericFunction>(downcast),
name,
getSignature(destructor),
reinterpret_cast<GenericFunction>(destructor));
}
EMSCRIPTEN_ALWAYS_INLINE explicit class_(const char* name) {
using namespace internal;
BaseSpecifier::template verify<ClassType>();
auto _getActualType = &getActualType<ClassType>;
auto upcast = BaseSpecifier::template getUpcaster<ClassType>();
auto downcast = BaseSpecifier::template getDowncaster<ClassType>();
auto destructor = &raw_destructor<ClassType>;
_embind_register_class(
TypeID<ClassType>::get(),
TypeID<AllowedRawPointer<ClassType>>::get(),
TypeID<AllowedRawPointer<const ClassType>>::get(),
BaseSpecifier::get(),
getSignature(_getActualType),
reinterpret_cast<GenericFunction>(_getActualType),
getSignature(upcast),
reinterpret_cast<GenericFunction>(upcast),
getSignature(downcast),
reinterpret_cast<GenericFunction>(downcast),
name,
getSignature(destructor),
reinterpret_cast<GenericFunction>(destructor));
}
Reverse-engineering
FTW
// Implemented in JavaScript. Don't call these directly.
extern "C" {
...
void _embind_register_class(
...
);
...
}
// Implemented in JavaScript. Don't call these directly.
extern "C" {
...
void _embind_register_class(
TYPEID classType,
TYPEID pointerType,
TYPEID constPointerType,
TYPEID baseClassType,
const char* getActualTypeSignature,
GenericFunction getActualType,
const char* upcastSignature,
GenericFunction upcast,
const char* downcastSignature,
GenericFunction downcast,
const char* className,
const char* destructorSignature,
GenericFunction destructor);
...
}
#![feature(core_intrinsics)]
::std::intrinsics::type_id::<T>()
#![feature(core_intrinsics)]
::std::intrinsics::type_id::<T>() as u32
// Implemented in JavaScript. Don't call these directly.
extern "C" {
...
void _embind_register_class(
TYPEID classType,
TYPEID pointerType,
TYPEID constPointerType,
TYPEID baseClassType,
const char* getActualTypeSignature,
GenericFunction getActualType,
const char* upcastSignature,
GenericFunction upcast,
const char* downcastSignature,
GenericFunction downcast,
const char* className,
const char* destructorSignature,
GenericFunction destructor);
...
}
extern fn get_actual_type<T: 'static>(arg: *const void) -> u32 {
unsafe {
type_id::<T>()
}
}
// Implemented in JavaScript. Don't call these directly.
extern "C" {
...
void _embind_register_class(
TYPEID classType,
TYPEID pointerType,
TYPEID constPointerType,
TYPEID baseClassType,
const char* getActualTypeSignature,
GenericFunction getActualType,
const char* upcastSignature,
GenericFunction upcast,
const char* downcastSignature,
GenericFunction downcast,
const char* className,
const char* destructorSignature,
GenericFunction destructor);
...
}
void smth(int x, float y, const char *z);
void smth(int x, float y, const char *z);
"vifi"
// Implemented in JavaScript. Don't call these directly.
extern "C" {
...
void _embind_register_class(
TYPEID classType,
TYPEID pointerType,
TYPEID constPointerType,
TYPEID baseClassType,
const char* getActualTypeSignature,
GenericFunction getActualType,
const char* upcastSignature,
GenericFunction upcast,
const char* downcastSignature,
GenericFunction downcast,
const char* className,
const char* destructorSignature,
GenericFunction destructor);
...
}
// Implemented in JavaScript. Don't call these directly.
extern "C" {
...
void _embind_register_class(
TYPEID classType,
TYPEID pointerType,
TYPEID constPointerType,
TYPEID baseClassType,
const char* getActualTypeSignature,
GenericFunction getActualType,
const char* upcastSignature,
GenericFunction upcast,
const char* downcastSignature,
GenericFunction downcast,
const char* className,
const char* destructorSignature,
GenericFunction destructor);
...
}
::std::intrinsics::type_name::<T>()
CString::new(::std::intrinsics::type_name::<T>())
.unwrap()
.as_ptr(),
// Implemented in JavaScript. Don't call these directly.
extern "C" {
...
void _embind_register_class(
TYPEID classType,
TYPEID pointerType,
TYPEID constPointerType,
TYPEID baseClassType,
const char* getActualTypeSignature,
GenericFunction getActualType,
const char* upcastSignature,
GenericFunction upcast,
const char* downcastSignature,
GenericFunction downcast,
const char* className,
const char* destructorSignature,
GenericFunction destructor);
...
}
extern fn destructure<T: 'static>(arg: *mut void) {
unsafe {
Box::from_raw(arg as *mut T);
}
}
// Implemented in JavaScript. Don't call these directly.
extern "C" {
...
void _embind_register_class(
TYPEID classType,
TYPEID pointerType,
TYPEID constPointerType,
TYPEID baseClassType,
const char* getActualTypeSignature,
GenericFunction getActualType,
const char* upcastSignature,
GenericFunction upcast,
const char* downcastSignature,
GenericFunction downcast,
const char* className,
const char* destructorSignature,
GenericFunction destructor);
...
}
unsafe {
_embind_register_class(
type_id::<T>(),
type_id::<*mut T>(),
type_id::<*const T>(),
null(),
b"ii0".as_ptr(),
get_actual_type::<T>,
b"v0".as_ptr(),
noop,
b"v0".as_ptr(),
noop,
CString::new(type_name::<T>()).unwrap().as_ptr(),
b"vi0".as_ptr(),
destructure::<T>
)
}
unsafe {
_embind_register_class(
type_id::<T>(),
type_id::<*mut T>(),
type_id::<*const T>(),
null(),
cstr!("ii"),
get_actual_type::<T>,
cstr!("v"),
noop,
cstr!("v"),
noop,
CString::new(type_name::<T>()).unwrap().as_ptr(),
cstr!("vi"),
destructure::<T>
)
}
void _embind_register_class_constructor(
TYPEID classType,
unsigned argCount,
const TYPEID argTypes[],
const char* invokerSignature,
GenericFunction invoker,
GenericFunction constructor);
extern {
fn _embind_register_class_constructor(
cls_type: TypeId,
arg_count: usize,
arg_types: *const TypeId,
invoker_signature: CStr,
invoker: extern fn (
fn () -> Box<void>
) -> *mut void,
ctor: fn () -> Box<void>
);
}
#[allow(improper_ctypes)]
extern {
fn _embind_register_class_constructor(
cls_type: TypeId,
arg_count: usize,
arg_types: *const TypeId,
invoker_signature: CStr,
invoker: extern fn (
fn () -> Box<void>
) -> *mut void,
ctor: fn () -> Box<void>
);
}
extern fn invoker(f: fn () -> Box<void>) -> *mut void {
Box::into_raw(f())
}
unsafe {
let arg_types = [type_id::<*mut T>()];
_embind_register_class_constructor(
type_id::<T>(),
arg_types.len(),
arg_types.as_ptr(),
cstr!("ii"),
invoker,
::std::mem::transmute(
Box::<T>::default as fn () -> Box<_>
)
)
}
register_class::<MyStruct>();
register_class_default_ctor::<MyStruct>();
_embind_register_*
• void
• bool
• integer
• float
• std_string
• std_wstring
• memory_view
• function
• class
• enum
• smart_ptr
• ...
JavaScript static libraries
mergeInto(LibraryManager.library, {
my_js: function() {
alert('hi');
},
});
#[link_args = "--js-library rustlib.js"]
extern {
fn my_js();
}
mergeInto(LibraryManager.library, {
_embind_register_rust_string__deps: ['$registerType'],
_embind_register_rust_string: function(rawType) {
registerType(rawType, {
name: "&str",
'argPackAdvance': 8,
'readValueFromPointer': function (pointer) {
pointer >>= 2;
var length = HEAPU32[pointer + 1];
pointer = HEAPU32[pointer];
return Pointer_stringify(pointer, length);
}
});
},
})
#[link_args = "--js-library rustlib.js"]
extern {
fn _embind_register_rust_string(type_id: u32);
}
...
_embind_register_rust_string(type_id::<&str>());
Garbage collection
Garbage collection
window [1]
5
Garbage collection
window [2]
5
_emval_incref (aka Clone)
Garbage collection
window [2] "document"
5 6
_emval_take_value(...)
aka
Val::from("document").handle
Garbage collection
window [2] "document" document
5 6 7
_emval_get_property(...)
aka
global.get("document").handle
Garbage collection
window [1] document
5 7
_emval_decref(...)
aka
Drop for "document"
and
Drop for window
Serde + Emscripten
#[derive(Serialize)]
struct S {
x: &'static str,
y: u64,
z: [f64; 2]
}
let s = S {
x: "hello, world",
y: 42,
z: [123.456, 789.]
};
let val = s.serialize(Serializer).unwrap();
{
x: "hello, world",
y: 42,
z: [123.456, 789]
}
Speed (2.8M JSON)
native JSON.parse
serde-json
0ms 25ms 50ms 75ms 100ms
Speed (2.8M JSON)
via JSON
embind
0ms 27.5ms 55ms 82.5ms 110ms
Useful links
• https://github.com/RReverser/asmjs-experiments - safe
bindings for Embind
• https://kripken.github.io/emscripten-site/docs/
api_reference/emscripten.h.html - Emscripten APIs
• https://github.com/rust-lang/rust/pull/41409 - allow
linking JS libraries as normal libs
• https://github.com/rust-lang/cargo/pull/3954 - let Cargo
run binaries, tests, benchmarks on Emscripten target
via Node.js
unsafe {
get_questions()
}
Ingvar Stepanyan
@RReverser

Weitere ähnliche Inhalte

Was ist angesagt?

HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
Dmitry Soshnikov
 

Was ist angesagt? (20)

ES6 - Next Generation Javascript
ES6 - Next Generation JavascriptES6 - Next Generation Javascript
ES6 - Next Generation Javascript
 
JavaScript ES6
JavaScript ES6JavaScript ES6
JavaScript ES6
 
Esprima - What is that
Esprima - What is thatEsprima - What is that
Esprima - What is that
 
PHP 7 – What changed internally? (Forum PHP 2015)
PHP 7 – What changed internally? (Forum PHP 2015)PHP 7 – What changed internally? (Forum PHP 2015)
PHP 7 – What changed internally? (Forum PHP 2015)
 
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
 
Xlab #1: Advantages of functional programming in Java 8
Xlab #1: Advantages of functional programming in Java 8Xlab #1: Advantages of functional programming in Java 8
Xlab #1: Advantages of functional programming in Java 8
 
LetSwift RxSwift 시작하기
LetSwift RxSwift 시작하기LetSwift RxSwift 시작하기
LetSwift RxSwift 시작하기
 
Explaining ES6: JavaScript History and What is to Come
Explaining ES6: JavaScript History and What is to ComeExplaining ES6: JavaScript History and What is to Come
Explaining ES6: JavaScript History and What is to Come
 
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and JasmineRails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
 
連邦の白いヤツ 「Objective-C」
連邦の白いヤツ 「Objective-C」連邦の白いヤツ 「Objective-C」
連邦の白いヤツ 「Objective-C」
 
JavaScript on the GPU
JavaScript on the GPUJavaScript on the GPU
JavaScript on the GPU
 
The state of your own hypertext preprocessor
The state of your own hypertext preprocessorThe state of your own hypertext preprocessor
The state of your own hypertext preprocessor
 
Don't Be Afraid of Abstract Syntax Trees
Don't Be Afraid of Abstract Syntax TreesDon't Be Afraid of Abstract Syntax Trees
Don't Be Afraid of Abstract Syntax Trees
 
Static Optimization of PHP bytecode (PHPSC 2017)
Static Optimization of PHP bytecode (PHPSC 2017)Static Optimization of PHP bytecode (PHPSC 2017)
Static Optimization of PHP bytecode (PHPSC 2017)
 
Rails on Oracle 2011
Rails on Oracle 2011Rails on Oracle 2011
Rails on Oracle 2011
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP Generators
 
Mongoskin - Guilin
Mongoskin - GuilinMongoskin - Guilin
Mongoskin - Guilin
 
ES2015 workflows
ES2015 workflowsES2015 workflows
ES2015 workflows
 
FalsyValues. Dmitry Soshnikov - ECMAScript 6
FalsyValues. Dmitry Soshnikov - ECMAScript 6FalsyValues. Dmitry Soshnikov - ECMAScript 6
FalsyValues. Dmitry Soshnikov - ECMAScript 6
 
PHP 7 – What changed internally?
PHP 7 – What changed internally?PHP 7 – What changed internally?
PHP 7 – What changed internally?
 

Ähnlich wie Rust ⇋ JavaScript

From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)
Night Sailer
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
Dmitry Buzdin
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)
Kang-min Liu
 
JavaScript for PHP developers
JavaScript for PHP developersJavaScript for PHP developers
JavaScript for PHP developers
Stoyan Stefanov
 

Ähnlich wie Rust ⇋ JavaScript (20)

Groovy
GroovyGroovy
Groovy
 
MiamiJS - The Future of JavaScript
MiamiJS - The Future of JavaScriptMiamiJS - The Future of JavaScript
MiamiJS - The Future of JavaScript
 
From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
 
PHPSpec BDD for PHP
PHPSpec BDD for PHPPHPSpec BDD for PHP
PHPSpec BDD for PHP
 
Introdução ao Perl 6
Introdução ao Perl 6Introdução ao Perl 6
Introdução ao Perl 6
 
EcmaScript unchained
EcmaScript unchainedEcmaScript unchained
EcmaScript unchained
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)
 
Real life-coffeescript
Real life-coffeescriptReal life-coffeescript
Real life-coffeescript
 
JavaScript for PHP developers
JavaScript for PHP developersJavaScript for PHP developers
JavaScript for PHP developers
 
JavaScript 2016 for C# Developers
JavaScript 2016 for C# DevelopersJavaScript 2016 for C# Developers
JavaScript 2016 for C# Developers
 
Wheels we didn't re-invent: Perl's Utility Modules
Wheels we didn't re-invent: Perl's Utility ModulesWheels we didn't re-invent: Perl's Utility Modules
Wheels we didn't re-invent: Perl's Utility Modules
 
Message in a bottle
Message in a bottleMessage in a bottle
Message in a bottle
 
Modern Perl
Modern PerlModern Perl
Modern Perl
 
Wakanday JS201 Best Practices
Wakanday JS201 Best PracticesWakanday JS201 Best Practices
Wakanday JS201 Best Practices
 
PHP tips and tricks
PHP tips and tricks PHP tips and tricks
PHP tips and tricks
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applications
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
 
Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4
 
Php my sql - functions - arrays - tutorial - programmerblog.net
Php my sql - functions - arrays - tutorial - programmerblog.netPhp my sql - functions - arrays - tutorial - programmerblog.net
Php my sql - functions - arrays - tutorial - programmerblog.net
 

Mehr von Ingvar Stepanyan (7)

A very quick intro to astrophotography
A very quick intro to astrophotographyA very quick intro to astrophotography
A very quick intro to astrophotography
 
Asyncifying WebAssembly for the modern Web
Asyncifying WebAssembly for the modern WebAsyncifying WebAssembly for the modern Web
Asyncifying WebAssembly for the modern Web
 
How I tried to compile JavaScript
How I tried to compile JavaScriptHow I tried to compile JavaScript
How I tried to compile JavaScript
 
es6.concurrency()
es6.concurrency()es6.concurrency()
es6.concurrency()
 
React for WinRT apps
React for WinRT appsReact for WinRT apps
React for WinRT apps
 
Creating own language made easy
Creating own language made easyCreating own language made easy
Creating own language made easy
 
JS: Audio Data Processing
JS: Audio Data ProcessingJS: Audio Data Processing
JS: Audio Data Processing
 

Kürzlich hochgeladen

Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

Kürzlich hochgeladen (20)

Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 

Rust ⇋ JavaScript