feedjira 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +8 -0
  5. data/CHANGELOG.md +162 -0
  6. data/Gemfile +17 -0
  7. data/Guardfile +5 -0
  8. data/README.md +242 -0
  9. data/Rakefile +6 -0
  10. data/benchmarks/README.md +90 -0
  11. data/benchmarks/basic.rb +31 -0
  12. data/benchmarks/feed_list.txt +10 -0
  13. data/benchmarks/feed_xml/apple.xml +149 -0
  14. data/benchmarks/feed_xml/cnn.xml +278 -0
  15. data/benchmarks/feed_xml/daring_fireball.xml +1697 -0
  16. data/benchmarks/feed_xml/engadget.xml +604 -0
  17. data/benchmarks/feed_xml/feedjira_commits.xml +370 -0
  18. data/benchmarks/feed_xml/gizmodo.xml +2 -0
  19. data/benchmarks/feed_xml/loop.xml +441 -0
  20. data/benchmarks/feed_xml/rails.xml +1938 -0
  21. data/benchmarks/feed_xml/white_house.xml +951 -0
  22. data/benchmarks/feed_xml/xkcd.xml +2 -0
  23. data/benchmarks/fetching_systems.rb +23 -0
  24. data/benchmarks/other_libraries.rb +73 -0
  25. data/feedjira.gemspec +27 -0
  26. data/lib/feedjira.rb +16 -0
  27. data/lib/feedjira/core_ext.rb +3 -0
  28. data/lib/feedjira/core_ext/date.rb +19 -0
  29. data/lib/feedjira/core_ext/string.rb +9 -0
  30. data/lib/feedjira/core_ext/time.rb +31 -0
  31. data/lib/feedjira/feed.rb +459 -0
  32. data/lib/feedjira/feed_entry_utilities.rb +66 -0
  33. data/lib/feedjira/feed_utilities.rb +103 -0
  34. data/lib/feedjira/parser.rb +20 -0
  35. data/lib/feedjira/parser/atom.rb +61 -0
  36. data/lib/feedjira/parser/atom_entry.rb +34 -0
  37. data/lib/feedjira/parser/atom_feed_burner.rb +22 -0
  38. data/lib/feedjira/parser/atom_feed_burner_entry.rb +35 -0
  39. data/lib/feedjira/parser/google_docs_atom.rb +28 -0
  40. data/lib/feedjira/parser/google_docs_atom_entry.rb +29 -0
  41. data/lib/feedjira/parser/itunes_rss.rb +50 -0
  42. data/lib/feedjira/parser/itunes_rss_item.rb +41 -0
  43. data/lib/feedjira/parser/itunes_rss_owner.rb +12 -0
  44. data/lib/feedjira/parser/rss.rb +24 -0
  45. data/lib/feedjira/parser/rss_entry.rb +37 -0
  46. data/lib/feedjira/parser/rss_feed_burner.rb +23 -0
  47. data/lib/feedjira/parser/rss_feed_burner_entry.rb +43 -0
  48. data/lib/feedjira/version.rb +3 -0
  49. data/spec/feedjira/feed_entry_utilities_spec.rb +62 -0
  50. data/spec/feedjira/feed_spec.rb +762 -0
  51. data/spec/feedjira/feed_utilities_spec.rb +273 -0
  52. data/spec/feedjira/parser/atom_entry_spec.rb +86 -0
  53. data/spec/feedjira/parser/atom_feed_burner_entry_spec.rb +47 -0
  54. data/spec/feedjira/parser/atom_feed_burner_spec.rb +56 -0
  55. data/spec/feedjira/parser/atom_spec.rb +76 -0
  56. data/spec/feedjira/parser/google_docs_atom_entry_spec.rb +22 -0
  57. data/spec/feedjira/parser/google_docs_atom_spec.rb +31 -0
  58. data/spec/feedjira/parser/itunes_rss_item_spec.rb +63 -0
  59. data/spec/feedjira/parser/itunes_rss_owner_spec.rb +18 -0
  60. data/spec/feedjira/parser/itunes_rss_spec.rb +58 -0
  61. data/spec/feedjira/parser/rss_entry_spec.rb +85 -0
  62. data/spec/feedjira/parser/rss_feed_burner_entry_spec.rb +85 -0
  63. data/spec/feedjira/parser/rss_feed_burner_spec.rb +57 -0
  64. data/spec/feedjira/parser/rss_spec.rb +57 -0
  65. data/spec/sample_feeds/AmazonWebServicesBlog.xml +797 -0
  66. data/spec/sample_feeds/AmazonWebServicesBlogFirstEntryContent.xml +63 -0
  67. data/spec/sample_feeds/AtomFeedWithSpacesAroundEquals.xml +61 -0
  68. data/spec/sample_feeds/FeedBurnerUrlNoAlternate.xml +28 -0
  69. data/spec/sample_feeds/GoogleDocsList.xml +188 -0
  70. data/spec/sample_feeds/HREFConsideredHarmful.xml +314 -0
  71. data/spec/sample_feeds/HREFConsideredHarmfulFirstEntry.xml +22 -0
  72. data/spec/sample_feeds/ITunesWithSpacesInAttributes.xml +63 -0
  73. data/spec/sample_feeds/PaulDixExplainsNothing.xml +175 -0
  74. data/spec/sample_feeds/PaulDixExplainsNothingAlternate.xml +175 -0
  75. data/spec/sample_feeds/PaulDixExplainsNothingFirstEntryContent.xml +19 -0
  76. data/spec/sample_feeds/PaulDixExplainsNothingWFW.xml +174 -0
  77. data/spec/sample_feeds/SamRuby.xml +583 -0
  78. data/spec/sample_feeds/TechCrunch.xml +1515 -0
  79. data/spec/sample_feeds/TechCrunchFirstEntry.xml +9 -0
  80. data/spec/sample_feeds/TechCrunchFirstEntryDescription.xml +3 -0
  81. data/spec/sample_feeds/TenderLovemaking.xml +516 -0
  82. data/spec/sample_feeds/TenderLovemakingFirstEntry.xml +66 -0
  83. data/spec/sample_feeds/TrotterCashionHome.xml +611 -0
  84. data/spec/sample_feeds/TypePadNews.xml +368 -0
  85. data/spec/sample_feeds/atom_with_link_tag_for_url_unmarked.xml +31 -0
  86. data/spec/sample_feeds/itunes.xml +67 -0
  87. data/spec/sample_feeds/pet_atom.xml +497 -0
  88. data/spec/spec_helper.rb +88 -0
  89. metadata +229 -0
@@ -0,0 +1,63 @@
1
+
2
+ <div xmlns="http://www.w3.org/1999/xhtml"><p>
3
+ Late last year an entrepreneur from Turkey visited me at Amazon HQ in Seattle.
4
+
5
+ We talked about his plans to use AWS as part of his new social video
6
+ portal startup. I won't spill any beans before he's ready to talk
7
+ about it himself, but I will say that he has a really good concept,
8
+ strong backers, and infectious enthusiasm for the online world.</p>
9
+ </p>
10
+
11
+ <p>
12
+ He's now ready to hire a software architect and designer in order to
13
+ bring his vision to life. I've posted the job below; you can
14
+ send your resume to <a href="mailto:apply@web.tv">apply@web.tv</a>
15
+ if you are interested, qualified, and located in the right part
16
+ of the world.
17
+ </p>
18
+
19
+ <div style="padding:10px;margin-left:20px;margin-right:20px;margin-bottom:10px;border:1px dotted black;background-color:#e0e0e0;">
20
+
21
+ <div style="text-align:center;font-size:120%;font-weight:bold;">Software Architect & Designer</div>
22
+
23
+ <p>
24
+ We are a reputable Internet technology, software services and e-commerce company based
25
+ in
26
+ <a href="http://en.wikipedia.org/wiki/Istanbul">Istanbul</a> and
27
+ <a href="http://en.wikipedia.org/wiki/Bursa">Bursa</a>,
28
+ <a href="http://en.wikipedia.org/wiki/Turkey">Turkey</a>.
29
+ We are looking for a talented Software Architect who will
30
+ be working in Istanbul for a certain period of time, for our new global scale
31
+ "social video portal" project. Below are the qualifications required and job
32
+ description for the position to be held.
33
+ <p>
34
+
35
+ <style>
36
+ .li20090116 {padding-bottom:6px;}
37
+ </style>
38
+
39
+ <p>Qualifications:</p>
40
+
41
+ <ul>
42
+ <li class="li20090116" >Extensive knowledge of web technologies.</li>
43
+ <li class="li20090116">Experienced in web based application design and development.</li>
44
+ <li class="li20090116">Solid bacground in object oriented design and development.</li>
45
+ <li class="li20090116">Preferrably experienced in live broadcasting over the internet, video streaming, video sharing and social networking web site development and design.</li>
46
+ <li class="li20090116">Knowledge and experience of design and development of multi-tier, distributed, massively multi-user systems.</li>
47
+ <li class="li20090116">Experienced in Cloud Computing applications (preferably with AWS).</li>
48
+ <li class="li20090116">Very good command of PHP or Python.</li>
49
+ <li class="li20090116">Experinced in relational database design.</li>
50
+ <li class="li20090116">Familarity with Erlang, and knowledge or experience of Java, C/C++, Ajax, Adobe Flex, mySQL is a plus.</li>
51
+ <li class="li20090116">Self motivated, enthusiastic, team player.</li>
52
+ </ul>
53
+
54
+ <p>Job Description:</p>
55
+ <ul>
56
+ <li class="li20090116">Will be mainly responsible for designing the overall system for a multi-tier, massively multi-user live video multi-casting, videosharing web site which will also have features of a social network.</li>
57
+ <li class="li20090116">Will be involved in Design and Development phases of software development cycle. Will contribute to the Analysis phase.</li>
58
+ <li class="li20090116">Will lead the Software Development Team for the period of the contract and report to the Project Coordinator.</li>
59
+ </ul>
60
+ </div>
61
+
62
+ <p>-- Jeff;</p>
63
+ </div>
@@ -0,0 +1,61 @@
1
+
2
+ <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
3
+ <!--
4
+ This atom/xml feed is an index to active advisories, watches and warnings
5
+ issued by the National Weather Service. This index file is not the complete
6
+ Common Alerting Protocol (CAP) alert message. To obtain the complete CAP
7
+ alert, please follow the links for each entry in this index. Also note the
8
+ CAP message uses a style sheet to convey the information in a human readable
9
+ format. Please view the source of the CAP message to see the complete data
10
+ set. Not all information in the CAP message is contained in this index of
11
+ active alerts.
12
+ -->
13
+ <feed
14
+ xmlns = "http://www.w3.org/2005/Atom"
15
+ xmlns:cap = "urn:oasis:names:tc:emergency:cap:1.1"
16
+ xmlns:ha = "http://www.alerting.net/namespace/index_1.0"
17
+ >
18
+ <!-- TZN = <EST> -->
19
+ <!-- TZO = <-5> -->
20
+ <!-- http-date = Wed, 07 Nov 2012 02:17:00 GMT -->
21
+ <id>http://alerts.weather.gov/cap/wwaatmget.php?x=MEC015&amp;y=0</id>
22
+ <generator>NWS CAP Server</generator>
23
+ <updated>2012-11-07T09:17:00-05:00</updated>
24
+ <author>
25
+ <name>w-nws.webmaster@noaa.gov</name>
26
+ </author>
27
+ <title>Current Watches, Warnings and Advisories for Lincoln (MEC015) Maine Issued by the National Weather Service</title>
28
+ <link href="http://alerts.weather.gov/cap/wwaatmget.php?x=MEC015&amp;y=0"/>
29
+ <entry>
30
+ <id>http://alerts.weather.gov/cap/wwacapget.php?x=ME124CCF70CDD4.WinterWeatherAdvisory.124CCF729F10ME.CARWSWCAR.b113b32cf3dd0946aab63451118d16e7</id>
31
+ <updated>2012-11-07T04:09:00-05:00</updated>
32
+ <published>2012-11-07T04:09:00-05:00</published>
33
+ <author>
34
+ <name>w-nws.webmaster@noaa.gov</name>
35
+ </author>
36
+ <title>Winter Weather Advisory issued November 07 at 4:09AM EST until November 08 at 12:00PM EST by NWS</title>
37
+ <link href="http://alerts.weather.gov/cap/wwacapget.php?x=ME124CCF70CDD4.WinterWeatherAdvisory.124CCF729F10ME.CARWSWCAR.b113b32cf3dd0946aab63451118d16e7"/>
38
+ <summary>...WINTER WEATHER ADVISORY IN EFFECT FROM 7 PM THIS EVENING TO NOON EST THURSDAY... THE NATIONAL WEATHER SERVICE IN CARIBOU HAS ISSUED A WINTER WEATHER ADVISORY FOR SNOW AND MIXED PRECIPITATION...WHICH IS IN EFFECT FROM 7 PM THIS EVENING TO NOON EST THURSDAY. * PRECIPITATION TYPE...SNOW...SLEET AND FREEZING RAIN</summary>
39
+ <cap:event>Winter Weather Advisory</cap:event>
40
+ <cap:effective>2012-11-07T04:09:00-05:00</cap:effective>
41
+ <cap:expires>2012-11-07T16:00:00-05:00</cap:expires>
42
+ <cap:status>Actual</cap:status>
43
+ <cap:msgType>Alert</cap:msgType>
44
+ <cap:category>Met</cap:category>
45
+ <cap:urgency>Expected</cap:urgency>
46
+ <cap:severity>Minor</cap:severity>
47
+ <cap:certainty>Likely</cap:certainty>
48
+ <cap:areaDesc>Central Penobscot; Central Washington; Interior Hancock; Northern Penobscot; Northern Washington; Southeast Aroostook; Southern Penobscot; Southern Piscataquis</cap:areaDesc>
49
+ <cap:polygon/>
50
+ <cap:geocode>
51
+ <valueName>FIPS6</valueName>
52
+ <value>023003 023009 023019 023021 023029</value>
53
+ <valueName>UGC</valueName>
54
+ <value>MEZ005 MEZ006 MEZ011 MEZ015 MEZ016 MEZ017 MEZ031 MEZ032</value>
55
+ </cap:geocode>
56
+ <cap:parameter>
57
+ <valueName>VTEC</valueName>
58
+ <value>/O.NEW.KCAR.WW.Y.0024.121108T0000Z-121108T1700Z/</value>
59
+ </cap:parameter>
60
+ </entry>
61
+ </feed>
@@ -0,0 +1,28 @@
1
+
2
+ <?xml version="1.0" encoding="UTF-8"?>
3
+ <?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?>
4
+ <feed xmlns="http://www.w3.org/2005/Atom">
5
+
6
+ <title>QQQQ</title>
7
+
8
+ <link href="http://example.com/"/>
9
+ <updated>2010-09-18T10:02:20-07:00</updated>
10
+ <id>QQQQ</id>
11
+ <author>
12
+ <name>QQQQ</name>
13
+ <email>QQQQ@example.com</email>
14
+ </author>
15
+
16
+
17
+ <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml"
18
+ href="http://feeds.feedburner.com/QQQQ"/>
19
+ <feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="QQQQ"/>
20
+ <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/"/>
21
+ <entry>
22
+ <title>QQQQ</title>
23
+ <link href="http://example.com/QQQQ.html"/>
24
+ <updated>2010-08-11T00:00:00-07:00</updated>
25
+ <id>http://example.com/QQQQ.html</id>
26
+ <content type="html">QQQQ</content>
27
+ </entry>
28
+ </feed>
@@ -0,0 +1,188 @@
1
+
2
+ <feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/"
3
+ xmlns:docs="http://schemas.google.com/docs/2007" xmlns:batch="http://schemas.google.com/gdata/batch"
4
+ xmlns:gd="http://schemas.google.com/g/2005" gd:etag="W/&quot;DUMFR3YyfCt7ImA9WxNTFU0.&quot;">
5
+
6
+ <!-- Unique identifier of this feed. Not unique between users. -->
7
+ <id>https://docs.google.com/feeds/default/private/full</id>
8
+
9
+ <!-- Date this feed was last updated. Do NOT use this, provided for Atom compliance only. -->
10
+ <updated>2009-08-17T11:10:16.894Z</updated>
11
+
12
+ <!-- Title of this feed result. -->
13
+ <title>Available Documents - john.smith.example@gmail.com</title>
14
+
15
+ <!-- Link at which a user could consume the same content given here, but in a web browser with a user interface. -->
16
+ <link rel="alternate" type="text/html" href="https://docs.google.com"/>
17
+
18
+ <!-- Link at which you can add documents or files using resumable upload. -->
19
+ <link rel="http://schemas.google.com/g/2005#resumable-create-media" type="application/atom+xml"
20
+ href="https://docs.google.com/feeds/upload/create-session/default/private/full"/>
21
+
22
+ <!-- Link at which you can fetch the next page of results from this feed. -->
23
+ <link rel="next" type="application/atom+xml"
24
+ href="https://docs.google.com/feeds/default/private/full?start-key=EAEaFgoSCb2YGEPMAAACAG"/>
25
+
26
+ <!-- Link at which you can fetch this same feed. -->
27
+ <link rel="self" type="application/atom+xml"
28
+ href="https://docs.google.com/feeds/default/private/full/"/>
29
+
30
+ <!-- Link at which you can fetch this same feed. -->
31
+ <link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"
32
+ href="https://docs.google.com/feeds/default/private/full"/>
33
+
34
+ <!-- Deprecated. Use resumable-create-media instead. -->
35
+ <!-- Link at which you can POST new entries with metadata only to this feed. -->
36
+ <link rel="http://schemas.google.com/g/2005#post" type="application/atom+xml"
37
+ href="https://docs.google.com/feeds/default/private/full"/>
38
+
39
+ <!-- Link at which you can send batch requests to this feed. -->
40
+ <link rel="http://schemas.google.com/g/2005#batch" type="application/atom+xml"
41
+ href="https://docs.google.com/feeds/default/private/full/batch"/>
42
+
43
+ <!-- Information about the user who authorized this request. -->
44
+ <author>
45
+ <name>John Smith</name>
46
+ <email>john.smith.example@gmail.com</email>
47
+ </author>
48
+
49
+ <!-- NOT supported, provided for protocol compliance only. -->
50
+ <openSearch:startIndex>1</openSearch:startIndex>
51
+
52
+ <!-- The ETag here is used to identify the version of this entry. -->
53
+ <entry gd:etag="'EVJVTBICRit7ImBq'">
54
+ <!-- A unique, permanent identifier for this entry. -->
55
+ <id>https://docs.google.com/feeds/id/document%3A12345</id>
56
+
57
+ <!-- Title of this resource. -->
58
+ <title>2010 Income Tax Policy</title>
59
+
60
+ <!-- Description of this resource (currently visible in the preview pane in the UI). -->
61
+ <docs:description>Describes how to file income tax for 2010.</docs:description>
62
+
63
+ <!-- Resource ID of this document. -->
64
+ <gd:resourceId>document:12345</gd:resourceId>
65
+
66
+ <!-- Date this document was created (the "published" name of this element is mis-leading, but this is Atom standard). -->
67
+ <published>2009-07-22T19:02:57.616Z</published>
68
+
69
+ <!-- Information about the owner of this document (not necessarily the user authorizing this request). -->
70
+ <author>
71
+ <name>Jenna Dolsom</name>
72
+ <email>jenna.dolsom.example@gmail.com</email>
73
+ </author>
74
+
75
+ <!-- Date this entry was last updated (either by Google's systems, the API, or a user in a web browser). -->
76
+ <updated>2009-07-29T20:31:39.804Z</updated>
77
+
78
+ <!-- Date this document was last edited by a user in the document editor in a web browser. -->
79
+ <app:edited xmlns:app="http://www.w3.org/2007/app">2009-07-31T17:21:26.497Z</app:edited>
80
+
81
+ <!-- Information about the user who last modified this entry (not necessarily the user authorizing this request). -->
82
+ <gd:lastModifiedBy>
83
+ <name>Aaron Jensen</name>
84
+ <email>aaron.jensen.example@gmail.com</email>
85
+ </gd:lastModifiedBy>
86
+
87
+ <!-- Date this document was last viewed in a web browser by any user. -->
88
+ <gd:lastViewed>2009-07-31T17:21:26.273Z</gd:lastViewed>
89
+
90
+ <!-- The "kind" of this entry. In this case, a word processing document. -->
91
+ <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/docs/2007#document" label="document"/>
92
+
93
+ <!-- This entry has been viewed by the user, so it has a "viewed" category. -->
94
+ <category scheme="http://schemas.google.com/g/2005/labels" term="http://schemas.google.com/g/2005/labels#viewed" label="viewed"/>
95
+
96
+ <!-- Link at which you can download the actual document this entry describes. -->
97
+ <content type="text/html" src="https://docs.google.com/feeds/download/documents/Export?docId=12345"/>
98
+
99
+ <!-- This document is in one collection, detailed here. -->
100
+ <link rel="http://schemas.google.com/docs/2007#parent" type="application/atom+xml"
101
+ href="https://docs.google.com/feeds/default/private/full/folder%3A12345" title="ACollectionName"/>
102
+
103
+ <!-- Link at which you can open this document in a web browser. -->
104
+ <link rel="alternate" type="text/html" href="https://docs.google.com/Doc?docid=12345&amp;hl=en"/>
105
+
106
+ <!-- Link at which you can fetch only this entry. -->
107
+ <link rel="self" type="application/atom+xml" href="https://docs.google.com/feeds/default/private/full/document%3A12345"/>
108
+
109
+ <!-- Link at which you can PUT updates to this entry. -->
110
+ <link rel="edit" type="application/atom+xml" href="https://docs.google.com/feeds/default/private/full/document%3A12345"/>
111
+
112
+ <!-- Link at which you can PUT updates to this entry's content (deprecated, use resumable below). -->
113
+ <link rel="edit-media" type="text/html" href="https://docs.google.com/feeds/default/media/document%3A12345"/>
114
+
115
+ <!-- Link at which you can PUT resumable updates to this entry's content. -->
116
+ <link rel="http://schemas.google.com/g/2005#resumable-edit-media" type="application/atom+xml"
117
+ href="https://docs.google.com/feeds/upload/create-session/default/private/full/document%3A12345"/>
118
+
119
+ <!-- Link at which you can fetch a thumbnail of this resource. -->
120
+ <link rel="http://schemas.google.com/docs/2007/thumbnail" type="image/jpeg" href="https://lh3.googleusercontent.com/TQRs812345=s220"/>
121
+
122
+ <!-- Link at which you can create, retrieve, update, and delete ACL entries for this document. -->
123
+ <gd:feedLink rel="http://schemas.google.com/acl/2007#accessControlList"
124
+ href="https://docs.google.com/feeds/default/private/full/document%3A12345/acl"/>
125
+
126
+ <!-- Link at which you can create, retrieve, update, and delete revisions of this document. -->
127
+ <gd:feedLink rel="http://schemas.google.com/docs/2007/revisions"
128
+ href="https://docs.google.com/feeds/default/private/full/document%3A12345/revisions"/>
129
+
130
+ <!-- Number of bytes of the owner's quota this document uses. Native Google Docs currently use 0 bytes. -->
131
+ <gd:quotaBytesUsed>0</gd:quotaBytesUsed>
132
+
133
+ <!-- "true" if writers can invite other users to view and edit this document. -->
134
+ <docs:writersCanInvite value="true"/>
135
+
136
+ <!-- Given for files only. An MD5 checksum used to verify the contents of this file. -->
137
+ <!-- Some old files are being processed. Those files will not have this element yet. -->
138
+ <docs:md5Checksum>2b01142f7481c7b056c4b410d28f33cf</docs:md5Checksum>
139
+
140
+ <!-- Original filename of file at time of upload, if available. -->
141
+ <!-- Only available for resources of type file or pdf. -->
142
+ <!-- Shown here as example only. This element is not given for resources of type document. -->
143
+ <docs:filename>MyFile.pdf</docs:filename>
144
+
145
+ <!-- Current name of resource, with file extension from docs:filename appended, if available. -->
146
+ <!-- If the current name already has an extension, then the extension from docs:filename is not appended. -->
147
+ <!-- If docs:filename does not have an extension, then the current name is given unaltered. -->
148
+ <!-- Only available for resources of type file or pdf. -->
149
+ <!-- Shown here as example only. This element is not given for resources of type document. -->
150
+ <docs:suggestedFilename>TaxDocument.pdf</docs:suggestedFilename>
151
+ </entry>
152
+ <entry xmlns:gd="http://schemas.google.com/g/2005" gd:etag="'HhJSFgpeRyt7ImBq'">
153
+ <id>https://docs.google.com/feeds/id/pdf%3A12345</id>
154
+ <published>2009-04-09T18:23:09.035Z</published>
155
+ <updated>2009-04-09T18:23:09.035Z</updated>
156
+ <app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-18T22:16:02.388Z</app:edited>
157
+ <category scheme="http://schemas.google.com/g/2005/labels" term="http://schemas.google.com/g/2005/labels#starred" label="starred"/>
158
+ <category scheme="http://schemas.google.com/g/2005/labels" term="http://schemas.google.com/g/2005/labels#viewed" label="viewed"/>
159
+ <category scheme="http://schemas.google.com/g/2005/labels" term="http://schemas.google.com/g/2005/labels#hidden" label="hidden"/>
160
+ <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/docs/2007#pdf" label="pdf"/>
161
+ <title>PDF's Title</title>
162
+ <content type="application/pdf"
163
+ src="https://doc-04-20-docs.googleusercontent.com/docs/secure/m71240...U1?h=1630126&amp;e=download&amp;gd=true"/>
164
+ <link rel="alternate" type="text/html" href="https://docs.google.com/fileview?id=12345&amp;hl=en"/>
165
+ <link rel="self" type="application/atom+xml" href="https://docs.google.com/feeds/default/private/full/pdf%3A12345"/>
166
+ <link rel="edit" type="application/atom+xml" href="https://docs.google.com/feeds/default/private/full/pdf%3A12345"/>
167
+ <link rel="edit-media" type="application/pdf" href="https://docs.google.com/feeds/default/media/pdf%3A12345"/>
168
+ <link rel="http://schemas.google.com/g/2005#resumable-edit-media" type="application/atom+xml"
169
+ href="https://docs.google.com/feeds/upload/create-session/default/private/full/pdf%3A12345"/>
170
+ <author>
171
+ <name>user</name>
172
+ <email>user@gmail.com</email>
173
+ </author>
174
+ <gd:resourceId>pdf:12345</gd:resourceId>
175
+ <gd:lastModifiedBy>
176
+ <name>user</name>
177
+ <email>user@gmail.com</email>
178
+ </gd:lastModifiedBy>
179
+ <gd:lastViewed>2009-06-18T22:16:02.384Z</gd:lastViewed>
180
+ <gd:quotaBytesUsed>108538</gd:quotaBytesUsed>
181
+ <docs:writersCanInvite value="false"/>
182
+ <docs:md5Checksum>2b01142f7481c7b056c4b410d28f33cf</docs:md5Checksum>
183
+ <gd:feedLink rel="http://schemas.google.com/acl/2007#accessControlList"
184
+ href="https://docs.google.com/feeds/default/private/full/pdf%3A12345/acl"/>
185
+ <gd:feedLink rel="http://schemas.google.com/docs/2007/revisions"
186
+ href="https://docs.google.com/feeds/default/private/full/document%3A12345/revisions"/>
187
+ </entry>
188
+ </feed>
@@ -0,0 +1,314 @@
1
+
2
+ <?xml version="1.0" encoding="utf-8"?>
3
+
4
+ <rdf:RDF
5
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
6
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
7
+ xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
8
+ xmlns:admin="http://webns.net/mvcb/"
9
+ xmlns:content="http://purl.org/rss/1.0/modules/content/"
10
+ xmlns:cc="http://web.resource.org/cc/"
11
+ xmlns="http://purl.org/rss/1.0/">
12
+
13
+ <channel rdf:about="http://www.avibryant.com/">
14
+ <title>HREF Considered Harmful</title>
15
+ <link>http://www.avibryant.com/</link>
16
+ <description>Avi Bryant</description>
17
+ <dc:language>en-US</dc:language>
18
+ <dc:creator></dc:creator>
19
+ <dc:date>2008-09-02T12:50:07-07:00</dc:date>
20
+ <admin:generatorAgent rdf:resource="http://www.typepad.com/" />
21
+
22
+
23
+ <items>
24
+ <rdf:Seq><rdf:li rdf:resource="http://www.avibryant.com/2008/09/chrome-v8-and-s.html" />
25
+ <rdf:li rdf:resource="http://www.avibryant.com/2008/06/maglev-recap.html" />
26
+ <rdf:li rdf:resource="http://www.avibryant.com/2008/05/maglev.html" />
27
+ <rdf:li rdf:resource="http://www.avibryant.com/2008/05/those-who-misre.html" />
28
+ <rdf:li rdf:resource="http://www.avibryant.com/2008/03/ive-had-a-numbe.html" />
29
+ <rdf:li rdf:resource="http://www.avibryant.com/2008/01/dont-panic.html" />
30
+ <rdf:li rdf:resource="http://www.avibryant.com/2008/01/dna-as-code.html" />
31
+ <rdf:li rdf:resource="http://www.avibryant.com/2007/10/code-as-screenp.html" />
32
+ <rdf:li rdf:resource="http://www.avibryant.com/2007/09/code-generation.html" />
33
+ <rdf:li rdf:resource="http://www.avibryant.com/2007/07/moving.html" />
34
+ </rdf:Seq>
35
+ </items>
36
+
37
+ </channel>
38
+
39
+ <item rdf:about="http://www.avibryant.com/2008/09/chrome-v8-and-s.html">
40
+ <title>Chrome, V8 and Strongtalk</title>
41
+ <link>http://www.avibryant.com/2008/09/chrome-v8-and-s.html</link>
42
+ <description>There&#39;s lots to like about Google&#39;s new web browser, Chrome, which was released today. When I read the awesome comic strip introduction yesterday, however, the thing that stood out most for me was in very small type: the name Lars...</description>
43
+ <content:encoded>&lt;p&gt;There&#39;s lots to like about Google&#39;s new web browser, &lt;a href=&quot;http://www.google.com/chrome&quot;&gt;Chrome&lt;/a&gt;, which was released today.&amp;nbsp; When I read the awesome &lt;a href=&quot;http://www.google.com/googlebooks/chrome/&quot;&gt;comic strip introduction&lt;/a&gt; yesterday, however, the thing that stood out most for me was in very small type: the name Lars Bak attached to the V8 JavaScript engine.&amp;nbsp; I know of Lars from his work on Self, Strongtalk, HotSpot and OOVM, and his involvement in V8 says a lot about the kind of language implementation it will be.&amp;nbsp; David Griswold has posted some &lt;a href=&quot;http://groups.google.com/group/strongtalk-general/browse_thread/thread/40eb8f405fbd3041&quot;&gt;more information &lt;/a&gt;on the Strongtalk list:
44
+
45
+ &lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;
46
+ The V8 development team has multiple members of the original
47
+ Animorphic team; it is headed by Lars Bak, who was the technical lead
48
+ for both Strongtalk and the HotSpot Java VM (as well as a huge
49
+ contributor to the original Self VM).&amp;nbsp; &amp;nbsp;I think that you will find
50
+ that V8 has a lot of the creamy goodness of the Strongtalk and Self
51
+ VMs, with many big architectural improvements
52
+ &lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;
53
+
54
+ I&#39;ll post more on this later, but things are getting interesting...&lt;/p&gt;
55
+
56
+ &lt;p&gt;Update: the V8 code is already &lt;a href=&quot;http://code.google.com/apis/v8/&quot;&gt;available&lt;/a&gt;, and builds and runs fine on Mac OS X.&amp;nbsp; From the &lt;a href=&quot;http://code.google.com/apis/v8/design.html&quot;&gt;design docs&lt;/a&gt;, it&#39;s pretty clear that this is indeed what I was hoping for: a mainstream, open source dynamic language implementation that learned and applies the lessons from Smalltalk, Self and Strongtalk.&amp;nbsp; Most telling are that the only two papers cited in that document are titled &amp;quot;An Efficient Implementation of Self&amp;quot; and &amp;quot;An Efficient Implementation of the Smalltalk-80 System&amp;quot;.&lt;/p&gt;
57
+
58
+ &lt;p&gt;The &amp;quot;classes as nodes in a state machine&amp;quot; trick for expando properties is especially neat.&lt;/p&gt;
59
+
60
+ &lt;p&gt;The bad news: V8 is over 100,000 lines of C++.&lt;/p&gt;
61
+
62
+ &lt;p&gt;&amp;nbsp;&lt;/p&gt;
63
+
64
+ &lt;p&gt;&lt;img src=&quot;http://www.avibryant.com/files/picture_19.png&quot; /&gt;&lt;/p&gt;</content:encoded>
65
+
66
+
67
+
68
+ <dc:creator>Avi</dc:creator>
69
+ <dc:date>2008-09-02T12:50:07-07:00</dc:date>
70
+ </item>
71
+ <item rdf:about="http://www.avibryant.com/2008/06/maglev-recap.html">
72
+ <title>MagLev recap</title>
73
+ <link>http://www.avibryant.com/2008/06/maglev-recap.html</link>
74
+ <description>There has been a huge response to the MagLev demo I gave on Friday, most of it enthusiastic, though not without the inevitable skepticism that comes with any announcement. For those who weren&#39;t at RailsConf, here&#39;s a quick summary of...</description>
75
+ <content:encoded>&lt;p&gt;There has been a huge response to the MagLev &lt;a href=&quot;http://www.avibryant.com/2008/05/maglev.html&quot;&gt;demo&lt;/a&gt; I gave on Friday, &lt;a href=&quot;http://blog.obiefernandez.com/content/2008/05/maglev-is-gemst.html&quot;&gt;most&lt;/a&gt; &lt;a href=&quot;http://www.cincomsmalltalk.com/userblogs/antony/blogView?showComments=true&amp;printTitle=MagLev,_game_over_..._very_possibly.&amp;entry=3389637476&quot;&gt;of&lt;/a&gt; &lt;a href=&quot;http://dotneverland.blogspot.com/2008/04/maglev-ruby-vm.html&quot;&gt;it&lt;/a&gt; &lt;a href=&quot;http://antoniocangiano.com/2008/05/31/maglev-rocks/&quot;&gt;enthusiastic&lt;/a&gt;, though not without the inevitable &lt;a href=&quot;http://headius.blogspot.com/2008/06/maglev.html&quot;&gt;skepticism&lt;/a&gt; that comes with any announcement.&lt;/p&gt;
76
+
77
+ &lt;p&gt;For those who weren&#39;t at RailsConf, here&#39;s a quick summary of how the demo went.&lt;/p&gt;
78
+
79
+ &lt;p&gt;I started off by describing MagLev as a &quot;full stack Ruby implementation&quot;, in the same way that Rails is a full stack web framework. To understand what I mean by that, see my &lt;a href=&quot;http://www.avibryant.com/2008/03/ive-had-a-numbe.html&quot;&gt;earlier post&lt;/a&gt; on the Gemstone architecture: not only does MagLev provide a new (and fast) VM for Ruby, but it also provides an integrated shared memory object cache, and integrated transparent persistence. This fully replaces the typical Rails stack of many mongrel instances + several memcached instances + MySQL.&lt;/p&gt;
80
+
81
+ &lt;p&gt;As a first demo, I showed a &quot;magic trick&quot; with two maglev instances running an irb-like shell in side by side terminal windows. A $hat global was defined in each, which just wraps an array and lets you put things in it. In the left window, I put a Rabbit into the $hat. I then looked at the $hat on the right and showed that the Rabbit had magically been transported there.&lt;/p&gt;
82
+
83
+ &lt;pre&gt;
84
+ &gt;&gt; $hat
85
+ =&gt; #&amp;lt;Hat:0x0c184bfd01 @contents=[
86
+ () ()
87
+ ( &#39;.&#39; )
88
+ (&quot;)_(&quot;)
89
+ ]&gt;
90
+ &lt;/pre&gt;
91
+
92
+ &lt;p&gt;How is this possible? Because they&#39;re the same hat. The integrated VMs, cache, and storage conspire to create an illusion that global state is shared across all instances: no matter how many VMs you add, over however many machines, they all see and work with the same set of Ruby objects.&lt;/p&gt;
93
+
94
+ &lt;p&gt;There&#39;s no limit to what kinds of objects can be shared this way: procs and classes work just as well as arrays and strings. This isn&#39;t RPC - the objects are copied into a shared cache when they&#39;re created or modified, and if (but only if) another VM needs the object, it will pull it out of the cache and work on the local copy. All of these copies are kept in sync, and any changes are also written to disk by the storage engine so that the entire model is persistent.&lt;/p&gt;
95
+
96
+ &lt;p&gt;This only applies to globally reachable objects - local variables, method arguments and so on aren&#39;t generally shared.&lt;/p&gt;
97
+
98
+ &lt;p&gt;Obviously, with this kind of synchronization there has to be some concern for concurrency. MagLev handles this with transactions. Each VM has its own transaction state. When a VM enters a transaction, all of its changes are only locally visible until it is asked to commit. At that point, all of its changes get recorded to the cache and to disk and are available to every other VM.&lt;/p&gt;
99
+
100
+ &lt;p&gt;A transaction can be aborted, in which case *everything* that has happened in that VM since the last commit (object modifications, creation, method or class definition, etc) will get rolled back. A transaction commit can also fail if it conflicts with concurrent changes elsewhere (for example, two VMs modifying the same instance variable of the same object at once).&lt;/p&gt;
101
+
102
+ &lt;p&gt;Because these shared objects are stored on disk, and are lazily loaded into the VMs only when needed, it means you can work with datasets that have many, many more objects than would fit into available RAM. I showed a dataset that I had loaded in which contained 100 million movie reviews, and took up somewhere around 10GB. I could instantly pull in a single movie, modify it, and commit that change, without needing to load the other couple hundred million objects into RAM.&lt;/p&gt;
103
+
104
+ &lt;p&gt;As a final demo, I showed how far MagLev has currently gotten with compatibility by running a simple WEBrick servlet.&lt;/p&gt;
105
+
106
+ &lt;p&gt;At this point, Bob Walker took over. He gave some company background on Gemstone (they&#39;ve been working on multi-user persistent dynamic language VMs since 1982), and some technical details on MagLev (the VM is a modified version of their Gemstone/S Smalltalk VM, with some Ruby-specific bytecodes; the bytecode is JITted to native code before execution). Then he showed some micro-benchmarks: for what it&#39;s worth, MagLev is anywhere from 6 times to (in the extreme case) 111 times faster than the standard 1.8.6 Ruby interpreter on things like fibonacci, block execution, method dispatch, and so on.&lt;/p&gt;
107
+
108
+ &lt;p&gt;Bob then talked about scale. Gemstone has many customers running things like commodities exchanges, derivatives trading, container shipping, and so on that operate at very large scale on top of the same underlying technology as MagLev. Here are a couple of recent unsolicited quotes from a &lt;a href=&quot;http://discuss.joelonsoftware.com/default.asp?biz.5.594244.20&quot;&gt;thread&lt;/a&gt; on the Joel on Software forums:&lt;/p&gt;
109
+
110
+ &lt;blockquote&gt;
111
+ &quot;I work for a major shipping company. We have a massive OODB and
112
+ Smalltalk Application (500 gig range) with 3 million lines of code.
113
+ We have 2000 plus daily users. We can do 700 transactions a second
114
+ before slowing down. We also have a Java + SQL +EMS system. On a
115
+ good day they can do 70 transactions a second, with three times the
116
+ hardware.&quot; --Timo (Saturday, February 16, 2008)
117
+
118
+ &lt;p&gt; &quot;Along side with the major shipping company, we are a major &lt;br /&gt;
119
+ commodities exchange using GS and ST and while our operational DB is &lt;br /&gt;
120
+ small (about 5 GB at the start of the trading day to less than 75 GB &lt;br /&gt;
121
+ and the end) we are probably one of the fastest. We easily handle &lt;br /&gt;
122
+ transaction rates approaching 6000/sec with about 8000+ daily &lt;br /&gt;
123
+ users. Our average data center round trip times are in the 2-3 ms &lt;br /&gt;
124
+ range.&quot; --GemStone Weenie (Monday, February 18, 2008)&lt;br /&gt;
125
+ &lt;/blockquote&gt;&lt;/p&gt;
126
+
127
+ &lt;p&gt;It&#39;s worth noting that that&#39;s 6000 writes per second, sustained, and that this application peaks at about 3x that. By comparison, Twitter was once reported as having 600 requests/s (read and write).&lt;/p&gt;
128
+
129
+ &lt;p&gt;Bob then moved onto the vision for MagLev going forward. A few important points:&lt;br /&gt;
130
+ &lt;ul&gt;&lt;br /&gt;
131
+ &lt;li&gt;It doesn&#39;t run Rails yet, but it will.&lt;br /&gt;
132
+ &lt;li&gt;It will be RubySpec compliant.&lt;br /&gt;
133
+ &lt;li&gt;The Ruby source will be released. The C source code for the VM most likely will remain closed (but anything is possible).&lt;br /&gt;
134
+ &lt;li&gt;There will be a free version which will work for most uses, and a paid version for large-scale deployment.&lt;br /&gt;
135
+ &lt;li&gt;Look for another announcement/demo at RailsConf Europe in September.&lt;br /&gt;
136
+ &lt;/ul&gt;&lt;/p&gt;
137
+
138
+ &lt;p&gt;After that we retired to the DoubleTree for a keg of Ruby ale.&lt;/p&gt;</content:encoded>
139
+
140
+
141
+
142
+ <dc:creator>Avi</dc:creator>
143
+ <dc:date>2008-06-01T11:36:26-07:00</dc:date>
144
+ </item>
145
+ <item rdf:about="http://www.avibryant.com/2008/05/maglev.html">
146
+ <title>MagLev</title>
147
+ <link>http://www.avibryant.com/2008/05/maglev.html</link>
148
+ <description>People have by now probably gotten a little sick of me saying that we really need to take Smalltalk technology and apply it to Ruby - see, for example, pretty much anything I wrote in November 2006, or my RailsConf...</description>
149
+ <content:encoded>&lt;p&gt;People have by now probably gotten a little sick of me saying that we really need to take Smalltalk technology and apply it to Ruby - see, for example, pretty much anything I wrote in &lt;a href=&quot;http://www.avibryant.com/2006/11/index.html&quot;&gt;November 2006&lt;/a&gt;, or my &lt;a href=&quot;http://railsconf.blip.tv/file/568689/&quot;&gt;RailsConf keynote&lt;/a&gt; from last year.&lt;/p&gt;
150
+
151
+ &lt;p&gt;This year, I&#39;m going back to RailsConf, but with some concrete good news: we&#39;ve finally &lt;a href=&quot;http://ruby.gemstone.com/&quot;&gt;done it&lt;/a&gt;, and it rocks.&lt;/p&gt;
152
+
153
+ &lt;p&gt;If you&#39;re want to see the first real demo* of Ruby running on Gemstone&#39;s very cool originally-for-Smalltalk platform, drop by on &lt;a href=&quot;http://en.oreilly.com/rails2008/public/schedule/detail/4351&quot;&gt;Friday afternoon&lt;/a&gt;. I&#39;m excited to see what everyone thinks.&lt;/p&gt;
154
+
155
+ &lt;p&gt;(* I did do a teaser at &lt;a href=&quot;http://www.meshconference.com/meshu/avi-bryant.php&quot;&gt;MeshU&lt;/a&gt;)&lt;/p&gt;</content:encoded>
156
+
157
+
158
+
159
+ <dc:creator>Avi</dc:creator>
160
+ <dc:date>2008-05-28T21:47:20-07:00</dc:date>
161
+ </item>
162
+ <item rdf:about="http://www.avibryant.com/2008/05/those-who-misre.html">
163
+ <title>Those who misremember history...</title>
164
+ <link>http://www.avibryant.com/2008/05/those-who-misre.html</link>
165
+ <description>In Dynamic Languages Strike Back, Steve Yegge says StrongTalk was really interesting. They added a static type system, an optional static type system on top of Smalltalk that sped it up like 20x, or maybe it was 12x. Why do...</description>
166
+ <content:encoded>&lt;p&gt;In &lt;a href=&quot;http://steve-yegge.blogspot.com/2008/05/dynamic-languages-strike-back.html&quot;&gt;Dynamic Languages Strike Back&lt;/a&gt;, Steve Yegge says&lt;br /&gt;
167
+ &lt;blockquote&gt;&lt;br /&gt;
168
+ StrongTalk was really interesting. They added a static type system, an optional static type system on top of Smalltalk that sped it up like 20x, or maybe it was 12x.&lt;br /&gt;
169
+ &lt;/blockquote&gt;&lt;/p&gt;
170
+
171
+ &lt;p&gt;Why do people make this stuff up? The following two statements are true:&lt;/p&gt;
172
+
173
+ &lt;ol&gt;
174
+ &lt;li&gt;Strongtalk has an optional static type system.
175
+ &lt;li&gt;Strongtalk is 15-20x faster than most other Smalltalk systems.
176
+ &lt;/ol&gt;
177
+
178
+ &lt;p&gt;What&#39;s false is the causal link Steve is claiming between them. They are entirely independent. Strongtalk was that much faster whether you used the &lt;i&gt;optional&lt;/i&gt; static type system or not. Strongtalk&#39;s optimizing compiler completely ignored the types, and it made your program run not one iota faster to add them.&lt;/p&gt;
179
+
180
+ &lt;p&gt;Update: see also Dave Griswold on&lt;a href=&quot;http://www.strongtalk.org/history.html&quot;&gt;Strongtalk&#39;s history&lt;/a&gt;:&lt;br /&gt;
181
+ &lt;blockquote&gt;&lt;br /&gt;
182
+ ... we had a type system and a compilation technology, which together were perfectly suited for a great production Smalltalk system, since they were independent of each other. This independence was critical, since the system would need to accept untyped as well as typed code, so that people could use the type system as much or as little as they wanted to, without impacting performance.&lt;br /&gt;
183
+ &lt;/blockquote&gt;&lt;/p&gt;</content:encoded>
184
+
185
+
186
+
187
+ <dc:creator>Avi</dc:creator>
188
+ <dc:date>2008-05-12T16:50:25-07:00</dc:date>
189
+ </item>
190
+ <item rdf:about="http://www.avibryant.com/2008/03/ive-had-a-numbe.html">
191
+ <title>Ruby and other gems</title>
192
+ <link>http://www.avibryant.com/2008/03/ive-had-a-numbe.html</link>
193
+ <description>I&#39;ve had a number of conversations recently about Gemstone Smalltalk, largely in the wake of their announcement of support for my web framework, Seaside. It&#39;s complicated to explain Gemstone to people. It&#39;s not just an object database (though it is...</description>
194
+ <content:encoded>&lt;p&gt;I&#39;ve had a number of conversations recently about Gemstone Smalltalk, largely in the wake of their announcement of support for my web framework, Seaside. It&#39;s complicated to explain Gemstone to people. It&#39;s not just an object database (though it is that), and it&#39;s not just a Smalltalk implementation (though it&#39;s that, too). The best thing I can compare it to is a Ruby on Rails deployment: not the framework, but the entire cluster of servers and software that goes into a large scale Rails app. Which is to say, perhaps, that Gemstone is best understood not as a piece of software but as an architecture.&lt;/p&gt;
195
+
196
+ &lt;p&gt;At a high level, a typical Rails deployment looks like this: a cluster of servers supports one storage engine, several memory caches, and many worker processes. In Rails, the storage engine is always a relational database (usually MySQL), and sits on an especially hefty server by itself. Any number of other smaller, identical servers are each configured to run one memory cache (memcached) and 8-12 or so worker processes (Ruby interpreters running Rails and the Mongrel web server, generally just referred to as &quot;mongrels&quot;).&lt;/p&gt;
197
+
198
+ &lt;p&gt;The mongrels accept the web requests and run the actual application code. The objects inside these worker processes are live objects: they&#39;re sending and receiving messages, executing methods, changing state, and so on. They exist only inside the memory of a particular mongrel, for the duration of a single request that the mongrel is processing.&lt;/p&gt;
199
+
200
+ &lt;p&gt;Many objects need to be persisted for longer than that, and these get written to and read from the storage engine - in Rails, using ActiveRecord. The storage engine is centralized (though it may be replicated to protect against failure), so that all of the worker processes see a consistent view of the data: if one of the mongrels modifies an object and commits that change to MySQL, the others will see that change the next time they need to load that object. The objects inside the storage engine are dead - they don&#39;t do anything until they&#39;re loaded into a worker process - but they&#39;re well preserved: they&#39;re kept on disk, not memory, so they&#39;ll survive a server reboot or other catastrophe.&lt;/p&gt;
201
+
202
+ &lt;p&gt;Loading from and saving to the storage engine is relatively slow, and keeping objects there eats disk space, so the memory cache is an important third player in this game. A mongrel that&#39;s gone to the work of retrieving an object from MySQL might stash a copy in memcached for the other mongrels to retrieve, more quickly, if and when they need the same one. An object that&#39;s expensive to build - like a piece of complex HTML - but not important enough to save to disk might also be placed there for the convenience of the other workers on the same server. In Rails, the cache has to be managed carefully, so that you don&#39;t get out of sync with the consistent view of data maintained by the storage engine, but the work pays off with lower loads and faster response times. Objects in the cache are dead - usually marshalled into a meaningless string - and also transient, since the cache is purely in memory.&lt;/p&gt;
203
+
204
+ &lt;p&gt;What about Gemstone? As it happens, the architecture is exactly the same: there&#39;s a single storage engine (called a &quot;stone&quot;), a memory cache on each server (the &quot;shared page cache&quot;), and any number of Smalltalk VM worker processes (&quot;gems&quot;). The gems handle the requests and run the code, and they stash objects in the page cache for speed and in the stone for persistence. The difference is, in Gemstone, these have all been designed from the ground up to work together as quickly and seamlessly as possible. In particular, this means two things:&lt;/p&gt;
205
+
206
+ &lt;p&gt;1. Each part of the architecture uses exactly the same format to store the objects: whether it&#39;s a live object running in a gem, a cached object in the page cache, or a stored object on disk, the sequence of bytes is exactly the same. Unlike in Rails, where you have to be mapping and marshalling at every step, in Gemstone copying objects from storage to cache to worker process is pretty much just that - a simple byte copy. This makes it &lt;b&gt;fast&lt;/b&gt;.&lt;/p&gt;
207
+
208
+ &lt;p&gt;2. Objects are automatically kept in sync between each part of the system. The worker processes always load objects from the memory cache, because they can trust it to grab a recent copy from storage if needed. They also always save to the cache, because it will write the same change through to the storage without being asked. The gems also keep track of which objects have changed so that you don&#39;t have to, and will update the cache - and get updates from other gems back - automatically and transparently. The effect is as if all of your worker processes were running their objects inside a single, consistent and impossibly large chunk of persistent memory. This makes it &lt;b&gt;easy&lt;/b&gt;.&lt;/p&gt;
209
+
210
+ &lt;p&gt;To be extra clear, here&#39;s the mapping I&#39;m trying to describe:&lt;/p&gt;
211
+
212
+ &lt;table border=&quot;1&quot;&gt;
213
+ &lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th colspan=&quot;2&quot;&gt;Rails&lt;/th&gt;&lt;th colspan=&quot;2&quot;&gt;Gemstone&lt;/th&gt;&lt;/tr&gt;
214
+ &lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;Provided By&lt;/th&gt;&lt;th&gt;Stores&lt;/th&gt;&lt;th&gt;Provided By&lt;/th&gt;&lt;th&gt;Stores&lt;/th&gt;&lt;/tr&gt;
215
+ &lt;tr&gt;&lt;th&gt;Storage Engine&lt;/th&gt;&lt;td&gt;MySQL&lt;/td&gt;&lt;td&gt;objects mapped to relational tables&lt;/td&gt;&lt;td&gt;&quot;Stone&quot; object store&lt;/td&gt;&lt;td&gt;Smalltalk objects&lt;/td&gt;&lt;/tr&gt;
216
+ &lt;tr&gt;&lt;th&gt;Memory Cache&lt;/th&gt;&lt;td&gt;memcached&lt;/td&gt;&lt;td&gt;objects marshalled to strings&lt;/td&gt;&lt;td&gt;Shared page cache&lt;/td&gt;&lt;td&gt;Smalltalk objects&lt;/td&gt;&lt;/tr&gt;
217
+ &lt;tr&gt;&lt;th&gt;Worker Process&lt;/th&gt;&lt;td&gt;MRI/Mongrel&lt;/td&gt;&lt;td&gt;Ruby objects&lt;/td&gt;&lt;td&gt;&quot;Gem&quot; Smalltalk VM&lt;/td&gt;&lt;td&gt;Smalltalk objects&lt;/td&gt;&lt;/tr&gt;
218
+ &lt;/table&gt;
219
+
220
+ &lt;p&gt;So there you have it: Gemstone, it&#39;s like Rails, but faster and easier. If only it ran Ruby...&lt;/p&gt;</content:encoded>
221
+
222
+
223
+
224
+ <dc:creator>Avi</dc:creator>
225
+ <dc:date>2008-03-08T01:02:38-08:00</dc:date>
226
+ </item>
227
+ <item rdf:about="http://www.avibryant.com/2008/01/dont-panic.html">
228
+ <title>Don&#39;t Panic</title>
229
+ <link>http://www.avibryant.com/2008/01/dont-panic.html</link>
230
+ <description>So what happened was, I was at my house on Galiano Island with my shiny new iPhone and without, at the time, either high speed internet or EDGE coverage, and I thought &quot;gee, wouldn&#39;t it be nice if...&quot;. And I...</description>
231
+ <content:encoded>&lt;p&gt;So &lt;a href=&quot;http://www.tbray.org/ongoing/When/200x/2003/04/06/WhatHappenedWas&quot;&gt;what happened was&lt;/a&gt;, I was at my house on &lt;a href=&quot;http://en.wikipedia.org/wiki/Galiano_Island&quot;&gt;Galiano Island&lt;/a&gt; with my shiny new iPhone and without, at the time, either high speed internet or EDGE coverage, and I thought &quot;gee, wouldn&#39;t it be nice if...&quot;. And I did some hacking, and then I mentioned it to &lt;a href=&quot;http://collison.ie&quot;&gt;Patrick Collison&lt;/a&gt; who was sharing office space with us and he ignored my hacking and did a ton of his own, and even though I now have DSL and EDGE out there it *is* nice: all of Wikipedia, stored and searchable in 2GB of your iPhone&#39;s flash drive. Get it &lt;a href=&quot;http://collison.ie/wikipedia-iphone/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
232
+
233
+ &lt;p&gt;It&#39;s not perfect yet - there&#39;s no images, just text, and the parser is pretty basic and doesn&#39;t know about tables and stuff, and clicking on links can be flaky and slow, and if you do happen to have a network around it&#39;s probably a better experience to just go to wikipedia.org, but: there&#39;s really nothing quite like holding the sum of human knowledge in the palm of your hand. Patrick, I owe you many drams of whiskey whenever you&#39;re back in town.&lt;/p&gt;</content:encoded>
234
+
235
+
236
+
237
+ <dc:creator>Avi</dc:creator>
238
+ <dc:date>2008-01-21T00:43:00-08:00</dc:date>
239
+ </item>
240
+ <item rdf:about="http://www.avibryant.com/2008/01/dna-as-code.html">
241
+ <title>DNA as Code</title>
242
+ <link>http://www.avibryant.com/2008/01/dna-as-code.html</link>
243
+ <description>Over the holidays I was chatting with my brother the biophysicist about his research. Roughly speaking, he is trying to create DNA sequences that encode molecular motors. I was trying to understand what it meant to hack DNA from a...</description>
244
+ <content:encoded>&lt;p&gt;Over the holidays I was chatting with my brother the biophysicist about his research. Roughly speaking, he is trying to create DNA sequences that encode molecular motors. I was trying to understand what it meant to hack DNA from a programmer&#39;s perspective. Today I read &lt;a href=&quot;http://ds9a.nl/amazing-dna/index.html&quot;&gt;this&lt;/a&gt;, which is in a very similar spirit. Two interesting data points from our conversation: one, the code my brother is &quot;writing&quot; is a few kilobase long, and could be represented in well under one kB of binary data. Two, his edit/compile/run cycle is about three weeks long, although he can do a dozen or so in parallel.&lt;/p&gt;
245
+
246
+ &lt;p&gt;I thought these numbers were impressively small, especially that you could produce a working motor from a few hundred bytes of information (try that in Autocad...). He thought of them as huge, because they made it infeasible to brute-force the design by generating all the random variations and seeing which ones worked.&lt;/p&gt;
247
+
248
+ &lt;p&gt;I&#39;m certainly glad it doesn&#39;t take me three weeks to do a new build...&lt;/p&gt;</content:encoded>
249
+
250
+
251
+
252
+ <dc:creator>Avi</dc:creator>
253
+ <dc:date>2008-01-02T18:55:23-08:00</dc:date>
254
+ </item>
255
+ <item rdf:about="http://www.avibryant.com/2007/10/code-as-screenp.html">
256
+ <title>Code as Screenplay</title>
257
+ <link>http://www.avibryant.com/2007/10/code-as-screenp.html</link>
258
+ <description>Giles Bowkett writes Debugger support is like nail-biting support, or farting-in-public support. Its absence is a feature. You want to avoid supporting bad habits. If programmers have to break their bad habits, that&#39;s a good thing. I have a confession...</description>
259
+ <content:encoded>&lt;p&gt;Giles Bowkett &lt;a href=&quot;http://gilesbowkett.blogspot.com/2007/10/debugger-support-considered-harmful.html&quot;&gt;writes&lt;/a&gt;&lt;br /&gt;
260
+ &lt;blockquote&gt;&lt;br /&gt;
261
+ Debugger support is like nail-biting support, or farting-in-public support. Its absence is a feature. You want to avoid supporting bad habits. If programmers have to break their bad habits, that&#39;s a good thing.&lt;br /&gt;
262
+ &lt;/blockquote&gt;&lt;/p&gt;
263
+
264
+ &lt;p&gt;I have a confession to make: I bite my nails. That&#39;s a bad habit, and I readily admit it. I also use a debugger. That&#39;s not.&lt;/p&gt;
265
+
266
+ &lt;p&gt;Let me explain. Giles&#39; argument seems to rest on this point:&lt;br /&gt;
267
+ &lt;blockquote&gt;&lt;br /&gt;
268
+ Debuggers are based on the idea that the code base has enough places bugs could happen that the work of locating the bug is involved enough to justify machine assistance. This is not true of well-tested code. It is not true of code you understand, either.&lt;br /&gt;
269
+ &lt;/blockquote&gt;&lt;/p&gt;
270
+
271
+ &lt;p&gt;What Giles glosses over is how you come to understand the code in the first place. &lt;b&gt;Nothing&lt;/b&gt; helps you understand code - whether you wrote it or someone else did - better than stepping through it in a debugger. Since Giles is a sometime &lt;a href=&quot;http://gilesgoatboy.blogspot.com/2007/03/wrote-screenplay.html&quot;&gt;screenwriter&lt;/a&gt;, maybe this analogy is appropriate: reading the code is like reading a screenplay. Writing tests is maybe like drawing storyboards (they help you visualize the final product). Using a debugger is like &lt;b&gt;actually watching the damn movie&lt;/b&gt;. With a jog wheel so you can slow it down. And no matter how good a screenwriter you are, no matter how good your director&#39;s storyboards are, when it comes time to cut the film you&#39;re going to find out that you didn&#39;t understand the movie as well as you thought you did, and you&#39;re going to need to watch the footage, sometimes frame by frame, and modify the movie accordingly.&lt;/p&gt;
272
+
273
+ &lt;p&gt;Programs are the same way. Writing tests and reading code show you your program the way you want it to be, but only a debugger shows you the way your program &lt;i&gt;is&lt;/i&gt;. Maybe screenwriters sit around in bars in LA and talk about how &lt;i&gt;real&lt;/i&gt; filmmakers just read scripts, and the movies themselves are a crutch - me, I guess I like crutches.&lt;/p&gt;
274
+
275
+ &lt;p&gt;See also: &lt;a href=&quot;http://collison.ie/blog/?p=25&quot;&gt;Patrick Collison&lt;/a&gt;, &lt;a href=&quot;http://programming.reddit.com/info/5yle2/comments/c029w0a&quot;&gt;Ben Matasar&lt;/a&gt;, and &lt;a href=&quot;http://programming.reddit.com/info/5yle2/comments/c029w7w&quot;&gt;Slava Pestov&lt;/a&gt;.&lt;/p&gt;</content:encoded>
276
+
277
+
278
+
279
+ <dc:creator>Avi</dc:creator>
280
+ <dc:date>2007-10-18T14:23:24-07:00</dc:date>
281
+ </item>
282
+ <item rdf:about="http://www.avibryant.com/2007/09/code-generation.html">
283
+ <title>Code generation in Smalltalk and Ruby</title>
284
+ <link>http://www.avibryant.com/2007/09/code-generation.html</link>
285
+ <description>Neal Ford had a recent post about the difference between code-generation (he calls it &quot;meta-programming&quot;, but that&#39;s an overloaded and ambiguous term) in Ruby and Smalltalk. The core of his point is this: in Ruby, code generation is done at...</description>
286
+ <content:encoded>&lt;p&gt;Neal Ford had a recent &lt;a href=&quot;http://memeagora.blogspot.com/2007/09/ruby-matters-meta-programming-synthesis.html&quot;&gt;post&lt;/a&gt; about the difference between code-generation (he calls it &quot;meta-programming&quot;, but that&#39;s an overloaded and ambiguous term) in Ruby and Smalltalk. The core of his point is this: in Ruby, code generation is done at runtime, which means that what gets checked into your source code repository is a high level statement like &quot;has_many :foo&quot;, which then generates the code when it is executed. In Smalltalk, code generation is done at development time (triggered by some custom wizard-like extension to the IDE), and so the generated code itself is checked in and the intent, according to Neal, is lost (as a trade-off for other benefits, like the ability to take the generated code into consideration when doing refactorings and so on, whereas in Ruby that code is invisible to any static analysis).&lt;/p&gt;
287
+
288
+ &lt;p&gt;This is a straw man: Smalltalkers understand the need to capture (and later modify) the intent as well as anyone else does. The solution is to make the generated code round-trippable. If you look at any real Smalltalk tools that generate code based on a custom tool (the &lt;a href=&quot;http://www.refactory.com/Software/SmaCC/&quot;&gt;SmaCC&lt;/a&gt; parser generator is a good example), it will preserve the settings from that tool, for example in a class comment, and the tool will let you inspect the intent, modify the intent, and regenerate the code.&lt;/p&gt;
289
+
290
+ &lt;p&gt;To be concrete: any self-respecting Smalltalk tool that let you generate all the code associated with a &quot;has_many&quot; expression would annotate those methods with the &quot;has_many&quot; intent, in a way that the tools could understand, present to the user, and modify.&lt;/p&gt;
291
+
292
+ &lt;p&gt;(James Robertson &lt;a href=&quot;http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3366525548&quot;&gt;points out&lt;/a&gt; that ORM tools in Smalltalk tend not to use code generation anyway, but I don&#39;t think that really answers Neal&#39;s point.)&lt;/p&gt;</content:encoded>
293
+
294
+
295
+
296
+ <dc:creator>Avi</dc:creator>
297
+ <dc:date>2007-09-06T13:46:17-07:00</dc:date>
298
+ </item>
299
+ <item rdf:about="http://www.avibryant.com/2007/07/moving.html">
300
+ <title>Moving</title>
301
+ <link>http://www.avibryant.com/2007/07/moving.html</link>
302
+ <description>Just a quick note that I&#39;ve moved this blog to a new platform (typepad) and a new URL (www.avibryant.com). If you were subscribed to the old one, you shouldn&#39;t have to do anything, because the feeds are redirected. However, although...</description>
303
+ <content:encoded>&lt;p&gt;Just a quick note that I&#39;ve moved this blog to a new platform (typepad) and a new URL (www.avibryant.com). If you were subscribed to the old one, you shouldn&#39;t have to do anything, because the feeds are redirected. However, although all of the old posts are imported, the old permalinks are currently broken. When I find the time over the next week I&#39;ll set up the mapping for them but for now, if you came here from a link to a specific post, I apologize.&lt;/p&gt;</content:encoded>
304
+
305
+
306
+
307
+ <dc:creator>Avi</dc:creator>
308
+ <dc:date>2007-07-04T23:15:25-07:00</dc:date>
309
+ </item>
310
+
311
+
312
+ </rdf:RDF>
313
+ <!-- ph=1 -->
314
+ <!-- nhm:dynamic-ssi -->