From 506eac507f74ec9620f305587c1cbf913d645516 Mon Sep 17 00:00:00 2001
From: Jeremy Kauffman <jeremy@lbry.io>
Date: Fri, 30 Nov 2018 11:26:58 -0500
Subject: [PATCH 01/29] proposed readme changes

---
 README.md | 48 ++++++++++++++++++++----------------------------
 1 file changed, 20 insertions(+), 28 deletions(-)

diff --git a/README.md b/README.md
index 009ba6ae..25160d4f 100644
--- a/README.md
+++ b/README.md
@@ -1,19 +1,15 @@
 # Spee.ch
-Spee.ch is a [NodeJS](https://nodejs.org) React web app that reads and publishes images and videos to and from the [LBRY](https://lbry.io/) blockchain.
+Spee.ch is a [NodeJS](https://nodejs.org) React web app that reads and publishes images, videos and other assets to and from the [LBRY](https://lbry.io/) blockchain.
 
-You can create your own custom version of spee.ch by installing this code base and then creating your own custom components and styles to override the defaults. (More details/guide on how to do that coming soon.)
+Succinctly, via spee.ch, you can have a user-friendly, custom-designed image and video hosting site that is backed by a decentralized network. Via just a set of config files, you can spin your entire site back up including assets, with no backing up necessary.
 
-Spee.ch depends on two other lbry technologies:
-  * [chainquery](https://github.com/lbryio/chainquery) - a normalized database of the blockchain data.  We've provided credentials to use a public chainquery service. You can also install it on your own server to avoid being affected by the commons.
-  * [lbrynet](https://github.com/lbryio/lbry) - a daemon that handles your wallet and transactions.
-![App GIF](https://spee.ch/e/speechgif.gif)
+## Installation
 
-## Install
+### Ubuntu Step-by-Step
 
-### Ubuntu Step by Step
-[Ubuntu Install Guide](./docs/ubuntuinstall.md)
+[Step-by-step Ubuntu Install Guide](./docs/ubuntuinstall.md)
 
-### Quickstart Overview
+### Full Instructions
 
 #### Get some information ready:
   * mysqlusername
@@ -21,7 +17,7 @@ Spee.ch depends on two other lbry technologies:
   * domainname or 'http://localhost'
   * speechport = 3000
 
-#### Install and Set Up System Dependencies:
+#### Install and Set Up Dependencies
   * Firewall open ports
     * 22
     * 80
@@ -49,7 +45,7 @@ Spee.ch depends on two other lbry technologies:
     * _note: even running on http://localhost, you must redirect http or https to port 3000_
 
 
-#### Clone a spee.ch repo (choose one)
+#### Clone spee.ch
   * release version for stable production
 ```
 $ git clone -b release https://github.com/lbryio/spee.ch.git
@@ -95,8 +91,8 @@ Check out the [customization guide](https://github.com/lbryio/spee.ch/blob/readm
 
 #### (optional) add custom components and update the styles
 
-  * Create custom components by creating React components in `site/custom/src/` (further instructions coming soon)
-  * Update the CSS by changing the files in `site/custom/scss` (further instructions and refactor coming soon)
+  * Create custom components by creating React components in `site/custom/src/`
+  * Update or override the CSS by changing the files in `site/custom/scss`
 
 #### (optional) install your own chainquery
 Instructions are coming at [lbry-docker] to install your own chainquery instance using docker-compose. This will require 50GB of preferably SSD space and at least 10 minutes to download, possibly much longer.
@@ -222,7 +218,8 @@ Spee.ch also runs a sync tool, which decodes blocks from the `LBRY` blockchain a
   *  To run only tests that do not require LBC, run `npm run test:no-lbc`
 
 ### URL formats
-Spee.ch has a few types of URL formats that return different assets from the LBRY network.  Below is a list of all possible URLs for the content on spee.ch
+Spee.ch has a few types of URL formats that return different assets from the LBRY network.  Below is a list of all possible URLs for the content on spee.ch. You can learn more about LBRY URLs [here](https://lbry.tech/resources/uri).
+
 * retrieve the controlling `LBRY` claim:
   * https://spee.ch/`claim`
   * https://spee.ch/`claim`.`ext` (serve)
@@ -240,22 +237,17 @@ Spee.ch has a few types of URL formats that return different assets from the LBR
   * https://spee.ch/`@channel`:`channel_id`/`claim`
   * https://spee.ch/`@channel`:`channel_id`/`claim`.`ext` (serve)
 
+### Dependencies
+
+Spee.ch depends on two other lbry technologies:
+  * [chainquery](https://github.com/lbryio/chainquery) - a normalized database of the blockchain data.  We've provided credentials to use a public chainquery service. You can also install it on your own server to avoid being affected by the commons.
+  * [lbrynet](https://github.com/lbryio/lbry) - a daemon that handles your wallet and transactions.
+![App GIF](https://spee.ch/e/speechgif.gif)
+
+
 ### Bugs
 If you find a bug or experience a problem, please report your issue here on GitHub and find us in the lbry discord!
 
-### Issue tags in this repo
-#### level 1
-Issues that anyone with basic web development can handle; little-to-no experience with the spee.ch codebase is required.
-
-#### level 2
-Familiarity with web apps is required, but little-to-no familiarity with the lbry daemon is necessary
-
-#### level 3
-Familiarity with the spee.ch code base and how the lbry daemon functions is required
-
-#### level 4
-Issues with lbry (e.g. the spee.ch wallet, lbrynet configuration, etc.) that require strong familiarity with the lbry daemon and/or network to fix. Generally these issues are best suited for the `lbry` `protocol team` but are reported in this repo because they are part of the spee.ch implementation
-
 ## License
 
 This project is MIT licensed. For the full license, see [LICENSE](LICENSE).
-- 
2.45.3


From 82c6b966e4131325eca3cfe7f5a29c1e170c4837 Mon Sep 17 00:00:00 2001
From: Jeremy Kauffman <jeremy@lbry.io>
Date: Tue, 4 Dec 2018 11:35:59 -0500
Subject: [PATCH 02/29] Update README.md

---
 README.md | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index 25160d4f..9f203a2b 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,11 @@
 # Spee.ch
-Spee.ch is a [NodeJS](https://nodejs.org) React web app that reads and publishes images, videos and other assets to and from the [LBRY](https://lbry.io/) blockchain.
 
-Succinctly, via spee.ch, you can have a user-friendly, custom-designed image and video hosting site that is backed by a decentralized network. Via just a set of config files, you can spin your entire site back up including assets, with no backing up necessary.
+spee.ch provides a user-friendly, custom-designed, image and video hosting site backed by a decentralized network and 
+blockchain ([LBRY](https://lbry.tech/)). Via just a small set of config files, you can spin your an entire spee.ch site back up including assets.
+
+For a completely open, unrestricted example of a spee.ch site, check out https://www.spee.ch.
+
+For a closed, custom-hosted and branded example, check out https://lbry.theantimedia.com/.
 
 ## Installation
 
-- 
2.45.3


From 959c06746d6302a9181ad1c3b857ebb4b7cd4a45 Mon Sep 17 00:00:00 2001
From: Jeremy Kauffman <jeremy@lbry.io>
Date: Tue, 4 Dec 2018 11:38:48 -0500
Subject: [PATCH 03/29] Update README.md

---
 README.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index 9f203a2b..2e505ab2 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@
 spee.ch provides a user-friendly, custom-designed, image and video hosting site backed by a decentralized network and 
 blockchain ([LBRY](https://lbry.tech/)). Via just a small set of config files, you can spin your an entire spee.ch site back up including assets.
 
+![App GIF](https://spee.ch/e/speechgif.gif)
+
 For a completely open, unrestricted example of a spee.ch site, check out https://www.spee.ch.
 
 For a closed, custom-hosted and branded example, check out https://lbry.theantimedia.com/.
@@ -246,8 +248,6 @@ Spee.ch has a few types of URL formats that return different assets from the LBR
 Spee.ch depends on two other lbry technologies:
   * [chainquery](https://github.com/lbryio/chainquery) - a normalized database of the blockchain data.  We've provided credentials to use a public chainquery service. You can also install it on your own server to avoid being affected by the commons.
   * [lbrynet](https://github.com/lbryio/lbry) - a daemon that handles your wallet and transactions.
-![App GIF](https://spee.ch/e/speechgif.gif)
-
 
 ### Bugs
 If you find a bug or experience a problem, please report your issue here on GitHub and find us in the lbry discord!
-- 
2.45.3


From 204686b690048d5821c82be0f9c068196b166550 Mon Sep 17 00:00:00 2001
From: jessop <jessopb@gmail.com>
Date: Tue, 4 Dec 2018 12:43:37 -0500
Subject: [PATCH 04/29] checks bidstate on top-free claimnames

---
 server/chainquery/bundle.js               | 5 ++---
 server/chainquery/queries/claimQueries.js | 5 ++---
 2 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/server/chainquery/bundle.js b/server/chainquery/bundle.js
index 4a96169b..a859bd5d 100644
--- a/server/chainquery/bundle.js
+++ b/server/chainquery/bundle.js
@@ -873,8 +873,7 @@ var claimQueries = (db, table, sequelize) => ({
     logger$1.debug(`claim.getAllChannelClaims for ${channelClaimId}`);
 
     const defaultWhereClauses = {
-      bid_state:
-      { [sequelize.Op.or]: ['Controlling', 'Active', 'Accepted'] }
+      bid_state: { [sequelize.Op.or]: ['Controlling', 'Active', 'Accepted'] }
     };
 
     const addWhereClauses = (whereClauses, params) => {
@@ -969,7 +968,7 @@ var claimQueries = (db, table, sequelize) => ({
   getTopFreeClaimIdByClaimName: async (name) => {
     return await table.findAll({
       // TODO: Limit 1
-      where: { name },
+      where: { name, bid_state: { [sequelize.Op.or]: ['Controlling', 'Active', 'Accepted'] }  },
       order: [['effective_amount', 'DESC'], ['height', 'ASC']],
     }).then(result => {
       if(result.length === 0) {
diff --git a/server/chainquery/queries/claimQueries.js b/server/chainquery/queries/claimQueries.js
index cf4b532b..521cda04 100644
--- a/server/chainquery/queries/claimQueries.js
+++ b/server/chainquery/queries/claimQueries.js
@@ -72,8 +72,7 @@ export default (db, table, sequelize) => ({
     logger.debug(`claim.getAllChannelClaims for ${channelClaimId}`);
 
     const defaultWhereClauses = {
-      bid_state:
-      { [sequelize.Op.or]: ['Controlling', 'Active', 'Accepted'] }
+      bid_state: { [sequelize.Op.or]: ['Controlling', 'Active', 'Accepted'] }
     };
 
     const addWhereClauses = (whereClauses, params) => {
@@ -168,7 +167,7 @@ export default (db, table, sequelize) => ({
   getTopFreeClaimIdByClaimName: async (name) => {
     return await table.findAll({
       // TODO: Limit 1
-      where: { name },
+      where: { name, bid_state: { [sequelize.Op.or]: ['Controlling', 'Active', 'Accepted'] }  },
       order: [['effective_amount', 'DESC'], ['height', 'ASC']],
     }).then(result => {
       if(result.length === 0) {
-- 
2.45.3


From 3c6b378611a5a1d9c531b5a62c047ea101503684 Mon Sep 17 00:00:00 2001
From: Shawn <shawn@kafei.io>
Date: Tue, 4 Dec 2018 12:11:14 -0600
Subject: [PATCH 05/29] Increase file wait delay

---
 server/controllers/api/claim/get/index.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/server/controllers/api/claim/get/index.js b/server/controllers/api/claim/get/index.js
index 2bfbf2b1..47423119 100644
--- a/server/controllers/api/claim/get/index.js
+++ b/server/controllers/api/claim/get/index.js
@@ -38,7 +38,7 @@ const claimGet = async ({ ip, originalUrl, params }, res) => {
     try {
       await waitOn({
         resources: [ lbrynetResult.file_name ],
-        delay    : 100,
+        delay    : 500,
         timeout  : 10000, // 10 seconds
       });
     } catch (e) {}
-- 
2.45.3


From 9c0e0b789e15a238f3f7e5663da697fda4745a6c Mon Sep 17 00:00:00 2001
From: jessop <jessopb@gmail.com>
Date: Tue, 4 Dec 2018 13:11:24 -0500
Subject: [PATCH 06/29] fixes bug in lbryurl copy

---
 client/src/containers/AssetInfo/view.jsx | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/client/src/containers/AssetInfo/view.jsx b/client/src/containers/AssetInfo/view.jsx
index a5c58941..9fc1899e 100644
--- a/client/src/containers/AssetInfo/view.jsx
+++ b/client/src/containers/AssetInfo/view.jsx
@@ -27,6 +27,7 @@ class AssetInfo extends React.Component {
         shortId: channelShortId,
       };
       channelCanonicalUrl = `${createCanonicalLink({channel})}`;
+      console.log(channelName)
     }
     return (
       <div className='asset-info'>
@@ -120,7 +121,7 @@ class AssetInfo extends React.Component {
                 }
                 content={
                   <ClickToCopy
-                    id={'short-link'}
+                    id={'lbry-permanent-url'}
                     value={`${channelName}#${certificateId}/${name}`}
                   />
                 }
-- 
2.45.3


From d8e13cbfcf1170b36c7acc6ef2b4c87aaae72a81 Mon Sep 17 00:00:00 2001
From: Shawn K <skhameneh@gmail.com>
Date: Tue, 4 Dec 2018 12:14:15 -0600
Subject: [PATCH 07/29] Update view.jsx

---
 client/src/containers/AssetInfo/view.jsx | 1 -
 1 file changed, 1 deletion(-)

diff --git a/client/src/containers/AssetInfo/view.jsx b/client/src/containers/AssetInfo/view.jsx
index 9fc1899e..6876d8a1 100644
--- a/client/src/containers/AssetInfo/view.jsx
+++ b/client/src/containers/AssetInfo/view.jsx
@@ -27,7 +27,6 @@ class AssetInfo extends React.Component {
         shortId: channelShortId,
       };
       channelCanonicalUrl = `${createCanonicalLink({channel})}`;
-      console.log(channelName)
     }
     return (
       <div className='asset-info'>
-- 
2.45.3


From b49cb4484c531b0ba0e970bccb4710d87af62f8e Mon Sep 17 00:00:00 2001
From: Travis Eden <daovist@gmail.com>
Date: Mon, 12 Nov 2018 08:25:48 -0500
Subject: [PATCH 08/29] mark pending claims; move them to front of list; show
 proper notification

---
 client/src/containers/AssetDisplay/view.jsx   | 28 +++++++++++--------
 .../api/channel/claims/getChannelClaims.js    |  6 ++++
 server/utils/getClaimData.js                  |  1 +
 3 files changed, 24 insertions(+), 11 deletions(-)

diff --git a/client/src/containers/AssetDisplay/view.jsx b/client/src/containers/AssetDisplay/view.jsx
index 98a78366..2102f12b 100644
--- a/client/src/containers/AssetDisplay/view.jsx
+++ b/client/src/containers/AssetDisplay/view.jsx
@@ -46,7 +46,7 @@ class AssetDisplay extends React.Component {
   }
   render () {
     const { status, error, asset } = this.props;
-    const { name, claimData: { claimId, contentType, thumbnail, outpoint } } = asset;
+    const { name, claimData: { claimId, contentType, thumbnail, outpoint, pending } } = asset;
     // the outpoint is added to force the browser to re-download the asset after an update
     // issue: https://github.com/lbryio/spee.ch/issues/607
     let fileExt;
@@ -68,16 +68,22 @@ class AssetDisplay extends React.Component {
           <p>Curious what magic is happening here? <a className='link--primary' target='blank' href='https://lbry.io/faq/what-is-lbry'>Learn more.</a></p>
         </div>
         }
-        {(status === ERROR) &&
-        <div>
-          <Row>
-            <p>Unfortunately, we couldn't download your asset from LBRY.  You can help us out by sharing the following error message in the <a className='link--primary' href='https://chat.lbry.io' target='_blank'>LBRY discord</a>.</p>
-          </Row>
-          <Row>
-            <p id='error-message'><i>{error}</i></p>
-          </Row>
-        </div>
-        }
+        {(status === ERROR) && (
+          pending ? (
+            <div>
+              <p>This content is pending confirmation on the LBRY blockchain. It should be available in the next few minutes, please check back or refresh.</p>
+            </div>
+          ) : (
+            <div>
+              <Row>
+                <p>Unfortunately, we couldn't download your asset from LBRY.  You can help us out by sharing the following error message in the <a className='link--primary' href='https://chat.lbry.io' target='_blank'>LBRY discord</a>.</p>
+              </Row>
+              <Row>
+                <p id='error-message'><i>{error}</i></p>
+              </Row>
+            </div>
+          )
+        )}
         {(status === AVAILABLE) &&
         <AvailableContent
           contentType={contentType}
diff --git a/server/controllers/api/channel/claims/getChannelClaims.js b/server/controllers/api/channel/claims/getChannelClaims.js
index 61c2c639..dd0dce8f 100644
--- a/server/controllers/api/channel/claims/getChannelClaims.js
+++ b/server/controllers/api/channel/claims/getChannelClaims.js
@@ -17,6 +17,12 @@ const getChannelClaims = async (channelName, channelShortId, page) => {
     channelClaims = await chainquery.claim.queries.getAllChannelClaims(channelId, params);
   }
 
+  const split = channelClaims.reduce(
+    (acc, val) => val.dataValues.height === 0 ? { ...acc, zero: acc.zero.concat(val) } : { ...acc, nonzero: acc.nonzero.concat(val) },
+    { zero: [], nonzero: [] }
+  );
+  channelClaims = split.zero.concat(split.nonzero);
+
   const processingChannelClaims = channelClaims ? channelClaims.map((claim) => getClaimData(claim)) : [];
   const processedChannelClaims = await Promise.all(processingChannelClaims);
 
diff --git a/server/utils/getClaimData.js b/server/utils/getClaimData.js
index 0271f36b..ea5f080b 100644
--- a/server/utils/getClaimData.js
+++ b/server/utils/getClaimData.js
@@ -28,5 +28,6 @@ module.exports = async (data) => {
     thumbnail  : data.generated_thumbnail || data.thumbnail_url || data.thumbnail,
     outpoint   : data.transaction_hash_id || data.outpoint,
     host,
+    pending: Boolean(data.height === 0),
   });
 };
-- 
2.45.3


From cdbd5eee804bdd5e282372ef8e6a52e88d2a1051 Mon Sep 17 00:00:00 2001
From: Travis Eden <daovist@gmail.com>
Date: Wed, 14 Nov 2018 19:51:25 -0800
Subject: [PATCH 09/29] add pending marker

---
 client/scss/_asset-preview.scss              |  4 ++++
 client/scss/_claim-pending.scss              | 12 ++++++++++++
 client/scss/all.scss                         |  1 +
 client/src/components/AssetPreview/index.jsx | 18 +++++++++++++++++-
 4 files changed, 34 insertions(+), 1 deletion(-)
 create mode 100644 client/scss/_claim-pending.scss

diff --git a/client/scss/_asset-preview.scss b/client/scss/_asset-preview.scss
index f420531d..a05c2a2c 100644
--- a/client/scss/_asset-preview.scss
+++ b/client/scss/_asset-preview.scss
@@ -1,3 +1,7 @@
+.asset-preview {
+  position: relative;
+}
+
 .asset-preview__image {
   width  : 100%;
   padding: 0;
diff --git a/client/scss/_claim-pending.scss b/client/scss/_claim-pending.scss
new file mode 100644
index 00000000..906743ee
--- /dev/null
+++ b/client/scss/_claim-pending.scss
@@ -0,0 +1,12 @@
+.claim-pending {
+  display: inline-block;
+  position: absolute;
+  top: 10px;
+  left: 10px;
+  padding: 5px;
+  border-radius: 5px;
+  border: 2px solid red;
+  color: red;
+  font-weight: bold;
+  background-color: white;
+}
diff --git a/client/scss/all.scss b/client/scss/all.scss
index 07601eb5..8414492e 100644
--- a/client/scss/all.scss
+++ b/client/scss/all.scss
@@ -18,6 +18,7 @@
 @import '~scss/_button';
 @import '~scss/_button-primary';
 @import '~scss/_button-secondary';
+@import '~scss/_claim-pending';
 @import '~scss/_click-to-copy';
 @import '~scss/_form-feedback';
 @import '~scss/_horizontal-split';
diff --git a/client/src/components/AssetPreview/index.jsx b/client/src/components/AssetPreview/index.jsx
index 13b17ef9..8c139f45 100644
--- a/client/src/components/AssetPreview/index.jsx
+++ b/client/src/components/AssetPreview/index.jsx
@@ -2,8 +2,14 @@ import React from 'react';
 import { Link } from 'react-router-dom';
 import createCanonicalLink from '../../../../utils/createCanonicalLink';
 
+const ClaimPending = () => {
+  return (
+    <div className='claim-pending'>PENDING</div>
+  );
+};
+
 const AssetPreview = ({ defaultThumbnail, claimData }) => {
-  const {name, fileExt, contentType, thumbnail, title} = claimData;
+  const {name, fileExt, contentType, thumbnail, title, pending} = claimData;
   const showUrl = createCanonicalLink({asset: {...claimData}});
   const embedUrl = `${showUrl}.${fileExt}`;
   switch (contentType) {
@@ -27,6 +33,7 @@ const AssetPreview = ({ defaultThumbnail, claimData }) => {
       return (
         <Link to={showUrl} className='asset-preview'>
           <div>
+<<<<<<< HEAD
             <div className='asset-preview__play-wrapper'>
               <img
                 className={'asset-preview__video'}
@@ -36,6 +43,15 @@ const AssetPreview = ({ defaultThumbnail, claimData }) => {
               <div className='asset-preview__play-overlay'></div>
             </div>
             <h3 className='asset-preview__title'>{title}</h3>
+=======
+            {pending && <ClaimPending/>}
+            <img
+              className={'asset-preview-video'}
+              src={thumbnail || defaultThumbnail}
+              alt={name}
+            />
+            <h3 className='list-title'>{title}</h3>
+>>>>>>> add pending marker
           </div>
         </Link>
       );
-- 
2.45.3


From d05cf1e71e69801947d10a1fba20ba3da56c5f72 Mon Sep 17 00:00:00 2001
From: Travis Eden <daovist@gmail.com>
Date: Wed, 14 Nov 2018 19:51:51 -0800
Subject: [PATCH 10/29] hide pending images on channel page

---
 client/src/components/AssetPreview/index.jsx | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/client/src/components/AssetPreview/index.jsx b/client/src/components/AssetPreview/index.jsx
index 8c139f45..209b42b2 100644
--- a/client/src/components/AssetPreview/index.jsx
+++ b/client/src/components/AssetPreview/index.jsx
@@ -17,6 +17,9 @@ const AssetPreview = ({ defaultThumbnail, claimData }) => {
     case 'image/jpg':
     case 'image/png':
     case 'image/gif':
+      if (pending) {
+        return null;
+      }
       return (
         <Link to={showUrl} className='asset-preview'>
           <div>
-- 
2.45.3


From d089554fe42ed5acab84b277d1ea5db61246b312 Mon Sep 17 00:00:00 2001
From: Shawn <shawn@kafei.io>
Date: Tue, 4 Dec 2018 12:22:26 -0600
Subject: [PATCH 11/29] Add unsaved resolved file conflicts

---
 client/src/components/AssetPreview/index.jsx | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/client/src/components/AssetPreview/index.jsx b/client/src/components/AssetPreview/index.jsx
index 209b42b2..5599709e 100644
--- a/client/src/components/AssetPreview/index.jsx
+++ b/client/src/components/AssetPreview/index.jsx
@@ -17,9 +17,6 @@ const AssetPreview = ({ defaultThumbnail, claimData }) => {
     case 'image/jpg':
     case 'image/png':
     case 'image/gif':
-      if (pending) {
-        return null;
-      }
       return (
         <Link to={showUrl} className='asset-preview'>
           <div>
@@ -36,7 +33,6 @@ const AssetPreview = ({ defaultThumbnail, claimData }) => {
       return (
         <Link to={showUrl} className='asset-preview'>
           <div>
-<<<<<<< HEAD
             <div className='asset-preview__play-wrapper'>
               <img
                 className={'asset-preview__video'}
@@ -46,15 +42,6 @@ const AssetPreview = ({ defaultThumbnail, claimData }) => {
               <div className='asset-preview__play-overlay'></div>
             </div>
             <h3 className='asset-preview__title'>{title}</h3>
-=======
-            {pending && <ClaimPending/>}
-            <img
-              className={'asset-preview-video'}
-              src={thumbnail || defaultThumbnail}
-              alt={name}
-            />
-            <h3 className='list-title'>{title}</h3>
->>>>>>> add pending marker
           </div>
         </Link>
       );
-- 
2.45.3


From d8a2903e654cce91251f06faa812b77155b23660 Mon Sep 17 00:00:00 2001
From: jessop <jessopb@gmail.com>
Date: Wed, 5 Dec 2018 14:54:14 -0500
Subject: [PATCH 12/29] adds CORS headers to serveFile

---
 server/controllers/assets/utils/serveFile.js | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/server/controllers/assets/utils/serveFile.js b/server/controllers/assets/utils/serveFile.js
index 7344fdb2..8500dbe6 100644
--- a/server/controllers/assets/utils/serveFile.js
+++ b/server/controllers/assets/utils/serveFile.js
@@ -6,8 +6,10 @@ const serveFile = ({ filePath, fileType }, res) => {
   }
   const sendFileOptions = {
     headers: {
-      'X-Content-Type-Options': 'nosniff',
-      'Content-Type'          : fileType,
+      'X-Content-Type-Options'      : 'nosniff',
+      'Content-Type'                : fileType,
+      'Access-Control-Allow-Origin' : '*',
+      'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept',
     },
   };
   logger.debug(`fileOptions for ${filePath}:`, sendFileOptions);
-- 
2.45.3


From 20dc54ba054082c0dbd2caf0fefad99fa6cc693f Mon Sep 17 00:00:00 2001
From: jessop <jessopb@gmail.com>
Date: Thu, 6 Dec 2018 21:28:28 -0500
Subject: [PATCH 13/29] bugfixes around display of permanentURIs

---
 client/src/containers/AssetInfo/view.jsx   |  6 ++++--
 client/src/containers/PublishTool/index.js |  4 ++--
 client/src/utils/buildURI.js               | 10 ---------
 client/src/utils/createPermanentURI.js     | 24 ++++++++++++++++++++++
 utils/createModuleAliases.js               |  6 ++++++
 5 files changed, 36 insertions(+), 14 deletions(-)
 delete mode 100644 client/src/utils/buildURI.js
 create mode 100644 client/src/utils/createPermanentURI.js

diff --git a/client/src/containers/AssetInfo/view.jsx b/client/src/containers/AssetInfo/view.jsx
index 6876d8a1..8b76b907 100644
--- a/client/src/containers/AssetInfo/view.jsx
+++ b/client/src/containers/AssetInfo/view.jsx
@@ -9,6 +9,8 @@ import HorizontalSplit from '@components/HorizontalSplit';
 import siteConfig from '@config/siteConfig.json';
 import createCanonicalLink from '../../../../utils/createCanonicalLink';
 import AssetInfoFooter from '../../components/AssetInfoFooter/index';
+import { createPermanentURI } from '@clientutils/createPermanentURI';
+
 const { details: { host } } = siteConfig;
 
 class AssetInfo extends React.Component {
@@ -121,7 +123,7 @@ class AssetInfo extends React.Component {
                 content={
                   <ClickToCopy
                     id={'lbry-permanent-url'}
-                    value={`${channelName}#${certificateId}/${name}`}
+                    value={`${createPermanentURI(asset)}`}
                   />
                 }
               />
@@ -142,7 +144,7 @@ class AssetInfo extends React.Component {
                 </a>
                 <a
                   className={'link--primary'}
-                  href={`https://open.lbry.io/${channelName}#${certificateId}/${name}`}
+                  href={`https://open.lbry.io/${createPermanentURI(asset)}`}
                   download={name}
                 >
                   LBRY URL
diff --git a/client/src/containers/PublishTool/index.js b/client/src/containers/PublishTool/index.js
index 0e0d4b4f..335553d9 100644
--- a/client/src/containers/PublishTool/index.js
+++ b/client/src/containers/PublishTool/index.js
@@ -1,14 +1,14 @@
 import {connect} from 'react-redux';
 import View from './view';
 import {selectAsset} from '../../selectors/show';
-import {buildURI} from '../../utils/buildURI';
+import {createPermanentURI} from '@clientutils/createPermanentURI';
 
 const mapStateToProps = props => {
   const { show, publish } = props;
   const asset = selectAsset(show);
   let uri;
   if (asset) {
-    uri = `lbry://${buildURI(asset)}`;
+    uri = `lbry://${createPermanentURI(asset)}`;
   }
   return {
     disabled  : publish.disabled,
diff --git a/client/src/utils/buildURI.js b/client/src/utils/buildURI.js
deleted file mode 100644
index b6fb599c..00000000
--- a/client/src/utils/buildURI.js
+++ /dev/null
@@ -1,10 +0,0 @@
-export const buildURI = asset => {
-  let channelName, certificateId, name, claimId;
-  if (asset.claimData) {
-    ({ channelName, certificateId, name, claimId } = asset.claimData);
-  }
-  if (channelName) {
-    return `${channelName}:${certificateId}/${name}`;
-  }
-  return `${claimId}/${name}`;
-};
diff --git a/client/src/utils/createPermanentURI.js b/client/src/utils/createPermanentURI.js
new file mode 100644
index 00000000..10f570e4
--- /dev/null
+++ b/client/src/utils/createPermanentURI.js
@@ -0,0 +1,24 @@
+/*
+{ channelName, certificateId, name, claimId } = { claimData } = asset
+
+permanentUrl for a channel
+@channelName#certificateId
+
+permanentUrl for an asset in a channel
+@channelName#certificateId/name
+
+permanentUrl for an asset published anonymously
+name#claimId
+*/
+
+export const createPermanentURI = asset => {
+  let channelName, certificateId, name, claimId;
+  if (asset.claimData) {
+    ({ channelName, certificateId, name, claimId } = asset.claimData);
+  }
+  else return 'Error: unknown asset at createPermanentURI.js';
+  if (channelName) {
+    return `${channelName}#${certificateId}/${name}`;
+  }
+  return `${name}#${claimId}`;
+};
diff --git a/utils/createModuleAliases.js b/utils/createModuleAliases.js
index b9129f47..00506bb9 100644
--- a/utils/createModuleAliases.js
+++ b/utils/createModuleAliases.js
@@ -34,6 +34,11 @@ module.exports = () => {
   moduleAliases['@config'] = resolve('site/config');
   moduleAliases['@private'] = resolve('site/private');
 
+  // aliases for utils
+  moduleAliases['@globalutils'] = resolve('utils');
+  moduleAliases['@clientutils'] = resolve(`${DEFAULT_ROOT}/utils`);
+  // moduleAliases['@serverutils'] = resolve('server/utils');
+
   // create specific aliases for locally defined components in the following folders
   moduleAliases = addAliasesForCustomComponentFolder('containers', moduleAliases);
   moduleAliases = addAliasesForCustomComponentFolder('components', moduleAliases);
@@ -48,6 +53,7 @@ module.exports = () => {
   moduleAliases['@sagas'] = resolve(`${DEFAULT_ROOT}/sagas`);
   moduleAliases['@app'] = resolve(`${DEFAULT_ROOT}/app.js`);
 
+
   // return finished aliases
   return moduleAliases;
 };
-- 
2.45.3


From 596a4b70a358bac5ca856118989d59f60577e8e0 Mon Sep 17 00:00:00 2001
From: jessop <jessopb@gmail.com>
Date: Sat, 8 Dec 2018 23:11:10 -0500
Subject: [PATCH 14/29] clarity changes to docs

---
 README.md             |  8 ++++----
 docs/ubuntuinstall.md | 30 +++++++++++++-----------------
 2 files changed, 17 insertions(+), 21 deletions(-)

diff --git a/README.md b/README.md
index 2e505ab2..64d44cb6 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,7 @@ For a closed, custom-hosted and branded example, check out https://lbry.theantim
 #### Get some information ready:
   * mysqlusername
   * mysqlpassword
-  * domainname or 'http://localhost'
+  * domainname or 'http://localhost:3000'
   * speechport = 3000
 
 #### Install and Set Up Dependencies
@@ -31,10 +31,10 @@ For a closed, custom-hosted and branded example, check out https://lbry.theantim
     * 3333
     * 4444
   * [NodeJS](https://nodejs.org)
-  * [MySQL](https://dev.mysql.com/doc/refman/8.0/en/installing.html)
+  * [MySQL version 5.7 or higher](https://dev.mysql.com/doc/refman/8.0/en/installing.html)
     * mysqlusername or root
     * mysqlpassword
-    * You may need
+    * Requires mysql_native_password plugin
     ```
     mysql> `ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'yourpassword';`
     ```
@@ -89,7 +89,7 @@ $ npm run start
 ```
 
 #### View in browser
- *  Visit [http://localhost:3000](http://localhost:3000) in your browser
+ * Visit [http://localhost:3000](http://localhost:3000) in your browser
 
 #### Customize your app
 
diff --git a/docs/ubuntuinstall.md b/docs/ubuntuinstall.md
index 9f1f98aa..454cb327 100644
--- a/docs/ubuntuinstall.md
+++ b/docs/ubuntuinstall.md
@@ -6,23 +6,23 @@
   * Ability to use SSH (putty + public key for windows users)
   * Ubuntu 16.04 or 18.04 VPS with root access
     * Your login info ready
+    * Exposed ports: 22, 80, 443, 3333, 4444
   * Domain name with @ and www pointed at your VPS IP
-    * alternatively, specify http://localhost
+    * _alternatively, specify http://localhost:3000 as domain during speech configuration_
   * Ability to send 5+ LBRY credits to an address
   * Noncommercial use
-    * _(configuration examples for nginx and certbot are included as an alternative)_
+    * _alternative configuration examples for nginx and certbot are [here](https://github.com/lbryio/spee.ch/tree/master/docs/setup/conf/nginx)_
 
 ## You'll be installing:
-  * MySQL DB
+  * MySQL DB version 5.7 or higher
     * Default Port 3306
+    * mysql_native_password plugin
   * NodeJS v8+
-  * Https proxy server
-    * Caddy for personal use
-    * Exposed ports: 22, 80, 443, 3333, 4444
-    * Reverse proxies 80 redirected to 443 to App on 3000
-  * Spee.ch started on port 3000
+  * Caddy - https reverse proxy server
+    * automatically obtains tls certificate
+    * Redirects 80 (http) to 443 (https) to Speech on 3000 
   * Lbrynet DAEMON started on ports 3333 and 4444
-
+  * Spee.ch started on port 3000
 
 # 1. Setup OS and install dependencies
 ## OS
@@ -184,15 +184,13 @@ tmux allows you to run multiple things in different sessions. Useful for manuall
 ## Detatch tmux session
   `Control + b`, then `d`
 
-<<<<<<< Updated upstream
   * `tmux` if you want to get back into tmux
 
   * `Control+b`, then `)` while in tmux session to cycle back to your lbrynet session to see output
-=======
+  
   `tmux`
 
   _note: `Control+b`, then `)` while in tmux session to cycle back to your lbrynet session to see output_
->>>>>>> Stashed changes
 
 ## Display wallet address to which to send 5+ LBC.
 
@@ -227,19 +225,17 @@ tmux allows you to run multiple things in different sessions. Useful for manuall
 
   `npm run configure`
 
-<<<<<<< Updated upstream
-=======
   (once your wallet balance has cleared)
 
   `npm run configure`
 
->>>>>>> Stashed changes
+
     * Database: lbry
     * Username: root
     * Password: your_mysql_password
     * Port: 3000
     * Site Title: Your Site Name
-    * Enter your site's domain name: https://example.com or http://localhost
+    * Enter your site's domain name: https://example.com or http://localhost:3000
     * Enter a directory where uploads should be stored: (/home/lbry/Uploads)
 
   `npm run start`
@@ -255,7 +251,7 @@ tmux allows you to run multiple things in different sessions. Useful for manuall
  npm install -g pm2
  ```
 
-### 7 Maintenance Proceedures
+### 7 Maintenance Procedures
 
 #### Change daemon
   * backup wallet (private keys!) to a safe place
-- 
2.45.3


From 7391df8e840bd4e6959be11c89523c51c028d272 Mon Sep 17 00:00:00 2001
From: Niko Storni <niko@lbry.io>
Date: Sat, 10 Nov 2018 19:11:12 -0500
Subject: [PATCH 15/29] run eslint pre-hook

---
 server/middleware/autoblockPublishMiddleware.js |  4 ++++
 server/middleware/logMetricsMiddleware.js       |  4 ++++
 server/render/src/handleShowRender.jsx          | 11 +++++++----
 3 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/server/middleware/autoblockPublishMiddleware.js b/server/middleware/autoblockPublishMiddleware.js
index 4c4456fb..08cc6e3f 100644
--- a/server/middleware/autoblockPublishMiddleware.js
+++ b/server/middleware/autoblockPublishMiddleware.js
@@ -58,7 +58,11 @@ const autoblockPublishBodyMiddleware = (req, res, next) => {
     let ip = (req.headers['x-forwarded-for'] || req.connection.remoteAddress).split(/,\s?/)[0];
     const { channelName } = req.body;
 
+<<<<<<< HEAD
     if (channelName && publishingChannelWhitelist.indexOf(channelName.toLowerCase()) !== -1) {
+=======
+    if (channelName && publishingChannelWhitelist.indexOf(channelName) !== -1) {
+>>>>>>> run eslint pre-hook
       delete ipCounts[ip];
     }
   }
diff --git a/server/middleware/logMetricsMiddleware.js b/server/middleware/logMetricsMiddleware.js
index e4ddaceb..05c8ceb0 100644
--- a/server/middleware/logMetricsMiddleware.js
+++ b/server/middleware/logMetricsMiddleware.js
@@ -27,7 +27,11 @@ function logMetricsMiddleware (req, res, next) {
 
     db.Metrics.create({
       time      : Date.now(),
+<<<<<<< HEAD
       isInternal: /node-fetch/.test(userAgent),
+=======
+      isInternal: /node\-fetch/.test(userAgent),
+>>>>>>> run eslint pre-hook
       isChannel : res.isChannel,
       claimId   : res.claimId,
       routePath : httpContext.get('routePath'),
diff --git a/server/render/src/handleShowRender.jsx b/server/render/src/handleShowRender.jsx
index 6e527b0c..ca7d28b8 100644
--- a/server/render/src/handleShowRender.jsx
+++ b/server/render/src/handleShowRender.jsx
@@ -53,20 +53,23 @@ module.exports = (req, res) => {
   const runSaga = (action !== false && saga !== false);
 
   const renderPage = (store) => {
-
     // Workaround, remove when a solution for async httpContext exists
     const showState = store.getState().show;
     const assetKeys = Object.keys(showState.assetList);
+<<<<<<< HEAD
     
     if(assetKeys.length !== 0) {
+=======
+    if (assetKeys.length !== 0) {
+>>>>>>> run eslint pre-hook
       res.claimId = showState.assetList[assetKeys[0]].claimId;
     } else {
       const channelKeys = Object.keys(showState.channelList);
 
-      if(channelKeys.length !== 0) {
+      if (channelKeys.length !== 0) {
         res.claimId = showState.channelList[channelKeys[0]].longId;
         res.isChannel = true;
-        }
+      }
     }
 
     // render component to a string
@@ -119,7 +122,7 @@ module.exports = (req, res) => {
           console.log(`redirecting ${req.originalUrl} to ${canonicalUrl}`);
           res.redirect(canonicalUrl);
         }
-        return renderPage(store)
+        return renderPage(store);
       });
   } else {
     const store = createStore(Reducers);
-- 
2.45.3


From 81cc5a83237c37a466df305cd2bb97450f3444dd Mon Sep 17 00:00:00 2001
From: Niko Storni <niko@lbry.io>
Date: Sat, 10 Nov 2018 23:31:09 -0500
Subject: [PATCH 16/29] add travis

---
 .travis.yml | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)
 create mode 100644 .travis.yml

diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 00000000..83e7d55f
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,37 @@
+sudo: true
+dist: xenial
+#addons:
+#  apt:
+#    sources:
+#      - mysql-5.7-trusty
+#    packages:
+#      - mysql-server
+#      - mysql-client
+language: node_js
+node_js:
+  - "lts/*"
+cache:
+  directories:
+    - "node_modules"
+#services:
+#  - mysql
+
+before_install:
+#  - sudo mysql -e "use mysql; update user set authentication_string=PASSWORD('password') where User='root'; update user set plugin='mysql_native_password';FLUSH PRIVILEGES;"
+#  - sudo mysql_upgrade -u root -ppassword
+#  - sudo service mysql restart
+#  - mysql -u root -ppassword -e 'CREATE DATABASE IF NOT EXISTS lbry;'
+#  - mysql -u root -ppassword -e "CREATE USER 'lbry'@'localhost' IDENTIFIED BY 'lbry';"
+#  - mysql -u root -ppassword -e "GRANT ALL ON lbry.* TO 'lbry'@'localhost';"
+#  - sudo service mysql restart
+  - dpkg --compare-versions `npm -v` ge 6.4.0 || npm i -g npm@^6.4.0
+
+install:
+  - npm i
+
+script:
+  - npm run fix
+  - npm run build
+  - git diff --exit-code
+
+
-- 
2.45.3


From 4684e28fdbb65dcbea8211d2fa3a228c8a038608 Mon Sep 17 00:00:00 2001
From: Shawn <shawn@kafei.io>
Date: Sun, 9 Dec 2018 23:18:39 -0600
Subject: [PATCH 17/29] Revert "run eslint pre-hook"

This reverts commit 7391df8e840bd4e6959be11c89523c51c028d272.
---
 server/middleware/autoblockPublishMiddleware.js |  4 ----
 server/middleware/logMetricsMiddleware.js       |  4 ----
 server/render/src/handleShowRender.jsx          | 11 ++++-------
 3 files changed, 4 insertions(+), 15 deletions(-)

diff --git a/server/middleware/autoblockPublishMiddleware.js b/server/middleware/autoblockPublishMiddleware.js
index 08cc6e3f..4c4456fb 100644
--- a/server/middleware/autoblockPublishMiddleware.js
+++ b/server/middleware/autoblockPublishMiddleware.js
@@ -58,11 +58,7 @@ const autoblockPublishBodyMiddleware = (req, res, next) => {
     let ip = (req.headers['x-forwarded-for'] || req.connection.remoteAddress).split(/,\s?/)[0];
     const { channelName } = req.body;
 
-<<<<<<< HEAD
     if (channelName && publishingChannelWhitelist.indexOf(channelName.toLowerCase()) !== -1) {
-=======
-    if (channelName && publishingChannelWhitelist.indexOf(channelName) !== -1) {
->>>>>>> run eslint pre-hook
       delete ipCounts[ip];
     }
   }
diff --git a/server/middleware/logMetricsMiddleware.js b/server/middleware/logMetricsMiddleware.js
index 05c8ceb0..e4ddaceb 100644
--- a/server/middleware/logMetricsMiddleware.js
+++ b/server/middleware/logMetricsMiddleware.js
@@ -27,11 +27,7 @@ function logMetricsMiddleware (req, res, next) {
 
     db.Metrics.create({
       time      : Date.now(),
-<<<<<<< HEAD
       isInternal: /node-fetch/.test(userAgent),
-=======
-      isInternal: /node\-fetch/.test(userAgent),
->>>>>>> run eslint pre-hook
       isChannel : res.isChannel,
       claimId   : res.claimId,
       routePath : httpContext.get('routePath'),
diff --git a/server/render/src/handleShowRender.jsx b/server/render/src/handleShowRender.jsx
index ca7d28b8..6e527b0c 100644
--- a/server/render/src/handleShowRender.jsx
+++ b/server/render/src/handleShowRender.jsx
@@ -53,23 +53,20 @@ module.exports = (req, res) => {
   const runSaga = (action !== false && saga !== false);
 
   const renderPage = (store) => {
+
     // Workaround, remove when a solution for async httpContext exists
     const showState = store.getState().show;
     const assetKeys = Object.keys(showState.assetList);
-<<<<<<< HEAD
     
     if(assetKeys.length !== 0) {
-=======
-    if (assetKeys.length !== 0) {
->>>>>>> run eslint pre-hook
       res.claimId = showState.assetList[assetKeys[0]].claimId;
     } else {
       const channelKeys = Object.keys(showState.channelList);
 
-      if (channelKeys.length !== 0) {
+      if(channelKeys.length !== 0) {
         res.claimId = showState.channelList[channelKeys[0]].longId;
         res.isChannel = true;
-      }
+        }
     }
 
     // render component to a string
@@ -122,7 +119,7 @@ module.exports = (req, res) => {
           console.log(`redirecting ${req.originalUrl} to ${canonicalUrl}`);
           res.redirect(canonicalUrl);
         }
-        return renderPage(store);
+        return renderPage(store)
       });
   } else {
     const store = createStore(Reducers);
-- 
2.45.3


From 105282b6a3f3a54b48709567cabd762c298e7a21 Mon Sep 17 00:00:00 2001
From: Shawn <shawn@kafei.io>
Date: Sun, 9 Dec 2018 23:29:23 -0600
Subject: [PATCH 18/29] Migrate to jobs

---
 .travis.yml | 34 ++++++++++++++++++----------------
 1 file changed, 18 insertions(+), 16 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 83e7d55f..d1d2ef88 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,22 +16,24 @@ cache:
 #services:
 #  - mysql
 
-before_install:
-#  - sudo mysql -e "use mysql; update user set authentication_string=PASSWORD('password') where User='root'; update user set plugin='mysql_native_password';FLUSH PRIVILEGES;"
-#  - sudo mysql_upgrade -u root -ppassword
-#  - sudo service mysql restart
-#  - mysql -u root -ppassword -e 'CREATE DATABASE IF NOT EXISTS lbry;'
-#  - mysql -u root -ppassword -e "CREATE USER 'lbry'@'localhost' IDENTIFIED BY 'lbry';"
-#  - mysql -u root -ppassword -e "GRANT ALL ON lbry.* TO 'lbry'@'localhost';"
-#  - sudo service mysql restart
-  - dpkg --compare-versions `npm -v` ge 6.4.0 || npm i -g npm@^6.4.0
+jobs:
+  include:
+    - stage: "Build"
+      name: "Build Spee.ch"
 
-install:
-  - npm i
-
-script:
-  - npm run fix
-  - npm run build
-  - git diff --exit-code
+      before_install:
+      #  - sudo mysql -e "use mysql; update user set authentication_string=PASSWORD('password') where User='root'; update user set plugin='mysql_native_password';FLUSH PRIVILEGES;"
+      #  - sudo mysql_upgrade -u root -ppassword
+      #  - sudo service mysql restart
+      #  - mysql -u root -ppassword -e 'CREATE DATABASE IF NOT EXISTS lbry;'
+      #  - mysql -u root -ppassword -e "CREATE USER 'lbry'@'localhost' IDENTIFIED BY 'lbry';"
+      #  - mysql -u root -ppassword -e "GRANT ALL ON lbry.* TO 'lbry'@'localhost';"
+      #  - sudo service mysql restart
+        - dpkg --compare-versions `npm -v` ge 6.4.0 || npm i -g npm@^6.4.0
 
+      install:
+        - npm i
 
+      script:
+      #  - npm run fix
+        - npm run build
-- 
2.45.3


From 31a65f566e6b42b57f2544293bc835d4ecd74e67 Mon Sep 17 00:00:00 2001
From: Shawn <shawn@kafei.io>
Date: Sun, 9 Dec 2018 23:44:00 -0600
Subject: [PATCH 19/29] Add test environment setup

---
 .travis.yml | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/.travis.yml b/.travis.yml
index d1d2ef88..8318861b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -37,3 +37,12 @@ jobs:
       script:
       #  - npm run fix
         - npm run build
+
+    - stage: "Setup Tests"
+      name: "Setup Test Environment"
+
+      script:
+        - cp ./cli/defaults/* ./site/config/
+        - echo '{ "sessionKey": "session", "masterPassword": false }' > ./site/private/authConfig.json
+        - npm start &
+        - sleep 10 # Attempt to collect output for 10 seconds
-- 
2.45.3


From 341b9e3a5fc2871bc691ec89f9dad25dc170674d Mon Sep 17 00:00:00 2001
From: Shawn <shawn@kafei.io>
Date: Sun, 9 Dec 2018 23:47:15 -0600
Subject: [PATCH 20/29] Adjust configuration before build

---
 .travis.yml | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 8318861b..c67fa48a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -18,6 +18,13 @@ cache:
 
 jobs:
   include:
+    - stage: "Configure"
+      name: "Configure Spee.ch"
+
+      script:
+        - cp ./cli/defaults/* ./site/config/
+        - echo '{ "sessionKey": "session", "masterPassword": false }' > ./site/private/authConfig.json
+
     - stage: "Build"
       name: "Build Spee.ch"
 
@@ -38,11 +45,9 @@ jobs:
       #  - npm run fix
         - npm run build
 
-    - stage: "Setup Tests"
-      name: "Setup Test Environment"
+    - stage: "Run"
+      name: "Run Test Environment"
 
       script:
-        - cp ./cli/defaults/* ./site/config/
-        - echo '{ "sessionKey": "session", "masterPassword": false }' > ./site/private/authConfig.json
         - npm start &
         - sleep 10 # Attempt to collect output for 10 seconds
-- 
2.45.3


From 68f7eb11b5082482432428521ff80ef4a0b54a5e Mon Sep 17 00:00:00 2001
From: Shawn <shawn@kafei.io>
Date: Sun, 9 Dec 2018 23:54:17 -0600
Subject: [PATCH 21/29] Adjust configuration before build

---
 .travis.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index c67fa48a..deb12441 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -23,7 +23,7 @@ jobs:
 
       script:
         - cp ./cli/defaults/* ./site/config/
-        - echo '{ "sessionKey": "session", "masterPassword": false }' > ./site/private/authConfig.json
+        - 'echo \'{ "sessionKey": "session", "masterPassword": false }\' > ./site/private/authConfig.json'
 
     - stage: "Build"
       name: "Build Spee.ch"
-- 
2.45.3


From 997e909117b0883f6043612801fdb270209fd372 Mon Sep 17 00:00:00 2001
From: Shawn <shawn@kafei.io>
Date: Mon, 10 Dec 2018 00:00:32 -0600
Subject: [PATCH 22/29] Fix YAML formatting

---
 .travis.yml | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index deb12441..6b46adcc 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -23,7 +23,8 @@ jobs:
 
       script:
         - cp ./cli/defaults/* ./site/config/
-        - 'echo \'{ "sessionKey": "session", "masterPassword": false }\' > ./site/private/authConfig.json'
+        - |
+          echo \'{ "sessionKey": "session", "masterPassword": false }\' > ./site/private/authConfig.json
 
     - stage: "Build"
       name: "Build Spee.ch"
-- 
2.45.3


From d3741c5da1274de75a0148aeb7fb353f3809acd6 Mon Sep 17 00:00:00 2001
From: Shawn <shawn@kafei.io>
Date: Mon, 10 Dec 2018 00:04:34 -0600
Subject: [PATCH 23/29] Adjust build order

---
 .travis.yml | 23 +++++++++++++----------
 1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 6b46adcc..7dfdee58 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -18,16 +18,8 @@ cache:
 
 jobs:
   include:
-    - stage: "Configure"
-      name: "Configure Spee.ch"
-
-      script:
-        - cp ./cli/defaults/* ./site/config/
-        - |
-          echo \'{ "sessionKey": "session", "masterPassword": false }\' > ./site/private/authConfig.json
-
-    - stage: "Build"
-      name: "Build Spee.ch"
+    - stage: "Setup"
+      name: "Setup Build Environment"
 
       before_install:
       #  - sudo mysql -e "use mysql; update user set authentication_string=PASSWORD('password') where User='root'; update user set plugin='mysql_native_password';FLUSH PRIVILEGES;"
@@ -42,6 +34,17 @@ jobs:
       install:
         - npm i
 
+    - stage: "Configure"
+      name: "Configure Spee.ch"
+
+      script:
+        - cp ./cli/defaults/* ./site/config/
+        - |
+          echo \'{ "sessionKey": "session", "masterPassword": false }\' > ./site/private/authConfig.json
+
+    - stage: "Build"
+      name: "Build Spee.ch"
+
       script:
       #  - npm run fix
         - npm run build
-- 
2.45.3


From 39bd8d43fe453fc272f28a7e3e6029a2497c1af6 Mon Sep 17 00:00:00 2001
From: Shawn <shawn@kafei.io>
Date: Mon, 10 Dec 2018 00:09:11 -0600
Subject: [PATCH 24/29] Define script for setup to disable automatic tests
 during setup

---
 .travis.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index 7dfdee58..454445e8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -31,7 +31,7 @@ jobs:
       #  - sudo service mysql restart
         - dpkg --compare-versions `npm -v` ge 6.4.0 || npm i -g npm@^6.4.0
 
-      install:
+      script:
         - npm i
 
     - stage: "Configure"
-- 
2.45.3


From 8651476242e1995d3eba113538b7c901472238de Mon Sep 17 00:00:00 2001
From: Shawn <shawn@kafei.io>
Date: Mon, 10 Dec 2018 00:12:14 -0600
Subject: [PATCH 25/29] Attempt to fix travis cache error

---
 .travis.yml | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index 454445e8..3c83b83c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -31,9 +31,11 @@ jobs:
       #  - sudo service mysql restart
         - dpkg --compare-versions `npm -v` ge 6.4.0 || npm i -g npm@^6.4.0
 
-      script:
+      install:
         - npm i
 
+      script: 'true' # Disables automatic stage tests
+
     - stage: "Configure"
       name: "Configure Spee.ch"
 
-- 
2.45.3


From 22cfb334093b1498889e5de9aab86a3c831abf93 Mon Sep 17 00:00:00 2001
From: Shawn <shawn@kafei.io>
Date: Mon, 10 Dec 2018 00:17:47 -0600
Subject: [PATCH 26/29] Consolidate jobs because Travis does not handle them
 well

---
 .travis.yml | 19 ++-----------------
 1 file changed, 2 insertions(+), 17 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 3c83b83c..8d31653b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -18,8 +18,8 @@ cache:
 
 jobs:
   include:
-    - stage: "Setup"
-      name: "Setup Build Environment"
+    - stage: "Build"
+      name: "Build and run test environment"
 
       before_install:
       #  - sudo mysql -e "use mysql; update user set authentication_string=PASSWORD('password') where User='root'; update user set plugin='mysql_native_password';FLUSH PRIVILEGES;"
@@ -34,26 +34,11 @@ jobs:
       install:
         - npm i
 
-      script: 'true' # Disables automatic stage tests
-
-    - stage: "Configure"
-      name: "Configure Spee.ch"
-
       script:
         - cp ./cli/defaults/* ./site/config/
         - |
           echo \'{ "sessionKey": "session", "masterPassword": false }\' > ./site/private/authConfig.json
-
-    - stage: "Build"
-      name: "Build Spee.ch"
-
-      script:
       #  - npm run fix
         - npm run build
-
-    - stage: "Run"
-      name: "Run Test Environment"
-
-      script:
         - npm start &
         - sleep 10 # Attempt to collect output for 10 seconds
-- 
2.45.3


From 2b3cd54f30abf430f1074fc33017ec83936d7f80 Mon Sep 17 00:00:00 2001
From: Shawn <shawn@kafei.io>
Date: Mon, 10 Dec 2018 00:20:39 -0600
Subject: [PATCH 27/29] Fix test authConfig.json

---
 .travis.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index 8d31653b..95af295c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -37,7 +37,7 @@ jobs:
       script:
         - cp ./cli/defaults/* ./site/config/
         - |
-          echo \'{ "sessionKey": "session", "masterPassword": false }\' > ./site/private/authConfig.json
+          echo '{ "sessionKey": "session", "masterPassword": false }' > ./site/private/authConfig.json
       #  - npm run fix
         - npm run build
         - npm start &
-- 
2.45.3


From d38d8f106138b7fbd4df9e026c944c397adc5a39 Mon Sep 17 00:00:00 2001
From: jessop <jessopb@gmail.com>
Date: Thu, 13 Dec 2018 22:43:03 -0500
Subject: [PATCH 28/29] Sets proper 404 status in most cases

---
 server/render/src/handleShowRender.jsx | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/server/render/src/handleShowRender.jsx b/server/render/src/handleShowRender.jsx
index 6e527b0c..b306ae5f 100644
--- a/server/render/src/handleShowRender.jsx
+++ b/server/render/src/handleShowRender.jsx
@@ -20,11 +20,11 @@ const createCanonicalLink = require('../../../utils/createCanonicalLink');
 const getCanonicalUrlFromShow = show => {
   const requestId = show.requestList[show.request.id];
   const requestType = show.request.type;
-  
+
   if (!requestId || !requestType) {
     return null;
   }
-  
+
   switch (requestType) {
     case 'ASSET_DETAILS':
       const asset = show.assetList[requestId.key];
@@ -57,16 +57,15 @@ module.exports = (req, res) => {
     // Workaround, remove when a solution for async httpContext exists
     const showState = store.getState().show;
     const assetKeys = Object.keys(showState.assetList);
-    
-    if(assetKeys.length !== 0) {
-      res.claimId = showState.assetList[assetKeys[0]].claimId;
-    } else {
-      const channelKeys = Object.keys(showState.channelList);
+    const channelKeys = Object.keys(showState.channelList);
 
-      if(channelKeys.length !== 0) {
-        res.claimId = showState.channelList[channelKeys[0]].longId;
-        res.isChannel = true;
-        }
+    if (assetKeys.length !== 0) {
+      res.claimId = showState.assetList[assetKeys[0]].claimId;
+    } else if (channelKeys.length !== 0) {
+      res.claimId = showState.channelList[channelKeys[0]].longId;
+      res.isChannel = true;
+    } else {
+      res.status(404);
     }
 
     // render component to a string
-- 
2.45.3


From dbddf06ff51d278f037cd0c345574860c171fe71 Mon Sep 17 00:00:00 2001
From: jessopb <36554050+jessopb@users.noreply.github.com>
Date: Fri, 14 Dec 2018 17:10:12 -0500
Subject: [PATCH 29/29] Revert "Sets proper 404 status in most cases"

---
 server/render/src/handleShowRender.jsx | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/server/render/src/handleShowRender.jsx b/server/render/src/handleShowRender.jsx
index b306ae5f..6e527b0c 100644
--- a/server/render/src/handleShowRender.jsx
+++ b/server/render/src/handleShowRender.jsx
@@ -20,11 +20,11 @@ const createCanonicalLink = require('../../../utils/createCanonicalLink');
 const getCanonicalUrlFromShow = show => {
   const requestId = show.requestList[show.request.id];
   const requestType = show.request.type;
-
+  
   if (!requestId || !requestType) {
     return null;
   }
-
+  
   switch (requestType) {
     case 'ASSET_DETAILS':
       const asset = show.assetList[requestId.key];
@@ -57,15 +57,16 @@ module.exports = (req, res) => {
     // Workaround, remove when a solution for async httpContext exists
     const showState = store.getState().show;
     const assetKeys = Object.keys(showState.assetList);
-    const channelKeys = Object.keys(showState.channelList);
-
-    if (assetKeys.length !== 0) {
+    
+    if(assetKeys.length !== 0) {
       res.claimId = showState.assetList[assetKeys[0]].claimId;
-    } else if (channelKeys.length !== 0) {
-      res.claimId = showState.channelList[channelKeys[0]].longId;
-      res.isChannel = true;
     } else {
-      res.status(404);
+      const channelKeys = Object.keys(showState.channelList);
+
+      if(channelKeys.length !== 0) {
+        res.claimId = showState.channelList[channelKeys[0]].longId;
+        res.isChannel = true;
+        }
     }
 
     // render component to a string
-- 
2.45.3