{"version":3,"sources":["../node_modules/slugify/index.js","UrlManager.js","makeId.js","LocalStorage.js","Firestore.js","Book.js","Auth.js","enhanceTextarea.js","story.js"],"names":["name","root","factory","exports","module","define","amd","charMap","JSON","parse","replace","string","options","Error","replacement","slug","split","reduce","result","ch","remove","trim","lower","toLowerCase","extend","customMap","key","slugify","require","UrlManager","book","pageName","encode","str","encodeURIComponent","ret","id","encodeBookName","url","exec","command","decodeURIComponent","makeId","len","text","possible","i","charAt","Math","floor","random","length","LocalStorage","Book","localStorage","bookList","buildBookList","data","pagesStr","stringify","pages","pageCount","Object","keys","size","canEdit","Promise","resolve","reject","unpack","json","pack","filter","bl","push","created","firebase","firestore","Timestamp","now","saveBookList","console","log","startsWith","map","undefined","Firestore","db","settings","timestampsInSnapshots","FieldValue","serverTimestamp","owner","auth","currentUser","uid","user","collection","doc","get","then","exists","catch","err","singleAttemptSave","code","batch","bookListingRef","set","bookRef","commit","delete","where","querySnapshot","forEach","booklisting","localStorageDB","firestoreDB","urlManager","startMessage","loaded","m","description","title","fromBookAndPage","textToHtml","getPageText","loadWithStorage","storage","deleteBook","load","save","getAllBooks","booklistings","sort","a","b","l","books","deleteAllBooks","Auth","ui","firebaseui","AuthUI","uiConfig","callbacks","signInSuccessWithAuthResult","loginPending","credentialHelper","CredentialHelper","NONE","signInFlow","signInOptions","provider","GoogleAuthProvider","PROVIDER_ID","customParameters","prompt","EmailAuthProvider","requireDisplayName","tosUrl","privacyPolicyUrl","isPendingRedirect","signIn","fn","onAuthStateChanged","start","signOut","isMobileSafari","test","navigator","userAgent","enhanceTextarea","ta","cb","el","style","boxSizing","mozBoxSizing","overflowY","clone","cloneNode","$","css","position","width","scrollWidth","top","attr","parentNode","appendChild","minHeight","scrollHeight","adjustHeight","textareaElement","value","outerHeight","diff","parseInt","window","getComputedStyle","height","clientHeight","newHeight","max","getCursorY","pos","prop","slice","unbind","on","e","keyCode","shiftKey","metaKey","ctrlKey","preventDefault","scrollToCursor","elY","screenY","offset","scrollY","innerHeight","scrollTo","scrollX","focus","sitePages","router","listBooks","listPages","showPage","handleHashChange","document","location","hash","parts","getUrlParts","handleBook","href","history","replaceState","x","y","onpopstate","scrollPos","state","onhashchange","editPage","getPageHeader","click","savePage","back","textarea","val","showPanel","redirectIfNeeded","cannonicalUrl","endsWith","assign","className","show","hide","html","getPageHtml","tocText","toggle","ol","append","confirm","list","ul","addBook","newText","hasText","setPageText","onChange","signedIn","modal","transferAnyLocalBooks"],"mappings":"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","file":"story.83224489.map","sourceRoot":"..","sourcesContent":["\n;(function (name, root, factory) {\n  if (typeof exports === 'object') {\n    module.exports = factory()\n    module.exports['default'] = factory()\n  }\n  /* istanbul ignore next */\n  else if (typeof define === 'function' && define.amd) {\n    define(factory)\n  }\n  else {\n    root[name] = factory()\n  }\n}('slugify', this, function () {\n  /* eslint-disable */\n  var charMap = JSON.parse('{\"$\":\"dollar\",\"%\":\"percent\",\"&\":\"and\",\"<\":\"less\",\">\":\"greater\",\"|\":\"or\",\"¢\":\"cent\",\"£\":\"pound\",\"¤\":\"currency\",\"¥\":\"yen\",\"©\":\"(c)\",\"ª\":\"a\",\"®\":\"(r)\",\"º\":\"o\",\"À\":\"A\",\"Á\":\"A\",\"Â\":\"A\",\"Ã\":\"A\",\"Ä\":\"A\",\"Å\":\"A\",\"Æ\":\"AE\",\"Ç\":\"C\",\"È\":\"E\",\"É\":\"E\",\"Ê\":\"E\",\"Ë\":\"E\",\"Ì\":\"I\",\"Í\":\"I\",\"Î\":\"I\",\"Ï\":\"I\",\"Ð\":\"D\",\"Ñ\":\"N\",\"Ò\":\"O\",\"Ó\":\"O\",\"Ô\":\"O\",\"Õ\":\"O\",\"Ö\":\"O\",\"Ø\":\"O\",\"Ù\":\"U\",\"Ú\":\"U\",\"Û\":\"U\",\"Ü\":\"U\",\"Ý\":\"Y\",\"Þ\":\"TH\",\"ß\":\"ss\",\"à\":\"a\",\"á\":\"a\",\"â\":\"a\",\"ã\":\"a\",\"ä\":\"a\",\"å\":\"a\",\"æ\":\"ae\",\"ç\":\"c\",\"è\":\"e\",\"é\":\"e\",\"ê\":\"e\",\"ë\":\"e\",\"ì\":\"i\",\"í\":\"i\",\"î\":\"i\",\"ï\":\"i\",\"ð\":\"d\",\"ñ\":\"n\",\"ò\":\"o\",\"ó\":\"o\",\"ô\":\"o\",\"õ\":\"o\",\"ö\":\"o\",\"ø\":\"o\",\"ù\":\"u\",\"ú\":\"u\",\"û\":\"u\",\"ü\":\"u\",\"ý\":\"y\",\"þ\":\"th\",\"ÿ\":\"y\",\"Ā\":\"A\",\"ā\":\"a\",\"Ă\":\"A\",\"ă\":\"a\",\"Ą\":\"A\",\"ą\":\"a\",\"Ć\":\"C\",\"ć\":\"c\",\"Č\":\"C\",\"č\":\"c\",\"Ď\":\"D\",\"ď\":\"d\",\"Đ\":\"DJ\",\"đ\":\"dj\",\"Ē\":\"E\",\"ē\":\"e\",\"Ė\":\"E\",\"ė\":\"e\",\"Ę\":\"e\",\"ę\":\"e\",\"Ě\":\"E\",\"ě\":\"e\",\"Ğ\":\"G\",\"ğ\":\"g\",\"Ģ\":\"G\",\"ģ\":\"g\",\"Ĩ\":\"I\",\"ĩ\":\"i\",\"Ī\":\"i\",\"ī\":\"i\",\"Į\":\"I\",\"į\":\"i\",\"İ\":\"I\",\"ı\":\"i\",\"Ķ\":\"k\",\"ķ\":\"k\",\"Ļ\":\"L\",\"ļ\":\"l\",\"Ľ\":\"L\",\"ľ\":\"l\",\"Ł\":\"L\",\"ł\":\"l\",\"Ń\":\"N\",\"ń\":\"n\",\"Ņ\":\"N\",\"ņ\":\"n\",\"Ň\":\"N\",\"ň\":\"n\",\"Ő\":\"O\",\"ő\":\"o\",\"Œ\":\"OE\",\"œ\":\"oe\",\"Ŕ\":\"R\",\"ŕ\":\"r\",\"Ř\":\"R\",\"ř\":\"r\",\"Ś\":\"S\",\"ś\":\"s\",\"Ş\":\"S\",\"ş\":\"s\",\"Š\":\"S\",\"š\":\"s\",\"Ţ\":\"T\",\"ţ\":\"t\",\"Ť\":\"T\",\"ť\":\"t\",\"Ũ\":\"U\",\"ũ\":\"u\",\"Ū\":\"u\",\"ū\":\"u\",\"Ů\":\"U\",\"ů\":\"u\",\"Ű\":\"U\",\"ű\":\"u\",\"Ų\":\"U\",\"ų\":\"u\",\"Ź\":\"Z\",\"ź\":\"z\",\"Ż\":\"Z\",\"ż\":\"z\",\"Ž\":\"Z\",\"ž\":\"z\",\"ƒ\":\"f\",\"Ơ\":\"O\",\"ơ\":\"o\",\"Ư\":\"U\",\"ư\":\"u\",\"ǈ\":\"LJ\",\"ǉ\":\"lj\",\"ǋ\":\"NJ\",\"ǌ\":\"nj\",\"Ș\":\"S\",\"ș\":\"s\",\"Ț\":\"T\",\"ț\":\"t\",\"˚\":\"o\",\"Ά\":\"A\",\"Έ\":\"E\",\"Ή\":\"H\",\"Ί\":\"I\",\"Ό\":\"O\",\"Ύ\":\"Y\",\"Ώ\":\"W\",\"ΐ\":\"i\",\"Α\":\"A\",\"Β\":\"B\",\"Γ\":\"G\",\"Δ\":\"D\",\"Ε\":\"E\",\"Ζ\":\"Z\",\"Η\":\"H\",\"Θ\":\"8\",\"Ι\":\"I\",\"Κ\":\"K\",\"Λ\":\"L\",\"Μ\":\"M\",\"Ν\":\"N\",\"Ξ\":\"3\",\"Ο\":\"O\",\"Π\":\"P\",\"Ρ\":\"R\",\"Σ\":\"S\",\"Τ\":\"T\",\"Υ\":\"Y\",\"Φ\":\"F\",\"Χ\":\"X\",\"Ψ\":\"PS\",\"Ω\":\"W\",\"Ϊ\":\"I\",\"Ϋ\":\"Y\",\"ά\":\"a\",\"έ\":\"e\",\"ή\":\"h\",\"ί\":\"i\",\"ΰ\":\"y\",\"α\":\"a\",\"β\":\"b\",\"γ\":\"g\",\"δ\":\"d\",\"ε\":\"e\",\"ζ\":\"z\",\"η\":\"h\",\"θ\":\"8\",\"ι\":\"i\",\"κ\":\"k\",\"λ\":\"l\",\"μ\":\"m\",\"ν\":\"n\",\"ξ\":\"3\",\"ο\":\"o\",\"π\":\"p\",\"ρ\":\"r\",\"ς\":\"s\",\"σ\":\"s\",\"τ\":\"t\",\"υ\":\"y\",\"φ\":\"f\",\"χ\":\"x\",\"ψ\":\"ps\",\"ω\":\"w\",\"ϊ\":\"i\",\"ϋ\":\"y\",\"ό\":\"o\",\"ύ\":\"y\",\"ώ\":\"w\",\"Ё\":\"Yo\",\"Ђ\":\"DJ\",\"Є\":\"Ye\",\"І\":\"I\",\"Ї\":\"Yi\",\"Ј\":\"J\",\"Љ\":\"LJ\",\"Њ\":\"NJ\",\"Ћ\":\"C\",\"Џ\":\"DZ\",\"А\":\"A\",\"Б\":\"B\",\"В\":\"V\",\"Г\":\"G\",\"Д\":\"D\",\"Е\":\"E\",\"Ж\":\"Zh\",\"З\":\"Z\",\"И\":\"I\",\"Й\":\"J\",\"К\":\"K\",\"Л\":\"L\",\"М\":\"M\",\"Н\":\"N\",\"О\":\"O\",\"П\":\"P\",\"Р\":\"R\",\"С\":\"S\",\"Т\":\"T\",\"У\":\"U\",\"Ф\":\"F\",\"Х\":\"H\",\"Ц\":\"C\",\"Ч\":\"Ch\",\"Ш\":\"Sh\",\"Щ\":\"Sh\",\"Ъ\":\"U\",\"Ы\":\"Y\",\"Ь\":\"\",\"Э\":\"E\",\"Ю\":\"Yu\",\"Я\":\"Ya\",\"а\":\"a\",\"б\":\"b\",\"в\":\"v\",\"г\":\"g\",\"д\":\"d\",\"е\":\"e\",\"ж\":\"zh\",\"з\":\"z\",\"и\":\"i\",\"й\":\"j\",\"к\":\"k\",\"л\":\"l\",\"м\":\"m\",\"н\":\"n\",\"о\":\"o\",\"п\":\"p\",\"р\":\"r\",\"с\":\"s\",\"т\":\"t\",\"у\":\"u\",\"ф\":\"f\",\"х\":\"h\",\"ц\":\"c\",\"ч\":\"ch\",\"ш\":\"sh\",\"щ\":\"sh\",\"ъ\":\"u\",\"ы\":\"y\",\"ь\":\"\",\"э\":\"e\",\"ю\":\"yu\",\"я\":\"ya\",\"ё\":\"yo\",\"ђ\":\"dj\",\"є\":\"ye\",\"і\":\"i\",\"ї\":\"yi\",\"ј\":\"j\",\"љ\":\"lj\",\"њ\":\"nj\",\"ћ\":\"c\",\"џ\":\"dz\",\"Ґ\":\"G\",\"ґ\":\"g\",\"฿\":\"baht\",\"ა\":\"a\",\"ბ\":\"b\",\"გ\":\"g\",\"დ\":\"d\",\"ე\":\"e\",\"ვ\":\"v\",\"ზ\":\"z\",\"თ\":\"t\",\"ი\":\"i\",\"კ\":\"k\",\"ლ\":\"l\",\"მ\":\"m\",\"ნ\":\"n\",\"ო\":\"o\",\"პ\":\"p\",\"ჟ\":\"zh\",\"რ\":\"r\",\"ს\":\"s\",\"ტ\":\"t\",\"უ\":\"u\",\"ფ\":\"f\",\"ქ\":\"k\",\"ღ\":\"gh\",\"ყ\":\"q\",\"შ\":\"sh\",\"ჩ\":\"ch\",\"ც\":\"ts\",\"ძ\":\"dz\",\"წ\":\"ts\",\"ჭ\":\"ch\",\"ხ\":\"kh\",\"ჯ\":\"j\",\"ჰ\":\"h\",\"ẞ\":\"SS\",\"Ạ\":\"A\",\"ạ\":\"a\",\"Ả\":\"A\",\"ả\":\"a\",\"Ấ\":\"A\",\"ấ\":\"a\",\"Ầ\":\"A\",\"ầ\":\"a\",\"Ẩ\":\"A\",\"ẩ\":\"a\",\"Ẫ\":\"A\",\"ẫ\":\"a\",\"Ậ\":\"A\",\"ậ\":\"a\",\"Ắ\":\"A\",\"ắ\":\"a\",\"Ằ\":\"A\",\"ằ\":\"a\",\"Ẳ\":\"A\",\"ẳ\":\"a\",\"Ẵ\":\"A\",\"ẵ\":\"a\",\"Ặ\":\"A\",\"ặ\":\"a\",\"Ẹ\":\"E\",\"ẹ\":\"e\",\"Ẻ\":\"E\",\"ẻ\":\"e\",\"Ẽ\":\"E\",\"ẽ\":\"e\",\"Ế\":\"E\",\"ế\":\"e\",\"Ề\":\"E\",\"ề\":\"e\",\"Ể\":\"E\",\"ể\":\"e\",\"Ễ\":\"E\",\"ễ\":\"e\",\"Ệ\":\"E\",\"ệ\":\"e\",\"Ỉ\":\"I\",\"ỉ\":\"i\",\"Ị\":\"I\",\"ị\":\"i\",\"Ọ\":\"O\",\"ọ\":\"o\",\"Ỏ\":\"O\",\"ỏ\":\"o\",\"Ố\":\"O\",\"ố\":\"o\",\"Ồ\":\"O\",\"ồ\":\"o\",\"Ổ\":\"O\",\"ổ\":\"o\",\"Ỗ\":\"O\",\"ỗ\":\"o\",\"Ộ\":\"O\",\"ộ\":\"o\",\"Ớ\":\"O\",\"ớ\":\"o\",\"Ờ\":\"O\",\"ờ\":\"o\",\"Ở\":\"O\",\"ở\":\"o\",\"Ỡ\":\"O\",\"ỡ\":\"o\",\"Ợ\":\"O\",\"ợ\":\"o\",\"Ụ\":\"U\",\"ụ\":\"u\",\"Ủ\":\"U\",\"ủ\":\"u\",\"Ứ\":\"U\",\"ứ\":\"u\",\"Ừ\":\"U\",\"ừ\":\"u\",\"Ử\":\"U\",\"ử\":\"u\",\"Ữ\":\"U\",\"ữ\":\"u\",\"Ự\":\"U\",\"ự\":\"u\",\"Ỳ\":\"Y\",\"ỳ\":\"y\",\"Ỵ\":\"Y\",\"ỵ\":\"y\",\"Ỷ\":\"Y\",\"ỷ\":\"y\",\"Ỹ\":\"Y\",\"ỹ\":\"y\",\"‘\":\"\\'\",\"’\":\"\\'\",\"“\":\"\\\\\\\"\",\"”\":\"\\\\\\\"\",\"†\":\"+\",\"•\":\"*\",\"…\":\"...\",\"₠\":\"ecu\",\"₢\":\"cruzeiro\",\"₣\":\"french franc\",\"₤\":\"lira\",\"₥\":\"mill\",\"₦\":\"naira\",\"₧\":\"peseta\",\"₨\":\"rupee\",\"₩\":\"won\",\"₪\":\"new shequel\",\"₫\":\"dong\",\"€\":\"euro\",\"₭\":\"kip\",\"₮\":\"tugrik\",\"₯\":\"drachma\",\"₰\":\"penny\",\"₱\":\"peso\",\"₲\":\"guarani\",\"₳\":\"austral\",\"₴\":\"hryvnia\",\"₵\":\"cedi\",\"₹\":\"indian rupee\",\"₽\":\"russian ruble\",\"₿\":\"bitcoin\",\"℠\":\"sm\",\"™\":\"tm\",\"∂\":\"d\",\"∆\":\"delta\",\"∑\":\"sum\",\"∞\":\"infinity\",\"♥\":\"love\",\"元\":\"yuan\",\"円\":\"yen\",\"﷼\":\"rial\"}')\n  /* eslint-enable */\n\n  function replace (string, options) {\n    if (typeof string !== 'string') {\n      throw new Error('slugify: string argument expected')\n    }\n\n    options = (typeof options === 'string')\n      ? {replacement: options}\n      : options || {}\n\n    var slug = string.split('')\n      .reduce(function (result, ch) {\n        return result + (charMap[ch] || ch)\n          // allowed\n          .replace(options.remove || /[^\\w\\s$*_+~.()'\"!\\-:@]/g, '')\n      }, '')\n      // trim leading/trailing spaces\n      .trim()\n      // convert spaces\n      .replace(/[-\\s]+/g, options.replacement || '-')\n\n    return options.lower ? slug.toLowerCase() : slug\n  }\n\n  replace.extend = function (customMap) {\n    for (var key in customMap) {\n      charMap[key] = customMap[key]\n    }\n  }\n\n  return replace\n}))\n","const slugify = require('slugify');\n\nclass UrlManager {\n  constructor() {\n\n  }\n  fromBookAndPage(book, pageName) {\n    function encodeBookName(name) {\n      return slugify(name.toLowerCase());\n    }\n    const encode = str => encodeURIComponent(str);\n    let ret = `#books/${encode(book.id)}/${encodeBookName(book.name)}`;\n    if (pageName) {\n      ret += `/${encode(pageName.toLowerCase())}`;\n    }\n    return ret;\n  }\n  getUrlParts(url) {\n    let [,command,id,book,slug] = /^.*#(?:\\/?([^/]+)*)(?:\\/?([^/]+)*)?(?:\\/?([^/]+)*)(?:\\/?([^/]+)*)?|/.exec(url);\n    return {command,id,book:book&&decodeURIComponent(book),slug:slug&&decodeURIComponent(slug).toLowerCase()};\n  }\n}\n\nmodule.exports = UrlManager;\n","function makeId(len = 5) {\n  var text = \"\";\n  var possible = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\n\n  for (var i = 0; i < len; i++)\n    text += possible.charAt(Math.floor(Math.random() * possible.length));\n\n  return text;\n}\n\nmodule.exports = makeId;\n","const makeId = require(\"./makeId.js\");\n\nclass LocalStorage {\n  // TODO: fix LocalStorage requires Book\n  constructor(Book) {\n    this.Book = Book;\n    if (localStorage.bookList) {\n      this.bookList = JSON.parse(localStorage.bookList);\n    } else {\n      this.bookList = [];\n      this.buildBookList();\n    }\n  }\n\n  pack(data) {\n    var pagesStr = JSON.stringify(data.pages);\n    const book = {\n      name: data.name,\n      pages: data.pages,\n      pageCount: Object.keys(data.pages).length,\n      size: pagesStr.length,\n      id: data.id\n    };\n    return book;\n  }\n\n  unpack(data) {\n    data.canEdit = true;\n    return data;\n  }\n\n  load(id) {\n    return new Promise((resolve, reject) => {\n      var str = localStorage[\"book/\"+id];\n      if (!str) {\n        reject(new Error(`Couldn't load book ${id}`));\n      } else {\n        resolve(this.unpack(JSON.parse(str)));\n      }\n    });\n  }\n\n  // TODO: Saving someone else's book creates a new book but doesn't redirect\n  save(name, json) {\n    return new Promise(resolve => {\n      json.id = json.id || makeId();\n\n      const book = this.pack(json);\n\n      this.bookList = this.bookList.filter(bl => bl.id != json.id);\n\n      this.bookList.push({\n        name: book.name,\n        created: book.created || firebase.firestore.Timestamp.now(),\n        pageCount: book.pageCount,\n        size: book.size,\n        id: json.id\n      });\n\n      localStorage.bookList = JSON.stringify(this.bookList);\n      localStorage[\"book/\" + json.id] = JSON.stringify(book);\n      resolve();\n    });\n  }\n\n  getAllBooks() {\n    return new Promise(resolve => {\n      resolve(this.bookList);\n    });\n  }\n\n  saveBookList() {\n    localStorage.bookList = JSON.stringify(this.bookList);\n  }\n\n  deleteBook(json) {\n    this.bookList = this.bookList.filter(bl => bl.id != json.id);\n    delete localStorage[\"book/\"+json.id];\n    this.saveBookList();\n    return new Promise(resolve => resolve());\n  }\n\n  deleteAllBooks() {\n    this.bookList = [];\n    this.saveBookList();\n  }\n\n  // TODO: remove buildBookList() once Jesse's books are imported?\n  buildBookList() {\n    console.log(\"Undeleting books...\");\n    Object.keys(localStorage)\n    .filter(key => key.startsWith(\"book/\"))\n    .map(key => {\n      let json = JSON.parse(localStorage[key]);\n      json.pages = undefined;\n      this.bookList.push(json);\n    });\n    this.saveBookList();\n  }\n\n}\n\nmodule.exports = LocalStorage;\n","// https://stackoverflow.com/questions/1349404/generate-random-string-characters-in-javascript\n\nconst makeId = require('./makeId.js');\n\nclass Firestore {\n\n  constructor() {\n    this.db = firebase.firestore();\n\n    // Disable deprecated features\n    this.db.settings({\n      timestampsInSnapshots: true\n    });\n  }\n\n  pack(data) {\n    var pagesStr = JSON.stringify(data.pages);\n    const book = {\n      name: data.name,\n      pages: pagesStr,\n      created:  firebase.firestore.FieldValue.serverTimestamp(),\n      pageCount: Object.keys(data.pages).length,\n      size: pagesStr.length,\n      owner: firebase.auth().currentUser.uid,\n      id: data.id\n    };\n    return book;\n  }\n\n  unpack(data) {\n    let canEdit = false;\n    const user = firebase.auth().currentUser;\n    if (user) {\n      canEdit = (data.owner === user.uid);\n    }\n\n    if (data.json) {\n      console.log(\"Loading old format\");\n      const json = JSON.parse(data.json);\n      json.canEdit = canEdit;\n      return json;\n    } else if (data.pages) {\n      console.log(\"Loading new format\");\n      data.pages = JSON.parse(data.pages);\n      data.canEdit = canEdit;\n      return data;\n    } else {\n      throw(new Error(\"Can't read data\"));\n    }\n  }\n\n  load(id) {\n    return new Promise((resolve,reject) => {\n      this.db.collection(\"books\").doc(id).get()\n      .then(doc => {\n        if (doc.exists) {\n          const book = this.unpack(doc.data());\n          resolve(book);\n        } else {\n          reject(\"Book doesn't exist\");\n        }\n      })\n      .catch(err => {\n        reject(err);\n      });\n    });\n  }\n\n  // TODO: handle id collisions\n\n  save(name, json) {\n    return new Promise((resolve, reject) => {\n      this.singleAttemptSave(name, json)\n      .then(() => {\n        resolve();\n      })\n      .catch(err => {\n\n        if (err.code === \"permission-denied\") {\n\n          // Retry the save with a different id\n          // It's statistically impossible to get an id collision twice in a row\n          // so if it fails a second time something else is wrong\n\n          // singleAttemptSave() will give us a new id\n          delete json.id;\n\n          this.singleAttemptSave(name, json)\n          .then(() => {\n            resolve();\n          })\n          .catch(err => {\n            reject(err);\n          });\n        } else reject(err);\n      });\n    });\n  }\n\n  singleAttemptSave(name, json) {\n    const user = firebase.auth().currentUser;\n    if (!user) {\n      throw(\"Must be logged in to save\");\n    }\n\n    json.id = json.id || makeId();\n    json.name = name;\n    const id = json.id;\n\n    const book = this.pack(json);\n\n    // Get a new write batch\n    const batch = this.db.batch();\n\n    // save the booklisting\n    const bookListingRef = this.db.collection(\"booklistings\").doc(id);\n    batch.set(bookListingRef, {\n      name: book.name,\n      created: book.created,\n      owner: book.owner,\n      pageCount: book.pageCount,\n      size: book.size\n    });\n\n    // save the book\n    const bookRef = this.db.collection(\"books\").doc(id);\n    batch.set(bookRef, book);\n\n    // Commit the batch\n    return batch.commit();\n  }\n\n  deleteBook(json) {\n    const batch = this.db.batch();\n\n    // save the booklisting\n    const bookListingRef = this.db.collection(\"booklistings\").doc(json.id);\n    batch.delete(bookListingRef);\n\n    // save the book\n    const bookRef = this.db.collection(\"books\").doc(json.id);\n    batch.delete(bookRef);\n\n    // Commit the batch\n    return batch.commit();\n  }\n\n  getAllBooks() {\n    return new Promise((resolve) => {\n      this.db.collection(\"booklistings\")\n        .where(\"owner\", \"==\", firebase.auth().currentUser.uid)\n          .get()\n          .then((querySnapshot) => {\n            let ret = [];\n\n            // TODO: sort books by time created\n            querySnapshot.forEach((doc) => {\n              let booklisting = doc.data();\n              booklisting.id = doc.id;\n              ret.push(booklisting);\n            });\n            resolve(ret);\n          });\n        });\n  }\n}\n\nmodule.exports = Firestore;\n","const UrlManager = require(\"./UrlManager.js\");\nconst LocalStorage = require(\"./LocalStorage.js\");\nconst Firestore = require(\"./Firestore.js\");\n\nconst localStorageDB = new LocalStorage(Book);\nconst firestoreDB = new Firestore(Book);\n\nconst urlManager = new UrlManager();\n\nconst startMessage = \"\";\n\nclass Book {\n  constructor(id, name) {\n    // TODO: handle confusion of having name here and in json.name\n    this.id = id;\n    this.name = name;\n    this.loaded = false;\n\n    this.json = {\n      name: name,\n      pages: { \"start\": startMessage }\n    };\n  }\n  static list(currentUser) {\n    const storage = currentUser ? firestoreDB : localStorageDB;\n    return new Promise(resolve => {\n      storage.getAllBooks().then(booklistings => {\n        booklistings = booklistings.sort((a,b) => a.created < b.created ? 1 : -1);\n        resolve(booklistings.map(l => new Book(l.id, l.name)));\n      });\n\n    });\n  }\n  setPageText(pageName, text) {\n    if (!text) {\n      delete this.json.pages[pageName];\n      if (pageName === \"start\") {\n        this.json.pages[pageName] = startMessage;\n      }\n    } else {\n      this.json.pages[pageName] = text;\n    }\n    return this.json.pages[pageName] !== undefined;\n  }\n  getPageText(pageName) {\n    return this.json.pages[pageName] || \"\";\n  }\n  textToHtml(text) {\n    return text.replace(/\\[([^\\[\\]]+)\\](?:\\((.*?)\\))?/g, (m,description,title) => {\n      title = title || description;\n      return \"<a href='\"+urlManager.fromBookAndPage(this,title)+\"'>\"+description+\"</a>\";\n    });\n  }\n  getPageHtml(pageName) {\n    return this.textToHtml(this.getPageText(pageName));\n  }\n  getPageHeader(pageName) {\n    if (!pageName || pageName === \"start\") {\n      return this.name;\n    }\n    return pageName;\n  }\n  listPages() {\n    return Object.keys(this.json.pages);\n  }\n  load() {\n    return new Promise((resolve) => {\n      this.loadWithStorage(localStorageDB)\n      .then(resolve)\n      .catch(() => {\n        console.log(\"Loading from db\");\n        this.loadWithStorage(firestoreDB)\n        .then(resolve);\n      });\n    });\n  }\n\n  delete(currentUser) {\n    const storage = currentUser ? firestoreDB : localStorageDB;\n    return storage.deleteBook(this.json);\n  }\n\n  loadWithStorage(storage) {\n\n    return storage.load(this.id)\n      .then(json => {\n        this.id = json.id;\n        this.name = json.name;\n        this.json = json;\n        this.loaded = true;\n        this.canEdit = json.canEdit;\n      });\n  }\n\n  save(currentUser) {\n    const storage = currentUser ? firestoreDB : localStorageDB;\n    return storage.save(this.name, this.json)\n    .then(() => {\n      this.id = this.json.id;\n    });\n  }\n\n  static transferAnyLocalBooks(currentUser) {\n    localStorageDB.getAllBooks().then(books => {\n      books = books.map(booklisting => new Book(booklisting.id, booklisting.name));\n      if (books.length) {\n        localStorageDB.deleteAllBooks();\n        console.log(\"Transferring books to server\",books);\n        books.forEach(book => {\n          book.loadWithStorage(localStorageDB).then(() => book.save(currentUser));\n        });\n      }\n    });\n  }\n}\n\nmodule.exports = Book;\n","/* global firebaseui */\n\nclass Auth {\n  constructor() {\n    // Initialize the FirebaseUI Widget using Firebase.\n    this.ui = new firebaseui.auth.AuthUI(firebase.auth());\n\n    // FirebaseUI config.\n    var uiConfig = {\n      callbacks: { signInSuccessWithAuthResult: () => { this.loginPending = false; } },\n      credentialHelper: firebaseui.auth.CredentialHelper.NONE,\n      signInFlow: \"redirect\",\n      signInOptions: [\n        {\n          provider: firebase.auth.GoogleAuthProvider.PROVIDER_ID,\n          customParameters: {\n            prompt: 'select_account'\n          }\n        },\n        {\n          provider: firebase.auth.EmailAuthProvider.PROVIDER_ID,\n          customParameters: {\n            requireDisplayName: false\n          }\n        }\n      ],\n      tosUrl: '<your-tos-url>',\n      privacyPolicyUrl: '<your-privacy-policy-url>'\n    };\n\n    this.uiConfig = uiConfig;\n\n    this.loginPending = this.ui.isPendingRedirect();\n    if (this.ui.isPendingRedirect()) {\n      // Calling ui.start() here doesn't actually show the UI;\n      // It clears the isPendingRedirect flag, and starts doing whatever\n      // magic it does to process the actual federated login. When it's\n      // done the signInSuccessWithAuthResult() callback will be called,\n      // and then the onAuthStateChanged() callback\n      this.signIn();\n    }\n\n  }\n\n  onChange(fn) {\n    firebase.auth().onAuthStateChanged(user => {\n      let ret = !!user;\n      if (this.loginPending) {\n        ret = undefined;\n      }\n      fn(ret, user);\n    });\n  }\n\n  signIn() {\n    this.ui.start('#firebaseui-auth-container', this.uiConfig);\n  }\n\n  signOut() {\n    firebase.auth().signOut();\n  }\n\n  currentUser() {\n    return firebase.auth().currentUser;\n  }\n}\n\nmodule.exports = Auth;\n","function isMobileSafari() {\n  return /iP(ad|hone|od).+Version\\/[\\d\\.]+.*Safari/i.test(navigator.userAgent);\n}\n\nfunction enhanceTextarea(ta, cb) {\n  let el = ta.get(0);\n\n  // we need box-sizing: border-box, if the textarea has padding\n  el.style.boxSizing = el.style.mozBoxSizing = 'border-box';\n\n  // we don't need any scrollbars, do we? :)\n  el.style.overflowY = 'hidden';\n\n  let clone = el.cloneNode();\n  $(clone).css({position:\"absolute\",width: el.scrollWidth, top: -1000}).attr(\"disabled\", true);\n  // $(clone).css({position:\"absolute\",top:-1000}).attr(\"disabled\", true);\n  el.parentNode.appendChild(clone);\n\n  // the minimum height initiated through the \"rows\" attribute\n  var minHeight = el.scrollHeight;\n\n  // Adapted from http://bdadam.com/blog/automatically-adapting-the-height-textarea.html\n  // Added a clone to fix scrolling weirdness\n  function adjustHeight(textareaElement, minHeight) {\n    clone.value = el.value;\n    var outerHeight = parseInt(window.getComputedStyle(clone).height, 10);\n    var diff = outerHeight - clone.clientHeight;\n\n    // set the correct height\n    // el.scrollHeight is the full height of the content, not just the visible part\n    let newHeight = Math.max(minHeight, clone.scrollHeight + diff);\n    // if (newHeight!=outerHeight)\n    el.style.height = newHeight + 'px';\n  }\n\n  function getCursorY(el) {\n    const pos = $(el).prop(\"selectionStart\");\n    clone.value = el.value.slice(0,pos);\n    return clone.scrollHeight;\n  }\n\n  function scrollToCursor(el) {\n    const elY = getCursorY(el);\n    const pageY = elY + $(el).offset().top;\n    const screenY = pageY - window.window.scrollY;\n\n    if (screenY < 50 || screenY > window.innerHeight/2.5) {\n      window.scrollTo(window.scrollX, $(el).offset().top + getCursorY(el) - window.innerHeight/3);\n    }\n  }\n\n\n  ta\n  .unbind()\n  .on(\"input propertychange resize\", function() {\n    adjustHeight(el, minHeight);\n  })\n  .on(\"keydown\", function(e) {\n    if ((e.keyCode === 13 && e.shiftKey) // shift+return\n      ||\n      (e.key === \"s\" && e.metaKey) // cmd+s\n      ||\n      (e.key === \"s\" && e.ctrlKey)) // ctrl+s\n    {\n      cb;\n      e.preventDefault();\n      return true;\n    }\n  })\n  .on(\"blur\", () => {\n    // savePage(book, pageName);\n  });\n\n  if (isMobileSafari()) {\n    ta\n    .on(\"keyup click propertychange\", function () {\n      scrollToCursor(el, minHeight);\n    });\n  }\n\n    // we adjust height to the initial content\n    adjustHeight(el, minHeight);\n  ta.focus();\n}\n\n\nmodule.exports = enhanceTextarea;\n","\nconst UrlManager = require(\"./UrlManager.js\");\nconst Book = require(\"./Book.js\");\nconst Auth = require(\"./Auth.js\");\nconst enhanceTextarea = require(\"./enhanceTextarea.js\");\n\n\nconst sitePages = {\n  \"\": \"#books/1STFV/getting-started/introduction\",\n};\n\n\n$(function () {\n  const urlManager = new UrlManager();\n\n  function router(listBooks, listPages, showPage) {\n    let book;\n\n    function handleHashChange() {\n      window.scrollTo(0,0);\n\n      let url = document.location.hash;\n\n      if (sitePages[url]) {\n        url = sitePages[url];\n      }\n      var parts = urlManager.getUrlParts(url);\n\n      if (parts.command !== \"books\") {\n        document.location.href = \"#books\";\n        return;\n      }\n\n      const handleBook = () => {\n        if (parts.slug) {\n          showPage(book, parts.slug);\n        } else {\n          listPages(book);\n        }\n      };\n\n      if (parts.id) {\n        if (book && book.loaded && book.id === parts.id) {\n          handleBook();\n          return;\n        }\n        book = new Book(parts.id, parts.book);\n        book.load().then(handleBook);\n      } else {\n        listBooks();\n      }\n\n\n    }\n\n    restoreScrollPositionOnBackButton();\n\n    window.onhashchange = handleHashChange;\n    handleHashChange();\n  }\n\n  let scrollPos = {x:window.scrollX, y:window.scrollY};\n\n  function restoreScrollPositionOnBackButton() {\n    $(\"body\").on(\"click\",\"a\",() => {\n      history.replaceState({x:window.scrollX, y:window.scrollY}, null, document.location.href);\n      return true;\n    });\n\n    window.onpopstate = (e) => {\n      scrollPos = e.state || {x:0, y:0};\n    };\n  }\n\n\n  function addBook() {\n    var title = prompt(\"What's the title of your book?\");\n    if (title) {\n      var book = new Book(null, title);\n      book.save(auth.currentUser()).then(() => {\n        console.log(\"Saved \"+book.json.id);\n        document.location.href = urlManager.fromBookAndPage(book,\"start\");\n      });\n    }\n  }\n\n  function editPage(book, pageName) {\n    $(\".cs-pageTitle\").text(book.getPageHeader(pageName));\n\n    $(\".cs-saveButton\").unbind().click(() => {\n      savePage(book, pageName);\n      return false;\n    });\n    $(\".cs-cancelButton\").unbind().click(() => {\n      if (book.getPageText(pageName)) {\n        showPage(book, pageName);\n      } else {\n        window.history.back();\n      }\n      return false;\n    });\n\n\n    let text = book.getPageText(pageName);\n\n    const textarea = $(\".cs-pageTextarea\");\n\n    textarea.val(text);\n    showPanel(\".cs-editPanel\");\n\n    enhanceTextarea(textarea, () => savePage(book, pageName));\n    textarea.focus();\n  }\n\n  function redirectIfNeeded(book, pageName) {\n    if (sitePages[document.location.hash]) {\n      return false;\n    }\n    const cannonicalUrl = urlManager.fromBookAndPage(book, pageName);\n    if (!document.location.href.endsWith(cannonicalUrl)) {\n      console.log(\"Redirecting to \",cannonicalUrl);\n      return document.location.assign(cannonicalUrl);\n    }\n  }\n\n  function showPanel(className) {\n    $(\".cs-page\").show();\n    $(\".cs-panel\").hide();\n    $(className).show();\n    window.scrollTo(scrollPos.x, scrollPos.y);\n  }\n\n\n  function showPage(book, pageName) {\n    redirectIfNeeded(book, pageName);\n\n    var html = book.getPageHtml(pageName);\n    if (!html) {\n      editPage(book, pageName);\n      return;\n    }\n\n    let tocText = book.name;\n    if (pageName === \"start\") {\n      tocText = \"Table of Contents\";\n    }\n    $(\".cs-TOCLink\").text(tocText).attr(\"href\",urlManager.fromBookAndPage(book));\n    $(\".cs-pageTitle\").text(book.getPageHeader(pageName));\n    $(\".cs-pageText\").html(html);\n    $(\".cs-editButton\").unbind().click(() => {\n      editPage(book, pageName);\n      return false;\n    });\n\n    showPanel(\".cs-readPanel\");\n  }\n\n  function listPages(book) {\n    redirectIfNeeded(book);\n\n    $(\".cs-bookTitle\").text(book.name);\n    $(\".cs-deleteBookButton\").toggle(book.canEdit);\n\n    var ol = $(\".cs-pageList\").html(\"\");\n    book.listPages().forEach(function (name) {\n      let a = $(\"<a>\").attr(\"href\", urlManager.fromBookAndPage(book,name)).text(name);\n      ol.append($(\"<li>\").append(a));\n    });\n\n    $(\".cs-deleteBookButton\").unbind().click(() => {\n      const confirmed = confirm(`Are you sure you want to delete the book \"${book.name}\"?`);\n      if (confirmed) {\n        book.delete(auth.currentUser()).then(() => document.location.assign(\"#books\"));\n      }\n      return false;\n    });\n\n    showPanel(\".cs-listPagesPanel\");\n  }\n\n  function listBooks() {\n    Book.list(auth.currentUser()).then(books => {\n      var ul = $(\".cs-bookList\").html(\"\");\n      $(\".cs-noBooksAlert\").toggle(books.length === 0);\n      books.forEach(book => {\n        let a = $(\"<a>\").attr(\"href\", urlManager.fromBookAndPage(book)).text(book.name);\n        ul.append($(\"<li>\").append(a));\n      });\n      showPanel(\".cs-listBooksPanel\");\n    });\n    $(\".cs-newBookButton\").unbind().click(() => {\n      addBook();\n      return false;\n    });\n  }\n\n  function savePage(book, pageName) {\n    // TODO: explicitly pass textarea value to savePage()\n    let newText = $(\"textarea\").val();\n\n    if (newText === book.getPageText(pageName)) {\n      showPage(book, pageName);\n      return;\n    }\n\n    const hasText = book.setPageText(pageName,newText);\n\n    // TODO: hide write latency?\n    book.save(auth.currentUser())\n    .then(() => {\n      if (hasText) {\n        showPage(book, pageName);\n      } else {\n        window.history.back();\n        // listPages(book);\n      }\n    });\n  }\n\n\n  const auth = new Auth();\n  auth.onChange((signedIn) => {\n    $(\".cs-signIn\").toggle(signedIn === false);\n    $(\".cs-signOut\").toggle(signedIn === true);\n    $(\".cs-signingIn\").toggle(signedIn === undefined);\n  });\n  $(() => {\n    $(\".cs-signIn\").click(() => {\n      $('#cs-authModal').modal();\n      auth.signIn();\n      return false;\n    });\n\n    $(\".cs-signOut\").click(() => {\n      auth.signOut();\n      return false;\n    });\n  });\n\n  auth.onChange((signedIn) => {\n    $('#cs-authModal').modal('hide');\n    if (signedIn != undefined) {\n      if (signedIn) {\n        Book.transferAnyLocalBooks(auth.currentUser());\n      }\n      router(listBooks, listPages, showPage);\n    }\n  });\n\n});\n"]}