<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On May 15, 2016, at 2:01 PM, Dave Abrahams &lt;<a href="mailto:dabrahams@apple.com" class="">dabrahams@apple.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">on Fri May 13 2016, Matthew Johnson &lt;</span><a href="http://matthew-at-anandabits.com/" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">matthew-AT-anandabits.com</a><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">&gt; wrote:</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">Sent from my iPad<br class=""><br class=""><blockquote type="cite" class="">On May 13, 2016, at 9:12 AM, Dave Abrahams &lt;<a href="mailto:dabrahams@apple.com" class="">dabrahams@apple.com</a>&gt; wrote:<br class=""><br class=""><br class=""><blockquote type="cite" class="">on Mon May 09 2016, Matthew Johnson &lt;<a href="http://matthew-at-anandabits.com" class="">matthew-AT-anandabits.com</a>&gt; wrote:<br class=""><br class="">&nbsp;&nbsp;My claim is that substituting the constraint of “it has value<br class="">&nbsp;&nbsp;semantics,” while presumably looser than the PureValue constraint, would<br class="">&nbsp;&nbsp;not compromise the correctness of your view controller, so not only is<br class="">&nbsp;&nbsp;the meaning of PureValue hard to define, but it doesn't buy you<br class="">&nbsp;&nbsp;anything. &nbsp;If you want to refute that, just show me the code.<br class=""><br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;This is not an algorithmic use but is still perfectly valid IMO.<br class=""><br class="">&nbsp;&nbsp;If the properties of PureValue matter to your view controller, there's<br class="">&nbsp;&nbsp;an algorithm somewhere that depends on those properties for its<br class="">&nbsp;&nbsp;correctness.<br class=""><br class="">In many cases it may just be view configuration that depends on those<br class="">properties. &nbsp;I suppose you can call view configuration code an<br class="">algorithm but I think that would fall outside of common usage.<br class=""></blockquote><br class="">It's an algorithm, or if the configuration is declarative, there's an<br class="">algorithm that manipulates it. &nbsp;That said, I still don't have a concrete<br class="">example of how view configuration can depend on these properties.<br class=""></blockquote><br class="">The algorithm might just be "copy x bit of data to y view property,<br class="">etc". &nbsp;That is so trivial that it feels like a stretch to call it an<br class="">algorithm.<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Algorithms can be trivial.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""></div></blockquote><div><br class=""></div><div>Fair enough. &nbsp;Although in most contexts people don’t use the word when discussing the trivial.</div><br class=""><blockquote type="cite" class=""><div class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">That "algorithm" doesn't depend on this property because it executes<br class="">at a single point in time. &nbsp;However, a view controller might depend on<br class="">that property in order to render properly across time (for example,<br class="">configuring cells as they scroll on and off screen).<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">The example is too abstract for me to understand.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Let me put this differently: I recognize that your concept of</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">“PureValue” may be a *sufficient* condition for some generic</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">algorithm/component to work, but it is never a *necessary* condition,</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">because genericity (or use of a superclass or protocol type) erases</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">details of the actual types involved from the point of view of the</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">algorithm/component. &nbsp;It doesn't matter if your type contains a class</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">reference if it has value semantic properties. &nbsp;My claim is that</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">PureValue is an overly-restrictive constraint that makes many things</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">less useful than they should be.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""></div></blockquote><div><br class=""></div><div>In many cases this is true - you don’t need more than value semantics as you define it. &nbsp;However it is not at all true that PureValue is never necessary for the correctness of code. &nbsp;I’m going to provide an example to the contrary below.</div><br class=""><blockquote type="cite" class=""><div class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">This property allows us to separate values from non-local mutation and<br class="">make such separation a requirement. &nbsp;Rather than observing mutations<br class="">of objects with KVO, etc we might prefer to observe something that<br class="">provides a new aggregate value instead, while requiring the entire<br class="">aggregate value itself to be (observably) immutable at all times<br class="">(because we stored it with a let property locally). &nbsp;This can make it<br class="">easier to reason about correct behavior of your code. &nbsp;But it doesn't<br class="">work unless all visible parts of the aggregate are immutable.<br class=""><br class="">If you're not familiar with Elm, Redux, etc it might be worth taking<br class="">a look. &nbsp;<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">That's a pretty broad link. &nbsp;At which parts do you think I should look?</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""></div></blockquote><div><br class=""></div><div>The piece that matters here is state management. &nbsp;The core concept is to tightly control how mutations happen. &nbsp;It is modeled in terms of state type T, an initial value t, an action type A (instances of which are mutation commands, as in the command pattern), and a reducer function (T, A) -&gt; T which produces a new state.</div><div><br class=""></div><div>Here’s a toy implementation that is somewhat simplistic but captures the essence of the concept:</div><div><br class=""></div><div>class&nbsp;Store&lt;State, Action&gt; {<br class="">&nbsp; &nbsp;&nbsp;typealias&nbsp;Reducer = (State,&nbsp;Action) -&gt;&nbsp;State<br class="">&nbsp; &nbsp;&nbsp;<br class="">&nbsp; &nbsp;&nbsp;var&nbsp;stateHistory: [State]<br class="">&nbsp; &nbsp;&nbsp;let&nbsp;reducer:&nbsp;Reducer<br class="">&nbsp; &nbsp;&nbsp;<br class="">&nbsp; &nbsp;&nbsp;init(initialState:&nbsp;State, reducer:&nbsp;Reducer) {<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;stateHistory&nbsp;= [initialState]<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.reducer&nbsp;= reducer<br class="">&nbsp; &nbsp;&nbsp;}<br class="">&nbsp; &nbsp;&nbsp;<br class="">&nbsp; &nbsp;&nbsp;func&nbsp;applyAction(action:&nbsp;Action) {<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;let&nbsp;newState =&nbsp;reducer(stateHistory.last!, action)<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;stateHistory.append(newState)<br class="">&nbsp; &nbsp;&nbsp;}<br class="">&nbsp; &nbsp;&nbsp;<br class="">&nbsp; &nbsp;&nbsp;var&nbsp;currentState:&nbsp;State&nbsp;{<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;stateHistory.last!<br class="">&nbsp; &nbsp;&nbsp;}<br class="">&nbsp; &nbsp;&nbsp;<br class="">&nbsp; &nbsp;&nbsp;var&nbsp;canUndo:&nbsp;Bool&nbsp;{<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;stateHistory.count&nbsp;&gt;&nbsp;1<br class="">&nbsp; &nbsp;&nbsp;}<br class="">&nbsp; &nbsp;&nbsp;<br class="">&nbsp; &nbsp;&nbsp;func&nbsp;undo() {<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;canUndo&nbsp;{<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;stateHistory.popLast()<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;}<br class="">&nbsp; &nbsp;&nbsp;}<br class="">}</div><div><br class=""></div><div>This design relies on State being a PureValue. &nbsp;The whole idea is that the only way any path of observation rooted at currentState can change is when the reducer returns a new state when it is called by `applyAction`. &nbsp;That guarantee cannot be provided by value semantics alone under your definition of value semantics. &nbsp;Further, each state in the history is intended to be a static snapshot of the “currentState” state at a specific point in time. &nbsp;All states should be logically independent from each other and from anything anywhere else in the program. &nbsp;This cannot be guaranteed under your definition of value semantics. &nbsp;</div><div><br class=""></div><div>If we allow State to be Array&lt;MyMutableReferenceType&gt; which has value semantics under your definition it is clear that we should have no expectation that the desired properties are preserved. &nbsp;The Store class is fundamentally broken if it can be used with State types that are not pure values.</div><div><br class=""></div><div>I’m not sure why it didn’t occur to me sooner, but this strategy for managing app state is very similar in nature to what Sean Parent discusses in his value semantics talk (<a href="https://www.youtube.com/watch?v=_BpMYeUFXv8" class="">https://www.youtube.com/watch?v=_BpMYeUFXv8</a>&nbsp;and related&nbsp;<a href="https://www.youtube.com/watch?v=bIhUE5uUFOA" class="">https://www.youtube.com/watch?v=bIhUE5uUFOA</a>).&nbsp;</div><div><br class=""></div><div>Sean discusses using value semantics to model applications state (he calls it document). &nbsp;His examples don’t use reified actions and reducer functions so it is a bit different but it relies on the same pure value semantics. &nbsp;The demo he gives in the talk is a toy example modeled on the design Photoshop uses to implement its history feature. &nbsp;This design relies on each document in the history being an aggregate which is a PureValue. &nbsp;This is not an academic discussion, but on with real world practical utility.</div><div><br class=""></div><div>Sean says “value semantics is similar to functional programming, except objects still have addresses and in-situ operations… &nbsp;You're trying to maintain the ability to locally reason about your code but you're not denying the fact that the machine has memory and you can do in-situ operations on it”. &nbsp;Towards the end he quotes from a discussion he had with John Backus (inventor of FP). &nbsp;John said: “it always annoyed me that FP and the no side effect way of programming had become a religion. &nbsp;With FP I was trying to come up with a mathematically rigorous way to program and I understood the complexities of having side effects. &nbsp;I always knew we had to deal with side effects, I just wanted a structured way to do it.” &nbsp;John agreed that Sean’s approach to value semantics provides such a structure. &nbsp;Allowing shared mutable references throws away that structured approach. &nbsp;(As an aside, this is the most exciting thing about value semantics IMO - it provides a structured approach to side effects, allowing local reasoning about code). &nbsp;</div><div><br class=""></div><div>Sean gives an example of how references break the ability to reason locally where he has two shared_ptrs that point to the same object:</div><div><br class=""></div><div>"If you look at it in terms of just the individual types you kind of do have value semantics. &nbsp;When I copy a shared pointer it copies the pointer with value semantic operations... &nbsp;The problem is the references. &nbsp;When I'm looking at a shared_ptr I'm looking at it as if I have the object. &nbsp;So really what I have is two objects that intersect. &nbsp;So really my object in the program is this whole connected mess. &nbsp;At any particular point in code I have difficulty reasoning about the whole thing. &nbsp;The shared structure breaks our ability to reason locally about code."</div><div><br class=""></div><div>Sean makes an important distinction between looking at individual types and looking at the aggregate as a whole. &nbsp;It is very important to him that the entire aggregate be logically independent as this facilitates local reasoning. &nbsp;This is exactly what I have been calling a pure value. &nbsp;Pure value never allows any intersection to be observed (immutable intersections are allowed because they cannot be observed, which Sean alludes to in passing). &nbsp;Incidentally, it is pretty clear from the talk that immutable intersection is heavily used in Photoshop history in order to keep memory use reasonable. &nbsp;This falls into the category of persistent data structures.</div><div><br class=""></div><div>My impression is that Sean’s definition of "value semantics” excludes “intersecting objects” (where the intersection is mutable) and is aligned with John’s “full value semantics” and the notion of “pure value” we have been discussing. &nbsp;</div><div><br class=""></div><div>-Matthew</div><div><br class=""></div><div><br class=""></div><div><br class=""></div><br class=""><blockquote type="cite" class=""><div class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">--<span class="Apple-converted-space">&nbsp;</span></span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">-Dave</span></div></blockquote></div><br class=""></body></html>