W3C home > Mailing lists > Public > public-houdini@w3.org > October 2016

[Houdini] Minutes Lisbon F2F 2016-09-22 Part II: Typed OM, Stringification behavior, CR for Paint, Appropriate string representation to use in specified style

From: Dael Jackson <daelcss@gmail.com>
Date: Sun, 9 Oct 2016 20:39:15 -0400
Message-ID: <CADhPm3vhG6Wo8=T1aR9gpiTPwE_xYMeNaviK6Y+9+B9yQ+P9-A@mail.gmail.com>
To: public-houdini@w3.org
Cc: www-style@w3.org
=================================================
   These are the official Houdini Task Force
     minutes. Unless you're correcting the
      minutes, please respond by starting
 a new thread with an appropriate subject line.
=================================================


Typed OM
--------

  - RESOLVED: StyleValue must be immutable.
  - RESOLVED: Specified style map should be live.
  - RESOLVED: Computed style map is live.

Stringification behavior
------------------------

  - There were three options presented for what to stringify:
      1) Minimal representation, which when reading it back it would
         be a different value than if you go through the old API.
      2) Try and reproduce behavior of old OM (which wasn't
         consistent across browsers).
      3) Always use source string.
  - RESOLVED: For computed style we'll use the minimal
              representation. This will give the same serialization
              as the CSSOM does for computed style when the values
              match.
  - A resolution wasn't reached for specified style, but the
      proposal was to re-serialize and pull out the string.

CR for Paint
------------

  - RESOLVED: Move global name resolution out of Paint level 1 to a
              future spec.
  - RESOLVED: Match canvas, transparent by default.
  - RESOLVED: Issue #1 resolved by matching properties/values syntax
              and adding input arguments.
  - RESOLVED: Paint API level 1 to CR (pending edits)

Appropriate string representation to use in specified style
-----------------------------------------------------------

  - shane presented three options:
      1. use string as-is
      2. round-trip through CSS parser
      3. minimal representation
  - There was a push to make sure that whatever approach is taken
      won't later become something we have to deal with for
      backwards compat.

===== FULL MINUTES BELOW ======

Agenda: https://github.com/w3c/css-houdini-drafts/wiki/TPAC-F2F-September-2016

Scribe: eae

Typed OM
========

  <dbaron> https://drafts.css-houdini.org/css-typed-om/

Should StyleValues be immutable?
--------------------------------

  shane: Two questions we couldn't resolve through issues on github
         that it would be good to have an answer for.
  shane: First up, "Should StyleValues be immutable?"
  shane: StyleValues are the values that are stored in the style
         map. Currently immutable. Cannot be changed, to update the
         value in the style map you have to create a new style
         value. I think this is the right solution but it is
         different from early assumptions.
  plinss: Difference between not being a live value and immutable.
  shane: One advantage of immutable is that it is obvious it is not
         live.
  dbaron: How do you make a new one?
  shane: Lots of constructors.
  shane: There are also parsers, from DOM Strings, for each type. So
         you could pass a Length type.

  dbaron: What does the parser look like in the spec?
  * shane presents the spec *
  dbaron: I see a from method on CSSLength
  dbaron: Some of the others don't have that.
  shane: We haven't finished it yet.
  TabAtkins: Everything will have a from.
  shane: There will be a from method on every subclass that takes a
         DOMString.
  shane: CSSStyleValue objects have a parse method which takes a
         property name and the string to parse.
  TabAtkins: The use case for this is to represent, as a css style
             value, anything we don't have a type for. Instead you
             can parse it with this and the value of it will be a
             cssvalue object.
  shane: Then there are more specific constructors for things like
         from(double value), from(Dictionary) etc
  shane: Lots of different ways to construct. Could have discussion
         about slimming that down.
  shane: Low cost of maintaining.

  plinss: What's the point of the dictionary?
  shane: Things like calc, takes a dictionary of values.
  TabAtkins: calc length stores as a sequence of just single unit
             values. If you want to do multiplication you have to do
             it on your own or do string parsing. Or use
             CSSLengthValue::multiple and friends.
  dbaron: There are a bunch of things that take a
          Sequence<CSSValue>. Can you have a Sequence of Sequences?
  TabAtkins: All are comma separated lists; one level.
  shane: We don't do things like transform. Doesn't make sense to
         consider first value of transform in isolation. Unlike
         background where the first value means something.
  dbaron: If you have something complicated as box shadow?
  TabAtkins: Would be a sequence of style values. Would be list of
             things where each thing represents a box shadow.
  shane: In the future there would be a box shadow type.
  dbaron: Is there a need for a definition of each type?
  TabAtkins: Not at the moment, needs to have some description.
             Opacity is easy, has one value, box shadow more complex.
  TabAtkins: If more complicated than a single value or comma
             separated list it would be represented by a style
             object.
  SimonSapin: There is one for each property?
  shane: There is a type for each grammar thing.
  TabAtkins: Right now we can only handle properties with a single
             production.
  TabAtkins: Eventually there will be things like a sequence of
             these types for box shadow.
  SimonSapin: Similar to have transition have specific text about it.
  TabAtkins: Yes. Specialized type that it would return.
  shane: Fundamentally quite similar.

  Rossen: Going back to the issue.
  shane: Question: Should these be immutable?
  shane: Anyone think otherwise?
  plinss: Not sure it's a bad idea; across the platform we have
          somethings that are live objects, some dead, some
          immutable. We should be consistent with the current trend
          wrt dead vs immutable.
  SimonSapin: Would sequences be immutable as well?
  TabAtkins: Yes, all attributes of things.
  shane: Can you make sequences immutable?
  TabAtkins: Frozen array?
  SimonSapin: Reconstruct each time? Is that easy?
  TabAtkins: Yes.
  SimonSapin: Okay.

  dbaron: I feel that there are a couple of things here being
          underspecified.
  TabAtkins: Yes, but hopefully not surprising.
  dbaron: How do you convert background position right 50% bottom
          30px into an appropriate thing?
  TabAtkins: We potentially loose some detail from specified values.
             Would get a calc length that specifies something.
  dbaron: calc length assumes we would never extend the syntax.
  TabAtkins: Not necessarily, let's talk about it later.
  shane: We wanted to talk about stringification. Maybe we can leave
         that at overflow and get back to later.

  dino: Examples would be nice.
  TabAtkins: We describe positions as a set of calc offsets
  <TabAtkins> background-position: top 10px right 10px;
  <TabAtkins> ==>
  <TabAtkins> el.styleMap.get('background-position')
  <TabAtkins> CSSPositionVAlue(CSSSimpleLength(10, 'px'),
              CSSCalcLength({px: -10, percent: 100}))
  SimonSapin: If we get a value that can be either calc length or a
              value, how do you tell the type?
  TabAtkins: Check type of object.
  SimonSapin: How?
  TabAtkins: Using standard js syntax, instanceOf
  JakeA: With background position, right 0 is the right hand side of
         the image. Is that represented here?
  TabAtkins: Yes, would be a 100% which is also right aligned.
  shane: Reasonably happy it being immutable?

  RESOLVED: Style value must be immutable.

How dead should the style maps be?
----------------------------------

  <nainar> https://github.com/w3c/css-houdini-drafts/issues/149
  shane: How dead is too dead.
  TabAtkins: When you pull a style map up, is the entire map dead or
             just the values?
  dbaron: The style map for specified style allows mutation.
  dbaron: You're asking whether to remove that?
  TabAtkins: We still need to be able to construct style maps
             appropriately
  [TabAtkins shows example from issue 149, comment from shane on Jul
    27.]
      var map = el.styleMap;
      map.get('height') // for argument's sake, CSSSimpleLength(100,
        'px')
      el.style.height = '200px';
      map.get('height') // will still return CSSSimpleLength(100,
        'px')
  shane: This seems strange, the computed style objects are not
         immutable. Having them be live is expensive?
  SimonSapin: Why would it be expensive?
  ojan: Would require style recalculation.
  dbaron: For gecko the non-live implementation for computed style
          would be easy.
  dbaron: In gecko when it changes style it get a new object.
  ojan: I think that matches the webkit and blink implementation.
  ojan: Computed style is cheap if it has already been computed.
        Non-live.
  ojan: Would be confusing for authors if it flushed style recalc.
  esprehn: Not sure how we wouldn't do that?
  esprehn: Need to resolve percentages?
  dbaron: Layout flushes.
  dbaron: getComputedStyle is live.
  SimonSapin: Depends on if you want computed values
  TabAtkins: Our intention is to use actual computed values, not
             resolved values.
  SimonSapin: So percentages stay that way.

  dbaron: One of the other question, does the style map get a flush?
  shane: I think it has to.
  dbaron: I think so too.
  gregwhitworth: So, what would that be in the example? 200px?
  ojan: Yes.

  dbaron: More complicated issue, if the element set style way
          before to 50px and here (line 2) you set it to 100px, If
          this line didn't flush it could still be 50px, or it
          flushed on line 2 and it's 100px, if it flushes later you
          might get 200
  shane: How live is it?
  gregwhitworth: To me, when you called it, it should be computed
                 before me it's what will be returned.
  TabAtkins: Flushed non-live?
  esprehn: If you want be non-live it should be a method.
  esprehn: .getStyleMap(), returns a new map every time. Ergonomics
           would be bad.
  esprehn: Would be hard, we lazy compute a lot.
  TabAtkins: Specified style should be live so you can set things?
  shane: So that you can set.

  ojan: We have element.styleMap is live, .getComputedStyleMap() is
        not a live thing. Has a snapshot problem.
  dbaron: Gecko doesn't have the snapshot problem. Most other
          implementations would.
  shane: Even across style updates?
  shane: What if I call element.getComputedStyleMap then do
         something to change it, is that reflect in the returned
         style map?
  esprehn: Yes, has to be, or we need to snapshot, which is
           expensive.
  esprehn: We do a lot lazily today, if we snapshot all lazily
           computed values must be computed at time of snapshot.
           Would be very expensive. We do it for limited things,
           alignment, user select etc.
  shane: I'm fine with it being live.
  ojan: I'm sad about it flushing style recalc on every getter
  gregwhitworth: We've been talking about this for two years. We
                 want to fix it but not realistic.

  surma: What if make the developer specify the values they want? So
         that we don't have to compute all of them?
  ojan: Would make me happy.
  dbaron: Similar to having it be live.
  ojan: For user agents that already compute it would be similar.
        Much easier for other implementations.
  ojan: element.getComputedStyleMap('list of properties')
  SimonSapin: Isn't that the same as .get?
  ojan: You could call get 15 minutes from now.
  dbaron: I don't think users will understand what is expensive or
          not.
  esprehn: Only protecting you against flushes on the same element.
           Not sure that would save one from much.
  ojan: Quite common I feel.

  shane: Why not just move getComputedStyleValue? So that the
         element is the map for the computed value?
  <shane> element.getComputedStyleMap().get('height');
  <shane> ^ NOOOOO
  <shane> element.getComputedStyleValue('height');
  <shane> ^ \o/
  ojan: Has same problem with interleaved read/writes.
  dbaron: The second one isn't that different from a live object.
  shane: Except the element is already live, we're not adding more
         live object.
  TabAtkins: Except it would still cause a flush for each ready if
             the developer isn't careful.
  shane: Idea of list of properties would be to return a guaranteed
         snapshot causing at most one flush. What's the downside?
  surma: List of properties.
  dbaron: A lot of work to avoid flushing, if that is what we want
          to avoid we should design for that explicitly.
  shane: Like a flag? avoidFlush?
  dbaron: Something like run this code without flushes with a
          callback?
  ojan: Can of worms.
  JakeA: Dom transactions kind of thing?
  iank: Yes, let's not get into that.

  JakeA: Making this API harder to deal with to try to solve dom
         transactions seems wrong
  TabAtkins: Three options. A) Live objects, B) Snapshot, expensive,
             C) snapshot for a few properties.

  ojan: Specified one should be live. No objections? Yay!

  RESOLVED: Specified style map should be live.

  [group votes for computed style map]
  <TabAtkins> C, then A
  <shane> A
  <surma> C > A
  <dbaron> A
  <eae> A
  <iank> NOT B
  <JakeA> A - but I don't know a ton about the problem
  <dino> C, but the API is very sucky so I don't like it.
  <nainar> A
  <Rossen> C
  <atotic> C
  <SimonSapin> A

  <iank> OMG NO WAIT!
  <ojan> what dino said!
  <dino> element.style.getComputedStyleMap('width').get('width') //
         yuck

  shane: No strong consensus. B can be ruled out.
  esprehn: Can we leave it as live for now? And then experiment with
           snapshotting?
  shane: Can I make a suggestion for C?
  <shane> element.style.getComputedStyleMap('width', 'height',
          '...') --> { width: ..., height: ...., }
  dino: Still seems really bad, element.style.getComputedStyleMap
        ('width', 'height', '...').width. Yick.
  <JakeA> const [width, height] = getComputedStylesThingy(['width',
          'height'])
  <TabAtkins> JakeA: Or `const {width, height} = ...`
  shane: A it is.

  RESOLVED: Computed style map is live. We are all sad.

  shane: That is all for typed om.
  SimonSapin: Getters over attributes communicates that it is more
              expensive.

Stringification behavior
========================

  <eae> https://github.com/w3c/css-houdini-drafts/issues/268
  shane: There are three different behaviors we could stringify.
  shane: First option is a minimal representation. Downside is that
         reading it back it would be a different value than if you
         go through the old API.
  shane: The second option would be to try to reproduce the behavior
         in the old OM.
  shane: It's not consistent across browsers.
  dbaron: Neither specified.
  shane: I don't want to do that UNLESS it comes straight from a
         stylesheet. Makes sense there.
  shane: Third option; always use the source string.
  shane: Currently speced is a combination of the three. Not ideal.
         We should pick one.

  shane: Would anyone object to always going with the minimal
         representation?
  dbaron: In a room full of implementors I don't think anyone is
          going to object.
  shane: Let's ask devrel?
  surma: I'd prefer numeric representation
  ojan: Need more examples.
  Rossen: What about colors?
  <shane> color: red;
  <shane> color: rgba(255, 0, 0, 1)
  ojan: Color is a good example of... depends on how you use it.
  eae: Helpful if you want to animate or manipulate it to get
       numeric value.
  ojan: Unexpected for authors.
  iank: I think rgb is OK. A lot of use cases are for quality
        testing. At least that is one use case.
  ojan: People do things like read out the value, if (color ==
        'red') etc.
  surma: but then they could skip the typed OM all together.
  aleks: Is there an option to do both?
  shane: Let's not do that.

  Rossen: When we're talking about css values, which are we talking
          about? Specified? Computed?
  Rossen: For computed there is no point in having original values
          (i.e. red). For specified on the other hand it makes a lot
          more sense.
  TabAtkins: You are proposing, values pulled out of stylesheets
             gets the parsed representation?
  Rossen: Right
  gregwhitworth: That is already not true. If you pull out color you
                 get rgb.
  gregwhitworth: I don't want getComputedStyle to not return
                 computed. Specified should stay specified.
  shane: We did this for color already, color names are aliases.
         Some browsers do it during parse.
  gregwhitworth: We should check with developers about use cases.
  shane: Keeping specified would be expensive.
  gregwhitworth: Don't we do that already for devtools?
  shane: Only with devtools open.
  shane: It's the most sane but I do not want to commit to it
         without investigation. Might be expensive or use a lot of
         extra memory.
  gregwhitworth: I feel like we need author feedback on this.

  shane: I think it's clear that we do not always want the minimal
         representation.
  shane: For computed style we DO want minimal.
  dbaron: Is this different from the minimal representation in
          getComputedStyle?
  ojan: This would not be resolved style. For width: auto you would
        get "auto".
  TabAtkins: Would only be different when the VALUES are different.
  shane: Serialization would be the same.

  RESOLVED: For computed style we'll use the minimal representation.
            This will give the same serialization as the CSSOM does
            for computed style when the values match.

  Rossen: Good! How about for specified?
  shane: There are again three cases.
  shane: We can't do anything for the first case, when you use a
         style value constructor. Minimal is only option.
  shane: Second case is using a parser, the most sensible options
         would be either minimal representation (same as for
         construct) or fateful string representation.
  TabAtkins: Minimal seems more consistent.
  shane: Would potentially change as you instantiate more types.
  shane: Without type we can only do the fateful representation,
         when we add type it would switch to minimal.
  TabAtkins: OM defines how to serialize.
  ojan: We're forced to use the string representation for types
        without an implementation. We don't want to change it when
        we add a new type.
  TabAtkins: OM already defines how to serialize, so we know how to
             do it.
  dbaron: Are we talking about computed or specified now?
  TabAtkins: Specified.
  <TabAtkins> CSSStyleVAlue.parse('box-shadow', "...")
  shane: Proposal re-serialize and pull out the string.
  ojan: Authors underestimate the memory overhead of keeping the
        strings.
  <dbaron> I think ojan convinced me that CSSStyleValue.parse()
           needs to serialize in specified values the same as things
           from a style sheet or a string-based setter -- but that
           doesn't necessarily apply to CSSLengthValue.from()
  <eae> dbaron++
  esprehn: One of the key problems with things like rgb is that it's
           hard for developers to know what it is and do comparison.
           With typed om we're fixing that so that one can compare
           and determine that it's red.

  [break for lunch]

  Scribe: jet

CR for Paint
============

  Rossen: Let's go over open issues.
  iank: A few issues from bz, heycam review back in June.
  iank: 17 open issues in GitHub.
  iank: A lot are text fixups.

Should registered paint names be limited to shadow trees they are in?
---------------------------------------------------------------------

  <nainar> https://github.com/w3c/css-houdini-drafts/issues/223
  iank: non-editorial bug ^
  esprehn: Global name resolution seems very hard.
  iank: Can move to CSS Paint API level 2
  TabAtkins: We already treat animations this way (via inheritance)
  esprehn: Does it work with variables?
  esprehn: Would be nice to solve this for CSS globally

  RESOLVED: move out of Paint level 1 to a future spec

Add "alpha" as an option
------------------------

  iank: Issue 220.
  <nainar> https://github.com/w3c/css-houdini-drafts/issues/220
  iank: Currently no alpha on an all-black canvas.
  ojan: If you know you're opaque you can optimize.

  TabAtkins: How about instead of alpha, you specify a BG color.
  TabAtkins: rgba color.
  TabAtkins: So we can paint something even when Paint callbacks
             aren't ready.
  iank: Currently we paint black on throws.
  TabAtkins: Default to transparent default image?
  TabAtkins: Before paint runs for the first time.
  dbaron: Even if default is opaque, if authors don't want that,
          people will turn off the optimization
  *anti-aliasing on opaque surfaces discussion ensues*

  iank: summary: what do we think about opaque by default?
  plinss: aka opt-in for alpha.
  JakeA: Canvas is transparent by default.
  surma: Opt-in is fine.
  surma: Can we match the behavior of having a transparent image by
         default?
  JakeA: We can have LCD anti-aliasing by default if opaque.
  ojan: I think this is true for all implementors who have LCD AA.
  surma: Matching canvas is desirable.
  <eae> having lcd aa with transparent backgrounds would require
        alpha per channel => a lot of extra memory.
  dbaron: Spec should mention both anti-aliasing of text and
          performance optimizations for things that are opaque.
  ojan: Background animated images occluded by transparency is a
        common use/perf hit.
  bz: Background size calls paint again?
  TabAtkins: yes

  RESOLVED: Match canvas, transparent by default
  RESOLVED: Issue #1 resolved by matching properties/values syntax
            and adding input arguments

  Rossen: Also add example for conic gradients

  RESOLVED: Paint API level 1 to CR (pending edits)

 Appropriate string representation to use in specified style
 ===========================================================

  shane: 1. use string as-is
  shane: 2. round-trip through CSS parser
  shane: 3. minimal representation
  shane: issue: which option to use?
  TabAtkins: Minimal representation can be safe but CSSOM may depend
             on things not represented
  TabAtkins: Probably safer to use as-is input string.
  TabAtkins: When we later add a box-shadow type, you'll get a
             minimal representation
  TabAtkins: for future types we can throw away the string.
  SimonSapin: Does this string get preserved after going through the
              style map?
  SimonSapin: Is this an exact string with whitespace/comments?
  TabAtkins: #1 preserves, #2 doesn't.
  TabAtkins: Better to retain a token stream?
  dbaron: Should test current implementations.
  shane: We resolved to not expose token streams in CSS.
  TabAtkins: Custom properties uses exact representation per CSS.
  TabAtkins: CSS.parse() preserves the original string
  TabAtkins: For memory, better to keep token stream or original
             string?
  esprehn: Give an example?
  TabAtkins: CSSStyleVale.parse(box-shadow: black)
  TabAtkins: Should we preserve the whitespace?
  esprehn: If we don't care about whitespace, save token stream.

  <TabAtkins> CSSStyleVAlue.parse('color', ' red')
  <TabAtkins> Does this give:
  <TabAtkins> 'red'
  <TabAtkins> or ' red'
  dbaron: We don't use token stream now, we use a typed value
          representation.
  dbaron: eg, specified style.
  dbaron: If you call CSSTRansformValue's constructor, then you get
          the specified style back, you need to construct a
          canonical string somehow
  dbaron: eg., for shadow: color, blur, x,y , spread.
  dbaron: If blur defaults to 0.0 you may omit it from the string.
  dbaron: Do you then use the constructAStringFromCSSStyleValue
          operation only when you call the constructor, or in other
          cases?
  dbaron: TabAtkins wants to use it in other cases.
  dbaron: Bad idea to use from shadowValue.parse() if we add
          properties later.
  dbaron: Currently records empty vs. zero
  dbaron: we may end up omitting or adding later.
  dbaron: We should follow CSSOM string generation rules though need
          better spec.
  <dbaron> or at least, we should unless we have a good reason to
           construct yet a different set of rules

  <esprehn> I'd prefer 'red', otherwise a CSSColorValue needs to
            have storage for the string
  <esprehn> trying to understand under what cases the space at the
            start matters
  <glazou> +1 to what esprehn said
  <glazou> esprehn: matters if you build a css-like language but
           still want to parse whitespace
  <TabAtkins> esprehn: It *probably doesn't* matter. I don't care
              about that. But the spaces stick around if we spec
              that you hold onto the original string.
  <TabAtkins> And they might not, if we spec that you just hold onto
              some value representation (probably token stream).
  <glazou> wait...
  <glazou> if we have a css parser
  <glazou> it should allow non-css languages based on css general
           syntax
  <Rossen> glazou, right, so you're agreeing we should keep the
           original input string
  <glazou> I agree that we should be able at least to detect there
           are leading ws
  <TabAtkins> glazou: That's a totes different topic.
  <glazou> one way or another
  <Rossen> glazou, agreed
  <glazou> in other terms, s* should be detected
  <glazou> FWIW, my jscssp parser preserves the original string on
           each construct *and* can detect ws and comments and
           report them individually

  TabAtkins: How about: if we build something out of a string, use
             CSSOM rules otherwise minimal representation.
  shane: This sounds horrible to implement.
  <shane> position: center center
  shane: In typed OM, I'd expect two length values 50% 50%.
  dbaron: Whatever we do today for specified style, let's use that
          and not make a new representation.
  shane: For typed OM center center isn't useful.
  dbaron: Typed OM should return 50% 50% but the style map should
          return what it does today.
  <TabAtkins> el.style.backgroundPosition = "center center"; print(
              el.styleMap.get("background-position") + ""); //yields
              "center center"
  <TabAtkins> Because print(el.style.backgroundPosition) also does.
  <esprehn> typedom CSSStyleValue today does: virtual String
            cssText() const { return toCSSValue()->cssText(); }
  <esprehn> so it converts to the old internal representation and
            returns that
  <TabAtkins> el.styleMap.set("background-position",
              CSSPositionValue.from("center center"); print(
              el.styleMap.get("background-position" + ""); // yields
              "center center"
  <TabAtkins> el.styleMap.set("background-position", CSSPositionValue
              (CSSLengthValue(50, "%"), CSSLengthValue(50, "%"));
              print(el.styleMap.get("background-position") + ""); //
              yields "50% 50%"
  dbaron: We wouldn't be here if we had types for all CSS values but
          we currently don't
  dbaron: but when we do, we shouldn't change and break
          backwards-compat.
  *chromium internals spoken here*

  <glazou> have you guys discussed access to the parser only or the
           lexer too ?
  <TabAtkins> glazou: Not yet. But look at
https://github.com/WICG/CSS-Parser-API
  <glazou> thx TabAtkins
  <TabAtkins> glazou: Better: http://wicg.github.io/CSS-Parser-API/
  <glazou> TabAtkins woah

  <gregwhitworth> http://jsbin.com/jupewavidi/edit?css,js,console,output
  <gregwhitworth> ^ testcase showing background-position

  TabAtkins: When we take a string straight to TypedOM without going
             thru the legacy system, do we reconstruct or return
             as-is?
  TabAtkins: if/when we change that CSSOM system, this will also
             change if we use the same system.
  Aleks: What is the use case for the string API?
Received on Monday, 10 October 2016 00:40:16 UTC

This archive was generated by hypermail 2.3.1 : Monday, 10 October 2016 00:40:17 UTC