Mercurial > cortex
view org/integration.org @ 300:c78917fb0615
created first version of the video which demonstrates all the senses
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Fri, 17 Feb 2012 11:06:27 -0700 |
parents | 47fe4f7b74b3 |
children | 4203c2140b95 |
line wrap: on
line source
1 #+title:2 #+author: Robert McIntyre3 #+email: rlm@mit.edu4 #+description:5 #+keywords: simulation, jMonkeyEngine3, clojure6 #+SETUPFILE: ../../aurellem/org/setup.org7 #+INCLUDE: ../../aurellem/org/level-0.org9 * Intro11 This is the ultimate test which features all of the senses that I've12 made so far. The blender file for the creature serves as an example of13 a fully equipped creature in terms of senses. You can find it [[../assets/Models/test-creature/hand.blend][here]].16 #+begin_html17 <div class="figure">18 <video controls="controls" width="755">19 <source src="../video/hand.ogg" type="video/ogg"20 preload="none" poster="../images/aurellem-1280x480.png" />21 </video>22 <p>Simulated Senses in a Virtual Environment</p>23 </div>24 #+end_html28 #+name: integration29 #+begin_src clojure30 (ns cortex.test.integration31 "let's play!"32 {:author "Robert McIntyre"}33 (:use (cortex world util body sense34 hearing touch vision proprioception movement))35 (:import (com.jme3.math ColorRGBA Vector3f))36 (:import java.io.File)37 (:import com.jme3.audio.AudioNode)38 (:import com.aurellem.capture.RatchetTimer))40 (dorun (cortex.import/mega-import-jme3))41 (rlm.rlm-commands/help)43 (def hand "Models/test-creature/hand.blend")45 (def output-base (File. "/home/r/proj/cortex/render/hand"))46 #+end_src48 For this demonstration I have to manually drive the muscles of the49 hand. I do this by creating a little mini-language to describe50 simulated muscle contraction.52 #+name: integration-253 #+begin_src clojure54 (defn motor-control-program55 "Create a function which will execute the motor script"56 [muscle-positions57 script]58 (let [current-frame (atom -1)59 keyed-script (group-by first script)60 current-forces (atom {}) ]61 (fn [effectors]62 (let [indexed-effectors (vec effectors)]63 (dorun64 (for [[_ part force] (keyed-script (swap! current-frame inc))]65 (swap! current-forces (fn [m] (assoc m part force)))))66 (doall (map (fn [effector power]67 (effector (int power)))68 effectors69 (map #(@current-forces % 0) muscle-positions)))))))71 (def muscle-positions72 [:pointer-2-e73 :pointer-2-f74 :thumb-175 :thumb-176 :pointer-1-e77 :pointer-1-f78 :thumb-2-e79 :thumb-2-f80 :middle-1-e81 :middle-1-f82 :pointer-3-f83 :pointer-3-e84 :middle-2-e85 :middle-2-f86 :middle-3-f87 :middle-3-e88 :pinky-2-e89 :pinky-2-f90 :pinky-3-f91 :pinky-3-e92 :ring-3-e93 :ring-3-f94 :ring-2-f95 :ring-2-e96 :ring-1-e97 :ring-1-f98 :thumb-1-e99 :thumb-1-f100 :pinky-1-f101 :pinky-1-e])103 (def full 9001)106 ;; Coreography:108 ;; Let the hand fall palm-up110 ;; it curls its phalanges, starting with the pinky.112 ;; it lets its phalanges fall back down.114 ;; block falls down onto the hand, accompanied by a sound. The block115 ;; can be seen by the hand's eye.117 ;; hand FORCEFULLY catapults the block so that it hits the camera.120 ;; the systax here is [keyframe body-part force]121 (def move-fingers122 [[300 :pinky-3-f 50]123 [320 :pinky-2-f 80]124 [340 :pinky-1-f 100]126 [310 :ring-3-f 100]127 [330 :ring-2-f 120]128 [350 :ring-1-f 140]130 [330 :middle-3-f 120]131 [340 :middle-2-f 120]132 [360 :middle-1-f 30]134 [350 :pointer-3-f 120]135 [360 :pointer-2-f 120]136 [380 :pointer-1-f 30]138 [800 :pinky-3-f 0]139 [800 :pinky-2-f 0]140 [800 :pinky-1-f 0]142 [800 :ring-3-f 0]143 [800 :ring-2-f 0]144 [800 :ring-1-f 0]146 [800 :middle-3-f 0]147 [800 :middle-2-f 0]148 [800 :middle-1-f 0]150 [800 :pointer-3-f 0]151 [800 :pointer-2-f 0]152 [800 :pointer-1-f 0]155 [800 :pinky-3-e 50]156 [800 :pinky-2-e 80]157 [800 :pinky-1-e 100]159 [800 :ring-3-e 100]160 [800 :ring-2-e 120]161 [800 :ring-1-e 140]163 [800 :middle-3-e 120]164 [800 :middle-2-e 120]165 [800 :middle-1-e 30]167 [800 :pointer-3-e 120]168 [800 :pointer-2-e 120]169 [800 :pointer-1-e 30]171 [870 :pinky-3-e 0]172 [870 :pinky-2-e 0]173 [870 :pinky-1-e 0]175 [870 :ring-3-e 0]176 [870 :ring-2-e 0]177 [870 :ring-1-e 0]179 [870 :middle-3-e 0]180 [870 :middle-2-e 0]181 [870 :middle-1-e 0]183 [870 :pointer-3-e 0]184 [870 :pointer-2-e 0]185 [870 :pointer-1-e 0]187 [1500 :pointer-1-f full]188 [1500 :pointer-2-f full]189 [1500 :pointer-3-f full]191 [1500 :middle-1-f full]192 [1500 :middle-2-f full]193 [1500 :middle-3-f full]195 [1510 :pointer-1-f 0]196 [1510 :pointer-2-f 0]197 [1510 :pointer-3-f 0]199 [1510 :middle-1-f 0]200 [1510 :middle-2-f 0]201 [1510 :middle-3-f 0]202 ])204 (defn gen-summon-ball [debug?]205 (let [wait (atom 1100)]206 (fn [world]207 (if (= 0 (swap! wait dec))208 (let [brick209 (box 0.8 0.8 0.8 :mass 0.05210 :position (Vector3f. -0.5 0 0.5)211 :color (ColorRGBA/Red))212 bell (AudioNode. (asset-manager)213 "Sounds/pure.wav" false)]214 (.play bell)215 (if debug?216 (.addControl217 brick218 (proxy [AbstractControl] []219 (controlUpdate [tpf]220 (println-repl (.getWorldTranslation brick)))221 (controlRender [_ _]))))222 (add-element world brick))))))224 (import com.aurellem.capture.Capture)226 (defn test-everything!227 ([] (test-everything! false))228 ([record?]229 (let [me (sphere 0.5 :color ColorRGBA/Blue :physical? false)231 base (File. "/home/r/proj/cortex/render/hand")234 creature (doto (load-blender-model hand)235 (body!))237 summon-ball (gen-summon-ball false)238 ;;;;;;;;;;;; Sensors/Effectors ;;;;;;;;;;;;;;;;;;;;;;;;;;;;239 touch (touch! creature)240 touch-display (view-touch)242 vision (vision! creature)243 vision-display (view-vision)245 hearing (hearing! creature)246 hearing-display (view-hearing)248 prop (proprioception! creature)249 prop-display (view-proprioception)251 control-script (motor-control-program252 muscle-positions move-fingers)253 muscles (movement! creature)254 muscle-display (view-movement)255 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;257 fix-display (gen-fix-display)]258 (world259 (nodify [creature260 (box 10 2 10 :position (Vector3f. 0 -9 0)261 :color ColorRGBA/Gray :mass 0)262 me])263 standard-debug-controls265 (fn [world]266 (.setTimer world (RatchetTimer. 60))267 (position-camera268 world (Vector3f. -0.13217318, 5.816415, -5.3089414)269 (Quaternion. 0.55685693, 0.0042774677, -0.0028673497, 0.83059245))271 (light-up-everything world)272 (enable-debug world)273 (add-camera! world274 (add-eye! creature275 (.getChild276 (.getChild creature "eyes") "eye"))277 (comp (view-image) BufferedImage!))279 (if record?280 (Capture/captureVideo281 world (File. base "main")))282 (if record?283 (Capture/captureAudio284 world (File. base "main.wav"))))285 (fn [world tpf]286 (prop-display287 (prop)288 (if record? (File. base "proprio")))289 (touch-display290 (map #(% (.getRootNode world)) touch)291 (if record? (File. base "touch")))292 (vision-display293 (map #(% world) vision)294 (if record? (File. base "vision")))295 (hearing-display296 (map #(% world) hearing)297 (if record? (File. base "hearing")))298 (muscle-display299 (control-script muscles)300 (if record? (File. base "muscle")))302 (summon-ball world)304 (.setLocalTranslation me (.getLocation (.getCamera world)))305 (fix-display world))))))306 #+end_src308 * Generating the Video310 Just a bunch of calls to imagemagick to arrange the data that311 =test-everything!= produces.313 #+name: magick-8314 #+begin_src clojure315 (ns cortex.video.magick8316 (:import java.io.File)317 (:use clojure.contrib.shell-out))319 (comment320 ;; list of touch targets321 0 middle-11322 1 middle-21323 2 middle-31324 3 pinky-11325 4 pinky-21326 5 pinky-31327 6 pointer-11328 7 pointer-21329 8 pointer-31330 9 ring-11331 10 ring-21332 11 ring-31333 12 thumb-11334 13 thumb-2.0011337 ;; list of vision targets338 0 :all339 1 :green340 2 :blue341 3 :red343 ;; list of proprio targets344 0 middle-11 -> middle-21345 1 middle-21 -> middle-31346 2 thumb-11 -> thumb-2.0011347 3 pointer-11 -> pointer-21348 4 pointer-21 -> pointer-31349 5 ring-21 -> ring-31350 6 ring-11 -> ring-21351 7 pinky-21 -> pinky-31352 8 pinky-11 -> pinky-21353 9 middle-11 -> palm1354 10 pinky-11 -> palm1355 11 palm1 -> pointer-11356 12 palm1 -> ring-11357 13 palm1 -> thumb-11360 ;; list of muscle targets361 0 :pointer-2-e362 1 :pointer-2-f363 2 :thumb-1364 3 :thumb-1365 4 :pointer-1-e366 5 :pointer-1-f367 6 :thumb-2-e368 7 :thumb-2-f369 8 :middle-1-e370 9 :middle-1-f371 10 :pointer-3-f372 11 :pointer-3-e373 12 :middle-2-e374 13 :middle-2-f375 14 :middle-3-f376 15 :middle-3-e377 16 :pinky-2-e378 17 :pinky-2-f379 18 :pinky-3-f380 19 :pinky-3-e381 20 :ring-3-e382 21 :ring-3-f383 22 :ring-2-f384 23 :ring-2-e385 24 :ring-1-e386 25 :ring-1-f387 26 :thumb-1-e388 27 :thumb-1-f389 28 :pinky-1-f390 29 :pinky-1-e391 )393 (def base (File. "/home/r/proj/cortex/render/hand"))395 (defn prepare-muscle [muscle]396 ["(" muscle "-rotate" "90" "-scale" "15x60!" ")"])398 (defn prepare-touch [touch]399 ["(" touch "-rotate" "180" ")"])401 (defn generate-top-finger [tip-flexor tip-extensor tip402 joint-2-3403 mid-flexor mid-extensor mid404 joint-1-2]405 ["("406 "-size" "113x357" "xc:transparent"407 (prepare-muscle tip-flexor) "-geometry" "+0+7" "-composite"408 (prepare-muscle tip-extensor) "-geometry" "+98+7" "-composite"409 (prepare-touch tip) "-geometry" "+18+0" "-composite"411 joint-2-3 "-geometry" "+32+79" "-composite"413 (prepare-muscle mid-flexor) "-geometry" "+19+131" "-composite"414 (prepare-muscle mid-extensor) "-geometry" "+80+131" "-composite"415 (prepare-touch mid) "-geometry" "+39+133" "-composite"417 joint-1-2 "-geometry" "+32+193" "-composite"418 ")"])420 (defn file-names [#^File dir]421 (map #(.getCanonicalPath %) (next (sort (file-seq dir)))))423 (defn file-groups [& paths]424 (apply (partial map list )425 (map (comp file-names #(File. base %))426 paths)))428 (defn pinky []429 (file-groups430 "muscle/18"431 "muscle/19"432 "touch/5"433 "proprio/7"435 "muscle/17"436 "muscle/16"437 "touch/4"438 "proprio/8"440 "muscle/28"441 "muscle/29"442 "touch/3"443 "proprio/10"))445 (defn ring []446 (file-groups447 "muscle/21"448 "muscle/20"449 "touch/11"450 "proprio/5"452 "muscle/22"453 "muscle/23"454 "touch/10"455 "proprio/6"457 "muscle/25"458 "muscle/24"459 "touch/9"460 "proprio/12"))462 (defn middle []463 (file-groups464 "muscle/14"465 "muscle/15"466 "touch/2"467 "proprio/1"469 "muscle/13"470 "muscle/12"471 "touch/1"472 "proprio/0"474 "muscle/9"475 "muscle/8"476 "touch/0"477 "proprio/9"))479 (defn pointer []480 (file-groups481 "muscle/10"482 "muscle/11"483 "touch/8"484 "proprio/4"486 "muscle/1"487 "muscle/0"488 "touch/7"489 "proprio/3"491 "muscle/5"492 "muscle/4"493 "touch/6"494 "proprio/11"))496 (defn thumb []497 (file-groups498 "muscle/7"499 "muscle/6"500 "touch/13"501 "proprio/2"503 "muscle/27"504 "muscle/26"505 "muscle/3"506 "muscle/2"507 "touch/12"508 "proprio/13"))510 (defn generate-finger511 [tip-flexor tip-extensor tip512 joint-2-3513 mid-flexor mid-extensor mid514 joint-1-2515 base-flexor base-extensor base516 joint-palm-1]517 ["("518 "-size" "113x357" "xc:transparent"519 (generate-top-finger520 tip-flexor tip-extensor tip521 joint-2-3522 mid-flexor mid-extensor mid523 joint-1-2) "-geometry" "+0+0" "-composite"524 (prepare-muscle base-flexor) "-geometry" "+19+245" "-composite"525 (prepare-muscle base-extensor) "-geometry" "+80+245" "-composite"526 (prepare-touch base) "-geometry" "+39+247" "-composite"527 joint-palm-1 "-geometry" "+32+307" "-composite"528 ")"])530 (defn generate-thumb531 [tip-flexor tip-extensor tip532 joint-1-2533 mid-flexor mid-extensor mid-flexor-2 mid-extensor-2 mid534 joint-palm-1]535 ["("536 "-size" "113x357" "xc:transparent"537 (generate-top-finger538 tip-flexor tip-extensor tip539 joint-1-2540 mid-flexor mid-extensor mid541 joint-palm-1) "-geometry" "+0+0" "-composite"542 (prepare-muscle mid-flexor-2) "-geometry" "+2+131" "-composite"543 (prepare-muscle mid-extensor-2) "-geometry" "+100+131" "-composite"544 ")"])546 (defn generate-hand547 [pinky-pieces548 ring-pieces549 middle-pieces550 pointer-pieces551 thumb-pieces]552 ["("553 "-size" "688x769" "xc:transparent"554 (apply generate-finger pinky-pieces)555 "-geometry" "+0+195" "-composite"556 (apply generate-finger ring-pieces)557 "-geometry" "+111+100" "-composite"558 (apply generate-finger middle-pieces)559 "-geometry" "+228+0" "-composite"560 "(" (apply generate-thumb thumb-pieces) "-background" "#00000000"561 "-rotate" "45" ")"562 "-geometry" "+300+420" "-composite"563 (apply generate-finger pointer-pieces)564 "-geometry" "+350+96" "-composite"565 ")"])567 (defn generate-vision568 [all green blue red]569 ["("570 "-size" "204x192" "xc:transparent"571 all "-geometry" "+0+0" "-composite"572 green "-geometry" "+113+0" "-composite"573 blue "-geometry" "+0+105" "-composite"574 red "-geometry" "+113+105" "-composite"575 ")"])577 (def test-muscle (File. base "muscle/0/0000000.png"))578 (def test-proprio (File. base "proprio/0/0000000.png"))579 (def test-tip (File. base "touch/2/0000000.png"))580 (def test-mid (File. base "touch/0/0000000.png"))581 (def test-vision (File. base "vision/0/0000000.png"))582 (def test-hearing (File. base "hearing/0/0000000.png"))583 (def test-main (File. base "main/0000000.png"))585 (def test-target (File. base "output.png"))587 (def background (File. base "background.png"))589 (use 'clojure.contrib.shell-out)591 (defn vision []592 (file-groups593 "vision/0"594 "vision/1"595 "vision/2"596 "vision/3"))598 (defn hearing []599 (file-names (File. base "hearing/0")))601 (defn main []602 (file-names (File. base "main")))604 (defn targets [dest max]605 (map606 (comp #(.getCanonicalPath %)607 #(File. (str base dest (format "%07d.png" %))))608 (range max)))611 (defn final-image [main [all red green blue] hearing612 pinky ring middle pointer thumb target]613 (println target)614 (apply615 sh616 (flatten617 ["convert"618 (.getCanonicalPath background)620 (generate-hand pinky ring middle pointer thumb)621 "-geometry" "+809+22" "-composite"623 (generate-vision all red green blue)624 "-geometry" "+974+599" "-composite"626 hearing627 "-geometry" "+784+819" "-composite"629 main630 "-geometry" "+78+202" "-composite"632 target])))634 (defn combine-files []635 (dorun636 (pmap final-image637 (main)638 (vision)639 (hearing)640 (pinky)641 (ring)642 (middle)643 (pointer)644 (thumb)645 (targets "/out/" (count (main))))))647 (defn subtitles []648 (file-names (File. base "subs")))650 (defn outs []651 (file-names (File. base "out")))654 (defn mix-subtitles []655 (let [subs (subtitles)656 targets (targets "/out-subs/" (count subs))657 overlay (.getCanonicalPath (File. base "output.png"))]658 (dorun659 (pmap660 (fn [sub target]661 (sh662 "convert"663 overlay664 sub "-geometry" "+0+0" "-composite"665 target))666 subs targets))))668 (defn out-subtitles []669 (file-names (File. base "out-subs")))672 (defn insert-subtitles []673 (let [subtitles (out-subtitles)674 outs (outs)675 targets (targets676 "/final/"677 (+ (count outs) (count subtitles)))]678 (dorun679 (pmap680 #(sh "cp" %1 %2)681 (concat subtitles outs) targets))))683 (defn generate-final []684 (combine-files)685 (mix-subtitles)686 (insert-subtitles))687 #+end_src689 #+begin_src sh :results silent690 cd /home/r/proj/cortex/render/hand692 sox --ignore-length main.wav main-delayed.wav delay 24694 mogrify -resize 755x final/*696 ffmpeg -r 60 -i final/%07d.png -i main-delayed.wav -b:a 128k \697 -b:v 9000k -c:a libvorbis -c:v libtheora hand.ogg698 #+end_src700 * COMMENT purgatory701 #+begin_src clojure702 (defn bullet-trans* []703 (let [obj-a (box 1.5 0.5 0.5 :color ColorRGBA/Red704 :position (Vector3f. 5 0 0)705 :mass 90)706 obj-b (sphere 0.5 :color ColorRGBA/Blue707 :position (Vector3f. -5 0 0)708 :mass 0)709 control-a (.getControl obj-a RigidBodyControl)710 control-b (.getControl obj-b RigidBodyControl)711 move-up? (atom nil)712 move-down? (atom nil)713 move-left? (atom nil)714 move-right? (atom nil)715 roll-left? (atom nil)716 roll-right? (atom nil)717 force 100718 swivel719 (.toRotationMatrix720 (doto (Quaternion.)721 (.fromAngleAxis (/ Math/PI 2)722 Vector3f/UNIT_X)))723 x-move724 (doto (Matrix3f.)725 (.fromStartEndVectors Vector3f/UNIT_X726 (.normalize (Vector3f. 1 1 0))))728 timer (atom 0)]729 (doto730 (ConeJoint.731 control-a control-b732 (Vector3f. -8 0 0)733 (Vector3f. 2 0 0)734 ;;swivel swivel735 ;;Matrix3f/IDENTITY Matrix3f/IDENTITY736 x-move Matrix3f/IDENTITY737 )738 (.setCollisionBetweenLinkedBodys false)739 (.setLimit (* 1 (/ Math/PI 4)) ;; twist740 (* 1 (/ Math/PI 4)) ;; swing span in X-Y plane741 (* 0 (/ Math/PI 4)))) ;; swing span in Y-Z plane742 (world (nodify743 [obj-a obj-b])744 (merge standard-debug-controls745 {"key-r" (fn [_ pressed?] (reset! move-up? pressed?))746 "key-t" (fn [_ pressed?] (reset! move-down? pressed?))747 "key-f" (fn [_ pressed?] (reset! move-left? pressed?))748 "key-g" (fn [_ pressed?] (reset! move-right? pressed?))749 "key-v" (fn [_ pressed?] (reset! roll-left? pressed?))750 "key-b" (fn [_ pressed?] (reset! roll-right? pressed?))})752 (fn [world]753 (enable-debug world)754 (set-gravity world Vector3f/ZERO)755 )757 (fn [world _]759 (if @move-up?760 (.applyForce control-a761 (Vector3f. force 0 0)762 (Vector3f. 0 0 0)))763 (if @move-down?764 (.applyForce control-a765 (Vector3f. (- force) 0 0)766 (Vector3f. 0 0 0)))767 (if @move-left?768 (.applyForce control-a769 (Vector3f. 0 force 0)770 (Vector3f. 0 0 0)))771 (if @move-right?772 (.applyForce control-a773 (Vector3f. 0 (- force) 0)774 (Vector3f. 0 0 0)))776 (if @roll-left?777 (.applyForce control-a778 (Vector3f. 0 0 force)779 (Vector3f. 0 0 0)))780 (if @roll-right?781 (.applyForce control-a782 (Vector3f. 0 0 (- force))783 (Vector3f. 0 0 0)))785 (if (zero? (rem (swap! timer inc) 100))786 (.attachChild787 (.getRootNode world)788 (sphere 0.05 :color ColorRGBA/Yellow789 :physical? false :position790 (.getWorldTranslation obj-a)))))791 )792 ))794 (defn test-joint [joint]795 (let [[origin top bottom floor] (world-setup joint)796 control (.getControl top RigidBodyControl)797 move-up? (atom false)798 move-down? (atom false)799 move-left? (atom false)800 move-right? (atom false)801 roll-left? (atom false)802 roll-right? (atom false)803 timer (atom 0)]805 (world806 (nodify [top bottom floor origin])807 (merge standard-debug-controls808 {"key-r" (fn [_ pressed?] (reset! move-up? pressed?))809 "key-t" (fn [_ pressed?] (reset! move-down? pressed?))810 "key-f" (fn [_ pressed?] (reset! move-left? pressed?))811 "key-g" (fn [_ pressed?] (reset! move-right? pressed?))812 "key-v" (fn [_ pressed?] (reset! roll-left? pressed?))813 "key-b" (fn [_ pressed?] (reset! roll-right? pressed?))})815 (fn [world]816 (light-up-everything world)817 (enable-debug world)818 (set-gravity world (Vector3f. 0 0 0))819 )821 (fn [world _]822 (if (zero? (rem (swap! timer inc) 100))823 (do824 ;; (println-repl @timer)825 (.attachChild (.getRootNode world)826 (sphere 0.05 :color ColorRGBA/Yellow827 :position (.getWorldTranslation top)828 :physical? false))829 (.attachChild (.getRootNode world)830 (sphere 0.05 :color ColorRGBA/LightGray831 :position (.getWorldTranslation bottom)832 :physical? false))))834 (if @move-up?835 (.applyTorque control836 (.mult (.getPhysicsRotation control)837 (Vector3f. 0 0 10))))838 (if @move-down?839 (.applyTorque control840 (.mult (.getPhysicsRotation control)841 (Vector3f. 0 0 -10))))842 (if @move-left?843 (.applyTorque control844 (.mult (.getPhysicsRotation control)845 (Vector3f. 0 10 0))))846 (if @move-right?847 (.applyTorque control848 (.mult (.getPhysicsRotation control)849 (Vector3f. 0 -10 0))))850 (if @roll-left?851 (.applyTorque control852 (.mult (.getPhysicsRotation control)853 (Vector3f. -1 0 0))))854 (if @roll-right?855 (.applyTorque control856 (.mult (.getPhysicsRotation control)857 (Vector3f. 1 0 0))))))))858 #+end_src861 * COMMENT generate source862 #+begin_src clojure :tangle ../src/cortex/test/integration.clj863 <<integration>>864 <<integration-2>>865 #+end_src867 #+begin_src clojure :tangle ../src/cortex/video/magick8.clj868 <<magick-8>>869 #+end_src