clementine 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. data/.gitignore +1 -0
  2. data/Gemfile +4 -2
  3. data/LICENSE.txt +22 -0
  4. data/README.md +11 -6
  5. data/Rakefile +22 -0
  6. data/clementine.gemspec +2 -1
  7. data/ext/clojure-clojurescript-bef56a7/.gitignore +13 -0
  8. data/ext/clojure-clojurescript-bef56a7/Clojurescript.iml +12 -0
  9. data/ext/clojure-clojurescript-bef56a7/README.md +29 -0
  10. data/ext/clojure-clojurescript-bef56a7/benchmark/cljs/benchmark_runner.cljs +155 -0
  11. data/ext/clojure-clojurescript-bef56a7/bin/cljsc +21 -0
  12. data/ext/clojure-clojurescript-bef56a7/bin/cljsc.bat +18 -0
  13. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/bin/cljsc.clj +0 -0
  14. data/ext/clojure-clojurescript-bef56a7/devnotes/README.org +35 -0
  15. data/ext/clojure-clojurescript-bef56a7/devnotes/bcrepl.org +13 -0
  16. data/ext/clojure-clojurescript-bef56a7/devnotes/cljs.org +500 -0
  17. data/ext/clojure-clojurescript-bef56a7/devnotes/corelib.org +583 -0
  18. data/ext/clojure-clojurescript-bef56a7/devnotes/day1.org +203 -0
  19. data/ext/clojure-clojurescript-bef56a7/devnotes/day2.org +44 -0
  20. data/ext/clojure-clojurescript-bef56a7/devnotes/talk.org +126 -0
  21. data/ext/clojure-clojurescript-bef56a7/devnotes/testing +13 -0
  22. data/ext/clojure-clojurescript-bef56a7/devnotes/todo.org +121 -0
  23. data/ext/clojure-clojurescript-bef56a7/epl-v10.html +261 -0
  24. data/ext/clojure-clojurescript-bef56a7/pom.template.xml +88 -0
  25. data/ext/clojure-clojurescript-bef56a7/samples/dom/.gitignore +2 -0
  26. data/ext/clojure-clojurescript-bef56a7/samples/dom/src/dom/test.cljs +48 -0
  27. data/ext/clojure-clojurescript-bef56a7/samples/dom/test.html +30 -0
  28. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/.gitignore +2 -0
  29. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/README.md +53 -0
  30. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/externed-lib.js +7 -0
  31. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/externs.js +3 -0
  32. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/hello-extern.html +14 -0
  33. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/hello-js-dev.html +18 -0
  34. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/hello-js.html +17 -0
  35. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/my-external-lib.js +3 -0
  36. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/src/hello-js/core.cljs +9 -0
  37. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/src/hello-js/extern-example.cljs +5 -0
  38. data/ext/clojure-clojurescript-bef56a7/samples/hello/.gitignore +2 -0
  39. data/ext/clojure-clojurescript-bef56a7/samples/hello/README.md +34 -0
  40. data/ext/clojure-clojurescript-bef56a7/samples/hello/hello-dev.html +18 -0
  41. data/ext/clojure-clojurescript-bef56a7/samples/hello/hello.html +13 -0
  42. data/ext/clojure-clojurescript-bef56a7/samples/hello/src/hello/core.cljs +8 -0
  43. data/ext/clojure-clojurescript-bef56a7/samples/hello/src/hello/foo/bar.cljs +4 -0
  44. data/ext/clojure-clojurescript-bef56a7/samples/nodehello.cljs +18 -0
  45. data/ext/clojure-clojurescript-bef56a7/samples/nodels.cljs +17 -0
  46. data/ext/clojure-clojurescript-bef56a7/samples/repl/.gitignore +2 -0
  47. data/ext/clojure-clojurescript-bef56a7/samples/repl/README.md +101 -0
  48. data/ext/clojure-clojurescript-bef56a7/samples/repl/index.html +27 -0
  49. data/ext/clojure-clojurescript-bef56a7/samples/repl/src/repl/test.cljs +73 -0
  50. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/.gitignore +2 -0
  51. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/README.md +42 -0
  52. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/index-advanced.html +80 -0
  53. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/index.html +88 -0
  54. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/reset.css +48 -0
  55. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/anneal.cljs +66 -0
  56. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/core.cljs +307 -0
  57. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/dom-helpers.cljs +95 -0
  58. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/layout.cljs +100 -0
  59. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/leaderboard.cljs +40 -0
  60. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/radial.cljs +91 -0
  61. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/showgraph.cljs +121 -0
  62. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/timeline.cljs +39 -0
  63. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/style.css +301 -0
  64. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/test_data.txt +1 -0
  65. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/tweet_maps.txt +1 -0
  66. data/ext/clojure-clojurescript-bef56a7/script/benchmark +30 -0
  67. data/ext/clojure-clojurescript-bef56a7/script/bootstrap +70 -0
  68. data/ext/clojure-clojurescript-bef56a7/script/browser-repl +16 -0
  69. data/ext/clojure-clojurescript-bef56a7/script/build +59 -0
  70. data/ext/clojure-clojurescript-bef56a7/script/clean +5 -0
  71. data/ext/clojure-clojurescript-bef56a7/script/closure-library-release/google-closure-library-third-party.pom.template +59 -0
  72. data/ext/clojure-clojurescript-bef56a7/script/closure-library-release/google-closure-library.pom.template +54 -0
  73. data/ext/clojure-clojurescript-bef56a7/script/closure-library-release/make-closure-library-jars.sh +87 -0
  74. data/ext/clojure-clojurescript-bef56a7/script/compile +41 -0
  75. data/ext/clojure-clojurescript-bef56a7/script/repl +13 -0
  76. data/ext/clojure-clojurescript-bef56a7/script/repl.bat +13 -0
  77. data/ext/clojure-clojurescript-bef56a7/script/repljs +15 -0
  78. data/ext/clojure-clojurescript-bef56a7/script/repljs.bat +14 -0
  79. data/ext/clojure-clojurescript-bef56a7/script/test +38 -0
  80. data/ext/clojure-clojurescript-bef56a7/script/test-compile +30 -0
  81. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/analyzer.clj +975 -0
  82. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/clj/cljs/closure.clj +173 -73
  83. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/compiler.clj +1081 -0
  84. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/core.clj +1158 -0
  85. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/clj/cljs/repl.clj +51 -25
  86. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/repl/browser.clj +258 -0
  87. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/repl/reflect.clj +75 -0
  88. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/clj/cljs/repl/rhino.clj +6 -5
  89. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/repl/server.clj +173 -0
  90. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/tagged_literals.clj +30 -0
  91. data/ext/clojure-clojurescript-bef56a7/src/cljs/cljs/core.cljs +7197 -0
  92. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/cljs/nodejs.cljs +1 -1
  93. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/cljs/nodejs_externs.js +0 -0
  94. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/cljs/nodejscli.cljs +1 -1
  95. data/ext/clojure-clojurescript-bef56a7/src/cljs/cljs/reader.cljs +551 -0
  96. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/dom.cljs +59 -13
  97. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/event.cljs +0 -0
  98. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/net.cljs +8 -7
  99. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/repl.cljs +2 -2
  100. data/ext/clojure-clojurescript-bef56a7/src/cljs/clojure/core/reducers.cljs +298 -0
  101. data/ext/clojure-clojurescript-bef56a7/src/cljs/clojure/data.cljs +162 -0
  102. data/ext/clojure-clojurescript-bef56a7/src/cljs/clojure/reflect.cljs +48 -0
  103. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/set.cljs +0 -0
  104. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/string.cljs +4 -10
  105. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/walk.cljs +0 -0
  106. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/zip.cljs +0 -0
  107. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/binding_test.cljs +7 -0
  108. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/binding_test_other_ns.cljs +3 -0
  109. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/core_test.cljs +1678 -0
  110. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/import_test.cljs +11 -0
  111. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/import_test/foo.cljs +5 -0
  112. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/letfn_test.cljs +19 -0
  113. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/macro_test.cljs +6 -0
  114. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/macro_test/macros.clj +5 -0
  115. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/ns_test.cljs +14 -0
  116. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/ns_test/bar.cljs +3 -0
  117. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/ns_test/foo.cljs +7 -0
  118. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/reader_test.cljs +124 -0
  119. data/ext/clojure-clojurescript-bef56a7/test/cljs/clojure/data_test.cljs +22 -0
  120. data/ext/clojure-clojurescript-bef56a7/test/cljs/clojure/string_test.cljs +97 -0
  121. data/ext/clojure-clojurescript-bef56a7/test/cljs/foo/ns_shadow_test.cljs +9 -0
  122. data/ext/clojure-clojurescript-bef56a7/test/cljs/test_runner.cljs +26 -0
  123. data/lib/clementine.rb +3 -24
  124. data/lib/clementine/clojurescript_engine.rb +9 -48
  125. data/lib/clementine/clojurescript_engine/base.rb +15 -0
  126. data/lib/clementine/clojurescript_engine/jruby.rb +46 -0
  127. data/lib/clementine/{clojurescript_engine_mri.rb → clojurescript_engine/mri.rb} +17 -10
  128. data/lib/clementine/version.rb +1 -1
  129. data/test/clojurescript_engine_test.rb +36 -14
  130. metadata +177 -83
  131. data/vendor/assets/lib/clojure.jar +0 -0
  132. data/vendor/assets/lib/compiler.jar +0 -0
  133. data/vendor/assets/lib/goog.jar +0 -0
  134. data/vendor/assets/lib/js.jar +0 -0
  135. data/vendor/assets/src/clj/cljs/compiler.clj +0 -1341
  136. data/vendor/assets/src/clj/cljs/core.clj +0 -702
  137. data/vendor/assets/src/clj/cljs/repl/browser.clj +0 -341
  138. data/vendor/assets/src/cljs/cljs/core.cljs +0 -3330
  139. data/vendor/assets/src/cljs/cljs/reader.cljs +0 -360
@@ -0,0 +1,80 @@
1
+ <!doctype html>
2
+ <!--[if lt IE 7 ]> <html lang="en" class="no-js ie6"> <![endif]-->
3
+ <!--[if IE 7 ]> <html lang="en" class="no-js ie7"> <![endif]-->
4
+ <!--[if IE 8 ]> <html lang="en" class="no-js ie8"> <![endif]-->
5
+ <!--[if IE 9 ]> <html lang="en" class="no-js ie9"> <![endif]-->
6
+ <!--[if (gt IE 9)|!(IE)]><!--> <html lang="en" class="no-js"> <!--<![endif]-->
7
+ <head>
8
+ <meta charset="UTF-8">
9
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
10
+
11
+ <title>TwitterBuzz: A ClojureScript Demo</title>
12
+ <meta name="description" content="Demo showing off the ClojureScript hotness">
13
+ <meta name="author" content="Clojure/core">
14
+
15
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
16
+
17
+ <link rel="apple-touch-icon" href="/apple-touch-icon.png">
18
+ <link rel="stylesheet" href="reset.css">
19
+ <link rel="stylesheet" href="style.css">
20
+
21
+ <!--[if lt IE 9]>
22
+ <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
23
+ <![endif]-->
24
+
25
+ </head>
26
+ <body>
27
+ <header>
28
+ <section id="header-inner">
29
+ <h1>TwitterBuzz: A ClojureScript Demo</h1>
30
+ <div>Learn more:
31
+ <a href="https://github.com/clojure/clojurescript" target="_clojurescript">ClojureScript</a> |
32
+ <a href="https://github.com/clojure/clojurescript/wiki" target="_clojurescript">Documentation</a> |
33
+ <a href="https://github.com/clojure/clojurescript/tree/master/samples/twitterbuzz"
34
+ target="_clojurescript">Source Code</a>
35
+ </div>
36
+ <h2 id="clojure"><img src="http://clojure.org/space/showimage/clojure-icon-50x50.png" width="50" height="50" alt="Clojure"></h2>
37
+ </section>
38
+ </header>
39
+
40
+ <section id="status-bar-wrap">
41
+ <section id="status-bar">
42
+ <input id="twitter-search-tag" value="" type="text" class="search" results="5" autosave="clojure" placeholder="Enter keywords..." autofocus />
43
+ <button id="twitter-search-button" type="submit" class="button green">Track</button>
44
+ <span id="tweet-status" class="tweet-status">Not Connected</span>
45
+ </section>
46
+ </section>
47
+
48
+ <section id="main-wrap">
49
+ <section id="main">
50
+
51
+ <section id="network">
52
+ </section>
53
+
54
+ <section id="leaderboard">
55
+ <h2>Leaderboard</h2>
56
+ <div id="leaderboard-content">
57
+ </div>
58
+ </section>
59
+
60
+ <section id="timeline" class="tweetbox">
61
+ <h2>Timeline</h2>
62
+ <div id="timeline-content">
63
+ </div>
64
+ </section>
65
+
66
+ <div class="clear"></div>
67
+ </section>
68
+
69
+ <div class="clear"></div>
70
+ </section>
71
+
72
+ <section id="avatar-hover" style="display: none">
73
+ <div id="avatar-hover-body" class="tweetbox"></div>
74
+ </section>
75
+
76
+ <script type="text/javascript" src="twitterbuzz.js"></script>
77
+
78
+ </body>
79
+ </html>
80
+
@@ -0,0 +1,88 @@
1
+ <!doctype html>
2
+ <!--[if lt IE 7 ]> <html lang="en" class="no-js ie6"> <![endif]-->
3
+ <!--[if IE 7 ]> <html lang="en" class="no-js ie7"> <![endif]-->
4
+ <!--[if IE 8 ]> <html lang="en" class="no-js ie8"> <![endif]-->
5
+ <!--[if IE 9 ]> <html lang="en" class="no-js ie9"> <![endif]-->
6
+ <!--[if (gt IE 9)|!(IE)]><!--> <html lang="en" class="no-js"> <!--<![endif]-->
7
+ <head>
8
+ <meta charset="UTF-8">
9
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
10
+
11
+ <title>TwitterBuzz: A ClojureScript Demo</title>
12
+ <meta name="description" content="Demo showing off the ClojureScript hotness">
13
+ <meta name="author" content="Clojure/core">
14
+
15
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
16
+
17
+ <link rel="apple-touch-icon" href="/apple-touch-icon.png">
18
+ <link rel="stylesheet" href="reset.css">
19
+ <link rel="stylesheet" href="style.css">
20
+
21
+ <!--[if lt IE 9]>
22
+ <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
23
+ <![endif]-->
24
+
25
+ </head>
26
+ <body>
27
+ <header>
28
+ <section id="header-inner">
29
+ <h1>TwitterBuzz: A ClojureScript Demo</h1>
30
+ <div>Learn more:
31
+ <a href="https://github.com/clojure/clojurescript" target="_clojurescript">ClojureScript</a> |
32
+ <a href="https://github.com/clojure/clojurescript/wiki" target="_clojurescript">Documentation</a> |
33
+ <a href="https://github.com/clojure/clojurescript/tree/master/samples/twitterbuzz"
34
+ target="_clojurescript">Source Code</a>
35
+ </div>
36
+ <h2 id="clojure"><img src="http://clojure.org/space/showimage/clojure-icon-50x50.png" width="50" height="50" alt="Clojure"></h2>
37
+ </section>
38
+ </header>
39
+
40
+ <section id="status-bar-wrap">
41
+ <section id="status-bar">
42
+ <input id="twitter-search-tag" value="" type="text" class="search" results="5" autosave="clojure" placeholder="Enter keywords..." autofocus />
43
+ <button id="twitter-search-button" type="submit" class="button green">Track</button>
44
+ <span id="tweet-status">Not Connected</span>
45
+ </section>
46
+ </section>
47
+
48
+ <section id="main-wrap">
49
+ <section id="main">
50
+
51
+ <section id="network">
52
+ </section>
53
+
54
+ <section id="leaderboard">
55
+ <h2>Leaderboard</h2>
56
+ <div id="leaderboard-content">
57
+ </div>
58
+ </section>
59
+
60
+ <section id="timeline" class="tweetbox">
61
+ <h2>Timeline</h2>
62
+ <div id="timeline-content">
63
+ </div>
64
+ </section>
65
+
66
+ <div class="clear"></div>
67
+ </section>
68
+
69
+ <div class="clear"></div>
70
+ </section>
71
+
72
+ <section id="avatar-hover" style="display: none">
73
+ <div id="avatar-hover-body" class="tweetbox"></div>
74
+ </section>
75
+
76
+ <!-- In unoptimized mode, additional script tags are required -->
77
+ <script type="text/javascript" src="out/goog/base.js"></script>
78
+ <script type="text/javascript" src="twitterbuzz.js"></script>
79
+ <script type="text/javascript">
80
+ goog.require('twitterbuzz.core');
81
+ goog.require('twitterbuzz.timeline');
82
+ goog.require('twitterbuzz.leaderboard');
83
+ goog.require('twitterbuzz.showgraph');
84
+ </script>
85
+
86
+ </body>
87
+ </html>
88
+
@@ -0,0 +1,48 @@
1
+ /* Eric Meyer's Reset Reloaded */
2
+ html, body, div, span, applet, object, iframe,
3
+ h1, h2, h3, h4, h5, h6, p, blockquote, pre,
4
+ a, abbr, acronym, address, big, cite, code,
5
+ del, dfn, em, font, img, ins, kbd, q, s, samp,
6
+ small, strike, strong, sub, sup, tt, var,
7
+ dl, dt, dd, ol, ul, li,
8
+ fieldset, form, label, legend,
9
+ table, caption, tbody, tfoot, thead, tr, th, td {
10
+ margin: 0;
11
+ padding: 0;
12
+ border: 0;
13
+ outline: 0;
14
+ font-weight: inherit;
15
+ font-style: inherit;
16
+ font-size: 100%;
17
+ font-family: inherit;
18
+ vertical-align: baseline;
19
+ }
20
+ /* remember to define focus styles! */
21
+ :focus {
22
+ outline: 0;
23
+ }
24
+ body {
25
+ line-height: 1;
26
+ color: black;
27
+ background: white;
28
+ }
29
+ ol, ul {
30
+ list-style: none;
31
+ }
32
+ /* tables still need 'cellspacing="0"' in the markup */
33
+ table {
34
+ border-collapse: separate;
35
+ border-spacing: 0;
36
+ }
37
+ caption, th, td {
38
+ text-align: left;
39
+ font-weight: normal;
40
+ }
41
+ blockquote:before, blockquote:after,
42
+ q:before, q:after {
43
+ content: "";
44
+ }
45
+ blockquote, q {
46
+ quotes: "" "";
47
+ }
48
+
@@ -0,0 +1,66 @@
1
+ ; Copyright (c) Rich Hickey. All rights reserved.
2
+ ; The use and distribution terms for this software are covered by the
3
+ ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4
+ ; which can be found in the file epl-v10.html at the root of this distribution.
5
+ ; By using this software in any fashion, you are agreeing to be bound by
6
+ ; the terms of this license.
7
+ ; You must not remove this notice, or any other, from this software.
8
+
9
+ (ns twitterbuzz.anneal)
10
+
11
+ (defn exp [x]
12
+ (js/Math.exp x))
13
+
14
+ (defn abs [x]
15
+ (js/Math.abs x))
16
+
17
+ (defn random []
18
+ (js/Math.random))
19
+
20
+ (defn standard-prob [e e1 temp]
21
+ (if (< e1 e)
22
+ 1
23
+ (exp (/ (- e e1) temp))))
24
+
25
+ (defn linear-cooling [steps]
26
+ (let [min (- 1 (/ steps (dec steps)))]
27
+ (fn [t]
28
+ (max min (- 1 (/ t steps))))))
29
+
30
+ (defn anneal
31
+ "Given an energy scoring function, a temperature function
32
+ (calculates temp given iteration t), a permutation function (creates
33
+ a candidate next state given a current state and iteration t), and
34
+ an acceptance probability function (of last next energy and temp),
35
+ yields a lazy seq of (accepted?) states of the form
36
+ {:state s :score :best best :best-score :t t}"
37
+
38
+ [energy ;;(energy state) -> score
39
+ temp ;;(temp t) -> 0-1.0
40
+ permute ;;(permute state t) -> new-state
41
+ prob ;;(prob e e1 temp) -> 0-1.0
42
+ state]
43
+
44
+ (let [init state
45
+ init-score (energy state)
46
+ step (fn step [{:keys [state score best best-score t]:as ret}]
47
+ (loop [next (permute state) t (inc t)]
48
+ (let [next-score (energy next)]
49
+ (if (> (prob score next-score (temp t)) (random))
50
+ (let [ret {:state next :score next-score :t t
51
+ :best (if (< next-score best-score) next best)
52
+ :best-score (min next-score best-score)}]
53
+ (lazy-seq (cons ret (step ret))))
54
+ (recur (permute state) (inc t))))))]
55
+ (step {:state init :score init-score :best init :best-score init-score :t 0})))
56
+
57
+
58
+ (comment
59
+
60
+ (take 10 (take-nth 100
61
+ (anneal #(abs (- % 42))
62
+ (linear-cooling 1000)
63
+ (fn [s _] (+ s (- (random) 0.5)))
64
+ standard-prob
65
+ 55)))
66
+ )
@@ -0,0 +1,307 @@
1
+ ; Copyright (c) Rich Hickey. All rights reserved.
2
+ ; The use and distribution terms for this software are covered by the
3
+ ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4
+ ; which can be found in the file epl-v10.html at the root of this distribution.
5
+ ; By using this software in any fashion, you are agreeing to be bound by
6
+ ; the terms of this license.
7
+ ; You must not remove this notice, or any other, from this software.
8
+
9
+ (ns twitterbuzz.core
10
+ (:require [twitterbuzz.dom-helpers :as dom]
11
+ [clojure.string :as string]
12
+ [goog.string :as gstring]
13
+ [goog.net.Jsonp :as jsonp]
14
+ [goog.Timer :as timer]
15
+ [goog.events :as events]
16
+ [goog.events.EventType :as event-type]
17
+ [goog.dom.classes :as classes]))
18
+
19
+ (def results-per-page 100)
20
+ (def max-missing-query 20)
21
+
22
+ (def initial-state {:max-id 0
23
+ :graph {}
24
+ :listeners {}
25
+ :tweet-count 0
26
+ :search-tag nil
27
+ :ignore-mentions #{}})
28
+
29
+ (def state (atom initial-state))
30
+
31
+ (defn add-listener
32
+ "Add a listener to the graph."
33
+ [graph k f]
34
+ (let [l (-> graph :listeners k)]
35
+ (assoc-in graph [:listeners k] (conj l f))))
36
+
37
+ (defn register
38
+ "Register a function to be called when new data arrives specifying
39
+ the event to receive updates for."
40
+ [event f]
41
+ (swap! state add-listener event f))
42
+
43
+ (def twitter-uri (goog.Uri. "http://search.twitter.com/search.json"))
44
+
45
+ (defn search-tag
46
+ "Get the current tag value from the page."
47
+ []
48
+ (.-value (dom/get-element :twitter-search-tag)))
49
+
50
+ (defn retrieve
51
+ "Send request to twitter."
52
+ [payload callback error-callback]
53
+ (.send (goog.net.Jsonp. twitter-uri)
54
+ payload
55
+ callback
56
+ error-callback))
57
+
58
+ (defn send-event
59
+ "For the given event, call every listener for that event, passing the
60
+ message."
61
+ ([event]
62
+ (send-event event nil))
63
+ ([event message]
64
+ (doseq [f (-> @state :listeners event)]
65
+ (f message))))
66
+
67
+ (defn parse-mentions
68
+ "Given a map representing a single tweet, return all mentions that
69
+ are found within the tweet text. Twitter usernames are not case
70
+ sensitive so mentioned usernames are always returned in lower case."
71
+ [tweet]
72
+ (map #(string/lower-case (apply str (drop 1 %)))
73
+ (re-seq (re-pattern "@\\w+") (:text tweet))))
74
+
75
+ (defn add-mentions
76
+ "Add the user to the mentions map for first user she mentions,
77
+ clearing the mentions map of user."
78
+ [graph user mentions]
79
+ (if-let [mention (first mentions)]
80
+ (let [graph (assoc graph mention (get graph mention {:username mention}))
81
+ node (get graph mention)
82
+ mentions-map (get node :mentions {})
83
+ graph (assoc-in graph [mention :mentions user] (inc (get mentions-map user 0)))]
84
+ (assoc-in graph [user :mentions] {}))
85
+ graph))
86
+
87
+ (defn update-graph
88
+ "Given a graph and a sequence of new tweets in chronological order,
89
+ update the graph."
90
+ [graph tweet-maps]
91
+ (reduce (fn [acc tweet]
92
+ (let [user (string/lower-case (:from_user tweet))
93
+ mentions (parse-mentions tweet)
94
+ node (get acc user {:mentions {}})]
95
+ (-> (assoc acc user
96
+ (assoc node :last-tweet (:text tweet)
97
+ :image-url (:profile_image_url tweet)
98
+ :username (:from_user tweet)))
99
+ (add-mentions user mentions))))
100
+ graph
101
+ (map #(select-keys % [:text :from_user :profile_image_url]) tweet-maps)))
102
+
103
+ (defn num-mentions [user]
104
+ (reduce + (vals (:mentions user))))
105
+
106
+ (defn update-state
107
+ "Given an old state, maximum id and a new sequence of tweets, return
108
+ an updated state."
109
+ [old-state max-id tweets]
110
+ (-> old-state
111
+ (assoc :max-id max-id)
112
+ (update-in [:tweet-count] #(+ % (count tweets)))
113
+ (assoc :graph (update-graph (:graph old-state) (reverse tweets)))))
114
+
115
+ (defn new-tweets [max-id tweets]
116
+ (filter #(> (:id %) max-id) tweets))
117
+
118
+ (defn new-tweets-callback
119
+ "Given a json object, update the state with any new information and
120
+ fire events."
121
+ [json]
122
+ (let [{:keys [max_id results]} (js->clj json :keywordize-keys true)
123
+ tweets (new-tweets (:max-id @state) results)]
124
+ (do (swap! state update-state max_id tweets)
125
+ (send-event :new-tweets tweets)
126
+ (send-event :graph-update (:graph @state)))))
127
+
128
+ (defn set-tweet-status [css-class message]
129
+ (doto (dom/set-text :tweet-status message)
130
+ (classes/set (name css-class))))
131
+
132
+ (defn error-callback [error]
133
+ (set-tweet-status :error "Twitter error"))
134
+
135
+ (defn add-missing-tweets
136
+ "Add missing data to the graph."
137
+ [graph tweets]
138
+ (let [new-tweets (reduce (fn [acc next-tweet]
139
+ (assoc acc (string/lower-case (:from_user next-tweet))
140
+ next-tweet))
141
+ {}
142
+ (sort-by :id tweets))]
143
+ (reduce (fn [acc [node-name {:keys [from_user text profile_image_url]}]]
144
+ (if-let [old-tweet (get graph node-name)]
145
+ (if (:last-tweet old-tweet)
146
+ acc
147
+ (assoc acc node-name
148
+ (merge old-tweet {:last-tweet text
149
+ :image-url profile_image_url
150
+ :username from_user})))
151
+ acc))
152
+ graph
153
+ new-tweets)))
154
+
155
+ (defn ignored
156
+ "Given a list of the usernames for missing tweets and the tweets
157
+ which are the result of a query for this missing data, return a set of
158
+ twitter usernames which will be ignored moving forward.
159
+
160
+ Names may be ignored because the twitter user does not exist or
161
+ just doesn't tweet."
162
+ [missing tweets]
163
+ (when (< (count tweets) results-per-page)
164
+ (let [users (set (map #(string/lower-case (:from_user %)) tweets))
165
+ missing (map string/lower-case missing)]
166
+ (reduce (fn [acc next-missing]
167
+ (if (contains? users next-missing)
168
+ acc
169
+ (conj acc next-missing)))
170
+ #{}
171
+ missing))))
172
+
173
+ (defn add-missing-callback
174
+ "Update the graph and the ignore-mentions list when data is received
175
+ from a missing user query."
176
+ [missing json]
177
+ (let [response (js->clj json :keywordize-keys true)
178
+ tweets (:results response)]
179
+ (if-let [error (:error response)]
180
+ (set-tweet-status :error error)
181
+ (do (swap! state (fn [old-state]
182
+ (assoc old-state
183
+ :graph (add-missing-tweets (:graph old-state) tweets)
184
+ :ignore-mentions (into (:ignore-mentions old-state)
185
+ (ignored missing tweets)))))
186
+ (send-event :new-tweets [])
187
+ (send-event :graph-update (:graph @state))))))
188
+
189
+ (defn missing-tweets
190
+ "Return a list of usernames with missing tweets in the graph."
191
+ [graph]
192
+ (->> (map second graph)
193
+ (remove :last-tweet)
194
+ (map :username)
195
+ (remove empty?)
196
+ (remove (:ignore-mentions @state))))
197
+
198
+ (defn fetch-mentioned-tweets
199
+ "Query twitter for usernames which are currently missing data in the
200
+ graph. Limit this query to max-missing-query names."
201
+ [missing]
202
+ (let [q (apply str (interpose " OR " (map #(str "from:" %)
203
+ (take max-missing-query missing))))]
204
+ (set-tweet-status :okay "Fetching mentioned tweets")
205
+ (retrieve (doto (js-obj)
206
+ (aset "q" q)
207
+ (aset "rpp" results-per-page))
208
+ #(add-missing-callback missing %)
209
+ error-callback)))
210
+
211
+ (defn fetch-new-tweets
212
+ "Use the current search tag to fetch new tweets from twitter."
213
+ []
214
+ (when-let [tag (:search-tag @state)]
215
+ (set-tweet-status :okay "Fetching tweets")
216
+ (retrieve (doto (js-obj)
217
+ (aset "q" tag)
218
+ (aset "rpp" results-per-page))
219
+ new-tweets-callback
220
+ error-callback)))
221
+
222
+ (defn fetch-tweets
223
+ "If there are missing tweets then fetch them, if not fetch new tweets."
224
+ []
225
+ (let [missing (missing-tweets (:graph @state))]
226
+ (if (seq missing)
227
+ (fetch-mentioned-tweets missing)
228
+ (fetch-new-tweets))))
229
+
230
+ (defn poll
231
+ "Request new data from twitter once every 24 seconds. This will put
232
+ you at the 150 request/hour rate limit. We can speed it up for the demo."
233
+ []
234
+ (let [timer (goog.Timer. 24000)]
235
+ (do (fetch-tweets)
236
+ (. timer (start))
237
+ (events/listen timer goog.Timer/TICK fetch-tweets))))
238
+
239
+ (defn do-track-button-clicked
240
+ "When the track button is clicked, reset to the initial state
241
+ keeping only the event listeners."
242
+ []
243
+ (do (let [listeners (:listeners @state)]
244
+ (reset! state (assoc initial-state :listeners listeners :search-tag (search-tag))))
245
+ (fetch-tweets)
246
+ (send-event :track-clicked)))
247
+
248
+ (defn start-app
249
+ "Start polling and listen for UI events."
250
+ []
251
+ (do (poll)
252
+ (events/listen (dom/get-element :twitter-search-button)
253
+ "click"
254
+ do-track-button-clicked)
255
+ (events/listen (dom/get-element :twitter-search-tag)
256
+ event-type/CHANGE
257
+ do-track-button-clicked)))
258
+
259
+ (start-app)
260
+
261
+ (defn link [url s]
262
+ (str "<a href='" url "' target='_twitterbuzz'>" s "</a>"))
263
+
264
+ (defn markup
265
+ "Add markup to tweet text to activate links."
266
+ [s]
267
+ (let [markup-f (fn [s] (let [w (string/trim s)]
268
+ (cond (gstring/startsWith w "http://")
269
+ (link w w)
270
+ (gstring/startsWith w "@")
271
+ (link (str "http://twitter.com/#!/" (re-find #"\w+" w)) w)
272
+ :else s)))]
273
+ (string/join " " (map markup-f (string/split s #"[ ]")))))
274
+
275
+ (comment
276
+
277
+ (parse-mentions {:text "What's up @sue: and @Larry"})
278
+
279
+ (add-mentions {} "jim" ["sue"])
280
+ (add-mentions {"sue" {}} "jim" ["sue"])
281
+
282
+ (def tweets [{:profile_image_url "url1"
283
+ :from_user "Jim"
284
+ :text "I like cookies!"}
285
+ {:profile_image_url "url2"
286
+ :from_user "sue"
287
+ :text "Me to @jim."}
288
+ {:profile_image_url "url3"
289
+ :from_user "bob"
290
+ :text "You shouldn't eat so many cookies @sue"}
291
+ {:profile_image_url "url4"
292
+ :from_user "sam"
293
+ :text "@Bob that was a cruel thing to say to @Sue."}
294
+ {:profile_image_url "url5"
295
+ :from_user "ted"
296
+ :text "@foo is awesome!"}])
297
+
298
+ (def graph (update-graph {} tweets))
299
+ (count graph)
300
+
301
+ (num-mentions (get graph "sue"))
302
+ (num-mentions (get graph "bob"))
303
+ (num-mentions (get graph "sam"))
304
+
305
+ (take 1 (reverse (sort-by #(num-mentions (second %)) (seq graph))))
306
+
307
+ )