text:
const Solid = require('../../index')
const path = require('path')
const fs = require('fs-extra')
const { UserStore } = require('oidc-auth-manager')
const UserAccount = require('../../lib/models/user-account')
const SolidAuthOIDC = require('solid-auth-oidc')

const fetch = require('node-fetch')
const localStorage = require('localstorage-memory')
const url = require('url')
const URL = require('whatwg-url').URL
global.URL = URL
global.URLSearchParams = require('whatwg-url').URLSearchParams

const supertest = require('supertest')
const nock = require('nock')
const chai = require('chai')
const expect = chai.expect
chai.use(require('dirty-chai'))

// In this test we always assume that we are Alice

describe('Authentication API (OIDC)', () => {
  let alice, bob

  let aliceServerUri = 'https://localhost:7000'
  let aliceWebId = 'https://localhost:7000/profile/card#me'
  let configPath = path.join(__dirname, '../../config')
  let aliceDbPath = path.join(__dirname,
    '../resources/accounts-scenario/alice/db')
  let userStorePath = path.join(aliceDbPath, 'oidc/users')
  let aliceUserStore = UserStore.from({ path: userStorePath, saltRounds: 1 })
  aliceUserStore.initCollections()

  let bobServerUri = 'https://localhost:7001'
  let bobDbPath = path.join(__dirname,
    '../resources/accounts-scenario/bob/db')

  const serverConfig = {
    sslKey: path.join(__dirname, '../keys/key.pem'),
    sslCert: path.join(__dirname, '../keys/cert.pem'),
    auth: 'oidc',
    webid: true,
    multiuser: false,
    configPath
  }

  const aliceRootPath = path.join(__dirname, '../resources/accounts-scenario/alice')
  const alicePod = Solid.createServer(
    Object.assign({
      root: aliceRootPath,
      serverUri: aliceServerUri,
      dbPath: aliceDbPath
    }, serverConfig)
  )
  const bobRootPath = path.join(__dirname, '../resources/accounts-scenario/bob')
  const bobPod = Solid.createServer(
    Object.assign({
      root: bobRootPath,
      serverUri: bobServerUri,
      dbPath: bobDbPath
    }, serverConfig)
  )

  function startServer (pod, port) {
    return new Promise((resolve) => {
      pod.listen(port, () => { resolve() })
    })
  }

  before(() => {
    return Promise.all([
      startServer(alicePod, 7000),
      startServer(bobPod, 7001)
    ]).then(() => {
      alice = supertest(aliceServerUri)
      bob = supertest(bobServerUri)
    })
  })

  after(() => {
    alicePod.close()
    bobPod.close()
    fs.removeSync(path.join(aliceDbPath, 'oidc/users'))
    fs.removeSync(path.join(aliceRootPath, 'index.html'))
    fs.removeSync(path.join(aliceRootPath, 'index.html.acl'))
    fs.removeSync(path.join(bobRootPath, 'index.html'))
    fs.removeSync(path.join(bobRootPath, 'index.html.acl'))
  })

  describe('Provider Discovery (POST /api/auth/select-provider)', () => {
    it('form should load on a get', done => {
      alice.get('/api/auth/select-provider')
        .expect(200)
        .expect((res) => { res.text.match(/Provider Discovery/) })
        .end(done)
    })

    it('should complain if WebID URI is missing', (done) => {
      alice.post('/api/auth/select-provider')
        .expect(400, done)
    })

    it('should prepend https:// to webid, if necessary', (done) => {
      alice.post('/api/auth/select-provider')
        .type('form')
        .send({ webid: 'localhost:7000' })
        .expect(302, done)
    })

    it("should return a 400 if endpoint doesn't have Link Headers", (done) => {
      // Fake provider, replies with 200 and no Link headers
      nock('https://amazingwebsite.tld').intercept('/', 'OPTIONS').reply(204)

      alice.post('/api/auth/select-provider')
        .send('webid=https://amazingwebsite.tld/')
        .expect(400)
        .end(done)
    })

    it('should redirect user to discovered provider if valid uri', (done) => {
      bob.post('/api/auth/select-provider')
        .send('webid=' + aliceServerUri)
        .expect(302)
        .end((err, res) => {
          let loginUri = res.header.location
          expect(loginUri.startsWith(aliceServerUri + '/authorize'))
          done(err)
        })
    })
  })

  describe('Login page (GET /login)', () => {
    it('should load the user login form', () => {
      return alice.get('/login')
        .expect(200)
    })
  })

  describe('Login by Username and Password (POST /login/password)', () => {
    // Logging in as alice, to alice's pod
    let aliceAccount = UserAccount.from({ webId: aliceWebId })
    let alicePassword = '12345'

    beforeEach(() => {
      aliceUserStore.initCollections()

      return aliceUserStore.createUser(aliceAccount, alicePassword)
        .catch(console.error.bind(console))
    })

    afterEach(() => {
      fs.removeSync(path.join(aliceDbPath, 'users/users'))
    })

    describe('after performing a correct login', () => {
      let response, cookie
      before(done => {
        aliceUserStore.initCollections()
        aliceUserStore.createUser(aliceAccount, alicePassword)
        alice.post('/login/password')
          .type('form')
          .send({ username: 'alice' })
          .send({ password: alicePassword })
          .end((err, res) => {
            response = res
            cookie = response.headers['set-cookie'][0]
            done(err)
          })
      })

      it('should redirect to /authorize', () => {
        const loginUri = response.headers.location
        expect(response).to.have.property('status', 302)
        expect(loginUri.startsWith(aliceServerUri + '/authorize'))
      })

      it('should set the cookie', () => {
        expect(cookie).to.match(/connect.sid=/)
      })

      it('should set the cookie with HttpOnly', () => {
        expect(cookie).to.match(/HttpOnly/)
      })

      it('should set the cookie with Secure', () => {
        expect(cookie).to.match(/Secure/)
      })

      describe('and performing a subsequent request', () => {
        describe('without that cookie', () => {
          let response
          before(done => {
            alice.get('/')
              .end((err, res) => {
                response = res
                done(err)
              })
          })

          it('should return a 401', () => {
            expect(response).to.have.property('status', 401)
          })
        })

        describe('with that cookie and a non-matching origin', () => {
          let response
          before(done => {
            alice.get('/')
              .set('Cookie', cookie)
              .set('Origin', bobServerUri)
              .end((err, res) => {
                response = res
                done(err)
              })
          })

          it('should return a 401', () => {
            expect(response).to.have.property('status', 401)
          })
        })

        describe('with that cookie but without origin', () => {
          let response
          before(done => {
            alice.get('/')
              .set('Cookie', cookie)
              .end((err, res) => {
                response = res
                done(err)
              })
          })

          it('should return a 200', () => {
            expect(response).to.have.property('status', 200)
          })
        })

        describe('with that cookie and a matching origin', () => {
          let response
          before(done => {
            alice.get('/')
              .set('Cookie', cookie)
              .set('Origin', aliceServerUri)
              .end((err, res) => {
                response = res
                done(err)
              })
          })

          it('should return a 200', () => {
            expect(response).to.have.property('status', 200)
          })
        })
      })
    })

    it('should throw a 400 if no username is provided', (done) => {
      alice.post('/login/password')
        .type('form')
        .send({ password: alicePassword })
        .expect(400, done)
    })

    it('should throw a 400 if no password is provided', (done) => {
      alice.post('/login/password')
        .type('form')
        .send({ username: 'alice' })
        .expect(400, done)
    })

    it('should throw a 400 if user is found but no password match', (done) => {
      alice.post('/login/password')
        .type('form')
        .send({ username: 'alice' })
        .send({ password: 'wrongpassword' })
        .expect(400, done)
    })
  })

  describe('Two Pods + Browser Login workflow', () => {
    // Step 1: Alice tries to access bob.com/shared-with-alice.txt, and
    //   gets redirected to bob.com's Provider Discovery endpoint
    it('401 Unauthorized -> redirect to provider discovery', (done) => {
      bob.get('/shared-with-alice.txt')
        .expect(401)
        .end((err, res) => {
          if (err) return done(err)
          let redirectString = 'http-equiv="refresh" ' +
            `content="0; url=${bobServerUri}/api/auth/select-provider`
          expect(res.text).to.match(new RegExp(redirectString))
          done()
        })
    })

    // Step 2: Alice enters her pod's URI to Bob's Provider Discovery endpoint
    it('Enter webId -> redirect to provider login', () => {
      return bob.post('/api/auth/select-provider')
        .send('webid=' + aliceServerUri)
        .expect(302)
        .then(res => {
          // Submitting select-provider form redirects to Alice's pod's /authorize
          let authorizeUri = res.header.location
          expect(authorizeUri.startsWith(aliceServerUri + '/authorize'))

          // Follow the redirect to /authorize
          let authorizePath = url.parse(authorizeUri).path
          return alice.get(authorizePath)
        })
        .then(res => {
          // Since alice not logged in to her pod, /authorize redirects to /login
          let loginUri = res.header.location
          expect(loginUri.startsWith('/login'))
        })
    })
  })

  describe('Two Pods + Web App Login Workflow', () => {
    let aliceAccount = UserAccount.from({ webId: aliceWebId })
    let alicePassword = '12345'

    let auth
    let authorizationUri, loginUri, authParams, callbackUri
    let loginFormFields = ''
    let bearerToken

    before(() => {
      auth = new SolidAuthOIDC({ store: localStorage, window: { location: {} } })
      let appOptions = {
        redirectUri: 'https://app.example.com/callback'
      }

      aliceUserStore.initCollections()

      return aliceUserStore.createUser(aliceAccount, alicePassword)
        .then(() => {
          return auth.registerClient(aliceServerUri, appOptions)
        })
        .then(registeredClient => {
          auth.currentClient = registeredClient
        })
    })

    after(() => {
      fs.removeSync(path.join(aliceDbPath, 'users/users'))
      fs.removeSync(path.join(aliceDbPath, 'oidc/op/tokens'))

      let clientId = auth.currentClient.registration['client_id']
      let registration = `_key_${clientId}.json`
      fs.removeSync(path.join(aliceDbPath, 'oidc/op/clients', registration))
    })

    // Step 1: An app makes a GET request and receives a 401
    it('should get a 401 error on a REST request to a protected resource', () => {
      return fetch(bobServerUri + '/shared-with-alice.txt')
        .then(res => {
          expect(res.status).to.equal(401)

          expect(res.headers.get('www-authenticate'))
            .to.equal(`Bearer realm="${bobServerUri}", scope="openid webid"`)
        })
    })

    // Step 2: App presents the Select Provider UI to user, determine the
    //   preferred provider uri (here, aliceServerUri), and constructs
    //   an authorization uri for that provider
    it('should determine the authorization uri for a preferred provider', () => {
      return auth.currentClient.createRequest({}, auth.store)
        .then(authUri => {
          authorizationUri = authUri

          expect(authUri.startsWith(aliceServerUri + '/authorize')).to.be.true()
        })
    })

    // Step 3: App redirects user to the authorization uri for login
    it('should redirect user to /authorize and /login', () => {
      return fetch(authorizationUri, { redirect: 'manual' })
        .then(res => {
          // Since user is not logged in, /authorize redirects to /login
          expect(res.status).to.equal(302)

          loginUri = new URL(res.headers.get('location'))
          expect(loginUri.toString().startsWith(aliceServerUri + '/login'))
            .to.be.true()

          authParams = loginUri.searchParams
        })
    })

    // Step 4: Pod returns a /login page with appropriate hidden form fields
    it('should display the /login form', () => {
      return fetch(loginUri.toString())
        .then(loginPage => {
          return loginPage.text()
        })
        .then(pageText => {
          // Login page should contain the relevant auth params as hidden fields

          authParams.forEach((value, key) => {
            let hiddenField = `<input type="hidden" name="${key}" id="${key}" value="${value}" />`

            let fieldRegex = new RegExp(hiddenField)

            expect(pageText).to.match(fieldRegex)

            loginFormFields += `${key}=` + encodeURIComponent(value) + '&'
          })
        })
    })

    // Step 5: User submits their username & password via the /login form
    it('should login via the /login form', () => {
      loginFormFields += `username=${'alice'}&password=${alicePassword}`

      return fetch(aliceServerUri + '/login/password', {
        method: 'POST',
        body: loginFormFields,
        redirect: 'manual',
        headers: {
          'content-type': 'application/x-www-form-urlencoded'
        },
        credentials: 'include'
      })
        .then(res => {
          expect(res.status).to.equal(302)
          let postLoginUri = res.headers.get('location')
          let cookie = res.headers.get('set-cookie')

          // Successful login gets redirected back to /authorize and then
          // back to app
          expect(postLoginUri.startsWith(aliceServerUri + '/authorize'))
            .to.be.true()

          return fetch(postLoginUri, { redirect: 'manual', headers: { cookie } })
        })
        .then(res => {
          // User gets redirected back to original app
          expect(res.status).to.equal(302)
          callbackUri = res.headers.get('location')
          expect(callbackUri.startsWith('https://app.example.com#'))
        })
    })

    // Step 6: Web App extracts tokens from the uri hash fragment, uses
    //  them to access protected resource
    it('should use id token from the callback uri to access shared resource', () => {
      auth.window.location.href = callbackUri

      let protectedResourcePath = bobServerUri + '/shared-with-alice.txt'

      return auth.initUserFromResponse(auth.currentClient)
        .then(webId => {
          expect(webId).to.equal(aliceWebId)

          return auth.issuePoPTokenFor(bobServerUri, auth.session)
        })
        .then(popToken => {
          bearerToken = popToken

          return fetch(protectedResourcePath, {
            headers: {
              'Authorization': 'Bearer ' + bearerToken
            }
          })
        })
        .then(res => {
          expect(res.status).to.equal(200)

          return res.text()
        })
        .then(contents => {
          expect(contents).to.equal('protected contents\n')
        })
    })

    it('should not be able to reuse the bearer token for bob server on another server', () => {
      let privateAliceResourcePath = aliceServerUri + '/private-for-alice.txt'

      return fetch(privateAliceResourcePath, {
        headers: {
          // This is Alice's bearer token with her own Web ID
          'Authorization': 'Bearer ' + bearerToken
        }
      })
        .then(res => {
          // It will get rejected; it was issued for Bob's server only
          expect(res.status).to.equal(403)
        })
    })
  })

  describe('Post-logout page (GET /goodbye)', () => {
    it('should load the post-logout page', () => {
      return alice.get('/goodbye')
        .expect(200)
    })
  })
})


text:
Namestnik načelnika Združenega štaba oboroženih sil ZDA (angleško Vice Chairman of the Joint Chiefs of Staff) je drugi najvišji pripadnik ameriških oboroženih sil; v primeru odsotnosti načelnika vodi on Združeni štab oboroženih sil ZDA. Položaj je bil ustanovljen z Goldwater-Nicholsonovom zakonom.

Seznam

Združeni štab oboroženih sil ZDA

redpajama_set_name: RedPajamaWikipedia


text:
9,468,435,411 is an odd composite number composed of three prime numbers multiplied together.
9468435411 is an odd composite number. It is composed of three distinct prime numbers multiplied together. It has a total of sixteen divisors.
33 × 2153 × 162881
(3 × 3 × 3 × 2153 × 162881)
Cardinal: 9468435411 can be written as Nine billion, four hundred sixty-eight million, four hundred thirty-five thousand, four hundred eleven.
Sum of prime factors: 165037
1 3 9 27 2153 6459 19377 58131 162881 488643 1465929 4397787 350682793 1052048379 3156145137 9468435411
Sum of all divisors σ(n): 14033913120
Sum of proper divisors (its aliquot sum) s(n): 4565477709
9468435411 is a deficient number, because the sum of its proper divisors (4565477709) is less than itself. Its deficiency is 4902957702
Binary: 10001101000101110011011011110100112
Hexadecimal: 0x2345CDBD3
Base-36: 4CL9FIR
9468435411 squared (94684354112) is 89651269132278738921
9468435411 cubed (94684354113) is 848857251293159254722020331531
The square root of 9468435411 is 97305.8857983421
9,468,435,411 seconds is equal to 301 years, 3 weeks, 3 days, 8 hours, 56 minutes, 51 seconds.
To count from 1 to 9,468,435,411 would take you about six hundred two years!
A cube with a volume of 9468435411 cubic inches would be around 176.3 feet tall.
Keywords: Divisors of 9468435411, math, Factors of 9468435411, curriculum, school, college, exams, university, Prime factorization of 9468435411, STEM, science, technology, engineering, physics, economics, calculator, nine billion, four hundred sixty-eight million, four hundred thirty-five thousand, four hundred eleven.

redpajama_set_name: RedPajamaCommonCrawl


text:
Hasbro Will Not be Revealing Toys From 'Rogue One' At New York Toy Fair
Hasbro announced today that they will not be publicly revealing any toys from this year's Rogue One: A Star Wars Story at New York Toy Fair, which takes place next weekend. The company released a statement saying,
"We wanted to let you know that there will be no toys based on Rogue One: A Star Wars Story shown at Toy Fair this year. While there will be a small selection of new Star Wars toys revealed at Toy Fair and in the days leading up to it, none of them will be directly based on the new characters from the upcoming film.
We know that there's a huge amount of anticipation for Star Wars toys this year, and we wanted to be forthcoming about this as we know it might make a difference for some of you in regards to travel plans. We're extremely excited for the year ahead and we look forward to working with each of you throughout the year."
We're seeing history repeat itself with this announcement. Last year, Hasbro informed fans that toys from The Force Awakens would not be featured at Toy Fair 2015. This statement seems to indicate that Lucasfilm and Disney are following a similar marketing strategy for Rogue One that they did for The Force Awakens, where the majority of the toys, with the exception of the Black Series Stormtrooper (which was a San Diego Comic Con exclusive) and the Black Series 6" scale First Order TIE Fighter (which was revealed at SDCC), were not revealed until the week before Force Friday in September.
I have to say, I'm disappointed by this news. While the release of The Force Awakens toys certainly was unique (the 24 hour live stream, unboxing event was especially fun), there were several issues with leaks and distribution (it was, and in some places still is, very difficult to find The Force Awakens toys after the initial rush of Force Friday, not to mention the amount of product available on Force Friday was disappointing). I had hoped that the presence of a display of Rogue One costumes at Nuremberg Toy Fair meant that things would be different this time around and that the promotion for Rogue One (for which there has been less than there had been for The Force Awakens at this point last year) would be getting going. I love the premise of Rogue One and am anxious to get a look at the film and learn more about these new characters. Not to mention the fact that there is far less general awareness about Rogue One than there was about The Force Awakens and Toy Fair (maybe paired with a Super Bowl ad) seemed like a perfect time to kick off the promotion. However, right now we'll have to settle for vague reports from behind closed door displays at Nuremberg Toy Fair.
Hopefully, this means there is something else cool in store from Hasbro and the other licensees. The advantage this Toy Fair has over last year's is that we are hot of the heels of the release of The Force Awakens and there are still many characters (Leia, Maz, Snoke, etc.) that have yet to be released as figures. We could still have a weekend of cool announcements in store.
Source: Furious Fanboys
Anthology Films News Collecting Collecting News Dominic Jones News Rogue One News Stand Alone Films
Handbag said...
"none of them will be directly based on the new characters from the upcoming film". The new characters. That gives me hope that legacy characters featuring will be toy'd...


Gaza: Between this Massacre and the Next One… What is to be done?
I. Historical Roots of the Conflict: When a Historian Lies!
Palestinian infants, women, men and fighters are under the Zionist fire day and night, but their resistance is still defiant.
UN DILEMA DE ESTE TIEMPO: ¿NUEVO CAPITALISMO O SOCIALISMO?
As so often, the term 'terrorism' has proved a rhetorical smokescreen under cover of which the strong crush the weak.
Interview with Egyptian economist Samir Amin.


text:
How to Manage Renovation Expectations
Home>Ideas | More in Modern
A 1930 House Gets a Vintage-Modern Remodel
A 1930 house gets an unexpected update in the hands of two creatives with an eye for mid-century finds
By Deborah Baldwin of This Old House magazine
Photo by Ellen McDermott
You can't always get what you want. But in the course of trying, you may get something even better.
That's how two big-city dwellers, Nick and Heidi Gamma, woke up one day in a Depression-era house in an exurban town they had barely heard of before they pushed their search to the outer limits of commutability.
Shown: The traditional dining room proves a perfect foil for a vintage Heywood-Wakefield dining table, first issued in 1948, and a handful of Heywood-Wakefield chairs. The candleholders were made by homeowner Heidi Gamma's grandfather. Original 1930 corner cabinets hold vintage dinnerware; framed mid-century jazz-album covers hang on one wall.
Chair fabric: Dwell Studio
Curtains: Crate & Barrel
Ceiling fixture: Rejuvenation
Paint (walls): Benjamin Moore's Horizon
Gammas at the Hearth
In terms of where to look, "we were winging it—we looked at about eighty houses," says Heidi, recalling their ever-widening hunt for something larger than the overstuffed 700-square-foot apartment they were renting in Queens, New York. "We needed to be out of the city. We just needed closets."
As a longtime collector of vintage movie posters and radio/turntable consoles and a certain type of honey-colored yellow birch furniture made by Heywood-Wakefield in the 1940s and '50s, Nick wasn't exactly in the market for a stone-and-clapboard house with a storybook roofline. Neither was Heidi. "We're huge mid-century lovers," she says. "We would have loved a really cool 1950s ranch."
Shown: Nick and Heidi Gamma with their daughter, Lilly, then 10, and Cooper, their bichon frise.
Vintage armchair: Heywood-Wakefield
Composed Living
But in the early 2000s such cool classics were pricey. The couple didn't have deep pockets—Nick was art directing and designing music CDs at the time, and Heidi worked in textile design. And they were thinking about having a baby. For two years they pored over listings looking for a place they both liked and could also afford, finally detouring to Trumbull, Connecticut, and a well-preserved earlier-period house—which suddenly felt just right. Situated on a nice lot not far from a train station, it held well-proportioned rooms, hardwood floors, and original details, including a wall-hung sink with legs and a tiled tub alcove in the one full bath. The house also offered a half bath and 1,076 more square feet than they had in the city—"a crazy amount of space," Nick recalls naively thinking at the time.
Shown: Vintage lamps and Heywood-Wakefield chairs and tables mingle with newer upholstered pieces in the serenely composed living room. Claiming the mantel are family photos and heirlooms and a letterpress print.
Rug: nuLoom
Paint: Behr's Toasty Gray (walls) and Benjamin Moore's White (trim)
Modern Hutch
There was no master suite, the previous owner made vague references to "minor puddling" in the basement, and the relatively new kitchen was not precisely to the couple's taste. But the house did have two floors, three bedrooms, and access to good schools and public parks—potent draws even when daughter Lilly, now 12, was still just a gleam. The couple said yes, picturing an easy rearrangement of their vintage finds in more spacious, freshly painted rooms.
Shown: A mid-century-modern hutch in the living room holds collectibles, including Russel Wright tableware and a selection of British pottery.
Hi-Fi Center
Heidi, who reveres old houses, recalls joy at finding many things right where the original builder had left them. She admits to being a bit obsessed. "I've always wondered if it was a kit house, and what was going on in 1930," she says. "It's not a Tudor Revival, and it has a center-hall Colonial layout. Maybe English Cottage-Style Colonial?"
Though a rear addition went in around 1950, for the most part previous owners had worked to maintain the house without letting it go. Not everyone would find this ideal, but "we're big fans of keeping the original integrity," Heidi says. "You're not going to find that original 1930 mud-wall-type tiling now, and you'll never get it back again. If something is functional, then I want to preserve a little history."
Shown: Homeowner Nick has a weakness for mid-century hi-fi and likes to crank up one of two vinyl-record-playing consoles, much to the bemusement of his daughter.
The couple were also determined to keep the existing layout, rather than tear it apart and open it up, as is the fashion. "I can see the desire to live in a more modern way, but I don't think this house lends itself to it—there aren't enough walls!" Heidi says.
But before they could settle in and enjoy the way their Heywood-Wakefield beauties played off the golden finish on the oak floors, they had to put their first personal touch on the one space no one sees—the basement, where it turned out "puddling" was a euphemism for "you may need a sump pump." After one particularly hard rain, Heidi was on the phone with a mason, who had to dig out and paper and tar the culprit wall. He also had to regrade part of the backyard and lay down a French drain. "Then he added basement window wells," Heidi continues. "Then he regraded another part of the yard and built a stone barrier with drainage against the back of the house."
Shown: Enlarged by previous owners to hold a breakfast nook, over time the kitchen needed only new appliances. Brushed-aluminum Kromex canisters and a pot rack add to the period mix. Throughout, says homeowner Heidi, "we worked hard to make the juxtapositions work."
Range and microwave: Kenmore
Rug: Dash & Albert
Paint: Benjamin Moore's Linen White (walls) and Roasted Sesame Seed (wainscot)
Color-Filled Cabinets
The clapboard siding called out for paint; porch columns and window trim needed work. Gradually, the couple's hands-off M.O. became more hands-on. Wintry ice dams led to leaks over the family room. The homeowners ordered up a roofer and fiberglass-asphalt shingles advertised as "heavyweight and extra strong," and added a 3-foot ice shield over the family room and along drip edges.
Shown: Existing cabinets coincidentally complement the homeowners' colorful collection of Fiestaware, Pyrex, and Jadite.
Quirky Tile
As time wore on, kitchen appliances had to be replaced, along with the upstairs toilet and the chimney's cracked lining. The dryer vent was not to code and had to be replaced and rerouted; the septic system became passé when the town supplied a sewer line. And then there was the new furnace, water heater, attic fan—and central AC.
Shown: The quirky tile complements the homeowners' colorful collection of Fiestaware, Pyrex, and Jadite.
Chevron Bedroom Wall
Which brings us to other water-related issues that sprang up in a house that was built, after all, some 17 years before you could buy a single-handle sink faucet. Along with the usual drips—the kind an apartment dweller can usually get the super to fix—the couple faced a phantom leak inside a wall behind charming peach and black bath tile. They really didn't want to replace the tile; as Nick puts it, "People either love it or hate it, but for me it is personal. It reminds me of my grandmother."
Shown: Daughter Lilly's room has an accent wall painted by her mom. "I nearly lost my mind," Heidi says of neatening the chevron lines. The nightstand is an heirloom.
Artwork: Tad Carpenter
Bedding: Pine Cone Hill
Lamp: Target
Lilly's Guitar
They turned to "this wonderful, patient plumber," Heidi says, referring to an enabler with more sympathy for a crazy quest than your average tradesman.
"It was challenging—Heidi wanted to keep it the way it was back in the day; you know she's pretty set on that," says philosopher-plumber Joe Tassitano, whose general observation vis-à-vis older houses is, "Each one has its quirks." After gingerly punching out a bit of tile and poking around, he tracked down the problem to a hole in a 1930 galvanized fitting. He was so taken aback by its location—"where it would never in a million years wear out"—he sent photos to his plumber friends.
Shown: The guitar belongs to Lilly, who plays double bass and ukulele as well.
Shelving: IKEA
More challenging was the full bath's American Standard China Shelfback sink, whose own leaks Tassitano traced to the faucet handles and fittings. Heidi wanted to save them. "We had to saw the valves off," Tassitano recalls, "and take the faucet apart and measure the length and diameter of the fittings and go online to find a company that still manufactures stuff like that. Then we had to match everything up and put it together."
Shown: Crisply patterned fabrics in a second-floor-landing alcove create a focal point that is visible from the front door.
Mixed in among these projects was the fun stuff, namely smartening up the decor as only two designers would know how to do. Over time, plaster walls and ceilings were restored and painted; the wood paneling in the family room was softened by a coat of pale gray-taupe. Heidi, with a hand from her mother-in-law, reupholstered weathered seating. New lighting gave existing spaces a lift.
Shown: In the master bedroom, a vintage Saul Bass–designed movie poster for Love in the Afternoon hangs over a bed flanked by lamps with vintage fiberglass shades; the artwork on the adjacent wall is by Tad Carpenter.
Lamp bases: IKEA
Paint (walls): Benjamin Moore's Classic Gray
Peachy Bath
The household evolved, too, adding a rescued bichon frise, Cooper, about four years ago. Nick went to work as design director of an in-house creative and strategy group at Viacom; he also moonlights out of an armoire in the family room. Heidi continues as a freelance textile designer—and could probably qualify as a general contractor, a good thing given the state of the vintage tub fittings. "The plumber is running from me," she jokes.
Shown: Working with a sympathetic plumber, the homeowners replaced the toilet and fixed leaks in the one full bath while preserving its original sink, faucets, and peach and black tile.
Toilet: Gerber
Sconces: Rejuvenation
Window blind: Pottery Barn
There's also the couple's dream of adding on. At first sight 1,700 square feet was "awesome," Nick says,"and now it's a little small. We would love to extend the family room, with a master bedroom above. Then Lilly could take our bedroom, and I would have a studio."
But that's in the distant future for the owners of a starter house that is beginning to look an awful lot like a forever house.
"We've been in the house 15 years," Nick says, and between its unique mix of old and new, and the town's schools, family-friendly vibe, and ample green space, "we love it here."
Shown: The reproduction shower fittings and the shower door are new. The tub and its fittings are original.
The homeowners drew from their collection of vintage wares to backdate a newish breakfast nook renovated by previous owners.
Dutch Door
The Dutch door in the front entry is believed to be original to the house.
Paint: Behr's Roasted Pepper (door); Sherwin-Williams's Macadamia (siding) and Extra White (trim)
Bath Circa 1930
Reproduction faucet parts and a willing plumber allowed the homeowners to preserve the original sink and faucet in the 1930 bath upstairs.
Corner Cupboards
Space-age Starburst china, made by Franciscan in the 1950s, fills one of the two original corner cupboards in the dining room.
Colorful tube radios and other collectibles brighten shelves in the family room.
The homeowners preserved the existing layout and many of the finishes in the three-bedroom, one-and-a-half-bath house, built in 1930. The rear family-room addition dates to about 1950.
More in Mid-century Modern Style and Modern
Civic-minded homeowners help resurrect a 1903 house in the heart of downtown, enlivening it with color and pattern to...
Phoenix Remodel Rising
This house wasn't what the homeowners were looking for—but it ended up being just what they wanted
An Eclectic 1930s House in L.A.
With its low-slung lines, streamlined interior, and openness to the outdoors, a refreshed 1955 house fully embraces...
A Modern Home for Lovers of the Great Outdoors
A free-flowing 1959 house with a lofty interior rises to the next level in the hands of two detail-obsessed owners
Mid-century Mastery House Tour
Used to designing for a fast sale, a real estate pro ignores the rules and remakes a 1930 house to fit his family—and...
1930s House Remodel: One of a Kind
A dilapidated 1927 house regains its serene period spirit, thanks to a meticulous do-it-yourself remodel
A DIY Renovation Becomes a Family Project
Ask TOH | Driveway, Shaker Table
This Old House TV
Arlington Arts & Crafts | Decorative Touches Make a Difference