text: /**
   * Copyright 2016 Google Inc. All rights reserved.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
  */
  
  // DO NOT EDIT THIS GENERATED OUTPUT DIRECTLY!
  // This file should be overwritten as part of your build process.
  // If you need to extend the behavior of the generated service worker, the best approach is to write
  // additional code and include it using the importScripts option:
  //   https://github.com/GoogleChrome/sw-precache#importscripts-arraystring
  //
  // Alternatively, it's possible to make changes to the underlying template file and then use that as the
  // new base for generating output, via the templateFilePath option:
  //   https://github.com/GoogleChrome/sw-precache#templatefilepath-string
  //
  // If you go that route, make sure that whenever you update your sw-precache dependency, you reconcile any
  // changes made to this original template file with your modified copy.
  
  // This generated service worker JavaScript will precache your site's resources.
  // The code needs to be saved in a .js file at the top-level of your site, and registered
  // from your pages in order to be used. See
  // https://github.com/googlechrome/sw-precache/blob/master/demo/app/js/service-worker-registration.js
  // for an example of how you can register this script and handle various service worker events.
  
  /* eslint-env worker, serviceworker */
  /* eslint-disable indent, no-unused-vars, no-multiple-empty-lines, max-nested-callbacks, space-before-function-paren, quotes, comma-spacing */
  'use strict';
  
  var precacheConfig = [["Lobbies.xcf","03cbc5d2f1a1ff23cf099ff609bd156f"],["README.md","b9bd5e7acdc7b8737a2aade0dc04f11a"],["ai.js","aa8873d7739c5ba17e345080c9e00e65"],["ai_trainer.js","3ac59c0688c3a4df0795e4defa7d999e"],["ai_trainer2.js","f54659fe71911d644461eb4746a5adb8"],["audio.js","7ca2591f7c55f2187ff2a3ad155bdd1f"],["base.js","9f5b7983b455af9d6c63b9d608db0f4b"],["emojitactics.css","0f287e30118727e0a61699850c31e77f"],["entities.js","d029b6eed7c4ef11ad2d214575dd26e8"],["index.html","72534976645fde08a7dbbbc16675dcac"],["manifest.json","3dbaa3824d9c2a27f054fe313cbf3bac"],["normalize.css","a168b2264b1a180f876dad1dd2692b09"],["simulate.html","7178eb8ad7c30f6a505d723e19725870"],["simulation.js","b3f7d9a0a1259f71b045e0b16cfd9f39"],["smile.png","ee794a1ba16a7db3678b154f1cfc2320"],["smileshield.xcf","99ba03f96a1b73bd76b44a1b88156fbd"],["story.js","953e5796ff776e495f760bba76d162aa"],["train.html","51eedf5258433469776ffded4c9192d8"],["version.js","f4411ccb5c5a02365b6adaf6516c2c6d"],["vue.min.js","6b89bb0afefda627404bf697b215274b"]];
  var cacheName = 'sw-precache-v3-sw-precache-' + (self.registration ? self.registration.scope : '');
  
  
  var ignoreUrlParametersMatching = [/^utm_/];
  
  
  
  var addDirectoryIndex = function (originalUrl, index) {
      var url = new URL(originalUrl);
      if (url.pathname.slice(-1) === '/') {
        url.pathname += index;
      }
      return url.toString();
    };
  
  var cleanResponse = function (originalResponse) {
      // If this is not a redirected response, then we don't have to do anything.
      if (!originalResponse.redirected) {
        return Promise.resolve(originalResponse);
      }
  
      // Firefox 50 and below doesn't support the Response.body stream, so we may
      // need to read the entire body to memory as a Blob.
      var bodyPromise = 'body' in originalResponse ?
        Promise.resolve(originalResponse.body) :
        originalResponse.blob();
  
      return bodyPromise.then(function(body) {
        // new Response() is happy when passed either a stream or a Blob.
        return new Response(body, {
          headers: originalResponse.headers,
          status: originalResponse.status,
          statusText: originalResponse.statusText
        });
      });
    };
  
  var createCacheKey = function (originalUrl, paramName, paramValue,
                             dontCacheBustUrlsMatching) {
      // Create a new URL object to avoid modifying originalUrl.
      var url = new URL(originalUrl);
  
      // If dontCacheBustUrlsMatching is not set, or if we don't have a match,
      // then add in the extra cache-busting URL parameter.
      if (!dontCacheBustUrlsMatching ||
          !(url.pathname.match(dontCacheBustUrlsMatching))) {
        url.search += (url.search ? '&' : '') +
          encodeURIComponent(paramName) + '=' + encodeURIComponent(paramValue);
      }
  
      return url.toString();
    };
  
  var isPathWhitelisted = function (whitelist, absoluteUrlString) {
      // If the whitelist is empty, then consider all URLs to be whitelisted.
      if (whitelist.length === 0) {
        return true;
      }
  
      // Otherwise compare each path regex to the path of the URL passed in.
      var path = (new URL(absoluteUrlString)).pathname;
      return whitelist.some(function(whitelistedPathRegex) {
        return path.match(whitelistedPathRegex);
      });
    };
  
  var stripIgnoredUrlParameters = function (originalUrl,
      ignoreUrlParametersMatching) {
      var url = new URL(originalUrl);
      // Remove the hash; see https://github.com/GoogleChrome/sw-precache/issues/290
      url.hash = '';
  
      url.search = url.search.slice(1) // Exclude initial '?'
        .split('&') // Split into an array of 'key=value' strings
        .map(function(kv) {
          return kv.split('='); // Split each 'key=value' string into a [key, value] array
        })
        .filter(function(kv) {
          return ignoreUrlParametersMatching.every(function(ignoredRegex) {
            return !ignoredRegex.test(kv[0]); // Return true iff the key doesn't match any of the regexes.
          });
        })
        .map(function(kv) {
          return kv.join('='); // Join each [key, value] array into a 'key=value' string
        })
        .join('&'); // Join the array of 'key=value' strings into a string with '&' in between each
  
      return url.toString();
    };
  
  
  var hashParamName = '_sw-precache';
  var urlsToCacheKeys = new Map(
    precacheConfig.map(function(item) {
      var relativeUrl = item[0];
      var hash = item[1];
      var absoluteUrl = new URL(relativeUrl, self.location);
      var cacheKey = createCacheKey(absoluteUrl, hashParamName, hash, false);
      return [absoluteUrl.toString(), cacheKey];
    })
  );
  
  function setOfCachedUrls(cache) {
    return cache.keys().then(function(requests) {
      return requests.map(function(request) {
        return request.url;
      });
    }).then(function(urls) {
      return new Set(urls);
    });
  }
  
  self.addEventListener('install', function(event) {
    event.waitUntil(
      caches.open(cacheName).then(function(cache) {
        return setOfCachedUrls(cache).then(function(cachedUrls) {
          return Promise.all(
            Array.from(urlsToCacheKeys.values()).map(function(cacheKey) {
              // If we don't have a key matching url in the cache already, add it.
              if (!cachedUrls.has(cacheKey)) {
                var request = new Request(cacheKey, {credentials: 'same-origin'});
                return fetch(request).then(function(response) {
                  // Bail out of installation unless we get back a 200 OK for
                  // every request.
                  if (!response.ok) {
                    throw new Error('Request for ' + cacheKey + ' returned a ' +
                      'response with status ' + response.status);
                  }
  
                  return cleanResponse(response).then(function(responseToCache) {
                    return cache.put(cacheKey, responseToCache);
                  });
                });
              }
            })
          );
        });
      }).then(function() {
        
        // Force the SW to transition from installing -> active state
        return self.skipWaiting();
        
      })
    );
  });
  
  self.addEventListener('activate', function(event) {
    var setOfExpectedUrls = new Set(urlsToCacheKeys.values());
  
    event.waitUntil(
      caches.open(cacheName).then(function(cache) {
        return cache.keys().then(function(existingRequests) {
          return Promise.all(
            existingRequests.map(function(existingRequest) {
              if (!setOfExpectedUrls.has(existingRequest.url)) {
                return cache.delete(existingRequest);
              }
            })
          );
        });
      }).then(function() {
        
        return self.clients.claim();
        
      })
    );
  });
  
  
  self.addEventListener('fetch', function(event) {
    if (event.request.method === 'GET') {
      // Should we call event.respondWith() inside this fetch event handler?
      // This needs to be determined synchronously, which will give other fetch
      // handlers a chance to handle the request if need be.
      var shouldRespond;
  
      // First, remove all the ignored parameters and hash fragment, and see if we
      // have that URL in our cache. If so, great! shouldRespond will be true.
      var url = stripIgnoredUrlParameters(event.request.url, ignoreUrlParametersMatching);
      shouldRespond = urlsToCacheKeys.has(url);
  
      // If shouldRespond is false, check again, this time with 'index.html'
      // (or whatever the directoryIndex option is set to) at the end.
      var directoryIndex = 'index.html';
      if (!shouldRespond && directoryIndex) {
        url = addDirectoryIndex(url, directoryIndex);
        shouldRespond = urlsToCacheKeys.has(url);
      }
  
      // If shouldRespond is still false, check to see if this is a navigation
      // request, and if so, whether the URL matches navigateFallbackWhitelist.
      var navigateFallback = '';
      if (!shouldRespond &&
          navigateFallback &&
          (event.request.mode === 'navigate') &&
          isPathWhitelisted([], event.request.url)) {
        url = new URL(navigateFallback, self.location).toString();
        shouldRespond = urlsToCacheKeys.has(url);
      }
  
      // If shouldRespond was set to true at any point, then call
      // event.respondWith(), using the appropriate cache key.
      if (shouldRespond) {
        event.respondWith(
          caches.open(cacheName).then(function(cache) {
            return cache.match(urlsToCacheKeys.get(url)).then(function(response) {
              if (response) {
                return response;
              }
              throw Error('The cached response that was expected is missing.');
            });
          }).catch(function(e) {
            // Fall back to just fetch()ing the request if some unexpected error
            // prevented the cached response from being valid.
            console.warn('Couldn\'t serve response for "%s" from cache: %O', event.request.url, e);
            return fetch(event.request);
          })
        );
      }
    }
  });
  
  
  
  
  
  
  
  