Alfresco                     The Clojure way                                              Carlo Sciolla, Sr R&D Developer ...
public void printAllNames(repo) {                                          AuthenticationUtil.runAs(new RunAsWork () {    ...
(defn print-all-names [repo]                                          (run-as (admin)                                     ...
(defn print-all-names [repo]   Java interop                                          (AuthenticationUtil/runAs            ...
(defmacro run-as                                          [user f]                                          `(let [work# (...
(defn print-all-names [repo]                                          (run-as (admin)                                     ...
(defn print-all-names [repo]                                          (run-as (admin)                                     ...
(defn print-all-names [repo]                                          (run-as (admin)                                     ...
Parenthesis count                                                   VS                                                    ...
the sexp and the city                   or: How I learned to stop worrying and love the parens                           A...
sexp = | primitive-elem                                                     | list of s-expression                        ...
Symbols: ns/foo                     Keywords: :key                      odd?                                 ::qualified  ...
list      (c “list” :something)                           vector        [“vector” 42 :foobar]                             ...
list      (quote (c “list” :something))                              list      ‘(c “list” :something)                     ...
function definition                    name                                        (defn print-all-names [repo]    paramet...
immutability                                                and the art of motorcycle maintenance                         ...
Horse horse = new Horse(14);                           horse.getPosition();                                       ??      ...
(defn move [h]                    {:pos (inc (:pos h))})                  (def horse                    {:pos 14})        ...
Structural sharing                           When creating a new version of a value, Clojure runtime optimizes the        ...
horse                                                                                                   t                 ...
the seq librabry                           ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
clojure.core/seq                                        ([coll])                                          Returns a seq on...
distinct filter remove for keep keep-indexed cons concat                                        lazy-cat mapcat cycle inte...
fully functional                           ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
(map println [“one” “two” “three”])                                        (doseq [x [“one” “two” “three”]] (println x))  ...
(defn print-all-names [repo]                                          (run-as (admin)                                     ...
distinct filter remove for keep keep-indexed cons concat                                        lazy-cat mapcat cycle inte...
clojure.core/tree-seq                                        ([branch? children root])                                    ...
clojure.core/tree-seq                                        ([branch? children root])                                    ...
(defn type-qname [node]                                                                                           (m/qname...
clojure.core/tree-seq                                        ([branch? children root])                                    ...
(defn children [node]                                          (n/children node)))                                        ...
(defn print-all-names [repo] (defn to-seq [node]                                          (run-as (admin)             (tre...
the lord of the repl                             one repl to bring them all and in the lexical scope, bind them           ...
read         R                                                                              user> (defn    Y [r]          ...
read         R                                                                              user> (defn    Y [r]          ...
read         R                                     prompt                                                                 ...
+                                        $ curl -X POST -u admin:admin                                           http://lo...
user> (def folder                                                (a/as-admin                                              ...
Trying it out                           We know we should already be able to reduce the Alfresco repository               ...
concurrency                           ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
private HashMap _map = new HashMap();                                         public void oneMore(Object k, Object v) {   ...
Software Transactional Memory                           Similarly to databases, Clojure runtime uses transactions to handl...
(def _shared (ref {}))                                        (defn update                                         [old k ...
sync   coord                                        clojure.core/ref                                        ([x] [x & opti...
the clojure way                           ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
(map #(property % name) (query “@cm:name:”Sites””))                           (defn query                             "Ret...
(write! “new content” node)                           (write!                             [^String src node]              ...
(to-seq (company-home))                           (defn to-seq                             [root]                         ...
John       McCarthy       4 September 1927 - 24 October 2011                           ALFRESCO THE CLOJURE WAY | November...
Q/A                           ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
Carlo Sciolla                                                                              sr. R&D Developer              ...
Upcoming SlideShare
Loading in...5
×

Oral presentation v2

782

Published on

hhhh

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
782
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
0
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Transcript of "Oral presentation v2"

    1. 1. Alfresco The Clojure way Carlo Sciolla, Sr R&D Developer at Backbase ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    2. 2. public void printAllNames(repo) { AuthenticationUtil.runAs(new RunAsWork () { public Object doWork(){ for (NodeRef node : getAllNodes(repo)) { String name = getName(node); System.out.println(name); } } }, AuthenticationUtil.getAdminUserNAme()) } Sample user story As admin, I want to loop through all the nodes from the Alfresco repository, So that I can print their names ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    3. 3. (defn print-all-names [repo] (run-as (admin) (doseq [node (to-seq repo)] (println (property node “cm:name”))))) #LOC < 1/2 Sample user story As admin, I want to loop through all the nodes from the Alfresco repository, So that I can print their names ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    4. 4. (defn print-all-names [repo] Java interop (AuthenticationUtil/runAs (reify AuthenticationUtil$RunAsWork (doWork [this] (doseq [node (to-seq repo)] (println (property node “cm:name”))))) (admin))) How to get there Having only moved parenthesis around and tweaked it a bit, we eventually translated our code into Clojure. We still have to get rid of the anonymous class. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    5. 5. (defmacro run-as [user f] `(let [work# (reify AuthenticationUtil$RunAsWork (~doWork [~this] ~f))] (AuthenticationUtil/runAs work# ~user))) Reflection on massive steroids Macros are “special” functions that, at compile time, shuffle the pieces they receive in input and return a function. They’re misterious and powerful: don’t try to decode it now, young jedi. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    6. 6. (defn print-all-names [repo] (run-as (admin) (doseq [node (to-seq repo)] (println (property node “cm:name”))))) Straight to the point Clojure, as any Lisp, allows you to easily create clear and concise DSLs. New functions to enhance expressivity to your programs. Fewer lines to maintain. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    7. 7. (defn print-all-names [repo] (run-as (admin) (doseq [node (to-seq repo)] (println (property node “cm:name”))))) https://github.com/skuro/lambdalf Here be Lambdalf While Clojure allows direct access to Java classes and instances, lambdalf provides a more idiomatic access to the core Alfresco API. You’ll see some examples along the way. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    8. 8. (defn print-all-names [repo] (run-as (admin) (doseq [node (to-seq repo)] (println (property node “cm:name”))))) Lost In Superfluous Parenthesis? It is usually perceived that Lisp code has an overwhelming amount of parenthesis. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    9. 9. Parenthesis count VS 26 18 24 w/expanded macro Lost In Superfluous Parenthesis? It is usually perceived that Lisp code has an overwhelming amount of parenthesis. It’s usually unfair. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    10. 10. the sexp and the city or: How I learned to stop worrying and love the parens ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    11. 11. sexp = | primitive-elem | list of s-expression Symbolic Expressions List based data structures. They may be a nested list of smaller S- expressions. Best known for their use in Lisp. (Wikipedia) ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    12. 12. Symbols: ns/foo Keywords: :key odd? ::qualified + :ns/qualified this!is_a+single*symbol-42 :can+be!weird Literals: “string” c space tab 42 3.14 42/11 36r16 true false #”^[a-zA-Z]*” nil Primitive data types Basic building blocks. Most of them should look familiar, or meaningful. Hopefully. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    13. 13. list (c “list” :something) vector [“vector” 42 :foobar] map {:question “life, universe and everything” :answer 42} set #{“foo” 42 :bar} Collections or sequences All aggregate data types can be encapsulated under the same interface: ISeq. Use the powerful Clojure sequence processing library to rule them all, but beware: they are all immutable! ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    14. 14. list (quote (c “list” :something)) list ‘(c “list” :something) (defn print-all-names [repo] (run-as (admin) function calls (doseq [node (to-seq repo)] (println (property node “cm:name”))))) LISt Processing Lists are king among data structures in any Lisp: they also happen to be code (homoiconicity). Lists are executed by evaluating the first symbol to a function, then calling it with the others as parameters. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    15. 15. function definition name (defn print-all-names [repo] parameters declaration (run-as (admin) (doseq [node (to-seq repo)] (println (property node “cm:name”))))) Functions Functional languages needs functions to be first class citizens. In Clojure, functions can be passed as parameters, put into a collection or returned as the result of an execution. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    16. 16. immutability and the art of motorcycle maintenance ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    17. 17. Horse horse = new Horse(14); horse.getPosition(); ?? t Where is the horse? The same “thing” such as a variable or an Object, can be completely different at different moments in time. We call such things identities, and they relate to a sequence of values. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    18. 18. (defn move [h] {:pos (inc (:pos h))}) (def horse {:pos 14}) (:pos horse) ; 14 (move horse) ; {:pos 15} Persistent data structures All data structures are immutable after their creation. As such, you never change them, but rather create new versions of it. We call them values, and are effectively easier to handle than Objects. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    19. 19. Structural sharing When creating a new version of a value, Clojure runtime optimizes the process and allows different version of the same data structure to share parts in memory. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    20. 20. horse t values Identities and values Identities refer to a logical sequence of values, which are distinct, though possibly similar, compound entities. They allow us to bring time into the picture. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    21. 21. the seq librabry ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    22. 22. clojure.core/seq ([coll]) Returns a seq on the collection. If the collection is empty, returns nil. (seq nil) returns nil. seq also works on Strings, native Java arrays (of reference types) and any objects that implement Iterable. seq to rule them all Quite intentionally, you can reduce all Clojure data structures and Java collections, iterables, Strings and arrays to the very same interface. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    23. 23. distinct filter remove for keep keep-indexed cons concat lazy-cat mapcat cycle interleave interpose rest next fnext nnext drop drop-while nthnext for take take-nth take-while butlast drop-last for flatten reverse sort sort-by shuffle split-at split-with partition partition-all partition-by map pmap mapcat for replace reductions map-indexed seque first ffirst nfirst second nth when-first last rand-nth zipmap into reduce set vec into-array to- array-2d frequencies group-by apply not-empty some reduce seq? every? not-every? not-any? empty? some filter doseq dorun doall seq vals keys rseq subseq rsubseq lazy-seq repeatedly iterate repeat replicate range line-seq resultset-seq re-seq tree-seq file-seq xml-seq iterator-seq enumeration-seq One-stop shop Dealing with a single abstraction allows for the same functions to be applicable to an incredible number of problems. The richness of the seq library is the only swiss army knife you need. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    24. 24. fully functional ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    25. 25. (map println [“one” “two” “three”]) (doseq [x [“one” “two” “three”]] (println x)) (for [x [“one” “two” “three”]] (println x)) (loop [s [“one” “two” “three”]] (println (first s)) (if (next s) (recur (rest s)))) Functional looping Despite being usually a fundamental part of a programming language course, Clojure doesn’t strictly need any special looping construct, even if it provides one nonetheless. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    26. 26. (defn print-all-names [repo] (run-as (admin) (doseq [node (to-seq repo)] (println (property node “cm:name”))))) Sequencing Alfresco Nodes in Alfresco are stored as a tree. Surely enough, trees can be represented as nested sequences, allowing for the seq library to disclose its power. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    27. 27. distinct filter remove for keep keep-indexed cons concat lazy-cat mapcat cycle interleave interpose rest next fnext nnext drop drop-while nthnext for take take-nth take-while butlast drop-last for flatten reverse sort sort-by shuffle split-at split-with partition partition-all partition-by map pmap mapcat for replace reductions map-indexed seque first ffirst nfirst second nth when-first last rand-nth zipmap into reduce set vec into-array to- array-2d frequencies group-by apply not-empty some reduce seq? every? not-every? not-any? empty? some filter doseq dorun doall seq vals keys rseq subseq rsubseq lazy-seq repeatedly iterate repeat replicate range line-seq resultset-seq re-seq tree-seq file-seq xml-seq iterator-seq enumeration-seq Depth first traversal Using the standard seq library, you can compose a linear sequence out of a tree structure (of nested sequences). ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    28. 28. clojure.core/tree-seq ([branch? children root]) Returns a lazy sequence of the nodes in a tree, via a depth-first walk. branch? must be a fn of one arg that returns true if passed a node that can have children (but may not). children must be a fn of one arg that returns a sequence of the children. Will only be called on nodes for which branch? returns true. root is the root node of the tree. Anatomy of a tree-seq Functions are first class, and tree-seq is a higher order fn that takes two functions and a data structure to create a flat sequence. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    29. 29. clojure.core/tree-seq ([branch? children root]) Returns a lazy sequence of the nodes in a tree, via a depth-first walk. branch? must be a fn of one arg that returns true if passed a node that can have children (but may not). children must be a fn of one arg that returns a sequence of the children. Will only be called on nodes for which branch? returns true. root is the root node of the tree. Thinking Alfresco Peer to peer associations allow you to create logical trees regardless of files and folders structure. For the time being, let’s assume we’re only interested into parent child assocs between nodes. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    30. 30. (defn type-qname [node] (m/qname (.getType (node-service) (c/c2j node)))) (defn branch? [node] (qname-isa? (type-qname node) (qname "cm:folder"))) (defn qname-isa? [child parent] (.isSubClass (dictionary-service) (qname child) (defn qname [qname-str] (qname parent))) (let [[prefix name] (QName/splitPrefixedQName qname-str)] (QName/createQName prefix name (namespace-service)))) First step We know that cm:contains is provided as part of cm:folder definition. We check that the given node is of a compatible type. Lambdalf provides here some Clojure/Java type conversion. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    31. 31. clojure.core/tree-seq ([branch? children root]) Returns a lazy sequence of the nodes in a tree, via a depth-first walk. branch? must be a fn of one arg that returns true if passed a node that can have children (but may not). children must be a fn of one arg that returns a sequence of the children. Will only be called on nodes for which branch? returns true. root is the root node of the tree. Populate the seq Navigating the tree means getting the children of the traversed node, if any. This is food for the NodeService. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    32. 32. (defn children [node] (n/children node))) (defn children [node] (into #{} (doall (map #(c/j2c (.getChildRef %)) (.getChildAssocs (node-service) (c/c2j node)))))) API bridge Lambdalf tries to shave the yak for you, and despite its code doesn’t shine by beauty, it allows for a clean user code. Again, Java and Clojure interact seamlessly here. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    33. 33. (defn print-all-names [repo] (defn to-seq [node] (run-as (admin) (tree-seq branch? children node)) (doseq [node (to-seq repo)] (println (property node “cm:name”))))) Wrapping it up Most of the mystery is now gone, the core of print-all-names has been demystified. While run-as is still magic, it’s easy to tell what’s for. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    34. 34. the lord of the repl one repl to bring them all and in the lexical scope, bind them ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    35. 35. read R user> (defn Y [r] eval E ((fn [f] (f f)) (fn [f] (r (fn [x] ((f f) x)))))) print P #user/Y user> loop L Almighty shell It’s common in all Lisp variations development model to have an open shell to a running environment, called REPL. Here you can define and test your own code against the running application. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    36. 36. read R user> (defn Y [r] eval E ((fn [f] (f f)) (fn [f] (r (fn [x] ((f f) x)))))) print P #user/Y user> loop L Live coding Similarly to scripted languages, your code is parsed and compiled into bytecode as soon as you enter it. In facts, you are altering the current runtime state. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    37. 37. read R prompt user> (defn Y [r] eval E ((fn [f] (f f)) (fn [f] (r (fn [x] ((f f) x)))))) print P #user/Y user> result loop L Live coding Similarly to scripted languages, your code is parsed and compiled into bytecode as soon as you enter it. In facts, you are altering the current runtime state. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    38. 38. + $ curl -X POST -u admin:admin http://localhost:8080/alfresco/service/swank {port : 4005} Swank server Opening a REPL server is just one web script call away. You’ll need a client to connect, major IDE and editors have one. As usual, Emacs is superior :-P ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    39. 39. user> (def folder (a/as-admin (first (s/query "TYPE:"cm:folder"")))) #user/folder user> (a/as-admin (n/property folder "cm:name")) "Sites" user> Baby steps Being an interactive shell, a REPL allows you to test code step by step. While it doesn’t free you from the duty of writing tests, it really helps assessing correctness or feasibility of new ideas. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    40. 40. Trying it out We know we should already be able to reduce the Alfresco repository to a seq, and we can try directly to see if our implementation works as expected. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    41. 41. concurrency ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    42. 42. private HashMap _map = new HashMap(); public void oneMore(Object k, Object v) { #fail _map.put(k, v); } Shared mutable state It’s sometimes desirable to access the same identity from different threads. When going concurrent, several tasks that used to be trivial are now extremely hard. OO makes it even harder. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    43. 43. Software Transactional Memory Similarly to databases, Clojure runtime uses transactions to handle concurrent access to shared mutable state. Every thread gets the current value, if changes occur outside, the transaction rolls back. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    44. 44. (def _shared (ref {})) (defn update [old k v] (assoc old k v)) (defn one-more [k v] (dosync (alter _shared update k v))) Concurrency IS rocket science Sorting out concurrency is an extremely difficult task. Clojure provides language level barriers against poorly designed concurrent access to shared mutable state. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    45. 45. sync coord clojure.core/ref ([x] [x & options]) clojure.core/atom ([x] [x & options]) clojure.core/agent ([state & options]) Thereʼs no silver bullet Different concurrent access patterns require different constructs. Programmers still have to pay attention to which kind of concurrency control to use. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    46. 46. the clojure way ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    47. 47. (map #(property % name) (query “@cm:name:”Sites””)) (defn query "Returns all the results of a search" ([q] (query StoreRef/STORE_REF_WORKSPACE_SPACESSTORE SearchService/LANGUAGE_LUCENE q)) ([store lang q] (with-open [rs (.query (search-service) store lang q)] (doall (map c/j2c (.getNodeRefs rs)))))) Warning: alpha code Lambdalf and Clojure webscripts have a long way ahead in terms of API maturity and usability, but the basic pieces are out there for you to start your journey into this new, fancy Lisp. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    48. 48. (write! “new content” node) (write! [^String src node] (let [noderef (c/c2j node) w (.getWriter (content-service) noderef ContentModel/PROP_CONTENT true)] (.putContent w (ByteArrayInputStream. (.getBytes src "UTF-8"))))) Warning: alpha code Lambdalf and Clojure webscripts have a long way ahead in terms of API maturity and usability, but the basic pieces are out there for you to start your journey into this new, fancy Lisp. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    49. 49. (to-seq (company-home)) (defn to-seq [root] (let [user (a/whoami) branch? (fn [x] (a/run-as user (m/qname-isa? (n/type-qname x) (m/qname "cm:folder")))) children (fn [x] (a/run-as user (n/children x)))] (tree-seq branch? children root))) Warning: alpha code Lambdalf and Clojure webscripts have a long way ahead in terms of API maturity and usability, but the basic pieces are out there for you to start your journey into this new, fancy Lisp called Clojure. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    50. 50. John McCarthy 4 September 1927 - 24 October 2011 ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    51. 51. Q/A ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011
    52. 52. Carlo Sciolla sr. R&D Developer http://skuro.tk @skuro http://backbase.com Thank you! “A language that doesnt affect the way you think about programming, is not worth knowing” Alan J. Perlis About me Content specialist, Clojurian, biker. ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuroFriday, November 4, 2011

    ×