[DRAFT] Introducing a Debug Build Configuration Test


(Erica Sadun) #1

https://gist.github.com/erica/d20639b409fe1b318c0e

Feedback solicited. Thanks, -- Erica

Introducing a Debug Build Configuration Test

Proposal: SE-00XX
Author(s): Erica Sadun <http://github.com/erica>
Status: TBD
Review manager: TBD
<https://gist.github.com/erica/d20639b409fe1b318c0e#introduction>Introduction

This proposal introduces a configuration test for debug builds.

This proposal was discussed on-list in the Introducing a Debug Build Configuration Test <applewebdata://0C1DDEF4-7986-4D7B-B837-C0CAEB2B24C2> thread.

<https://gist.github.com/erica/d20639b409fe1b318c0e#motivation>Motivation

Developers are used to including code specific to debug builds in their projects. Having a debug configuration test is an industry standard option. Under the current version of Swift you must add a command-line flag using -D <#flag#> (e.g. -D debug) and test in-code (#if debug), there's no consistent system-supplied way to differentiate code meant only for debug builds.

<https://gist.github.com/erica/d20639b409fe1b318c0e#detail-design>Detail Design

This proposal adds #if config(debug) to test for debug builds.

#if config(debug)
    // code for debug builds only
#endif
<https://gist.github.com/erica/d20639b409fe1b318c0e#background>Background

Joe Groff writes, "We specifically avoided making debug/release an #if condition because we considered #if to be the wrong point at which to start conditionalizing code generation for assertions. Though the final executable image's behavior is unavoidably dependent on whether asserts are enabled, we didn't want the SIL for inlineable code to be, since that would mean libraries with inlineable code would need to ship three times the amount of serialized SIL to support the right behavior in -Onone, -O, and -Ounchecked builds. Instead, the standard library has some hidden helper functions, _isDebugAssertConfiguration, _isReleaseAssertConfiguration, and _isFastAssertConfiguration, which are guaranteed to be constant-folded away before final code generation."

<https://gist.github.com/erica/d20639b409fe1b318c0e#current-art>Current Art

Swift currently supports the following configuration tests:

The literals true and false
The os() function that tests for OSX, iOS, watchOS, tvOS, and Linux
The arch() function that tests for x86_64, arm, arm64, and i386
The swift() function that tests for specific Swift language releases, e.g. swift(>=2.2)
<https://gist.github.com/erica/d20639b409fe1b318c0e#alternatives-considered>Alternatives Considered

There are no alternatives considered.


(Dmitri Gribenko) #2

Hi Erica,

Based on Joe's rationale that you are quoting, I think the intent is
that we want to restrict this directive to be statement-level only.
The API vended by a module should not be affected by the build mode.

Dmitri

···

On Mon, Mar 14, 2016 at 11:57 AM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

https://gist.github.com/erica/d20639b409fe1b318c0e

Feedback solicited. Thanks, -- Erica

Introducing a Debug Build Configuration Test

Proposal: SE-00XX
Author(s): Erica Sadun
Status: TBD
Review manager: TBD

Introduction

This proposal introduces a configuration test for debug builds.

This proposal was discussed on-list in the Introducing a Debug Build
Configuration Test thread.

Motivation

Developers are used to including code specific to debug builds in their
projects. Having a debug configuration test is an industry standard option.
Under the current version of Swift you must add a command-line flag using -D
<#flag#> (e.g. -D debug) and test in-code (#if debug), there's no consistent
system-supplied way to differentiate code meant only for debug builds.

Detail Design

This proposal adds #if config(debug) to test for debug builds.

#if config(debug)
    // code for debug builds only
#endif

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Jordan Rose) #3

What is a "debug build"? Is it one where testing is enabled? Where the optimization level is -Onone? (We've talked about having an -Odebug and/or -Oplayground at some point. Are those "debug builds"?) Is it one where asserts are not removed? (This can technically be controlled independently of -O, but we don't advertise the fact, and I'm not sure we even want that feature.)

Also, what is "config"? It doesn't mean anything to me on its own, which means I wouldn't know what else I can put besides "debug".

Jordan

···

On Mar 14, 2016, at 11:57 , Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

https://gist.github.com/erica/d20639b409fe1b318c0e

Feedback solicited. Thanks, -- Erica

Introducing a Debug Build Configuration Test

Proposal: SE-00XX
Author(s): Erica Sadun <http://github.com/erica>
Status: TBD
Review manager: TBD
<https://gist.github.com/erica/d20639b409fe1b318c0e#introduction>Introduction

This proposal introduces a configuration test for debug builds.

This proposal was discussed on-list in the Introducing a Debug Build Configuration Test <applewebdata://FB8B7ABA-BA05-4EF3-A260-C9959FBA2814> thread.

<https://gist.github.com/erica/d20639b409fe1b318c0e#motivation>Motivation

Developers are used to including code specific to debug builds in their projects. Having a debug configuration test is an industry standard option. Under the current version of Swift you must add a command-line flag using -D <#flag#> (e.g. -D debug) and test in-code (#if debug), there's no consistent system-supplied way to differentiate code meant only for debug builds.

<https://gist.github.com/erica/d20639b409fe1b318c0e#detail-design>Detail Design

This proposal adds #if config(debug) to test for debug builds.

#if config(debug)
    // code for debug builds only
#endif
<https://gist.github.com/erica/d20639b409fe1b318c0e#background>Background

Joe Groff writes, "We specifically avoided making debug/release an #if condition because we considered #if to be the wrong point at which to start conditionalizing code generation for assertions. Though the final executable image's behavior is unavoidably dependent on whether asserts are enabled, we didn't want the SIL for inlineable code to be, since that would mean libraries with inlineable code would need to ship three times the amount of serialized SIL to support the right behavior in -Onone, -O, and -Ounchecked builds. Instead, the standard library has some hidden helper functions, _isDebugAssertConfiguration, _isReleaseAssertConfiguration, and _isFastAssertConfiguration, which are guaranteed to be constant-folded away before final code generation."

<https://gist.github.com/erica/d20639b409fe1b318c0e#current-art>Current Art

Swift currently supports the following configuration tests:

The literals true and false
The os() function that tests for OSX, iOS, watchOS, tvOS, and Linux
The arch() function that tests for x86_64, arm, arm64, and i386
The swift() function that tests for specific Swift language releases, e.g. swift(>=2.2)
<https://gist.github.com/erica/d20639b409fe1b318c0e#alternatives-considered>Alternatives Considered

There are no alternatives considered.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Joe Groff) #4

I think the right thing here would be (in a separate proposal) to introduce an expression-level test for build configurations, so you could say something like this:

func assertIf64Bit(condition: @autoclosure () -> Bool) {
  if #condition(config(debug) && bits(64)) && condition() {
    fatalError("64-bit assertion failed")
  }
}

and the #-expression would be lowered to a SIL intrinsic that gets guaranteed-optimized like our _is*Configuration hacks do today. That would allow for platform-dependent code that doesn't depend on platform-dependent declarations to still be type-checked and diagnosed, and share build products up to the SIL optimization stage of the pipeline. If we have that then our original objection to config(debug) goes away.

-Joe

···

On Mar 14, 2016, at 1:04 PM, Dmitri Gribenko via swift-evolution <swift-evolution@swift.org> wrote:

On Mon, Mar 14, 2016 at 11:57 AM, Erica Sadun via swift-evolution > <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

https://gist.github.com/erica/d20639b409fe1b318c0e

Feedback solicited. Thanks, -- Erica

Introducing a Debug Build Configuration Test

Proposal: SE-00XX
Author(s): Erica Sadun
Status: TBD
Review manager: TBD

Introduction

This proposal introduces a configuration test for debug builds.

This proposal was discussed on-list in the Introducing a Debug Build
Configuration Test thread.

Motivation

Developers are used to including code specific to debug builds in their
projects. Having a debug configuration test is an industry standard option.
Under the current version of Swift you must add a command-line flag using -D
<#flag#> (e.g. -D debug) and test in-code (#if debug), there's no consistent
system-supplied way to differentiate code meant only for debug builds.

Detail Design

This proposal adds #if config(debug) to test for debug builds.

#if config(debug)
   // code for debug builds only
#endif

Hi Erica,

Based on Joe's rationale that you are quoting, I think the intent is
that we want to restrict this directive to be statement-level only.
The API vended by a module should not be affected by the build mode.


(Erica Sadun) #5

Could the debug build test take the form of a standard non-private function then
instead of _isDebugAssertConfiguration()? If the test is limited to methods,
introducing #if-style tests would be ugly.

How likely or easy is it for me to reframe the request for testing for debug to be as
simple as:

`if debugBuild() {...}`

with `debugBuild` vended by the standard library instead of as a build
configuration test?

-- E

···

On Mar 14, 2016, at 2:04 PM, Dmitri Gribenko <gribozavr@gmail.com> wrote:
Hi Erica,

Based on Joe's rationale that you are quoting, I think the intent is
that we want to restrict this directive to be statement-level only.
The API vended by a module should not be affected by the build mode.

Dmitri


(Erica Sadun) #6

Figuring out what debug *means* is an important first step. To "my people", it's the Xcode Build Configuration > Debug scheme setting. For language purposes, the only definition I can come up with at the moment is that debug is what happens when asserts can fire and are not disabled by compile-time optimizations.

Is there a better definition?

-- E

···

On Mar 15, 2016, at 11:28 AM, Jordan Rose <jordan_rose@apple.com> wrote:

What is a "debug build"? Is it one where testing is enabled? Where the optimization level is -Onone? (We've talked about having an -Odebug and/or -Oplayground at some point. Are those "debug builds"?) Is it one where asserts are not removed? (This can technically be controlled independently of -O, but we don't advertise the fact, and I'm not sure we even want that feature.)

Also, what is "config"? It doesn't mean anything to me on its own, which means I wouldn't know what else I can put besides "debug".

Jordan


#7

Is this really worst than wrapping some API section with #if os(OSX)?
Not that I am for API which change based on build setting, but a #if in the first
column is easy to spot as something conditionally compiled in.

Dany

···

Le 14 mars 2016 à 16:04, Dmitri Gribenko via swift-evolution <swift-evolution@swift.org> a écrit :

On Mon, Mar 14, 2016 at 11:57 AM, Erica Sadun via swift-evolution > <swift-evolution@swift.org> wrote:

https://gist.github.com/erica/d20639b409fe1b318c0e

Feedback solicited. Thanks, -- Erica

Introducing a Debug Build Configuration Test

Proposal: SE-00XX
Author(s): Erica Sadun
Status: TBD
Review manager: TBD

Introduction

This proposal introduces a configuration test for debug builds.

This proposal was discussed on-list in the Introducing a Debug Build
Configuration Test thread.

Motivation

Developers are used to including code specific to debug builds in their
projects. Having a debug configuration test is an industry standard option.
Under the current version of Swift you must add a command-line flag using -D
<#flag#> (e.g. -D debug) and test in-code (#if debug), there's no consistent
system-supplied way to differentiate code meant only for debug builds.

Detail Design

This proposal adds #if config(debug) to test for debug builds.

#if config(debug)
   // code for debug builds only
#endif

Hi Erica,

Based on Joe's rationale that you are quoting, I think the intent is
that we want to restrict this directive to be statement-level only.
The API vended by a module should not be affected by the build mode.


(Ben Rimmington) #8

Would `isOptimized` and `isOptimizedUnchecked` be useful, and also easier to specify?

···

On 15 Mar 2016, at 17:28, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

What is a "debug build"? Is it one where testing is enabled? Where the optimization level is -Onone? (We've talked about having an -Odebug and/or -Oplayground at some point. Are those "debug builds"?) Is it one where asserts are not removed? (This can technically be controlled independently of -O, but we don't advertise the fact, and I'm not sure we even want that feature.)

If you mean the `-assert-config` option, it is listed by the `swiftc -help` command.

-- Ben


(Shawn Erickson) #9

You would likely want to ensure debug related code could be optimized away
/ or not be included in release builds. I am not sure how a function would
achieve that.

···

On Tue, Mar 15, 2016 at 9:15 AM Erica Sadun via swift-evolution < swift-evolution@swift.org> wrote:

On Mar 14, 2016, at 2:04 PM, Dmitri Gribenko <gribozavr@gmail.com> wrote:
Hi Erica,

Based on Joe's rationale that you are quoting, I think the intent is
that we want to restrict this directive to be statement-level only.
The API vended by a module should not be affected by the build mode.

Dmitri

Could the debug build test take the form of a standard non-private
function then
instead of _isDebugAssertConfiguration()? If the test is limited to
methods,
introducing #if-style tests would be ugly.

How likely or easy is it for me to reframe the request for testing for
debug to be as
simple as:

`if debugBuild() {...}`

with `debugBuild` vended by the standard library instead of as a build
configuration test?

-- E

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(David Owens II) #10

Along the lines of what Jordan is saying, I don't think there even is a such thing a unifying definition of "debug build". Even your definition for "my people" is a collection of build settings.

The definition of "asserts can fire" is also problematic. Maybe if tied specifically to Swift's asserts, but honestly, Swift's asserts, as they are, are simply not sufficient for everyone's development model.

Here's an real example:

I have a set of test automation that I want to ensure works. However, running this automation with a blocking assert is not what I want. Instead, I've created a mechanism for asserts, configurable at runtime, for the way in which those asserts are handled. During automation, I want those asserts to simply log, but code execution is not halted. During my normal dev cycle though, I want those asserts to be raised immediately so the developer sees the error and can chose to investigate or ignore the assert.

The proposal seems to be trying to simplify something that is actually much more complicated in the wild.

All that said, there is a feature that I think your proposal is hinting towards: the ability to define named configs from set of flags and compiler options (essentially, the ability to define your scheme in a Swift-friendly way).

This feature would need coordination across the SwiftPM project as well though so you could define "MYCONFIG" as setting flags A-E, and likely other configuration settings. Then you would have the net of your proposal:

#if config(MYCONFIG)
#endif

-David

···

-----Original Message-----
From: swift-evolution-bounces@swift.org [mailto:swift-evolution-bounces@swift.org] On Behalf Of Erica Sadun via swift-evolution
Sent: Tuesday, March 15, 2016 11:20 AM
To: Jordan Rose <jordan_rose@apple.com>; Dmitri Gribenko <gribozavr@gmail.com>; Joe Groff <jgroff@apple.com>
Cc: swift-evolution <swift-evolution@swift.org>
Subject: Re: [swift-evolution] [DRAFT] Introducing a Debug Build Configuration Test

On Mar 15, 2016, at 11:28 AM, Jordan Rose <jordan_rose@apple.com> wrote:

What is a "debug build"? Is it one where testing is enabled? Where the optimization level is -Onone? (We've talked about having an -Odebug and/or -Oplayground at some point. Are those "debug builds"?) Is it one where asserts are not removed? (This can technically be controlled independently of -O, but we don't advertise the fact, and I'm not sure we even want that feature.)

Also, what is "config"? It doesn't mean anything to me on its own, which means I wouldn't know what else I can put besides "debug".

Jordan

Figuring out what debug *means* is an important first step. To "my people", it's the Xcode Build Configuration > Debug scheme setting. For language purposes, the only definition I can come up with at the moment is that debug is what happens when asserts can fire and are not disabled by compile-time optimizations.

Is there a better definition?

-- E

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Dmitri Gribenko) #11

A function can absolutely can do that, if it is implemented using a
builtin known to the optimizer.

Dmitri

···

On Tue, Mar 15, 2016 at 9:20 AM, Shawn Erickson <shawnce@gmail.com> wrote:

You would likely want to ensure debug related code could be optimized away /
or not be included in release builds. I am not sure how a function would
achieve that.
On Tue, Mar 15, 2016 at 9:15 AM Erica Sadun via swift-evolution > <swift-evolution@swift.org> wrote:

On Mar 14, 2016, at 2:04 PM, Dmitri Gribenko <gribozavr@gmail.com> wrote:
Hi Erica,

Based on Joe's rationale that you are quoting, I think the intent is
that we want to restrict this directive to be statement-level only.
The API vended by a module should not be affected by the build mode.

Dmitri

Could the debug build test take the form of a standard non-private
function then
instead of _isDebugAssertConfiguration()? If the test is limited to
methods,
introducing #if-style tests would be ugly.

How likely or easy is it for me to reframe the request for testing for
debug to be as
simple as:

`if debugBuild() {...}`

with `debugBuild` vended by the standard library instead of as a build
configuration test?

-- E

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Dmitri Gribenko) #12

I would like to update my draft proposal to introduce a test for debug configurations using a public function
rather than a build configuration test.

* Would the stdlib team be open to that?

No objections from me.

* What would be an appropriate name? `debugConfiguration`? `debugBuild`? `isDebugBuild`? `isDebugConfiguration`?

It seems like this API can be a property. "isDebug..." is a good
start, but a debug what? Build? Build configuration? I remember
Jordan was trying to rename the "build configuration" feature -- I
don't know where he arrived though.

OTOH, if you are willing to allow implementation complexity, you can
use '#if'-style conditional compilation, and allow arbitrary internal
and private APIs in the #if blocks. Just as long as uses are guarded
with same, we should be fine. I'm not sure if we want that user
model, though.

Dmitri

···

On Tue, Mar 15, 2016 at 9:31 AM, Erica Sadun <erica@ericasadun.com> wrote:

-- E

On Mar 15, 2016, at 10:21 AM, Dmitri Gribenko <gribozavr@gmail.com> wrote:

A function can absolutely can do that, if it is implemented using a
builtin known to the optimizer.

Dmitri

On Tue, Mar 15, 2016 at 9:20 AM, Shawn Erickson <shawnce@gmail.com> wrote:

You would likely want to ensure debug related code could be optimized away /
or not be included in release builds. I am not sure how a function would
achieve that.
On Tue, Mar 15, 2016 at 9:15 AM Erica Sadun via swift-evolution >>> <swift-evolution@swift.org> wrote:

On Mar 14, 2016, at 2:04 PM, Dmitri Gribenko <gribozavr@gmail.com> wrote:
Hi Erica,

Based on Joe's rationale that you are quoting, I think the intent is
that we want to restrict this directive to be statement-level only.
The API vended by a module should not be affected by the build mode.

Dmitri

Could the debug build test take the form of a standard non-private
function then
instead of _isDebugAssertConfiguration()? If the test is limited to
methods,
introducing #if-style tests would be ugly.

How likely or easy is it for me to reframe the request for testing for
debug to be as
simple as:

`if debugBuild() {...}`

with `debugBuild` vended by the standard library instead of as a build
configuration test?

-- E

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Erica Sadun) #13

I would like to update my draft proposal to introduce a test for debug configurations using a public function
rather than a build configuration test.

* Would the stdlib team be open to that?
* What would be an appropriate name? `debugConfiguration`? `debugBuild`? `isDebugBuild`? `isDebugConfiguration`?

-- E

···

On Mar 15, 2016, at 10:21 AM, Dmitri Gribenko <gribozavr@gmail.com> wrote:

A function can absolutely can do that, if it is implemented using a
builtin known to the optimizer.

Dmitri

On Tue, Mar 15, 2016 at 9:20 AM, Shawn Erickson <shawnce@gmail.com> wrote:

You would likely want to ensure debug related code could be optimized away /
or not be included in release builds. I am not sure how a function would
achieve that.
On Tue, Mar 15, 2016 at 9:15 AM Erica Sadun via swift-evolution >> <swift-evolution@swift.org> wrote:

On Mar 14, 2016, at 2:04 PM, Dmitri Gribenko <gribozavr@gmail.com> wrote:
Hi Erica,

Based on Joe's rationale that you are quoting, I think the intent is
that we want to restrict this directive to be statement-level only.
The API vended by a module should not be affected by the build mode.

Dmitri

Could the debug build test take the form of a standard non-private
function then
instead of _isDebugAssertConfiguration()? If the test is limited to
methods,
introducing #if-style tests would be ugly.

How likely or easy is it for me to reframe the request for testing for
debug to be as
simple as:

`if debugBuild() {...}`

with `debugBuild` vended by the standard library instead of as a build
configuration test?

-- E

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Shawn Erickson) #14

True. I was thinking to much in the content of the stdlib only but with a
builtin you can get things optimized away.

···

On Tue, Mar 15, 2016 at 9:22 AM Dmitri Gribenko <gribozavr@gmail.com> wrote:

A function can absolutely can do that, if it is implemented using a
builtin known to the optimizer.

Dmitri

On Tue, Mar 15, 2016 at 9:20 AM, Shawn Erickson <shawnce@gmail.com> wrote:
> You would likely want to ensure debug related code could be optimized
away /
> or not be included in release builds. I am not sure how a function would
> achieve that.
> On Tue, Mar 15, 2016 at 9:15 AM Erica Sadun via swift-evolution > > <swift-evolution@swift.org> wrote:
>>
>>
>>
>> On Mar 14, 2016, at 2:04 PM, Dmitri Gribenko <gribozavr@gmail.com> > wrote:
>> Hi Erica,
>>
>> Based on Joe's rationale that you are quoting, I think the intent is
>> that we want to restrict this directive to be statement-level only.
>> The API vended by a module should not be affected by the build mode.
>>
>> Dmitri
>>
>>
>>
>> Could the debug build test take the form of a standard non-private
>> function then
>> instead of _isDebugAssertConfiguration()? If the test is limited to
>> methods,
>> introducing #if-style tests would be ugly.
>>
>> How likely or easy is it for me to reframe the request for testing for
>> debug to be as
>> simple as:
>>
>> `if debugBuild() {...}`
>>
>> with `debugBuild` vended by the standard library instead of as a build
>> configuration test?
>>
>> -- E
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Brent Royal-Gordon) #15

I would like to update my draft proposal to introduce a test for debug configurations using a public function
rather than a build configuration test.

* Would the stdlib team be open to that?
* What would be an appropriate name? `debugConfiguration`? `debugBuild`? `isDebugBuild`? `isDebugConfiguration`?

I have a suggestion:

  if #isDebugBuild {
    ...
  }

That would allow you to capture a caller's debug setting, just as you can capture their file and line number:

  class Logger {
    enum LogLevel {
      case fatal, error, warn, info, debug, trace, off
    }
    
    init(logLevel: LogLevel) {
      ...
    }
    
    convenience init(debug: Bool = #isDebugBuild) {
      self.init(logLevel: debug ? .debug : .warn)
    }
    
    ...
  }

···

--
Brent Royal-Gordon
Architechies