mirah 0.0.4-java

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 (141) hide show
  1. data/History.txt +15 -0
  2. data/README.txt +51 -0
  3. data/Rakefile +86 -0
  4. data/bin/duby +10 -0
  5. data/bin/dubyc +10 -0
  6. data/bin/dubyp +10 -0
  7. data/bin/jrubyp +36 -0
  8. data/bin/mirah +9 -0
  9. data/bin/mirah.cmd +1 -0
  10. data/bin/mirahc +9 -0
  11. data/bin/mirahc.cmd +1 -0
  12. data/bin/mirahp +9 -0
  13. data/bin/mirahp.cmd +1 -0
  14. data/examples/ant/example-build.xml +7 -0
  15. data/examples/appengine/Rakefile +19 -0
  16. data/examples/appengine/Readme +29 -0
  17. data/examples/appengine/src/org/mirah/MirahApp.mirah +57 -0
  18. data/examples/appengine/src/org/mirah/list.dhtml +15 -0
  19. data/examples/appengine/war/WEB-INF/lib/dubydatastore.jar +0 -0
  20. data/examples/bintrees.mirah +66 -0
  21. data/examples/construction.mirah +8 -0
  22. data/examples/dynamic.mirah +17 -0
  23. data/examples/edb.mirah +3 -0
  24. data/examples/fib.mirah +16 -0
  25. data/examples/fields.mirah +22 -0
  26. data/examples/fractal.mirah +55 -0
  27. data/examples/java_thing.mirah +13 -0
  28. data/examples/plugins/appengine/Rakefile +55 -0
  29. data/examples/plugins/appengine/lib/com/google/appengine/ext/duby/db/datastore.rb +375 -0
  30. data/examples/plugins/appengine/src/com/google/appengine/ext/duby/db/Model.duby +336 -0
  31. data/examples/plugins/appengine/test/com/google/appengine/ext/duby/db/ModelTest.duby +113 -0
  32. data/examples/simple_class.mirah +12 -0
  33. data/examples/sort_closure.mirah +7 -0
  34. data/examples/swing.mirah +20 -0
  35. data/examples/tak.mirah +15 -0
  36. data/examples/test.edb +9 -0
  37. data/examples/wiki/Rakefile +18 -0
  38. data/examples/wiki/src/org/mirah/wiki/MirahWiki.duby +324 -0
  39. data/examples/wiki/src/org/mirah/wiki/edit.eduby.html +42 -0
  40. data/examples/wiki/src/org/mirah/wiki/error.eduby.html +2 -0
  41. data/examples/wiki/src/org/mirah/wiki/layout.eduby.html +69 -0
  42. data/examples/wiki/src/org/mirah/wiki/parser.eduby.html +7 -0
  43. data/examples/wiki/src/org/mirah/wiki/view.eduby.html +15 -0
  44. data/examples/wiki/war/WEB-INF/classes/test/HeredocContext.class +0 -0
  45. data/examples/wiki/war/WEB-INF/classes/test/MirahParser.class +0 -0
  46. data/examples/wiki/war/WEB-INF/lib/appengine-api.jar +0 -0
  47. data/examples/wiki/war/WEB-INF/lib/dubydatastore.jar +0 -0
  48. data/examples/wiki/war/WEB-INF/lib/jmeta-runtime.jar +0 -0
  49. data/examples/wiki/war/WEB-INF/lib/pegdown-stubs.jar +0 -0
  50. data/examples/wiki/war/WEB-INF/pegdown.jar +0 -0
  51. data/examples/wiki/war/app.yaml +21 -0
  52. data/examples/wiki/war/public/favicon.ico +0 -0
  53. data/examples/wiki/war/public/images/appengine_duby.png +0 -0
  54. data/examples/wiki/war/public/images/back.gif +0 -0
  55. data/examples/wiki/war/public/images/dir.gif +0 -0
  56. data/examples/wiki/war/public/images/file.gif +0 -0
  57. data/examples/wiki/war/public/javascripts/prettify.js +61 -0
  58. data/examples/wiki/war/public/robots.txt +0 -0
  59. data/examples/wiki/war/public/stylesheets/main.css +156 -0
  60. data/examples/wiki/war/public/stylesheets/prettify.css +1 -0
  61. data/examples/wiki/war/public/stylesheets/sh_style.css +66 -0
  62. data/examples/wiki/war/public/stylesheets/source.css +21 -0
  63. data/examples/wiki/war/public/wmd/images/bg-fill.png +0 -0
  64. data/examples/wiki/war/public/wmd/images/bg.png +0 -0
  65. data/examples/wiki/war/public/wmd/images/blockquote.png +0 -0
  66. data/examples/wiki/war/public/wmd/images/bold.png +0 -0
  67. data/examples/wiki/war/public/wmd/images/code.png +0 -0
  68. data/examples/wiki/war/public/wmd/images/h1.png +0 -0
  69. data/examples/wiki/war/public/wmd/images/hr.png +0 -0
  70. data/examples/wiki/war/public/wmd/images/img.png +0 -0
  71. data/examples/wiki/war/public/wmd/images/italic.png +0 -0
  72. data/examples/wiki/war/public/wmd/images/link.png +0 -0
  73. data/examples/wiki/war/public/wmd/images/ol.png +0 -0
  74. data/examples/wiki/war/public/wmd/images/redo.png +0 -0
  75. data/examples/wiki/war/public/wmd/images/separator.png +0 -0
  76. data/examples/wiki/war/public/wmd/images/ul.png +0 -0
  77. data/examples/wiki/war/public/wmd/images/undo.png +0 -0
  78. data/examples/wiki/war/public/wmd/images/wmd-on.png +0 -0
  79. data/examples/wiki/war/public/wmd/images/wmd.png +0 -0
  80. data/examples/wiki/war/public/wmd/showdown.js +421 -0
  81. data/examples/wiki/war/public/wmd/wmd-base.js +1799 -0
  82. data/examples/wiki/war/public/wmd/wmd-plus.js +311 -0
  83. data/examples/wiki/war/public/wmd/wmd.js +73 -0
  84. data/javalib/JRubyParser.jar +0 -0
  85. data/javalib/dynalang-invoke-0.1.jar +0 -0
  86. data/javalib/mirah-bootstrap.jar +0 -0
  87. data/javalib/mirah-parser.jar +0 -0
  88. data/lib/duby.rb +2 -0
  89. data/lib/mirah.rb +338 -0
  90. data/lib/mirah/appengine_tasks.rb +146 -0
  91. data/lib/mirah/ast.rb +615 -0
  92. data/lib/mirah/ast/call.rb +307 -0
  93. data/lib/mirah/ast/class.rb +311 -0
  94. data/lib/mirah/ast/flow.rb +364 -0
  95. data/lib/mirah/ast/intrinsics.rb +470 -0
  96. data/lib/mirah/ast/literal.rb +154 -0
  97. data/lib/mirah/ast/local.rb +89 -0
  98. data/lib/mirah/ast/method.rb +360 -0
  99. data/lib/mirah/ast/scope.rb +208 -0
  100. data/lib/mirah/ast/structure.rb +226 -0
  101. data/lib/mirah/ast/type.rb +130 -0
  102. data/lib/mirah/compiler.rb +341 -0
  103. data/lib/mirah/env.rb +33 -0
  104. data/lib/mirah/jvm/base.rb +258 -0
  105. data/lib/mirah/jvm/compiler.rb +885 -0
  106. data/lib/mirah/jvm/method_lookup.rb +203 -0
  107. data/lib/mirah/jvm/source_compiler.rb +737 -0
  108. data/lib/mirah/jvm/source_generator/builder.rb +444 -0
  109. data/lib/mirah/jvm/source_generator/loops.rb +110 -0
  110. data/lib/mirah/jvm/source_generator/precompile.rb +188 -0
  111. data/lib/mirah/jvm/source_generator/typer.rb +11 -0
  112. data/lib/mirah/jvm/typer.rb +151 -0
  113. data/lib/mirah/jvm/types.rb +416 -0
  114. data/lib/mirah/jvm/types/basic_types.rb +33 -0
  115. data/lib/mirah/jvm/types/boolean.rb +17 -0
  116. data/lib/mirah/jvm/types/enumerable.rb +65 -0
  117. data/lib/mirah/jvm/types/extensions.rb +86 -0
  118. data/lib/mirah/jvm/types/factory.rb +186 -0
  119. data/lib/mirah/jvm/types/floats.rb +86 -0
  120. data/lib/mirah/jvm/types/integers.rb +171 -0
  121. data/lib/mirah/jvm/types/intrinsics.rb +376 -0
  122. data/lib/mirah/jvm/types/literals.rb +74 -0
  123. data/lib/mirah/jvm/types/methods.rb +614 -0
  124. data/lib/mirah/jvm/types/number.rb +143 -0
  125. data/lib/mirah/nbcompiler.rb +29 -0
  126. data/lib/mirah/plugin/edb.rb +29 -0
  127. data/lib/mirah/plugin/gwt.rb +173 -0
  128. data/lib/mirah/plugin/java.rb +55 -0
  129. data/lib/mirah/transform.rb +266 -0
  130. data/lib/mirah/transform2.rb +728 -0
  131. data/lib/mirah/typer.rb +407 -0
  132. data/lib/mirah_task.rb +107 -0
  133. data/test/test_ast.rb +359 -0
  134. data/test/test_compilation.rb +112 -0
  135. data/test/test_env.rb +42 -0
  136. data/test/test_gwt.rb +58 -0
  137. data/test/test_java_typer.rb +183 -0
  138. data/test/test_javac_compiler.rb +63 -0
  139. data/test/test_jvm_compiler.rb +2607 -0
  140. data/test/test_typer.rb +221 -0
  141. metadata +235 -0
@@ -0,0 +1,7 @@
1
+ import java.util.Collections
2
+ import java.util.ArrayList
3
+
4
+ list = ArrayList.new [9,5,2,6,8,5,0,3,6,1,8,3,6,4,7,5,0,8,5,6,7,2,3]
5
+ puts "unsorted: #{list}"
6
+ Collections.sort(list) {|a,b| Integer(a).compareTo(b)}
7
+ puts "sorted: #{list}"
@@ -0,0 +1,20 @@
1
+ import javax.swing.JFrame
2
+ import javax.swing.JButton
3
+
4
+ # FIXME blocks need to be inside a MethodDefinition, but main doesn't
5
+ # have one.
6
+ def self.run
7
+ frame = JFrame.new "Welcome to Duby"
8
+ frame.setSize 300, 300
9
+ frame.setVisible true
10
+
11
+ button = JButton.new "Press me"
12
+ frame.add button
13
+ frame.show
14
+
15
+ button.addActionListener do |event|
16
+ JButton(event.getSource).setText "Duby Rocks!"
17
+ end
18
+ end
19
+
20
+ run
@@ -0,0 +1,15 @@
1
+ def tak(x:fixnum, y:fixnum, z:fixnum)
2
+ unless y < x
3
+ z
4
+ else
5
+ tak( tak(x-1, y, z),
6
+ tak(y-1, z, x),
7
+ tak(z-1, x, y))
8
+ end
9
+ end
10
+
11
+ i = 0
12
+ while i<1000
13
+ tak(24, 16, 8)
14
+ i+=1
15
+ end
@@ -0,0 +1,9 @@
1
+ <html>
2
+ <head>
3
+ <title><%= @message %></title>
4
+ </head>
5
+ <body>
6
+ <h1><%= @message %></h1>
7
+ </body>
8
+ </html>
9
+
@@ -0,0 +1,18 @@
1
+ # Hack to use the latest version instead of the gems when developing Mirah
2
+ if File.exist?('../../lib/mirah.rb')
3
+ $: << File.expand_path('../../lib')
4
+ end
5
+ if File.exist?('../../../bitescript/lib/bitescript.rb')
6
+ $: << File.expand_path('../../../bitescript/lib/')
7
+ end
8
+ require 'mirah/appengine_tasks'
9
+
10
+ appengine_app :app
11
+
12
+ DUBY_APP = "#{Duby.dest_path}/org/mirah/wiki/MirahWiki.class"
13
+ Templates = Dir.glob("#{Duby.source_path}/org/mirah/wiki/*.eduby.html")
14
+
15
+ Rake::Task[DUBY_APP].enhance(Templates)
16
+
17
+ task :app => DUBY_APP
18
+ task :default => :server
@@ -0,0 +1,324 @@
1
+ import javax.servlet.http.HttpServlet
2
+ import javax.servlet.http.HttpServletRequest
3
+ import javax.servlet.Filter
4
+ import com.google.appengine.ext.duby.db.Model
5
+ import com.google.appengine.api.datastore.Text
6
+ import java.util.Date
7
+ import org.pegdown.PegDownProcessorStub
8
+ import com.google.appengine.api.users.UserServiceFactory
9
+ import com.google.appengine.api.users.User
10
+ import java.util.ArrayList
11
+ import java.util.List
12
+
13
+ class Page < Model
14
+ property 'title', String
15
+ property 'body', Text
16
+ property 'userid', String
17
+ property 'user', User
18
+ property 'nickname', String
19
+ property 'comment', String
20
+ property 'created', Date
21
+ property 'version', Long
22
+ property 'locked', Boolean
23
+ end
24
+
25
+ class Helper < HttpServlet
26
+ def markdown(text:String)
27
+ return "" unless text
28
+ flags = 0x5ff
29
+ if @allow_html
30
+ flags |= 0x200 unless @allow_html
31
+ @html_markdown ||= PegDownProcessorStub.new(flags)
32
+ @html_markdown.markdownToHtml(text)
33
+ else
34
+ @nohtml_markdown ||= PegDownProcessorStub.new(flags)
35
+ @nohtml_markdown.markdownToHtml(text)
36
+ end
37
+ end
38
+
39
+ def html=(enabled:boolean)
40
+ @allow_html = enabled
41
+ end
42
+
43
+ def page_name(name:String)
44
+ if name.nil?
45
+ return "Main"
46
+ else
47
+ name = name.replaceAll("\\W", "")
48
+ end
49
+ if name.equals("")
50
+ "Main"
51
+ else
52
+ name
53
+ end
54
+ end
55
+
56
+ def h(text:String)
57
+ return "" unless text
58
+ text = text.replace("&", "&amp;")
59
+ text = text.replace("<", "&lt;")
60
+ text = text.replace(">", "&gt;")
61
+ text = text.replace("\"", "&quot;")
62
+ text.replace("'", "&#39;")
63
+ end
64
+
65
+ def h(o:Object)
66
+ h(o.toString)
67
+ end
68
+
69
+ def_edb(layout, 'org/mirah/wiki/layout.eduby.html')
70
+
71
+ def with_layout(content:String)
72
+ @content = content
73
+ layout
74
+ end
75
+
76
+ def title
77
+ @title
78
+ end
79
+
80
+ def title=(title:String)
81
+ @title = title
82
+ end
83
+
84
+ def users
85
+ @users ||= UserServiceFactory.getUserService()
86
+ end
87
+
88
+ macro def admin?
89
+ quote { users.isUserAdmin }
90
+ end
91
+
92
+ def user
93
+ users.getCurrentUser
94
+ end
95
+
96
+ def nickname
97
+ user.getNickname.replaceAll('@.*', '')
98
+ end
99
+
100
+ def extra_links
101
+ @links ||= ArrayList.new
102
+ end
103
+
104
+ def url
105
+ '/'
106
+ end
107
+ end
108
+
109
+ class ViewPage < Helper
110
+ def_edb(view, 'org/mirah/wiki/view.eduby.html')
111
+
112
+ def doGet(request, response)
113
+ @url = request.getRequestURI
114
+ self.title = @name = page_name(request.getPathInfo)
115
+ canonical = "/" + @name
116
+ unless canonical.equals(request.getPathInfo)
117
+ response.sendRedirect(canonical)
118
+ return
119
+ end
120
+
121
+ @page = Page.get(@name)
122
+ self.html = @page.locked if @page
123
+ response.getWriter.write(with_layout(view))
124
+ end
125
+
126
+ def url
127
+ @url
128
+ end
129
+
130
+ def extra_links
131
+ links = ArrayList.new
132
+ if @page
133
+ can_edit = admin?
134
+ can_edit = true unless @page.locked
135
+ if can_edit
136
+ links.add(["Edit", "/edit/#{@page.title}"])
137
+ end
138
+ end
139
+ links.add(["New Page", "javascript:void(newPage())"])
140
+ links
141
+ end
142
+ end
143
+
144
+ import java.util.logging.Logger
145
+
146
+ class EditPage < Helper
147
+ def_edb(edit, 'org/mirah/wiki/edit.eduby.html')
148
+ def_edb(error, 'org/mirah/wiki/error.eduby.html')
149
+
150
+ def logger
151
+ @logger ||= Logger.getLogger("EditPage")
152
+ end
153
+
154
+ def render(content:String)
155
+ @response.setContentType("text/html; charset=utf-8")
156
+ @response.getWriter.write(with_layout(content))
157
+ end
158
+
159
+ def url
160
+ @url
161
+ end
162
+
163
+ def doGet(request, response)
164
+ @url = request.getRequestURI
165
+ @response = response
166
+ @error = String(nil)
167
+ @name = page_name(request.getPathInfo)
168
+ @page = Page.get(@name)
169
+ if @page && @page.locked
170
+ unless admin?
171
+ @error = "You are not authorized to edit this page"
172
+ response.setStatus(403)
173
+ render(error)
174
+ return
175
+ end
176
+ end
177
+ render(edit)
178
+ end
179
+
180
+ def doPost(_request, _response)
181
+ @error = nil
182
+ @response = _response
183
+ @url = _request.getRequestURI
184
+
185
+ # TODO scope inside blocks is not quite right
186
+ this = self
187
+ request = _request
188
+ response = _response
189
+ is_admin = admin?
190
+
191
+ name = page_name(request.getPathInfo)
192
+
193
+ begin
194
+ edit_version = Long.parseLong(String(request.getParameter("version")))
195
+ rescue NumberFormatException
196
+ response.sendError(
197
+ 400, "Invalid version '#{request.getParameter("version")}'")
198
+ return
199
+ end
200
+
201
+ Model.transaction do
202
+ orig_page = Page.get(name)
203
+ current_version = orig_page ? orig_page.version : long(0)
204
+ if current_version != edit_version
205
+ @error = <<EOS
206
+ Version conflict. You are trying to edit version #{edit_version}, but
207
+ the current version is #{current_version}.
208
+ EOS
209
+ @page = orig_page
210
+ @name = name
211
+ response.setStatus(409)
212
+ this.render(this.edit)
213
+ return
214
+ end
215
+ if orig_page && orig_page.locked
216
+ unless is_admin
217
+ @error = "You are not authorized to edit this page"
218
+ response.setStatus(403)
219
+ this.render(this.error)
220
+ return
221
+ end
222
+ end
223
+
224
+ this.save_old_version(orig_page) if orig_page
225
+
226
+ if orig_page
227
+ page = orig_page
228
+ page.version = page.version + 1
229
+ else
230
+ page = Page.new(name)
231
+ page.title = name
232
+ page.version = 1
233
+ end
234
+
235
+ locked = is_admin && "locked".equals(request.getParameter("locked"))
236
+ page.body = String(request.getParameter("body"))
237
+ page.nickname = String(request.getParameter("nickname"))
238
+ page.comment = String(request.getParameter("comment"))
239
+ page.user = this.user
240
+ page.userid = this.user.getUserId
241
+ page.created = Date.new
242
+ page.locked = locked
243
+ page.save
244
+ response.sendRedirect("/wiki/" + name)
245
+ end
246
+ end
247
+
248
+ def save_old_version(orig_page:Page)
249
+ old_version = Page.new(orig_page)
250
+ old_version.title = orig_page.title
251
+ old_version.body = orig_page.body
252
+ old_version.userid = orig_page.userid
253
+ old_version.user = orig_page.user
254
+ old_version.nickname = orig_page.nickname
255
+ old_version.comment = orig_page.comment
256
+ old_version.created = orig_page.created
257
+ old_version.version = orig_page.version
258
+ old_version.locked = orig_page.locked
259
+ old_version.save
260
+ end
261
+ end
262
+
263
+ import test.MirahParser
264
+ import jmeta.BaseParser
265
+ class MirahParserPage < Helper
266
+ def_edb(render, 'org/mirah/wiki/parser.eduby.html')
267
+
268
+ def initialize
269
+ self.title = "Mirah Parser Test"
270
+ end
271
+
272
+ def doGet(request, response)
273
+ doPost(request, response)
274
+ end
275
+
276
+ def doPost(request, response)
277
+ @code = String(request.getParameter("code")) || "puts 'Hello, world!'"
278
+ parser = MirahParser.new
279
+ begin
280
+ @parsed = BaseParser.print_r(parser.parse(@code))
281
+ rescue => ex
282
+ @parsed = ex.getMessage
283
+ end
284
+ response.getWriter.write(with_layout(render))
285
+ end
286
+ end
287
+
288
+ class FederatedLogin < Helper
289
+ def doGet(request, response)
290
+ provider = request.getPathInfo
291
+ if provider && provider.length > 1
292
+ provider = provider.substring(1)
293
+ else
294
+ provider = 'www.google.com/accounts/o8/id'
295
+ end
296
+ continue = String(request.getParameter('continue')) || '/'
297
+ url = users.createLoginURL(continue, nil, provider, nil)
298
+ response.sendRedirect(url)
299
+ end
300
+ end
301
+
302
+ class LoginRequired < Helper
303
+ def doGet(request, response)
304
+ # This should be a page allowing people to select an OpenID provider.
305
+ # But I'm lazy so I'll just force them to use gmail...
306
+ continue = String(request.getParameter('continue'))
307
+ url = users.createLoginURL(continue, nil, 'www.google.com/accounts/o8/id', nil)
308
+ response.sendRedirect(url)
309
+ end
310
+ end
311
+
312
+ class MainFilter; implements Filter
313
+ def init(arg); end
314
+ def destroy; end
315
+ def doFilter(request, response, filters)
316
+ if "/".equals(HttpServletRequest(request).getRequestURI)
317
+ request.getRequestDispatcher('/wiki/Main').forward(request, response)
318
+ nil
319
+ else
320
+ filters.doFilter(request, response)
321
+ nil
322
+ end
323
+ end
324
+ end
@@ -0,0 +1,42 @@
1
+ <div>
2
+ <% if @error %>
3
+ <div id=error><%=h @error %></div>
4
+ <% end %>
5
+ <div>
6
+ <form method=post>
7
+ <textarea id=body name=body style="width:95%;font-family:monospace" rows=5
8
+ ><% if @page && @page.body %><%=h @page.body %><% end
9
+ %></textarea><br>
10
+ Your Name: <input name=nickname value="<%=h nickname %>"><br>
11
+ Comment: <input name=comment value=<% if @page %>
12
+ "Edited Page"
13
+ <% else %>
14
+ "Created Page"
15
+ <% end %>><br>
16
+ <input type=hidden name=version value="<%= @page ? @page.version : long(0) %>">
17
+ <% if admin? %>
18
+ Locked: <input name=locked value=locked type=checkbox <%= "checked" if @page && @page.locked%>><br>
19
+ <% end %>
20
+ <input type=submit name=Save>
21
+ </form>
22
+ </div>
23
+ <hr style="clear:all">
24
+ <div id=preview class="wmd-preview"></div>
25
+ <script>
26
+ (function(){
27
+ var ta = document.getElementById("body");
28
+ var sh = 0;
29
+ function resize() {
30
+ var nsh = ta.scrollHeight;
31
+ if (nsh != sh) {
32
+ ta.style.height = 0;
33
+ ta.style.height = (nsh + 100) + "px";
34
+ sh = ta.scrollHeight;
35
+ }
36
+ setTimeout(resize, 250);
37
+ }
38
+ resize();
39
+ })();
40
+ wmd_options={output:"markdown"};
41
+ </script>
42
+ <script type="text/javascript" src="/wmd/wmd.js""></script>
@@ -0,0 +1,2 @@
1
+ <h1>error:</h1>
2
+ <p><%=h @error %></p>
@@ -0,0 +1,69 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
5
+ <title><%=h @title %></title>
6
+ <link type="text/css" rel="stylesheet" href="/stylesheets/main.css">
7
+ <link href="/stylesheets/prettify.css" type="text/css" rel="stylesheet" />
8
+ <script type="text/javascript" src="/javascripts/prettify.js"></script>
9
+ </head>
10
+ <body onload="prettyPrint()">
11
+ <div id="page">
12
+ <div id="sidebar">
13
+
14
+ <h1>Mirah</h1>
15
+
16
+ <ul id="sidebar-items">
17
+
18
+ <li>
19
+ <h3>Join the community</h3>
20
+ <ul class="links">
21
+ <li><a href="/">Home Page</a></li>
22
+ <li><a href="http://github.com/mirah/mirah">github</a></li>
23
+ <li><a href="/wiki/Resources">Resources</a></li>
24
+ <li><a href="/wiki/MirahHowto">Howto</a></li>
25
+ <li><a
26
+ href="http://groups.google.com/group/mirah/"
27
+ target="_new">Send Feedback</a></li>
28
+ </ul>
29
+ </li>
30
+
31
+ <li>
32
+ <h3>Sample Apps</h3>
33
+ <ul class="links">
34
+ <li><a href="http://github.com/mirah/mirah/tree/master/examples/appengine/">Guestbook</a> |
35
+ <a href="http://github.com/jacortinas/appengine-rails-jquery-demo">Mustache</a></li>
36
+ </ul>
37
+ <a href="/wiki/MirahSamples">Sample Code</a>
38
+ </li>
39
+
40
+ <li>
41
+ <h3>Mirah Videos</h3>
42
+ <ul class="links">
43
+ <li><a href="http://www.youtube.com/watch?v=08rNKxW0PPo">ribrdb</a> |
44
+ <a href="http://confreaks.net/videos/196-rubyconf2009-ruby-mutants">headius</a></li>
45
+ </ul>
46
+ </li>
47
+
48
+ </div>
49
+
50
+ <div id="content">
51
+ <div id=hlinks>
52
+ <% if user %>
53
+ <%=h user.getEmail %>&nbsp;|&nbsp;
54
+ <% extra_links.each do |_pair|;pair = List(_pair) %>
55
+ <a href="<%=h pair.get(1)%>"><%=h pair.get(0)%></a>&nbsp;|&nbsp;
56
+ <% end %>
57
+ <a href="<%=h users.createLogoutURL('/')%>">Sign Out</a>
58
+ <% else %>
59
+ <a href="<%=users.createLoginURL(url)%>">Sign In</a>
60
+ <% end %>
61
+ </div>
62
+ <div id=wikicontent>
63
+ <%= @content %>
64
+ </div>
65
+ </div>
66
+ </div>
67
+ </body>
68
+ </html>
69
+