<commit_before>slugify = require('underscore.string').slugify # TODO: why _.string on client and _.str on server?

clone = (obj) ->
  return obj if obj is null or typeof (obj) isnt 'object'
  temp = obj.constructor()
  for key of obj
    temp[key] = clone(obj[key])
  temp

combineAncestralObject = (obj, propertyName) ->
  combined = {}
  while obj?[propertyName]
    for key, value of obj[propertyName]
      continue if combined[key]
      combined[key] = value
    if obj.__proto__
      obj = obj.__proto__
    else
      # IE has no __proto__. TODO: does this even work? At most it doesn't crash.
      obj = Object.getPrototypeOf(obj)
  combined

countries = [
  {country: 'united-states', countryCode: 'US', ageOfConsent: 13}
  {country: 'china', countryCode: 'CN'}
  {country: 'brazil', countryCode: 'BR'}

  # Loosely ordered by decreasing traffic as measured 2016-09-01 - 2016-11-07
  # TODO: switch to alphabetical ordering
  {country: 'united-kingdom', countryCode: 'GB', inEU: true, ageOfConsent: 13}
  {country: 'russia', countryCode: 'RU'}
  {country: 'australia', countryCode: 'AU'}
  {country: 'canada', countryCode: 'CA'}
  {country: 'france', countryCode: 'FR', inEU: true, ageOfConsent: 15}
  {country: 'taiwan', countryCode: 'TW'}
  {country: 'ukraine', countryCode: 'UA'}
  {country: 'poland', countryCode: 'PL', inEU: true, ageOfConsent: 13}
  {country: 'spain', countryCode: 'ES', inEU: true, ageOfConsent: 13}
  {country: 'germany', countryCode: 'DE', inEU: true, ageOfConsent: 16}
  {country: 'netherlands', countryCode: 'NL', inEU: true, ageOfConsent: 16}
  {country: 'hungary', countryCode: 'HU', inEU: true, ageOfConsent: 16}
  {country: 'japan', countryCode: 'JP'}
  {country: 'turkey', countryCode: 'TR'}
  {country: 'south-africa', countryCode: 'ZA'}
  {country: 'indonesia', countryCode: 'ID'}
  {country: 'new-zealand', countryCode: 'NZ'}
  {country: 'finland', countryCode: 'FI', inEU: true, ageOfConsent: 13}
  {country: 'south-korea', countryCode: 'KR'}
  {country: 'mexico', countryCode: 'MX'}
  {country: 'vietnam', countryCode: 'VN'}
  {country: 'singapore', countryCode: 'SG'}
  {country: 'colombia', countryCode: 'CO'}
  {country: 'india', countryCode: 'IN'}
  {country: 'thailand', countryCode: 'TH'}
  {country: 'belgium', countryCode: 'BE', inEU: true, ageOfConsent: 13}
  {country: 'sweden', countryCode: 'SE', inEU: true, ageOfConsent: 13}
  {country: 'denmark', countryCode: 'DK', inEU: true, ageOfConsent: 13}
  {country: 'czech-republic', countryCode: 'CZ', inEU: true, ageOfConsent: 15}
  {country: 'hong-kong', countryCode: 'HK'}
  {country: 'italy', countryCode: 'IT', inEU: true, ageOfConsent: 16}
  {country: 'romania', countryCode: 'RO', inEU: true, ageOfConsent: 16}
  {country: 'belarus', countryCode: 'BY'}
  {country: 'norway', countryCode: 'NO', inEU: true, ageOfConsent: 13}  # GDPR applies to EFTA
  {country: 'philippines', countryCode: 'PH'}
  {country: 'lithuania', countryCode: 'LT', inEU: true, ageOfConsent: 16}
  {country: 'argentina', countryCode: 'AR'}
  {country: 'malaysia', countryCode: 'MY'}
  {country: 'pakistan', countryCode: 'PK'}
  {country: 'serbia', countryCode: 'RS'}
  {country: 'greece', countryCode: 'GR', inEU: true, ageOfConsent: 15}
  {country: 'israel', countryCode: 'IL', inEU: true}
  {country: 'portugal', countryCode: 'PT', inEU: true, ageOfConsent: 13}
  {country: 'slovakia', countryCode: 'SK', inEU: true, ageOfConsent: 16}
  {country: 'ireland', countryCode: 'IE', inEU: true, ageOfConsent: 16}
  {country: 'switzerland', countryCode: 'CH', inEU: true, ageOfConsent: 16}  # GDPR applies to EFTA
  {country: 'peru', countryCode: 'PE'}
  {country: 'bulgaria', countryCode: 'BG', inEU: true, ageOfConsent: 14}
  {country: 'venezuela', countryCode: 'VE'}
  {country: 'austria', countryCode: 'AT', inEU: true, ageOfConsent: 14}
  {country: 'croatia', countryCode: 'HR', inEU: true, ageOfConsent: 16}
  {country: 'saudia-arabia', countryCode: 'SA'}
  {country: 'chile', countryCode: 'CL'}
  {country: 'united-arab-emirates', countryCode: 'AE'}
  {country: 'kazakhstan', countryCode: 'KZ'}
  {country: 'estonia', countryCode: 'EE', inEU: true, ageOfConsent: 13}
  {country: 'iran', countryCode: 'IR'}
  {country: 'egypt', countryCode: 'EG'}
  {country: 'ecuador', countryCode: 'EC'}
  {country: 'slovenia', countryCode: 'SI', inEU: true, ageOfConsent: 15}
  {country: 'macedonia', countryCode: 'MK'}
  {country: 'cyprus', countryCode: 'CY', inEU: true, ageOfConsent: 14}
  {country: 'latvia', countryCode: 'LV', inEU: true, ageOfConsent: 13}
  {country: 'luxembourg', countryCode: 'LU', inEU: true, ageOfConsent: 16}
  {country: 'malta', countryCode: 'MT', inEU: true, ageOfConsent: 16}
  {country: 'lichtenstein', countryCode: 'LI', inEU: true}  # GDPR applies to EFTA
  {country: 'iceland', countryCode: 'IS', inEU: true}  # GDPR applies to EFTA
]

inEU = (country) -> !!_.find(countries, (c) => c.country is slugify(country))?.inEU

ageOfConsent = (countryName, defaultIfUnknown=0) ->
  return defaultIfUnknown unless countryName
  country = _.find(countries, (c) => c.country is slugify(countryName))
  return defaultIfUnknown unless country
  return country.ageOfConsent if country.ageOfConsent
  return 16 if country.inEU
  return defaultIfUnknown

freeCampaignIds = ['5d1a8368abd38e8b5363bad9'] # CH1 campaign
internalCampaignIds = ['5eb34fc8dc0fd35e8eae66b0'] # CH2 playtest

courseIDs =
  CHAPTER_ONE: '5d41d731a8d1836b5aa3cba1'
  CHAPTER_TWO: '5d8a57abe8919b28d5113af1'
  CHAPTER_TWO_PLAYTEST: '5eb34fc8dc0fd35e8eae66b0'
  CHAPTER_THREE: '5e27600d1c9d440000ac3ee7'

orderedCourseIDs = [
  courseIDs.CHAPTER_ONE
  courseIDs.CHAPTER_TWO
  courseIDs.CHAPTER_TWO_PLAYTEST
  courseIDs.CHAPTER_THREE
]

courseAcronyms = {}
courseAcronyms[courseIDs.CHAPTER_ONE] = 'CH1'
courseAcronyms[courseIDs.CHAPTER_TWO] = 'CH2'
courseAcronyms[courseIDs.CHAPTER_TWO_PLAYTEST] = 'CH2P'
courseAcronyms[courseIDs.CHAPTER_THREE] = 'CH3'

# Harcoding module names for simplicity
# Use db to store these later when we add sophisticated module functionality, right now its only used for UI
courseModules = {}
courseModules[courseIDs.CHAPTER_ONE] = {
  '1': 'Objects and Methods'
}
courseModules[courseIDs.CHAPTER_TWO] = {
  '1': 'Algorithms and Syntax',
  '2': 'Debugging',
  '3': 'Variables',
  '4': 'Conditionals',
  '5': 'Capstone Intro',
  '6': 'Capstone Project'
}
courseModules[courseIDs.CHAPTER_TWO_PLAYTEST] = {
  '1': 'Algorithms and Syntax',
  '2': 'Debugging',
  '3': 'Variables',
  '4': 'Conditionals',
  '5': 'Capstone Intro',
  '6': 'Capstone Project'
}
courseModules[courseIDs.CHAPTER_THREE] = {
  '1': 'Review',
  '2': 'For Loops',
  '3': 'Nesting',
  '4': 'While Loops',
  '5': 'Capstone'
}

hourOfCodeOptions = {
  campaignId: freeCampaignIds[0],
  courseId: courseIDs.CHAPTER_ONE,
  name: 'Chapter 1: Up The Mountain',
  progressModalAfter: 1500000 #25 mins
}

registerHocProgressModalCheck = ->
  hocProgressModalCheck = setInterval(() =>
    if window.sessionStorage?.getItem('hoc_progress_modal_time') < new Date().getTime()
      window.sessionStorage.setItem('show_hoc_progress_modal', true)
      window.sessionStorage.removeItem('hoc_progress_modal_time')
      clearInterval(hocProgressModalCheck)
  , 60000) # every 1 min

petThangIDs = [
  '578d320d15e2501f00a585bd' # Wolf Pup
  '5744e3683af6bf590cd27371' # Cougar
  '5786a472a6c64135009238d3' # Raven
  '577d5d4dab818b210046b3bf' # Pugicorn
  '58c74b7c3d4a3d2900d43b7e' # Brown Rat
  '58c7614a62cc3a1f00442240' # Yetibab
  '58a262520b43652f00dad75e' # Phoenix
  '57869cf7bd31c14400834028' # Frog
  '578691f9bd31c1440083251d' # Polar Bear Cub
  '58a2712b0b43652f00dae5a4' # Blue Fox
  '58c737140ca7852e005deb8a' # Mimic
  '57586f0a22179b2800efda37' # Baby Griffin
]<commit_msg>Add Chapter 1 Revision to courses (#471)<commit_after>slugify = require('underscore.string').slugify # TODO: why _.string on client and _.str on server?

clone = (obj) ->
  return obj if obj is null or typeof (obj) isnt 'object'
  temp = obj.constructor()
  for key of obj
    temp[key] = clone(obj[key])
  temp

combineAncestralObject = (obj, propertyName) ->
  combined = {}
  while obj?[propertyName]
    for key, value of obj[propertyName]
      continue if combined[key]
      combined[key] = value
    if obj.__proto__
      obj = obj.__proto__
    else
      # IE has no __proto__. TODO: does this even work? At most it doesn't crash.
      obj = Object.getPrototypeOf(obj)
  combined

countries = [
  {country: 'united-states', countryCode: 'US', ageOfConsent: 13}
  {country: 'china', countryCode: 'CN'}
  {country: 'brazil', countryCode: 'BR'}

  # Loosely ordered by decreasing traffic as measured 2016-09-01 - 2016-11-07
  # TODO: switch to alphabetical ordering
  {country: 'united-kingdom', countryCode: 'GB', inEU: true, ageOfConsent: 13}
  {country: 'russia', countryCode: 'RU'}
  {country: 'australia', countryCode: 'AU'}
  {country: 'canada', countryCode: 'CA'}
  {country: 'france', countryCode: 'FR', inEU: true, ageOfConsent: 15}
  {country: 'taiwan', countryCode: 'TW'}
  {country: 'ukraine', countryCode: 'UA'}
  {country: 'poland', countryCode: 'PL', inEU: true, ageOfConsent: 13}
  {country: 'spain', countryCode: 'ES', inEU: true, ageOfConsent: 13}
  {country: 'germany', countryCode: 'DE', inEU: true, ageOfConsent: 16}
  {country: 'netherlands', countryCode: 'NL', inEU: true, ageOfConsent: 16}
  {country: 'hungary', countryCode: 'HU', inEU: true, ageOfConsent: 16}
  {country: 'japan', countryCode: 'JP'}
  {country: 'turkey', countryCode: 'TR'}
  {country: 'south-africa', countryCode: 'ZA'}
  {country: 'indonesia', countryCode: 'ID'}
  {country: 'new-zealand', countryCode: 'NZ'}
  {country: 'finland', countryCode: 'FI', inEU: true, ageOfConsent: 13}
  {country: 'south-korea', countryCode: 'KR'}
  {country: 'mexico', countryCode: 'MX'}
  {country: 'vietnam', countryCode: 'VN'}
  {country: 'singapore', countryCode: 'SG'}
  {country: 'colombia', countryCode: 'CO'}
  {country: 'india', countryCode: 'IN'}
  {country: 'thailand', countryCode: 'TH'}
  {country: 'belgium', countryCode: 'BE', inEU: true, ageOfConsent: 13}
  {country: 'sweden', countryCode: 'SE', inEU: true, ageOfConsent: 13}
  {country: 'denmark', countryCode: 'DK', inEU: true, ageOfConsent: 13}
  {country: 'czech-republic', countryCode: 'CZ', inEU: true, ageOfConsent: 15}
  {country: 'hong-kong', countryCode: 'HK'}
  {country: 'italy', countryCode: 'IT', inEU: true, ageOfConsent: 16}
  {country: 'romania', countryCode: 'RO', inEU: true, ageOfConsent: 16}
  {country: 'belarus', countryCode: 'BY'}
  {country: 'norway', countryCode: 'NO', inEU: true, ageOfConsent: 13}  # GDPR applies to EFTA
  {country: 'philippines', countryCode: 'PH'}
  {country: 'lithuania', countryCode: 'LT', inEU: true, ageOfConsent: 16}
  {country: 'argentina', countryCode: 'AR'}
  {country: 'malaysia', countryCode: 'MY'}
  {country: 'pakistan', countryCode: 'PK'}
  {country: 'serbia', countryCode: 'RS'}
  {country: 'greece', countryCode: 'GR', inEU: true, ageOfConsent: 15}
  {country: 'israel', countryCode: 'IL', inEU: true}
  {country: 'portugal', countryCode: 'PT', inEU: true, ageOfConsent: 13}
  {country: 'slovakia', countryCode: 'SK', inEU: true, ageOfConsent: 16}
  {country: 'ireland', countryCode: 'IE', inEU: true, ageOfConsent: 16}
  {country: 'switzerland', countryCode: 'CH', inEU: true, ageOfConsent: 16}  # GDPR applies to EFTA
  {country: 'peru', countryCode: 'PE'}
  {country: 'bulgaria', countryCode: 'BG', inEU: true, ageOfConsent: 14}
  {country: 'venezuela', countryCode: 'VE'}
  {country: 'austria', countryCode: 'AT', inEU: true, ageOfConsent: 14}
  {country: 'croatia', countryCode: 'HR', inEU: true, ageOfConsent: 16}
  {country: 'saudia-arabia', countryCode: 'SA'}
  {country: 'chile', countryCode: 'CL'}
  {country: 'united-arab-emirates', countryCode: 'AE'}
  {country: 'kazakhstan', countryCode: 'KZ'}
  {country: 'estonia', countryCode: 'EE', inEU: true, ageOfConsent: 13}
  {country: 'iran', countryCode: 'IR'}
  {country: 'egypt', countryCode: 'EG'}
  {country: 'ecuador', countryCode: 'EC'}
  {country: 'slovenia', countryCode: 'SI', inEU: true, ageOfConsent: 15}
  {country: 'macedonia', countryCode: 'MK'}
  {country: 'cyprus', countryCode: 'CY', inEU: true, ageOfConsent: 14}
  {country: 'latvia', countryCode: 'LV', inEU: true, ageOfConsent: 13}
  {country: 'luxembourg', countryCode: 'LU', inEU: true, ageOfConsent: 16}
  {country: 'malta', countryCode: 'MT', inEU: true, ageOfConsent: 16}
  {country: 'lichtenstein', countryCode: 'LI', inEU: true}  # GDPR applies to EFTA
  {country: 'iceland', countryCode: 'IS', inEU: true}  # GDPR applies to EFTA
]

inEU = (country) -> !!_.find(countries, (c) => c.country is slugify(country))?.inEU

ageOfConsent = (countryName, defaultIfUnknown=0) ->
  return defaultIfUnknown unless countryName
  country = _.find(countries, (c) => c.country is slugify(countryName))
  return defaultIfUnknown unless country
  return country.ageOfConsent if country.ageOfConsent
  return 16 if country.inEU
  return defaultIfUnknown

freeCampaignIds = ['5d1a8368abd38e8b5363bad9'] # CH1 campaign
internalCampaignIds = ['5eb34fc8dc0fd35e8eae66b0'] # CH2 playtest

courseIDs =
  CHAPTER_ONE: '5d41d731a8d1836b5aa3cba1'
  CHAPTER_TWO: '5d8a57abe8919b28d5113af1'
  CHAPTER_TWO_PLAYTEST: '5eb34fc8dc0fd35e8eae66b0'
  CHAPTER_THREE: '5e27600d1c9d440000ac3ee7'
  CHAPTER_ONE_REVISION_PLAYTEST: '5f0cb0b7a2492bba0b3520df'

orderedCourseIDs = [
  courseIDs.CHAPTER_ONE
  courseIDs.CHAPTER_TWO
  courseIDs.CHAPTER_TWO_PLAYTEST
  courseIDs.CHAPTER_THREE
  courseIDs.CHAPTER_ONE_REVISION_PLAYTEST
]

courseAcronyms = {}
courseAcronyms[courseIDs.CHAPTER_ONE] = 'CH1'
courseAcronyms[courseIDs.CHAPTER_TWO] = 'CH2'
courseAcronyms[courseIDs.CHAPTER_TWO_PLAYTEST] = 'CH2P'
courseAcronyms[courseIDs.CHAPTER_THREE] = 'CH3'
courseAcronyms[courseIDs.CHAPTER_ONE_REVISION_PLAYTEST] = 'CH1P'

# Harcoding module names for simplicity
# Use db to store these later when we add sophisticated module functionality, right now its only used for UI
courseModules = {}
courseModules[courseIDs.CHAPTER_ONE] = {
  '1': 'Objects and Methods'
}
courseModules[courseIDs.CHAPTER_TWO] = {
  '1': 'Algorithms and Syntax',
  '2': 'Debugging',
  '3': 'Variables',
  '4': 'Conditionals',
  '5': 'Capstone Intro',
  '6': 'Capstone Project'
}
courseModules[courseIDs.CHAPTER_TWO_PLAYTEST] = {
  '1': 'Algorithms and Syntax',
  '2': 'Debugging',
  '3': 'Variables',
  '4': 'Conditionals',
  '5': 'Capstone Intro',
  '6': 'Capstone Project'
}
courseModules[courseIDs.CHAPTER_THREE] = {
  '1': 'Review',
  '2': 'For Loops',
  '3': 'Nesting',
  '4': 'While Loops',
  '5': 'Capstone'
}
courseModules[courseIDs.CHAPTER_ONE_REVISION_PLAYTEST] = {
  '1': 'Objects and Methods'
}

hourOfCodeOptions = {
  campaignId: freeCampaignIds[0],
  courseId: courseIDs.CHAPTER_ONE,
  name: 'Chapter 1: Up The Mountain',
  progressModalAfter: 1500000 #25 mins
}

registerHocProgressModalCheck = ->
  hocProgressModalCheck = setInterval(() =>
    if window.sessionStorage?.getItem('hoc_progress_modal_time') < new Date().getTime()
      window.sessionStorage.setItem('show_hoc_progress_modal', true)
      window.sessionStorage.removeItem('hoc_progress_modal_time')
      clearInterval(hocProgressModalCheck)
  , 60000) # every 1 min

petThangIDs = [
  '578d320d15e2501f00a585bd' # Wolf Pup
  '5744e3683af6bf590cd27371' # Cougar
  '5786a472a6c64135009238d3' # Raven
  '577d5d4dab818b210046b3bf' # Pugicorn
  '58c74b7c3d4a3d2900d43b7e' # Brown Rat
  '58c7614a62cc3a1f00442240' # Yetibab
  '58a262520b43652f00dad75e' # Phoenix
  '57869cf7bd31c14400834028' # Frog
  '578691f9bd31c1440083251d' # Polar Bear Cub
  '58a2712b0b43652f00dae5a4' # Blue Fox
  '58c737140ca7852e005deb8a' # Mimic
  '57586f0a22179b2800efda37' # Baby Griffin
]
{'fraction_non_alphanumeric': 0.15161904761904763, 'fraction_numerical': 0.053142857142857144, 'mean_word_length': 5.481893004115227, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '770648', 'n_tokens_mistral': 6565, 'n_tokens_neox': 5940, 'n_words': 1442}