SlideShare une entreprise Scribd logo
1  sur  29
Télécharger pour lire hors ligne
Bindings
                                   The Zen of Montage




sch, @benoitmarchant, @montagejs
function Point(x, y) {
    this.x = x;
    this.y = y;
}
Point.prototype.magnitude = function () {
    return Math.sqrt(
        this.x * this.x +
        this.y * this.y
    );
};

var point = new Point(3, 4);
expect(point.magnitude()).toEqual(5);
var Montage = require("montage").Montage;
var Point = Montage.create(Montage, {
    didCreate: {
        value: function () {
            this.addOwnPropertyChangeListener("x", this, "coordinate");
            this.addOwnPropertyChangeListener("y", this, "coordiante");
        }
    },
    handleCoordinateChange: {
        value: function () {
            if (this.x == null || this.y == null) {
                 this.magnitude = null;
            } else {
                 this.magnitude = Math.sqrt(
                     this.x * this.x +
                     this.y * this.y
                 );
            }
        }
    }
});

var point = Point.create();
point.x = 3;
point.y = 4;
expect(point.magnitude).toEqual(5);
var Montage = require("montage").Montage;
var Point = Montage.create(Montage, {
    didCreate: {
        value: function () {
            this.defineBinding("magnitude", {
                 "<-": "(x ** 2 + y ** 2) // 2"
            });
        }
    }
});

var point = Point.create();
point.x = 3;
point.y = 4;
expect(point.magnitude).toEqual(5)
Discrete Change Listeners
● property changes
● range changes
● map changes
Property Changes
object.addOwnPropertyChangeListener
    (key, handler, token)

handler.handleTokenChange
    (value, key, object)

add/remove
propertyChange/beforePropertyChange
tokenChange/tokenWillChange
Map Changes
object.addMapChangeListener
    (handler, token) (any key)

handler.handleTokenMapChange
    (value, key, object)

add/remove
mapChange/beforeMapChange
mapChange/mapWillChange
Range Changes
object.addRangeChangeListener
    (handler, token)

handler.handleTokenRangeChange
    (plus, minus, index)

add/remove
rangeChange/beforeRangeChange
rangeChange/rangeWillChange
Array Range Changes
shift() → splice(0, 1)
unshift(...values) → splice(0, 0, ...values)
push(...values) → splice(length, 0, ...values)
pop() → splice(length - 1, 1)
clear() → splice(0, length)
set(index, value) → splice(index, 1, value)
swap(i, l, values) → splice(i, l, ...values)
© Sidney Harris — http://www.sciencecartoonsplus.com/
Bindings
a↔b                    a.has(b) ↔ c
a.b ↔ c.d              a == b ↔ c
a ← b.map{c}           a[b] ↔ c
a ← b.filter{c}        a.* ← c.map{d}
a ← b.sorted{c}        a[*] ← b.toMap()
a ← b.flatten()        a ← b.toMap{[.0, .1]}
sum, average,          r ← (x**2 + y**2) //2
reversed, enumerate,   f ↔ c * 1.8 + 32
items, some, every     a ← b.{x: .0, y: .1}
Pipelines




 http://montagejs.github.com/frb/grammar.xhtml
http://montagejs.github.com/frb/grammar.xhtml
Insert Demo Here
a.b ↔ c.d


this.defineBinding("a.b", {
    "<->": "c.d"
});

{
    "prototype": "montage",
    "bindings": {
        "a.b": {"<->": "c.d"}
    }
}
"selectionName": {
    "prototype": "montage/ui/dynamic-text.reel",
    "properties": {
        "element": {"#": "selectionName"}
    },
    "bindings": {
        "value": {
            "<-": "
                @selection.currentIteration.object.name + (
                    !@selection.currentIteration.isLast ?
                    ', ' : ''
                )
            "
        }
    }
}
// Repetition.Iteration
// didCreate:

this.defineBinding("isLast", {
    "<-": "
         visibleIndex ==
         repetition.iterations.length - 1
     "
});
// ContentController.Iteration
// didCreate:

this.defineBinding("selected", {
    "<->": "controller.selection.has(object)"
});
Insert More Awesomer Demo Here
"valueInput": {
    "prototype": "montage/ui/input-text.reel",
    "properties": {
        "element": {"#": "valueInput"}
    },
    "bindings": {
        "value": {
            "<->": "
                @owner.data
                [+@rowInput.value]
                [+@columnInput.value]
            "
        }
    }
}
function observeProperty(object, key, emit, source, parameters) {
    var cancel = Function.noop;
    function propertyChange(value, key, object) {
        cancel();
        cancel = emit(value, key, object) || Function.noop;
    }
    PropertyChanges.addOwnPropertyChangeListener(
        object, key, propertyChange
    );
    propertyChange(object[key], key, object);
    return once(function cancelPropertyObserver() {
        cancel();
        PropertyChanges.removeOwnPropertyChangeListener(
            object, key, propertyChange
        );
    });
}
exports.makeSumObserver = makeCollectionObserverMaker(
    function setup() {
        var sum = 0;
        return function rangeChange(plus, minus, index) {
            sum += plus.sum() - minus.sum();
            return sum;
        };
    }
);
Upcoming Changes
● array.property → array.map
  {property}


● array.count() →
  array.length
Upcoming Changes



this.defineBinding(target, targetPath, {
      "<- or <->": boundObjectPropertyPath,
      source: boundObject
});
http://{github,documentup}.com/montagejs/frb
http://{github,documentup}.com/montagejs/frb

Contenu connexe

Tendances

The Ring programming language version 1.7 book - Part 71 of 196
The Ring programming language version 1.7 book - Part 71 of 196The Ring programming language version 1.7 book - Part 71 of 196
The Ring programming language version 1.7 book - Part 71 of 196Mahmoud Samir Fayed
 
Gearman, from the worker's perspective
Gearman, from the worker's perspectiveGearman, from the worker's perspective
Gearman, from the worker's perspectiveBrian Aker
 
Gearmam, from the_worker's_perspective copy
Gearmam, from the_worker's_perspective copyGearmam, from the_worker's_perspective copy
Gearmam, from the_worker's_perspective copyBrian Aker
 
The Ring programming language version 1.8 book - Part 73 of 202
The Ring programming language version 1.8 book - Part 73 of 202The Ring programming language version 1.8 book - Part 73 of 202
The Ring programming language version 1.8 book - Part 73 of 202Mahmoud Samir Fayed
 
The evolution of redux action creators
The evolution of redux action creatorsThe evolution of redux action creators
The evolution of redux action creatorsGeorge Bukhanov
 
Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6Ignacio Martín
 
Cycle.js: Functional and Reactive
Cycle.js: Functional and ReactiveCycle.js: Functional and Reactive
Cycle.js: Functional and ReactiveEugene Zharkov
 
Redux Sagas - React Alicante
Redux Sagas - React AlicanteRedux Sagas - React Alicante
Redux Sagas - React AlicanteIgnacio Martín
 
Oops lab manual2
Oops lab manual2Oops lab manual2
Oops lab manual2Mouna Guru
 
20180721 code defragment
20180721 code defragment20180721 code defragment
20180721 code defragmentChiwon Song
 
Hyperparameter optimization landscape
Hyperparameter optimization landscapeHyperparameter optimization landscape
Hyperparameter optimization landscapeneptune.ml
 
Testing with Midje
Testing with MidjeTesting with Midje
Testing with MidjeTobias Bayer
 
Clojure testing with Midje
Clojure testing with MidjeClojure testing with Midje
Clojure testing with Midjeinovex GmbH
 
Tweaking the interactive grid
Tweaking the interactive gridTweaking the interactive grid
Tweaking the interactive gridRoel Hartman
 

Tendances (19)

The Ring programming language version 1.7 book - Part 71 of 196
The Ring programming language version 1.7 book - Part 71 of 196The Ring programming language version 1.7 book - Part 71 of 196
The Ring programming language version 1.7 book - Part 71 of 196
 
Gearman, from the worker's perspective
Gearman, from the worker's perspectiveGearman, from the worker's perspective
Gearman, from the worker's perspective
 
Gearmam, from the_worker's_perspective copy
Gearmam, from the_worker's_perspective copyGearmam, from the_worker's_perspective copy
Gearmam, from the_worker's_perspective copy
 
The Ring programming language version 1.8 book - Part 73 of 202
The Ring programming language version 1.8 book - Part 73 of 202The Ring programming language version 1.8 book - Part 73 of 202
The Ring programming language version 1.8 book - Part 73 of 202
 
The evolution of redux action creators
The evolution of redux action creatorsThe evolution of redux action creators
The evolution of redux action creators
 
Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6
 
Cycle.js: Functional and Reactive
Cycle.js: Functional and ReactiveCycle.js: Functional and Reactive
Cycle.js: Functional and Reactive
 
Redux Sagas - React Alicante
Redux Sagas - React AlicanteRedux Sagas - React Alicante
Redux Sagas - React Alicante
 
Oops lab manual2
Oops lab manual2Oops lab manual2
Oops lab manual2
 
Elm: give it a try
Elm: give it a tryElm: give it a try
Elm: give it a try
 
Container adapters
Container adaptersContainer adapters
Container adapters
 
20180721 code defragment
20180721 code defragment20180721 code defragment
20180721 code defragment
 
Chapter 6 arrays part-1
Chapter 6   arrays part-1Chapter 6   arrays part-1
Chapter 6 arrays part-1
 
Clojure functions midje
Clojure functions midjeClojure functions midje
Clojure functions midje
 
Hyperparameter optimization landscape
Hyperparameter optimization landscapeHyperparameter optimization landscape
Hyperparameter optimization landscape
 
Cquestions
Cquestions Cquestions
Cquestions
 
Testing with Midje
Testing with MidjeTesting with Midje
Testing with Midje
 
Clojure testing with Midje
Clojure testing with MidjeClojure testing with Midje
Clojure testing with Midje
 
Tweaking the interactive grid
Tweaking the interactive gridTweaking the interactive grid
Tweaking the interactive grid
 

Similaire à Bindings: the zen of montage

TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript IntroductionDmitry Sheiko
 
Object-Oriented JavaScript
Object-Oriented JavaScriptObject-Oriented JavaScript
Object-Oriented JavaScriptkvangork
 
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 6Dmitry Soshnikov
 
Functional programming using underscorejs
Functional programming using underscorejsFunctional programming using underscorejs
Functional programming using underscorejs偉格 高
 
Object Oriented JavaScript
Object Oriented JavaScriptObject Oriented JavaScript
Object Oriented JavaScriptJulie Iskander
 
Recompacting your react application
Recompacting your react applicationRecompacting your react application
Recompacting your react applicationGreg Bergé
 
Building Smart Async Functions For Mobile
Building Smart Async Functions For MobileBuilding Smart Async Functions For Mobile
Building Smart Async Functions For MobileGlan Thomas
 
The Canvas API for Rubyists
The Canvas API for RubyistsThe Canvas API for Rubyists
The Canvas API for Rubyistsdeanhudson
 
Taming that client side mess with Backbone.js
Taming that client side mess with Backbone.jsTaming that client side mess with Backbone.js
Taming that client side mess with Backbone.jsJarod Ferguson
 
Knockoutjs UG meeting presentation
Knockoutjs UG meeting presentationKnockoutjs UG meeting presentation
Knockoutjs UG meeting presentationValdis Iljuconoks
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016ES6 PPT FOR 2016
ES6 PPT FOR 2016Manoj Kumar
 
Create a java project that - Draw a circle with three random init.pdf
Create a java project that - Draw a circle with three random init.pdfCreate a java project that - Draw a circle with three random init.pdf
Create a java project that - Draw a circle with three random init.pdfarihantmobileselepun
 
Secrets of JavaScript Libraries
Secrets of JavaScript LibrariesSecrets of JavaScript Libraries
Secrets of JavaScript Librariesjeresig
 

Similaire à Bindings: the zen of montage (20)

TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
 
Object-Oriented JavaScript
Object-Oriented JavaScriptObject-Oriented JavaScript
Object-Oriented JavaScript
 
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
 
ES6 Overview
ES6 OverviewES6 Overview
ES6 Overview
 
Advanced JavaScript
Advanced JavaScript Advanced JavaScript
Advanced JavaScript
 
Functional programming using underscorejs
Functional programming using underscorejsFunctional programming using underscorejs
Functional programming using underscorejs
 
Javascript
JavascriptJavascript
Javascript
 
ECMAScript 5: Новое в JavaScript
ECMAScript 5: Новое в JavaScriptECMAScript 5: Новое в JavaScript
ECMAScript 5: Новое в JavaScript
 
Object Oriented JavaScript
Object Oriented JavaScriptObject Oriented JavaScript
Object Oriented JavaScript
 
Recompacting your react application
Recompacting your react applicationRecompacting your react application
Recompacting your react application
 
Building Smart Async Functions For Mobile
Building Smart Async Functions For MobileBuilding Smart Async Functions For Mobile
Building Smart Async Functions For Mobile
 
The Canvas API for Rubyists
The Canvas API for RubyistsThe Canvas API for Rubyists
The Canvas API for Rubyists
 
Taming that client side mess with Backbone.js
Taming that client side mess with Backbone.jsTaming that client side mess with Backbone.js
Taming that client side mess with Backbone.js
 
V8
V8V8
V8
 
Knockoutjs UG meeting presentation
Knockoutjs UG meeting presentationKnockoutjs UG meeting presentation
Knockoutjs UG meeting presentation
 
25-functions.ppt
25-functions.ppt25-functions.ppt
25-functions.ppt
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016ES6 PPT FOR 2016
ES6 PPT FOR 2016
 
Create a java project that - Draw a circle with three random init.pdf
Create a java project that - Draw a circle with three random init.pdfCreate a java project that - Draw a circle with three random init.pdf
Create a java project that - Draw a circle with three random init.pdf
 
Player x 0 y ga.docx
Player x 0 y ga.docxPlayer x 0 y ga.docx
Player x 0 y ga.docx
 
Secrets of JavaScript Libraries
Secrets of JavaScript LibrariesSecrets of JavaScript Libraries
Secrets of JavaScript Libraries
 

Dernier

Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesZilliz
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 

Dernier (20)

Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector Databases
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 

Bindings: the zen of montage